mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-common
synced 2026-01-21 11:56:44 +00:00
fix 16 bpp LZ image decompression
LZ image decompression was broken for 16 bpp: - stride was computed not computed correctly (as width*4). This caused also a buffer underflow; - stride in pixman is always multiple of 4 bytes (so for 16 bpp is ALIGN(width*2, 4)) so image decompressed by lz_decode as some missing bytes to be fixed. The alignment code is reused from LZ4 function. This fix also https://bugzilla.redhat.com/show_bug.cgi?id=1285469. Signed-off-by: Frediano Ziglio <fziglio@redhat.com> Acked-by: Pavel Grunt <pgrunt@redhat.com>
This commit is contained in:
parent
2a4bf49edd
commit
5603961ffa
@ -515,13 +515,30 @@ static pixman_image_t *canvas_get_jpeg(CanvasBase *canvas, SpiceImage *image)
|
|||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void canvas_fix_alignment(uint8_t *bits,
|
||||||
|
int stride_encoded, int stride_pixman,
|
||||||
|
int height)
|
||||||
|
{
|
||||||
|
if (stride_pixman > stride_encoded) {
|
||||||
|
// Fix the row alignment
|
||||||
|
int row;
|
||||||
|
uint8_t *dest = bits;
|
||||||
|
for (row = height - 1; row > 0; --row) {
|
||||||
|
uint32_t *dest_aligned, *dest_misaligned;
|
||||||
|
dest_aligned = (uint32_t *)(dest + stride_pixman*row);
|
||||||
|
dest_misaligned = (uint32_t*)(dest + stride_encoded*row);
|
||||||
|
memmove(dest_aligned, dest_misaligned, stride_encoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef USE_LZ4
|
#ifdef USE_LZ4
|
||||||
static pixman_image_t *canvas_get_lz4(CanvasBase *canvas, SpiceImage *image)
|
static pixman_image_t *canvas_get_lz4(CanvasBase *canvas, SpiceImage *image)
|
||||||
{
|
{
|
||||||
pixman_image_t *surface = NULL;
|
pixman_image_t *surface = NULL;
|
||||||
int dec_size, enc_size, available;
|
int dec_size, enc_size, available;
|
||||||
int stride, stride_abs, stride_encoded;
|
int stride, stride_abs, stride_encoded;
|
||||||
uint8_t *dest, *data, *data_end;
|
uint8_t *dest, *data, *data_end, *bits;
|
||||||
int width, height, top_down;
|
int width, height, top_down;
|
||||||
LZ4_streamDecode_t *stream;
|
LZ4_streamDecode_t *stream;
|
||||||
uint8_t spice_format;
|
uint8_t spice_format;
|
||||||
@ -576,6 +593,7 @@ static pixman_image_t *canvas_get_lz4(CanvasBase *canvas, SpiceImage *image)
|
|||||||
if (!top_down) {
|
if (!top_down) {
|
||||||
dest -= (stride_abs * (height - 1));
|
dest -= (stride_abs * (height - 1));
|
||||||
}
|
}
|
||||||
|
bits = dest;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Read next compressed block
|
// Read next compressed block
|
||||||
@ -594,20 +612,7 @@ static pixman_image_t *canvas_get_lz4(CanvasBase *canvas, SpiceImage *image)
|
|||||||
data += enc_size;
|
data += enc_size;
|
||||||
} while (data < data_end);
|
} while (data < data_end);
|
||||||
|
|
||||||
if (stride_abs > stride_encoded) {
|
canvas_fix_alignment(bits, stride_encoded, stride_abs, height);
|
||||||
// Fix the row alignment
|
|
||||||
int row;
|
|
||||||
dest = (uint8_t *)pixman_image_get_data(surface);
|
|
||||||
if (!top_down) {
|
|
||||||
dest -= (stride_abs * (height - 1));
|
|
||||||
}
|
|
||||||
for (row = height - 1; row > 0; --row) {
|
|
||||||
uint32_t *dest_aligned, *dest_misaligned;
|
|
||||||
dest_aligned = (uint32_t *)(dest + stride_abs*row);
|
|
||||||
dest_misaligned = (uint32_t*)(dest + stride_encoded*row);
|
|
||||||
memmove(dest_aligned, dest_misaligned, stride_encoded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LZ4_freeStreamDecode(stream);
|
LZ4_freeStreamDecode(stream);
|
||||||
return surface;
|
return surface;
|
||||||
@ -782,7 +787,6 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, SpiceImage *image,
|
|||||||
uint8_t *comp_buf = NULL;
|
uint8_t *comp_buf = NULL;
|
||||||
int comp_size;
|
int comp_size;
|
||||||
uint8_t *decomp_buf = NULL;
|
uint8_t *decomp_buf = NULL;
|
||||||
uint8_t *src;
|
|
||||||
pixman_format_code_t pixman_format;
|
pixman_format_code_t pixman_format;
|
||||||
LzImageType type, as_type;
|
LzImageType type, as_type;
|
||||||
SpicePalette *palette;
|
SpicePalette *palette;
|
||||||
@ -790,6 +794,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, SpiceImage *image,
|
|||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
int top_down;
|
int top_down;
|
||||||
|
int stride_encoded;
|
||||||
int stride;
|
int stride;
|
||||||
int free_palette;
|
int free_palette;
|
||||||
|
|
||||||
@ -818,10 +823,12 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, SpiceImage *image,
|
|||||||
lz_decode_begin(lz_data->lz, comp_buf, comp_size, &type,
|
lz_decode_begin(lz_data->lz, comp_buf, comp_size, &type,
|
||||||
&width, &height, &n_comp_pixels, &top_down, palette);
|
&width, &height, &n_comp_pixels, &top_down, palette);
|
||||||
|
|
||||||
|
stride_encoded = width;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LZ_IMAGE_TYPE_RGBA:
|
case LZ_IMAGE_TYPE_RGBA:
|
||||||
as_type = LZ_IMAGE_TYPE_RGBA;
|
as_type = LZ_IMAGE_TYPE_RGBA;
|
||||||
pixman_format = PIXMAN_LE_a8r8g8b8;
|
pixman_format = PIXMAN_LE_a8r8g8b8;
|
||||||
|
stride_encoded *= 4;
|
||||||
break;
|
break;
|
||||||
case LZ_IMAGE_TYPE_RGB32:
|
case LZ_IMAGE_TYPE_RGB32:
|
||||||
case LZ_IMAGE_TYPE_RGB24:
|
case LZ_IMAGE_TYPE_RGB24:
|
||||||
@ -832,6 +839,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, SpiceImage *image,
|
|||||||
case LZ_IMAGE_TYPE_PLT8:
|
case LZ_IMAGE_TYPE_PLT8:
|
||||||
as_type = LZ_IMAGE_TYPE_RGB32;
|
as_type = LZ_IMAGE_TYPE_RGB32;
|
||||||
pixman_format = PIXMAN_LE_x8r8g8b8;
|
pixman_format = PIXMAN_LE_x8r8g8b8;
|
||||||
|
stride_encoded *= 4;
|
||||||
break;
|
break;
|
||||||
case LZ_IMAGE_TYPE_A8:
|
case LZ_IMAGE_TYPE_A8:
|
||||||
as_type = LZ_IMAGE_TYPE_A8;
|
as_type = LZ_IMAGE_TYPE_A8;
|
||||||
@ -843,9 +851,11 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, SpiceImage *image,
|
|||||||
canvas->format == SPICE_SURFACE_FMT_32_ARGB)) {
|
canvas->format == SPICE_SURFACE_FMT_32_ARGB)) {
|
||||||
as_type = LZ_IMAGE_TYPE_RGB32;
|
as_type = LZ_IMAGE_TYPE_RGB32;
|
||||||
pixman_format = PIXMAN_LE_x8r8g8b8;
|
pixman_format = PIXMAN_LE_x8r8g8b8;
|
||||||
|
stride_encoded *= 4;
|
||||||
} else {
|
} else {
|
||||||
as_type = LZ_IMAGE_TYPE_RGB16;
|
as_type = LZ_IMAGE_TYPE_RGB16;
|
||||||
pixman_format = PIXMAN_x1r5g5b5;
|
pixman_format = PIXMAN_x1r5g5b5;
|
||||||
|
stride_encoded *= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -865,18 +875,18 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, SpiceImage *image,
|
|||||||
alloc_lz_image_surface(&lz_data->decode_data, pixman_format,
|
alloc_lz_image_surface(&lz_data->decode_data, pixman_format,
|
||||||
width, height, n_comp_pixels, top_down);
|
width, height, n_comp_pixels, top_down);
|
||||||
|
|
||||||
src = (uint8_t *)pixman_image_get_data(lz_data->decode_data.out_surface);
|
stride = pixman_image_get_stride(lz_data->decode_data.out_surface);
|
||||||
|
stride = abs(stride);
|
||||||
|
|
||||||
stride = (n_comp_pixels / height) * 4;
|
decomp_buf = (uint8_t *)pixman_image_get_data(lz_data->decode_data.out_surface);
|
||||||
if (!top_down) {
|
if (!top_down) {
|
||||||
stride = -stride;
|
decomp_buf -= stride * (height - 1);
|
||||||
decomp_buf = src + stride * (height - 1);
|
|
||||||
} else {
|
|
||||||
decomp_buf = src;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lz_decode(lz_data->lz, as_type, decomp_buf);
|
lz_decode(lz_data->lz, as_type, decomp_buf);
|
||||||
|
|
||||||
|
canvas_fix_alignment(decomp_buf, stride_encoded, stride, height);
|
||||||
|
|
||||||
if (free_palette) {
|
if (free_palette) {
|
||||||
free(palette);
|
free(palette);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user