From 9e2c203771e46c4af94bd84d5ae0023e65bfc36f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 8 Nov 2018 17:21:28 +0100 Subject: [PATCH] Fixed various issues with freerdp_bitmap_compress and interleaved_compress --- include/freerdp/codec/bitmap.h | 4 +- libfreerdp/codec/bitmap.c | 2065 +++++++++++++++++--------------- libfreerdp/codec/interleaved.c | 52 +- 3 files changed, 1113 insertions(+), 1008 deletions(-) diff --git a/include/freerdp/codec/bitmap.h b/include/freerdp/codec/bitmap.h index 2166cdfe6..6509e255d 100644 --- a/include/freerdp/codec/bitmap.h +++ b/include/freerdp/codec/bitmap.h @@ -32,8 +32,8 @@ extern "C" { #endif -FREERDP_API int freerdp_bitmap_compress(const char* in_data, int width, int height, - wStream* s, int bpp, int byte_limit, int start_line, wStream* temp_s, int e); +FREERDP_API SSIZE_T freerdp_bitmap_compress(const void* in_data, UINT32 width, UINT32 height, + wStream* s, UINT32 bpp, UINT32 byte_limit, UINT32 start_line, wStream* temp_s, UINT32 e); #ifdef __cplusplus } diff --git a/libfreerdp/codec/bitmap.c b/libfreerdp/codec/bitmap.c index c2603095a..7524bb99c 100644 --- a/libfreerdp/codec/bitmap.c +++ b/libfreerdp/codec/bitmap.c @@ -24,954 +24,506 @@ #include #include -#define GETPIXEL16(d, x, y, w) (*(((unsigned short*)d) + ((y) * (w) + (x)))) -#define GETPIXEL32(d, x, y, w) (*(((unsigned int*)d) + ((y) * (w) + (x)))) - -/*****************************************************************************/ -#define IN_PIXEL16(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ - { \ - if (in_ptr == 0) \ - { \ - in_pixel = 0; \ - } \ - else if (in_x < in_w) \ - { \ - in_pixel = GETPIXEL16(in_ptr, in_x, in_y, in_w); \ - } \ - else \ - { \ - in_pixel = in_last_pixel; \ - } \ - } - -/*****************************************************************************/ -#define IN_PIXEL32(in_ptr, in_x, in_y, in_w, in_last_pixel, in_pixel); \ - { \ - if (in_ptr == 0) \ - { \ - in_pixel = 0; \ - } \ - else if (in_x < in_w) \ - { \ - in_pixel = GETPIXEL32(in_ptr, in_x, in_y, in_w); \ - } \ - else \ - { \ - in_pixel = in_last_pixel; \ - } \ - } - -/*****************************************************************************/ -/* color */ -#define OUT_COLOR_COUNT2(in_count, in_s, in_data) \ - { \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ - { \ - temp = (0x3 << 5) | in_count; \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write_UINT16(in_s, in_data); \ - } \ - else if (in_count < 256 + 32) \ - { \ - Stream_Write_UINT8(in_s, 0x60); \ - temp = in_count - 32; \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write_UINT16(in_s, in_data); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf3); \ - Stream_Write_UINT16(in_s, in_count); \ - Stream_Write_UINT16(in_s, in_data); \ - } \ - } \ - in_count = 0; \ - } - -/*****************************************************************************/ -/* color */ -#define OUT_COLOR_COUNT3(in_count, in_s, in_data) \ - { \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ - { \ - temp = (0x3 << 5) | in_count; \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write_UINT8(in_s, in_data & 0xFF); \ - Stream_Write_UINT8(in_s, (in_data >> 8) & 0xFF); \ - Stream_Write_UINT8(in_s, (in_data >> 16) & 0xFF); \ - } \ - else if (in_count < 256 + 32) \ - { \ - Stream_Write_UINT8(in_s, 0x60); \ - temp = in_count - 32; \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write_UINT8(in_s, in_data & 0xFF); \ - Stream_Write_UINT8(in_s, (in_data >> 8) & 0xFF); \ - Stream_Write_UINT8(in_s, (in_data >> 16) & 0xFF); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf3); \ - Stream_Write_UINT16(in_s, in_count); \ - Stream_Write_UINT8(in_s, in_data & 0xFF); \ - Stream_Write_UINT8(in_s, (in_data >> 8) & 0xFF); \ - Stream_Write_UINT8(in_s, (in_data >> 16) & 0xFF); \ - } \ - } \ - in_count = 0; \ - } - -/*****************************************************************************/ -/* copy */ -#define OUT_COPY_COUNT2(in_count, in_s, in_data) \ - { \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ - { \ - temp = (0x4 << 5) | in_count; \ - Stream_Write_UINT8(in_s, temp); \ - temp = in_count * 2; \ - Stream_Write(in_s, Stream_Buffer(in_data), temp); \ - } \ - else if (in_count < 256 + 32) \ - { \ - Stream_Write_UINT8(in_s, 0x80); \ - temp = in_count - 32; \ - Stream_Write_UINT8(in_s, temp); \ - temp = in_count * 2; \ - Stream_Write(in_s, Stream_Buffer(in_data), temp); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf4); \ - Stream_Write_UINT16(in_s, in_count); \ - temp = in_count * 2; \ - Stream_Write(in_s, Stream_Buffer(in_data), temp); \ - } \ - } \ - in_count = 0; \ - Stream_SetPosition(in_data, 0); \ - } - -/*****************************************************************************/ -/* copy */ -#define OUT_COPY_COUNT3(in_count, in_s, in_data) \ - { \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ - { \ - temp = (0x4 << 5) | in_count; \ - Stream_Write_UINT8(in_s, temp); \ - temp = in_count * 3; \ - Stream_Write(in_s, Stream_Pointer(in_data), temp); \ - } \ - else if (in_count < 256 + 32) \ - { \ - Stream_Write_UINT8(in_s, 0x80); \ - temp = in_count - 32; \ - Stream_Write_UINT8(in_s, temp); \ - temp = in_count * 3; \ - Stream_Write(in_s, Stream_Pointer(in_data), temp); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf4); \ - Stream_Write_UINT16(in_s, in_count); \ - temp = in_count * 3; \ - Stream_Write(in_s, Stream_Pointer(in_data), temp); \ - } \ - } \ - in_count = 0; \ - Stream_SetPosition(in_data, 0); \ - } - -/*****************************************************************************/ -/* bicolor */ -#define OUT_BICOLOR_COUNT2(in_count, in_s, in_color1, in_color2) \ - { \ - if (in_count > 0) \ - { \ - if (in_count / 2 < 16) \ - { \ - temp = (0xe << 4) | (in_count / 2); \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write_UINT16(in_s, in_color1); \ - Stream_Write_UINT16(in_s, in_color2); \ - } \ - else if (in_count / 2 < 256 + 16) \ - { \ - Stream_Write_UINT8(in_s, 0xe0); \ - temp = in_count / 2 - 16; \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write_UINT16(in_s, in_color1); \ - Stream_Write_UINT16(in_s, in_color2); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf8); \ - temp = in_count / 2; \ - Stream_Write_UINT16(in_s, temp); \ - Stream_Write_UINT16(in_s, in_color1); \ - Stream_Write_UINT16(in_s, in_color2); \ - } \ - } \ - in_count = 0; \ - } - -/*****************************************************************************/ -/* bicolor */ -#define OUT_BICOLOR_COUNT3(in_count, in_s, in_color1, in_color2) \ - { \ - if (in_count > 0) \ - { \ - if (in_count / 2 < 16) \ - { \ - temp = (0xe << 4) | (in_count / 2); \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write_UINT8(in_s, in_color1 & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color1 >> 8) & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color1 >> 16) & 0xFF); \ - Stream_Write_UINT8(in_s, in_color2 & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color2 >> 8) & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color2 >> 16) & 0xFF); \ - } \ - else if (in_count / 2 < 256 + 16) \ - { \ - Stream_Write_UINT8(in_s, 0xe0); \ - temp = in_count / 2 - 16; \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write_UINT8(in_s, in_color1 & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color1 >> 8) & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color1 >> 16) & 0xFF); \ - Stream_Write_UINT8(in_s, in_color2 & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color2 >> 8) & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color2 >> 16) & 0xFF); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf8); \ - temp = in_count / 2; \ - Stream_Write_UINT16(in_s, temp); \ - Stream_Write_UINT8(in_s, in_color1 & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color1 >> 8) & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color1 >> 16) & 0xFF); \ - Stream_Write_UINT8(in_s, in_color2 & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color2 >> 8) & 0xFF); \ - Stream_Write_UINT8(in_s, (in_color2 >> 16) & 0xFF); \ - } \ - } \ - in_count = 0; \ - } - -/*****************************************************************************/ -/* fill */ -#define OUT_FILL_COUNT2(in_count, in_s) \ - { \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ - { \ - Stream_Write_UINT8(in_s, in_count); \ - } \ - else if (in_count < 256 + 32) \ - { \ - Stream_Write_UINT8(in_s, 0x0); \ - temp = in_count - 32; \ - Stream_Write_UINT8(in_s, temp); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf0); \ - Stream_Write_UINT16(in_s, in_count); \ - } \ - } \ - in_count = 0; \ - } - -/*****************************************************************************/ -/* fill */ -#define OUT_FILL_COUNT3(in_count, in_s) \ - { \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ - { \ - Stream_Write_UINT8(in_s, in_count); \ - } \ - else if (in_count < 256 + 32) \ - { \ - Stream_Write_UINT8(in_s, 0x0); \ - temp = in_count - 32; \ - Stream_Write_UINT8(in_s, temp); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf0); \ - Stream_Write_UINT16(in_s, in_count); \ - } \ - } \ - in_count = 0; \ - } - -/*****************************************************************************/ -/* mix */ -#define OUT_MIX_COUNT2(in_count, in_s) \ - { \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ - { \ - temp = (0x1 << 5) | in_count; \ - Stream_Write_UINT8(in_s, temp); \ - } \ - else if (in_count < 256 + 32) \ - { \ - Stream_Write_UINT8(in_s, 0x20); \ - temp = in_count - 32; \ - Stream_Write_UINT8(in_s, temp); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf1); \ - Stream_Write_UINT16(in_s, in_count); \ - } \ - } \ - in_count = 0; \ - } - -/*****************************************************************************/ -/* mix */ -#define OUT_MIX_COUNT3(in_count, in_s) \ - { \ - if (in_count > 0) \ - { \ - if (in_count < 32) \ - { \ - temp = (0x1 << 5) | in_count; \ - Stream_Write_UINT8(in_s, temp); \ - } \ - else if (in_count < 256 + 32) \ - { \ - Stream_Write_UINT8(in_s, 0x20); \ - temp = in_count - 32; \ - Stream_Write_UINT8(in_s, temp); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf1); \ - Stream_Write_UINT16(in_s, in_count); \ - } \ - } \ - in_count = 0; \ - } - -/*****************************************************************************/ -/* fom */ -#define OUT_FOM_COUNT2(in_count, in_s, in_mask, in_mask_len) \ - { \ - if (in_count > 0) \ - { \ - if ((in_count % 8) == 0 && in_count < 249) \ - { \ - temp = (0x2 << 5) | (in_count / 8); \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write(in_s, in_mask, in_mask_len); \ - } \ - else if (in_count < 256) \ - { \ - Stream_Write_UINT8(in_s, 0x40); \ - temp = in_count - 1; \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write(in_s, in_mask, in_mask_len); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf2); \ - Stream_Write_UINT16(in_s, in_count); \ - Stream_Write(in_s, in_mask, in_mask_len); \ - } \ - } \ - in_count = 0; \ - } - -/*****************************************************************************/ -/* fill or mix (fom) */ -#define OUT_FOM_COUNT3(in_count, in_s, in_mask, in_mask_len) \ - { \ - if (in_count > 0) \ - { \ - if ((in_count % 8) == 0 && in_count < 249) \ - { \ - temp = (0x2 << 5) | (in_count / 8); \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write(in_s, in_mask, in_mask_len); \ - } \ - else if (in_count < 256) \ - { \ - Stream_Write_UINT8(in_s, 0x40); \ - temp = in_count - 1; \ - Stream_Write_UINT8(in_s, temp); \ - Stream_Write(in_s, in_mask, in_mask_len); \ - } \ - else \ - { \ - Stream_Write_UINT8(in_s, 0xf2); \ - Stream_Write_UINT16(in_s, in_count); \ - Stream_Write(in_s, in_mask, in_mask_len); \ - } \ - } \ - in_count = 0; \ - } - -#define TEST_FILL \ - ((last_line == 0 && pixel == 0) || \ - (last_line != 0 && pixel == ypixel)) -#define TEST_MIX \ - ((last_line == 0 && pixel == mix) || \ - (last_line != 0 && pixel == (ypixel ^ mix))) -#define TEST_FOM TEST_FILL || TEST_MIX -#define TEST_COLOR pixel == last_pixel -#define TEST_BICOLOR \ - ( \ - (pixel != last_pixel) && \ - ( \ - (!bicolor_spin && pixel == bicolor1 && last_pixel == bicolor2) || \ - (bicolor_spin && pixel == bicolor2 && last_pixel == bicolor1) \ - ) \ - ) -#define RESET_COUNTS \ - { \ - bicolor_count = 0; \ - fill_count = 0; \ - color_count = 0; \ - mix_count = 0; \ - fom_count = 0; \ - fom_mask_len = 0; \ - bicolor_spin = 0; \ - } - -int freerdp_bitmap_compress(const char* srcData, int width, int height, - wStream* s, int bpp, int byte_limit, int start_line, wStream* temp_s, int e) +static INLINE UINT16 GETPIXEL16(const void* d, UINT32 x, UINT32 y, UINT32 w) { - char fom_mask[8192]; /* good for up to 64K bitmap */ - int lines_sent; - int pixel; - int count; - int color_count; - int last_pixel; - int bicolor_count; - int bicolor1; - int bicolor2; - int bicolor_spin; - int end; - size_t i; - int out_count; - int ypixel; - int last_ypixel; - int fill_count; - int mix_count; - int mix; - int fom_count; - int fom_mask_len; - int temp; /* used in macros */ + return (*(((const unsigned short*)d) + ((y) * (w) + (x)))); +} - Stream_SetPosition(temp_s, 0); - fom_mask_len = 0; - lines_sent = 0; - end = width + e; - count = 0; - color_count = 0; - last_pixel = 0; - last_ypixel = 0; - bicolor_count = 0; - bicolor1 = 0; - bicolor2 = 0; - bicolor_spin = 0; - fill_count = 0; - mix_count = 0; - fom_count = 0; +static INLINE UINT32 GETPIXEL32(const void* d, UINT32 x, UINT32 y, UINT32 w) +{ + return (*(((const unsigned int*)d) + ((y) * (w) + (x)))); +} - if ((bpp == 15) || (bpp == 16)) +/*****************************************************************************/ +static INLINE UINT16 IN_PIXEL16(const void* in_ptr, UINT32 in_x, UINT32 in_y, UINT32 in_w, + UINT16 in_last_pixel) +{ + if (in_ptr == 0) + return 0; + else if (in_x < in_w) + return GETPIXEL16(in_ptr, in_x, in_y, in_w); + else + return in_last_pixel; +} + +/*****************************************************************************/ +static INLINE UINT32 IN_PIXEL32(const void* in_ptr, UINT32 in_x, UINT32 in_y, UINT32 in_w, + UINT32 in_last_pixel) +{ + if (in_ptr == 0) + return 0; + else if (in_x < in_w) + return GETPIXEL32(in_ptr, in_x, in_y, in_w); + else + return in_last_pixel; +} + +/*****************************************************************************/ +/* color */ +static UINT16 out_color_count_2(UINT16 in_count, wStream* in_s, UINT16 in_data) +{ + if (in_count > 0) { - const char* line = srcData + width * start_line * 2; - const char *last_line = NULL; - mix = (bpp == 15) ? 0xBA1F : 0xFFFF; - out_count = end * 2; - - while (start_line >= 0 && out_count < 32768) + if (in_count < 32) { - i = Stream_GetPosition(s) + count * 2; - - if (i - (color_count * 2) >= byte_limit && - i - (bicolor_count * 2) >= byte_limit && - i - (fill_count * 2) >= byte_limit && - i - (mix_count * 2) >= byte_limit && - i - (fom_count * 2) >= byte_limit) - { - break; - } - - out_count += end * 2; - - for (i = 0; i < end; i++) - { - /* read next pixel */ - IN_PIXEL16(line, i, 0, width, last_pixel, pixel); - IN_PIXEL16(last_line, i, 0, width, last_ypixel, ypixel); - - if (!TEST_FILL) - { - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) - { - count -= fill_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_FILL_COUNT2(fill_count, s); - RESET_COUNTS; - } - - fill_count = 0; - } - - if (!TEST_MIX) - { - if (mix_count > 3 && - mix_count >= fill_count && - mix_count >= bicolor_count && - mix_count >= color_count && - mix_count >= fom_count) - { - count -= mix_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_MIX_COUNT2(mix_count, s); - RESET_COUNTS; - } - - mix_count = 0; - } - - if (!(TEST_COLOR)) - { - if (color_count > 3 && - color_count >= fill_count && - color_count >= bicolor_count && - color_count >= mix_count && - color_count >= fom_count) - { - count -= color_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_COLOR_COUNT2(color_count, s, last_pixel); - RESET_COUNTS; - } - - color_count = 0; - } - - if (!TEST_BICOLOR) - { - if (bicolor_count > 3 && - bicolor_count >= fill_count && - bicolor_count >= color_count && - bicolor_count >= mix_count && - bicolor_count >= fom_count) - { - if ((bicolor_count % 2) == 0) - { - count -= bicolor_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); - } - else - { - bicolor_count--; - count -= bicolor_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); - } - - RESET_COUNTS; - } - - bicolor_count = 0; - bicolor1 = last_pixel; - bicolor2 = pixel; - bicolor_spin = 0; - } - - if (!(TEST_FOM)) - { - if (fom_count > 3 && - fom_count >= fill_count && - fom_count >= color_count && - fom_count >= mix_count && - fom_count >= bicolor_count) - { - count -= fom_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); - RESET_COUNTS; - } - - fom_count = 0; - fom_mask_len = 0; - } - - if (TEST_FILL) - { - fill_count++; - } - - if (TEST_MIX) - { - mix_count++; - } - - if (TEST_COLOR) - { - color_count++; - } - - if (TEST_BICOLOR) - { - bicolor_spin = !bicolor_spin; - bicolor_count++; - } - - if (TEST_FOM) - { - if ((fom_count % 8) == 0) - { - fom_mask[fom_mask_len] = 0; - fom_mask_len++; - } - - if (pixel == (ypixel ^ mix)) - { - fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); - } - - fom_count++; - } - - Stream_Write_UINT16(temp_s, pixel); - count++; - last_pixel = pixel; - last_ypixel = ypixel; - } - - /* can't take fix, mix, or fom past first line */ - if (last_line == 0) - { - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) - { - count -= fill_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_FILL_COUNT2(fill_count, s); - RESET_COUNTS; - } - - fill_count = 0; - - if (mix_count > 3 && - mix_count >= fill_count && - mix_count >= bicolor_count && - mix_count >= color_count && - mix_count >= fom_count) - { - count -= mix_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_MIX_COUNT2(mix_count, s); - RESET_COUNTS; - } - - mix_count = 0; - - if (fom_count > 3 && - fom_count >= fill_count && - fom_count >= color_count && - fom_count >= mix_count && - fom_count >= bicolor_count) - { - count -= fom_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); - RESET_COUNTS; - } - - fom_count = 0; - fom_mask_len = 0; - } - - last_line = line; - line = line - width * 2; - start_line--; - lines_sent++; + const BYTE temp = ((0x3 << 5) | in_count) & 0xFF; + Stream_Write_UINT8(in_s, temp); } - - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) + else if (in_count < 256 + 32) { - count -= fill_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_FILL_COUNT2(fill_count, s); - } - else if (mix_count > 3 && - mix_count >= color_count && - mix_count >= bicolor_count && - mix_count >= fill_count && - mix_count >= fom_count) - { - count -= mix_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_MIX_COUNT2(mix_count, s); - } - else if (color_count > 3 && - color_count >= mix_count && - color_count >= bicolor_count && - color_count >= fill_count && - color_count >= fom_count) - { - count -= color_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_COLOR_COUNT2(color_count, s, last_pixel); - } - else if (bicolor_count > 3 && - bicolor_count >= mix_count && - bicolor_count >= color_count && - bicolor_count >= fill_count && - bicolor_count >= fom_count) - { - if ((bicolor_count % 2) == 0) - { - count -= bicolor_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); - } - else - { - bicolor_count--; - count -= bicolor_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); - } - - count -= bicolor_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); - } - else if (fom_count > 3 && - fom_count >= mix_count && - fom_count >= color_count && - fom_count >= fill_count && - fom_count >= bicolor_count) - { - count -= fom_count; - OUT_COPY_COUNT2(count, s, temp_s); - OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + const BYTE temp = (in_count - 32) & 0xFF; + Stream_Write_UINT8(in_s, 0x60); + Stream_Write_UINT8(in_s, temp); } else { - OUT_COPY_COUNT2(count, s, temp_s); + Stream_Write_UINT8(in_s, 0xf3); + Stream_Write_UINT16(in_s, in_count); + } + + Stream_Write_UINT16(in_s, in_data); + } + + return 0; +} +#define OUT_COLOR_COUNT2(in_count, in_s, in_data) \ + in_count = out_color_count_2(in_count, in_s, in_data) + +/*****************************************************************************/ +/* color */ +static UINT16 out_color_count_3(UINT16 in_count, wStream* in_s, UINT32 in_data) +{ + if (in_count > 0) + { + if (in_count < 32) + { + const BYTE temp = ((0x3 << 5) | in_count) & 0xFF; + Stream_Write_UINT8(in_s, temp); + } + else if (in_count < 256 + 32) + { + const BYTE temp = (in_count - 32) & 0xFF; + Stream_Write_UINT8(in_s, 0x60); + Stream_Write_UINT8(in_s, temp); + } + else + { + Stream_Write_UINT8(in_s, 0xf3); + Stream_Write_UINT16(in_s, in_count); + } + + Stream_Write_UINT8(in_s, in_data & 0xFF); + \ + Stream_Write_UINT8(in_s, (in_data >> 8) & 0xFF); + Stream_Write_UINT8(in_s, (in_data >> 16) & 0xFF); + } + + return 0; +} + +#define OUT_COLOR_COUNT3(in_count, in_s, in_data) \ + in_count = out_color_count_3(in_count, in_s, in_data) + +/*****************************************************************************/ +/* copy */ +static INLINE UINT16 out_copy_count_2(UINT16 in_count, wStream* in_s, wStream* in_data) + +{ + if (in_count > 0) + { + if (in_count < 32) + { + const BYTE temp = ((0x4 << 5) | in_count) & 0xFF; + Stream_Write_UINT8(in_s, temp); + } + else if (in_count < 256 + 32) + { + const BYTE temp = (in_count - 32) & 0xFF; + Stream_Write_UINT8(in_s, 0x80); + Stream_Write_UINT8(in_s, temp); + } + else + { + Stream_Write_UINT8(in_s, 0xf4); + Stream_Write_UINT16(in_s, in_count); + } + + Stream_Write(in_s, Stream_Buffer(in_data), in_count * 2); + } + + Stream_SetPosition(in_data, 0); + return 0; +} +#define OUT_COPY_COUNT2(in_count, in_s, in_data) \ + in_count = out_copy_count_2(in_count, in_s, in_data) +/*****************************************************************************/ +/* copy */ +static INLINE UINT16 out_copy_count_3(UINT16 in_count, wStream* in_s, wStream* in_data) +{ + if (in_count > 0) + { + if (in_count < 32) + { + const BYTE temp = ((0x4 << 5) | in_count) & 0xFF; + Stream_Write_UINT8(in_s, temp); + } + else if (in_count < 256 + 32) + { + const BYTE temp = (in_count - 32) & 0xFF; + Stream_Write_UINT8(in_s, 0x80); + Stream_Write_UINT8(in_s, temp); + } + else + { + Stream_Write_UINT8(in_s, 0xf4); + Stream_Write_UINT16(in_s, in_count); + } + + Stream_Write(in_s, Stream_Pointer(in_data), in_count * 3); + } + + Stream_SetPosition(in_data, 0); + return 0; +} +#define OUT_COPY_COUNT3(in_count, in_s, in_data) \ + in_count = out_copy_count_3(in_count, in_s, in_data) + +/*****************************************************************************/ +/* bicolor */ +static INLINE UINT16 out_bicolor_count_2(UINT16 in_count, wStream* in_s, UINT16 in_color1, + UINT16 in_color2) +{ + if (in_count > 0) + { + if (in_count / 2 < 16) + { + const BYTE temp = ((0xe << 4) | (in_count / 2)) & 0xFF; + Stream_Write_UINT8(in_s, temp); + } + else if (in_count / 2 < 256 + 16) + { + const BYTE temp = (in_count / 2 - 16) & 0xFF; + Stream_Write_UINT8(in_s, 0xe0); + Stream_Write_UINT8(in_s, temp); + } + else + { + Stream_Write_UINT8(in_s, 0xf8); + Stream_Write_UINT16(in_s, in_count / 2); + } + + Stream_Write_UINT16(in_s, in_color1); + Stream_Write_UINT16(in_s, in_color2); + } + + return 0; +} + +#define OUT_BICOLOR_COUNT2(in_count, in_s, in_color1, in_color2) \ + in_count = out_bicolor_count_2(in_count, in_s, in_color1, in_color2) + +/*****************************************************************************/ +/* bicolor */ +static INLINE UINT16 out_bicolor_count_3(UINT16 in_count, wStream* in_s, UINT32 in_color1, + UINT32 in_color2) +{ + if (in_count > 0) + { + if (in_count / 2 < 16) + { + const BYTE temp = ((0xe << 4) | (in_count / 2)) & 0xFF; + Stream_Write_UINT8(in_s, temp); + } + else if (in_count / 2 < 256 + 16) + { + const BYTE temp = (in_count / 2 - 16) & 0xFF; + Stream_Write_UINT8(in_s, 0xe0); + Stream_Write_UINT8(in_s, temp); + } + else + { + Stream_Write_UINT8(in_s, 0xf8); + Stream_Write_UINT16(in_s, in_count / 2); + } + + Stream_Write_UINT8(in_s, in_color1 & 0xFF); + Stream_Write_UINT8(in_s, (in_color1 >> 8) & 0xFF); + Stream_Write_UINT8(in_s, (in_color1 >> 16) & 0xFF); + Stream_Write_UINT8(in_s, in_color2 & 0xFF); + Stream_Write_UINT8(in_s, (in_color2 >> 8) & 0xFF); + Stream_Write_UINT8(in_s, (in_color2 >> 16) & 0xFF); + } + + return 0; +} + +#define OUT_BICOLOR_COUNT3(in_count, in_s, in_color1, in_color2) \ + in_count = out_bicolor_count_3(in_count, in_s, in_color1, in_color2) + +/*****************************************************************************/ +/* fill */ +static INLINE UINT16 out_fill_count_2(UINT16 in_count, wStream* in_s) +{ + if (in_count > 0) + { + if (in_count < 32) + { + Stream_Write_UINT8(in_s, in_count & 0xFF); + } + else if (in_count < 256 + 32) + { + const BYTE temp = (in_count - 32) & 0xFF; + Stream_Write_UINT8(in_s, 0x0); + Stream_Write_UINT8(in_s, temp); + } + else + { + Stream_Write_UINT8(in_s, 0xf0); + Stream_Write_UINT16(in_s, in_count); } } - else if (bpp == 24) + + return 0; +} + +#define OUT_FILL_COUNT2(in_count, in_s) \ + in_count = out_fill_count_2(in_count, in_s) + +/*****************************************************************************/ +/* fill */ +static INLINE UINT16 out_fill_count_3(UINT16 in_count, wStream* in_s) +{ + if (in_count > 0) { - const char* line = srcData + width * start_line * 4; - const char *last_line = NULL; - mix = 0xFFFFFF; - out_count = end * 3; - - while (start_line >= 0 && out_count < 32768) + if (in_count < 32) { - i = Stream_GetPosition(s) + count * 3; + Stream_Write_UINT8(in_s, in_count & 0xFF); + } + else if (in_count < 256 + 32) + { + const BYTE temp = (in_count - 32) & 0xFF; + Stream_Write_UINT8(in_s, 0x0); + Stream_Write_UINT8(in_s, temp); + } + else + { + Stream_Write_UINT8(in_s, 0xf0); + Stream_Write_UINT16(in_s, in_count); + } + } - if (i - (color_count * 3) >= byte_limit && - i - (bicolor_count * 3) >= byte_limit && - i - (fill_count * 3) >= byte_limit && - i - (mix_count * 3) >= byte_limit && - i - (fom_count * 3) >= byte_limit) - { - break; - } + return 0; +} +#define OUT_FILL_COUNT3(in_count, in_s) \ + in_count = out_fill_count_3(in_count, in_s) - out_count += end * 3; +/*****************************************************************************/ +/* mix */ +static INLINE UINT16 out_mix_count_2(UINT16 in_count, wStream* in_s) +{ + if (in_count > 0) + { + if (in_count < 32) + { + const BYTE temp = ((0x1 << 5) | in_count) & 0xFF; + Stream_Write_UINT8(in_s, temp); + } + else if (in_count < 256 + 32) + { + const BYTE temp = (in_count - 32) & 0xFF; + Stream_Write_UINT8(in_s, 0x20); + Stream_Write_UINT8(in_s, temp); + } + else + { + Stream_Write_UINT8(in_s, 0xf1); + Stream_Write_UINT16(in_s, in_count); + } + } - for (i = 0; i < end; i++) - { - /* read next pixel */ - IN_PIXEL32(line, i, 0, width, last_pixel, pixel); - IN_PIXEL32(last_line, i, 0, width, last_ypixel, ypixel); + return 0; +} +#define OUT_MIX_COUNT2(in_count, in_s) \ + in_count = out_mix_count_2(in_count, in_s) - if (!TEST_FILL) - { - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) - { - count -= fill_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_FILL_COUNT3(fill_count, s); - RESET_COUNTS; - } +/*****************************************************************************/ +/* mix */ +static INLINE UINT16 out_mix_count_3(UINT16 in_count, wStream* in_s) +{ + if (in_count > 0) + { + if (in_count < 32) + { + const BYTE temp = ((0x1 << 5) | in_count) & 0xFF; + Stream_Write_UINT8(in_s, temp); + } + else if (in_count < 256 + 32) + { + const BYTE temp = (in_count - 32) & 0xFF; + Stream_Write_UINT8(in_s, 0x20); + Stream_Write_UINT8(in_s, temp); + } + else + { + Stream_Write_UINT8(in_s, 0xf1); + Stream_Write_UINT16(in_s, in_count); + } + } - fill_count = 0; - } + return 0; +} - if (!TEST_MIX) - { - if (mix_count > 3 && - mix_count >= fill_count && - mix_count >= bicolor_count && - mix_count >= color_count && - mix_count >= fom_count) - { - count -= mix_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_MIX_COUNT3(mix_count, s); - RESET_COUNTS; - } +#define OUT_MIX_COUNT3(in_count, in_s) \ + in_count = out_mix_count_3(in_count, in_s) - mix_count = 0; - } +/*****************************************************************************/ +/* fom */ +static INLINE UINT16 out_from_count_2(UINT16 in_count, wStream* in_s, const char* in_mask, + size_t in_mask_len) +{ + if (in_count > 0) + { + if ((in_count % 8) == 0 && in_count < 249) + { + const BYTE temp = ((0x2 << 5) | (in_count / 8)) & 0xFF; + Stream_Write_UINT8(in_s, temp); + } + else if (in_count < 256) + { + const BYTE temp = (in_count - 1) & 0xFF; + Stream_Write_UINT8(in_s, 0x40); + Stream_Write_UINT8(in_s, temp); + } + else + { + Stream_Write_UINT8(in_s, 0xf2); + Stream_Write_UINT16(in_s, in_count); + } - if (!(TEST_COLOR)) - { - if (color_count > 3 && - color_count >= fill_count && - color_count >= bicolor_count && - color_count >= mix_count && - color_count >= fom_count) - { - count -= color_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_COLOR_COUNT3(color_count, s, last_pixel); - RESET_COUNTS; - } + Stream_Write(in_s, in_mask, in_mask_len); + } - color_count = 0; - } + return 0; +} +#define OUT_FOM_COUNT2(in_count, in_s, in_mask, in_mask_len) \ + in_count = out_from_count_2(in_count, in_s, in_mask, in_mask_len) - if (!TEST_BICOLOR) - { - if (bicolor_count > 3 && - bicolor_count >= fill_count && - bicolor_count >= color_count && - bicolor_count >= mix_count && - bicolor_count >= fom_count) - { - if ((bicolor_count % 2) == 0) - { - count -= bicolor_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); - } - else - { - bicolor_count--; - count -= bicolor_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); - } +/*****************************************************************************/ +/* fill or mix (fom) */ +static INLINE UINT16 out_from_count_3(UINT16 in_count, wStream* in_s, const char* in_mask, + size_t in_mask_len) +{ + if (in_count > 0) + { + if ((in_count % 8) == 0 && in_count < 249) + { + const BYTE temp = ((0x2 << 5) | (in_count / 8)) & 0xFF; + Stream_Write_UINT8(in_s, temp); + } + else if (in_count < 256) + { + const BYTE temp = (in_count - 1) & 0xFF; + Stream_Write_UINT8(in_s, 0x40); + Stream_Write_UINT8(in_s, temp); + } + else + { + Stream_Write_UINT8(in_s, 0xf2); + Stream_Write_UINT16(in_s, in_count); + } - RESET_COUNTS; - } + Stream_Write(in_s, in_mask, in_mask_len); + } - bicolor_count = 0; - bicolor1 = last_pixel; - bicolor2 = pixel; - bicolor_spin = 0; - } + return 0; +} +#define OUT_FOM_COUNT3(in_count, in_s, in_mask, in_mask_len) \ + in_count = out_from_count_3(in_count, in_s, in_mask, in_mask_len) - if (!(TEST_FOM)) - { - if (fom_count > 3 && - fom_count >= fill_count && - fom_count >= color_count && - fom_count >= mix_count && - fom_count >= bicolor_count) - { - count -= fom_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); - RESET_COUNTS; - } +#define TEST_FILL \ + ((last_line == 0 && pixel == 0) || \ + (last_line != 0 && pixel == ypixel)) +#define TEST_MIX \ + ((last_line == 0 && pixel == mix) || \ + (last_line != 0 && pixel == (ypixel ^ mix))) +#define TEST_FOM TEST_FILL || TEST_MIX +#define TEST_COLOR pixel == last_pixel +#define TEST_BICOLOR \ + ( \ + (pixel != last_pixel) && \ + ( \ + (!bicolor_spin && (pixel == bicolor1) && (last_pixel == bicolor2)) || \ + (bicolor_spin && (pixel == bicolor2) && (last_pixel == bicolor1)) \ + ) \ + ) +#define RESET_COUNTS \ + { \ + bicolor_count = 0; \ + fill_count = 0; \ + color_count = 0; \ + mix_count = 0; \ + fom_count = 0; \ + fom_mask_len = 0; \ + bicolor_spin = FALSE; \ + } - fom_count = 0; - fom_mask_len = 0; - } +static SSIZE_T freerdp_bitmap_compress_24(const void* srcData, UINT32 width, UINT32 height, + wStream* s, UINT32 byte_limit, UINT32 start_line, wStream* temp_s, UINT32 e) +{ + char fom_mask[8192]; /* good for up to 64K bitmap */ + SSIZE_T lines_sent = 0; + UINT16 count = 0; + UINT16 color_count = 0; + UINT32 last_pixel = 0; + UINT32 last_ypixel = 0; + UINT16 bicolor_count = 0; + UINT32 bicolor1 = 0; + UINT32 bicolor2 = 0; + BOOL bicolor_spin = FALSE; + UINT32 end = width + e; + UINT32 out_count = end * 3; + UINT16 fill_count = 0; + UINT16 mix_count = 0; + const UINT32 mix = 0xFFFFFF; + UINT16 fom_count = 0; + size_t fom_mask_len = 0; + const char* start = (const char*)srcData; + const char* line = start + width * start_line * 4; + const char* last_line = NULL; - if (TEST_FILL) - { - fill_count++; - } + while ((line >= start) && (out_count < 32768)) + { + UINT32 j; + size_t i = Stream_GetPosition(s) + count * 3U; - if (TEST_MIX) - { - mix_count++; - } + if ((i - (color_count * 3) >= byte_limit) && + (i - (bicolor_count * 3) >= byte_limit) && + (i - (fill_count * 3) >= byte_limit) && + (i - (mix_count * 3) >= byte_limit) && + (i - (fom_count * 3) >= byte_limit)) + { + break; + } - if (TEST_COLOR) - { - color_count++; - } + out_count += end * 3; - if (TEST_BICOLOR) - { - bicolor_spin = !bicolor_spin; - bicolor_count++; - } + for (j = 0; j < end; j++) + { + /* read next pixel */ + const UINT32 pixel = IN_PIXEL32(line, j, 0, width, last_pixel); + const UINT32 ypixel = IN_PIXEL32(last_line, j, 0, width, last_ypixel); - if (TEST_FOM) - { - if ((fom_count % 8) == 0) - { - fom_mask[fom_mask_len] = 0; - fom_mask_len++; - } - - if (pixel == (ypixel ^ mix)) - { - fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); - } - - fom_count++; - } - - Stream_Write_UINT8(temp_s, pixel & 0xff); - Stream_Write_UINT8(temp_s, (pixel >> 8) & 0xff); - Stream_Write_UINT8(temp_s, (pixel >> 16) & 0xff); - count++; - last_pixel = pixel; - last_ypixel = ypixel; - } - - /* can't take fix, mix, or fom past first line */ - if (last_line == 0) + if (!TEST_FILL) { if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) { + if (fill_count > count) + return -1; + count -= fill_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_FILL_COUNT3(fill_count, s); @@ -979,13 +531,19 @@ int freerdp_bitmap_compress(const char* srcData, int width, int height, } fill_count = 0; + } + if (!TEST_MIX) + { if (mix_count > 3 && - mix_count >= fill_count && - mix_count >= bicolor_count && - mix_count >= color_count && - mix_count >= fom_count) + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) { + if (mix_count > count) + return -1; + count -= mix_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_MIX_COUNT3(mix_count, s); @@ -993,13 +551,65 @@ int freerdp_bitmap_compress(const char* srcData, int width, int height, } mix_count = 0; + } - if (fom_count > 3 && - fom_count >= fill_count && - fom_count >= color_count && - fom_count >= mix_count && - fom_count >= bicolor_count) + if (!(TEST_COLOR)) + { + if (color_count > 3 && + color_count >= fill_count && + color_count >= bicolor_count && + color_count >= mix_count && + color_count >= fom_count) { + if (color_count > count) + return -1; + + count -= color_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_COLOR_COUNT3(color_count, s, last_pixel); + RESET_COUNTS; + } + + color_count = 0; + } + + if (!TEST_BICOLOR) + { + if (bicolor_count > 3 && + bicolor_count >= fill_count && + bicolor_count >= color_count && + bicolor_count >= mix_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) != 0) + bicolor_count--; + + if (bicolor_count > count) + return -1; + + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); + RESET_COUNTS; + } + + bicolor_count = 0; + bicolor1 = last_pixel; + bicolor2 = pixel; + bicolor_spin = FALSE; + } + + if (!(TEST_FOM)) + { + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + if (fom_count > count) + return -1; + count -= fom_count; OUT_COPY_COUNT3(count, s, temp_s); OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); @@ -1010,81 +620,558 @@ int freerdp_bitmap_compress(const char* srcData, int width, int height, fom_mask_len = 0; } - last_line = line; - line = line - width * 4; - start_line--; - lines_sent++; - } - - if (fill_count > 3 && - fill_count >= color_count && - fill_count >= bicolor_count && - fill_count >= mix_count && - fill_count >= fom_count) - { - count -= fill_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_FILL_COUNT3(fill_count, s); - } - else if (mix_count > 3 && - mix_count >= color_count && - mix_count >= bicolor_count && - mix_count >= fill_count && - mix_count >= fom_count) - { - count -= mix_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_MIX_COUNT3(mix_count, s); - } - else if (color_count > 3 && - color_count >= mix_count && - color_count >= bicolor_count && - color_count >= fill_count && - color_count >= fom_count) - { - count -= color_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_COLOR_COUNT3(color_count, s, last_pixel); - } - else if (bicolor_count > 3 && - bicolor_count >= mix_count && - bicolor_count >= color_count && - bicolor_count >= fill_count && - bicolor_count >= fom_count) - { - if ((bicolor_count % 2) == 0) + if (TEST_FILL) { - count -= bicolor_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); - } - else - { - bicolor_count--; - count -= bicolor_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); + fill_count++; } - count -= bicolor_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); + if (TEST_MIX) + { + mix_count++; + } + + if (TEST_COLOR) + { + color_count++; + } + + if (TEST_BICOLOR) + { + bicolor_spin = !bicolor_spin; + bicolor_count++; + } + + if (TEST_FOM) + { + if ((fom_count % 8) == 0) + { + fom_mask[fom_mask_len] = 0; + fom_mask_len++; + } + + if (pixel == (ypixel ^ mix)) + { + fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); + } + + fom_count++; + } + + Stream_Write_UINT8(temp_s, pixel & 0xff); + Stream_Write_UINT8(temp_s, (pixel >> 8) & 0xff); + Stream_Write_UINT8(temp_s, (pixel >> 16) & 0xff); + count++; + last_pixel = pixel; + last_ypixel = ypixel; } - else if (fom_count > 3 && - fom_count >= mix_count && - fom_count >= color_count && - fom_count >= fill_count && - fom_count >= bicolor_count) + + /* can't take fix, mix, or fom past first line */ + if (last_line == 0) { - count -= fom_count; - OUT_COPY_COUNT3(count, s, temp_s); - OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); - } - else - { - OUT_COPY_COUNT3(count, s, temp_s); + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + if (fill_count > count) + return -1; + + count -= fill_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FILL_COUNT3(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + if (mix_count > count) + return -1; + + count -= mix_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_MIX_COUNT3(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + if (fom_count > count) + return -1; + + count -= fom_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; } + + last_line = line; + line = line - width * 4; + start_line--; + lines_sent++; + } + + Stream_SetPosition(temp_s, 0); + + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + if (fill_count > count) + return -1; + + count -= fill_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FILL_COUNT3(fill_count, s); + } + else if (mix_count > 3 && + mix_count >= color_count && + mix_count >= bicolor_count && + mix_count >= fill_count && + mix_count >= fom_count) + { + if (mix_count > count) + return -1; + + count -= mix_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_MIX_COUNT3(mix_count, s); + } + else if (color_count > 3 && + color_count >= mix_count && + color_count >= bicolor_count && + color_count >= fill_count && + color_count >= fom_count) + { + if (color_count > count) + return -1; + + count -= color_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_COLOR_COUNT3(color_count, s, last_pixel); + } + else if (bicolor_count > 3 && + bicolor_count >= mix_count && + bicolor_count >= color_count && + bicolor_count >= fill_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) != 0) + bicolor_count--; + + if (bicolor_count > count) + return -1; + + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor2, bicolor1); + + if (bicolor_count > count) + return -1; + + count -= bicolor_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_BICOLOR_COUNT3(bicolor_count, s, bicolor1, bicolor2); + } + else if (fom_count > 3 && + fom_count >= mix_count && + fom_count >= color_count && + fom_count >= fill_count && + fom_count >= bicolor_count) + { + if (fom_count > count) + return -1; + + count -= fom_count; + OUT_COPY_COUNT3(count, s, temp_s); + OUT_FOM_COUNT3(fom_count, s, fom_mask, fom_mask_len); + } + else + { + OUT_COPY_COUNT3(count, s, temp_s); } return lines_sent; } + +static SSIZE_T freerdp_bitmap_compress_16(const void* srcData, UINT32 width, UINT32 height, + wStream* s, UINT32 bpp, UINT32 byte_limit, UINT32 start_line, wStream* temp_s, UINT32 e) +{ + char fom_mask[8192]; /* good for up to 64K bitmap */ + SSIZE_T lines_sent = 0; + UINT16 count = 0; + UINT16 color_count = 0; + UINT16 last_pixel = 0; + UINT16 last_ypixel = 0; + UINT16 bicolor_count = 0; + UINT16 bicolor1 = 0; + UINT16 bicolor2 = 0; + BOOL bicolor_spin = FALSE; + UINT32 end = width + e; + UINT32 out_count = end * 2; + UINT16 fill_count = 0; + UINT16 mix_count = 0; + const UINT32 mix = (bpp == 15) ? 0xBA1F : 0xFFFF; + UINT16 fom_count = 0; + size_t fom_mask_len = 0; + const char* start = (const char*) srcData; + const char* line = start + width * start_line * 2; + const char* last_line = NULL; + + while ((line >= start) && (out_count < 32768)) + { + UINT32 j; + size_t i = Stream_GetPosition(s) + count * 2; + + if ((i - (color_count * 2) >= byte_limit) && + (i - (bicolor_count * 2) >= byte_limit) && + (i - (fill_count * 2) >= byte_limit) && + (i - (mix_count * 2) >= byte_limit) && + (i - (fom_count * 2) >= byte_limit)) + { + break; + } + + out_count += end * 2; + + for (j = 0; j < end; j++) + { + /* read next pixel */ + const UINT16 pixel = IN_PIXEL16(line, j, 0, width, last_pixel); + const UINT16 ypixel = IN_PIXEL16(last_line, j, 0, width, last_ypixel); + + if (!TEST_FILL) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + if (fill_count > count) + return -1; + + count -= fill_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FILL_COUNT2(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + } + + if (!TEST_MIX) + { + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + if (mix_count > count) + return -1; + + count -= mix_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_MIX_COUNT2(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + } + + if (!(TEST_COLOR)) + { + if (color_count > 3 && + color_count >= fill_count && + color_count >= bicolor_count && + color_count >= mix_count && + color_count >= fom_count) + { + if (color_count > count) + return -1; + + count -= color_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_COLOR_COUNT2(color_count, s, last_pixel); + RESET_COUNTS; + } + + color_count = 0; + } + + if (!TEST_BICOLOR) + { + if ((bicolor_count > 3) && + (bicolor_count >= fill_count) && + (bicolor_count >= color_count) && + (bicolor_count >= mix_count) && + (bicolor_count >= fom_count)) + { + if ((bicolor_count % 2) != 0) + bicolor_count--; + + if (bicolor_count > count) + return -1; + + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); + RESET_COUNTS; + } + + bicolor_count = 0; + bicolor1 = last_pixel; + bicolor2 = pixel; + bicolor_spin = FALSE; + } + + if (!(TEST_FOM)) + { + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + if (fom_count > count) + return -1; + + count -= fom_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + if (TEST_FILL) + { + fill_count++; + } + + if (TEST_MIX) + { + mix_count++; + } + + if (TEST_COLOR) + { + color_count++; + } + + if (TEST_BICOLOR) + { + bicolor_spin = !bicolor_spin; + bicolor_count++; + } + + if (TEST_FOM) + { + if ((fom_count % 8) == 0) + { + fom_mask[fom_mask_len] = 0; + fom_mask_len++; + } + + if (pixel == (ypixel ^ mix)) + { + fom_mask[fom_mask_len - 1] |= (1 << (fom_count % 8)); + } + + fom_count++; + } + + Stream_Write_UINT16(temp_s, pixel); + count++; + last_pixel = pixel; + last_ypixel = ypixel; + } + + /* can't take fix, mix, or fom past first line */ + if (last_line == 0) + { + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + if (fill_count > count) + return -1; + + count -= fill_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FILL_COUNT2(fill_count, s); + RESET_COUNTS; + } + + fill_count = 0; + + if (mix_count > 3 && + mix_count >= fill_count && + mix_count >= bicolor_count && + mix_count >= color_count && + mix_count >= fom_count) + { + if (mix_count > count) + return -1; + + count -= mix_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_MIX_COUNT2(mix_count, s); + RESET_COUNTS; + } + + mix_count = 0; + + if (fom_count > 3 && + fom_count >= fill_count && + fom_count >= color_count && + fom_count >= mix_count && + fom_count >= bicolor_count) + { + if (fom_count > count) + return -1; + + count -= fom_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + RESET_COUNTS; + } + + fom_count = 0; + fom_mask_len = 0; + } + + last_line = line; + line = line - width * 2; + start_line--; + lines_sent++; + } + + Stream_SetPosition(temp_s, 0); + + if (fill_count > 3 && + fill_count >= color_count && + fill_count >= bicolor_count && + fill_count >= mix_count && + fill_count >= fom_count) + { + if (fill_count > count) + return -1; + + count -= fill_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FILL_COUNT2(fill_count, s); + } + else if (mix_count > 3 && + mix_count >= color_count && + mix_count >= bicolor_count && + mix_count >= fill_count && + mix_count >= fom_count) + { + if (mix_count > count) + return -1; + + count -= mix_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_MIX_COUNT2(mix_count, s); + } + else if (color_count > 3 && + color_count >= mix_count && + color_count >= bicolor_count && + color_count >= fill_count && + color_count >= fom_count) + { + if (color_count > count) + return -1; + + count -= color_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_COLOR_COUNT2(color_count, s, last_pixel); + } + else if (bicolor_count > 3 && + bicolor_count >= mix_count && + bicolor_count >= color_count && + bicolor_count >= fill_count && + bicolor_count >= fom_count) + { + if ((bicolor_count % 2) != 0) + bicolor_count--; + + if (bicolor_count > count) + return -1; + + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor2, bicolor1); + + if (bicolor_count > count) + return -1; + + count -= bicolor_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_BICOLOR_COUNT2(bicolor_count, s, bicolor1, bicolor2); + } + else if (fom_count > 3 && + fom_count >= mix_count && + fom_count >= color_count && + fom_count >= fill_count && + fom_count >= bicolor_count) + { + if (fom_count > count) + return -1; + + count -= fom_count; + OUT_COPY_COUNT2(count, s, temp_s); + OUT_FOM_COUNT2(fom_count, s, fom_mask, fom_mask_len); + } + else + { + OUT_COPY_COUNT2(count, s, temp_s); + } + + return lines_sent; +} + +SSIZE_T freerdp_bitmap_compress(const void* srcData, UINT32 width, UINT32 height, + wStream* s, UINT32 bpp, UINT32 byte_limit, UINT32 start_line, wStream* temp_s, UINT32 e) +{ + Stream_SetPosition(temp_s, 0); + + switch (bpp) + { + case 15: + case 16: + return freerdp_bitmap_compress_16(srcData, width, height, s, bpp, + byte_limit, start_line, temp_s, e); + + case 24: + return freerdp_bitmap_compress_24(srcData, width, height, s, + byte_limit, start_line, temp_s, e); + + default: + return -1; + } +} diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c index 15eec7c72..4dec1b505 100644 --- a/libfreerdp/codec/interleaved.c +++ b/libfreerdp/codec/interleaved.c @@ -381,11 +381,17 @@ BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette, UINT32 bpp) { - int status; + BOOL status; wStream* s; UINT32 DstFormat = 0; const size_t maxSize = 64 * 64 * 4; + if (!interleaved || !pDstData || !pSrcData) + return FALSE; + + if ((nWidth == 0) || (nHeight == 0)) + return FALSE; + if (nWidth % 4) { WLog_ERR(TAG, "interleaved_compress: width is not a multiple of 4"); @@ -400,31 +406,43 @@ BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, return FALSE; } - if (bpp == 24) - DstFormat = PIXEL_FORMAT_BGRX32; - else if (bpp == 16) - DstFormat = PIXEL_FORMAT_RGB16; - else if (bpp == 15) - DstFormat = PIXEL_FORMAT_RGB15; - else if (bpp == 8) - DstFormat = PIXEL_FORMAT_RGB8; + switch (bpp) + { + case 24: + DstFormat = PIXEL_FORMAT_BGRX32; + break; - if (!DstFormat) - return FALSE; + case 16: + DstFormat = PIXEL_FORMAT_RGB16; + break; + + case 15: + DstFormat = PIXEL_FORMAT_RGB15; + break; + + default: + return FALSE; + } if (!freerdp_image_copy(interleaved->TempBuffer, DstFormat, 0, 0, 0, nWidth, - nHeight, - pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette, FREERDP_FLIP_NONE)) + nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, + palette, FREERDP_FLIP_NONE)) return FALSE; - s = Stream_New(pDstData, maxSize); + s = Stream_New(pDstData, *pDstSize); if (!s) return FALSE; - status = freerdp_bitmap_compress((char*) interleaved->TempBuffer, nWidth, - nHeight, - s, bpp, maxSize, nHeight - 1, interleaved->bts, 0); + Stream_SetPosition(interleaved->bts, 0); + + if (freerdp_bitmap_compress(interleaved->TempBuffer, nWidth, nHeight, + s, bpp, maxSize, nHeight - 1, + interleaved->bts, 0) < 0) + status = FALSE; + else + status = TRUE; + Stream_SealLength(s); *pDstSize = (UINT32) Stream_Length(s); Stream_Free(s, FALSE);