From e8d016187810f9c038370da14c24d744ed250e14 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Thu, 14 Apr 2016 17:56:40 +0100
Subject: [PATCH 2/5] 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>
---
spice-common/common/canvas_base.c | 54 +++++++++++++++++++++++----------------
1 file changed, 32 insertions(+), 22 deletions(-)
diff --git a/spice-common/common/canvas_base.c b/spice-common/common/canvas_base.c
index fa4d373..45dd75f 100644
--- a/spice-common/common/canvas_base.c
+++ b/spice-common/common/canvas_base.c
@@ -515,13 +515,30 @@ static pixman_image_t *canvas_get_jpeg(CanvasBase *canvas, SpiceImage *image)
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
static pixman_image_t *canvas_get_lz4(CanvasBase *canvas, SpiceImage *image)
{
pixman_image_t *surface = NULL;
int dec_size, enc_size, available;
int stride, stride_abs, stride_encoded;
- uint8_t *dest, *data, *data_end;
+ uint8_t *dest, *data, *data_end, *bits;
int width, height, top_down;
LZ4_streamDecode_t *stream;
uint8_t spice_format;
@@ -576,6 +593,7 @@ static pixman_image_t *canvas_get_lz4(CanvasBase *canvas, SpiceImage *image)
if (!top_down) {
dest -= (stride_abs * (height - 1));
}
+ bits = dest;
do {
// Read next compressed block
@@ -594,20 +612,7 @@ static pixman_image_t *canvas_get_lz4(CanvasBase *canvas, SpiceImage *image)
data += enc_size;
} while (data < data_end);
- if (stride_abs > stride_encoded) {
- // 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);
- }
- }
+ canvas_fix_alignment(bits, stride_encoded, stride_abs, height);
LZ4_freeStreamDecode(stream);
return surface;
@@ -782,7 +787,6 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, SpiceImage *image,
uint8_t *comp_buf = NULL;
int comp_size;
uint8_t *decomp_buf = NULL;
- uint8_t *src;
pixman_format_code_t pixman_format;
LzImageType type, as_type;
SpicePalette *palette;
@@ -790,6 +794,7 @@ static pixman_image_t *canvas_get_lz(CanvasBase *canvas, SpiceImage *image,
int width;
int height;
int top_down;
+ int stride_encoded;
int stride;
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,
&width, &height, &n_comp_pixels, &top_down, palette);
+ stride_encoded = width;
switch (type) {
case LZ_IMAGE_TYPE_RGBA:
as_type = LZ_IMAGE_TYPE_RGBA;
pixman_format = PIXMAN_LE_a8r8g8b8;
+ stride_encoded *= 4;
break;
case LZ_IMAGE_TYPE_RGB32:
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:
as_type = LZ_IMAGE_TYPE_RGB32;
pixman_format = PIXMAN_LE_x8r8g8b8;
+ stride_encoded *= 4;
break;
case 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)) {
as_type = LZ_IMAGE_TYPE_RGB32;
pixman_format = PIXMAN_LE_x8r8g8b8;
+ stride_encoded *= 4;
} else {
as_type = LZ_IMAGE_TYPE_RGB16;
pixman_format = PIXMAN_x1r5g5b5;
+ stride_encoded *= 2;
}
break;
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,
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) {
- stride = -stride;
- decomp_buf = src + stride * (height - 1);
- } else {
- decomp_buf = src;
+ decomp_buf -= stride * (height - 1);
}
lz_decode(lz_data->lz, as_type, decomp_buf);
+ canvas_fix_alignment(decomp_buf, stride_encoded, stride, height);
+
if (free_palette) {
free(palette);
}
--
2.8.1