summaryrefslogtreecommitdiffstats
path: root/rdp/rdp_bitmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'rdp/rdp_bitmap.c')
-rw-r--r--rdp/rdp_bitmap.c917
1 files changed, 917 insertions, 0 deletions
diff --git a/rdp/rdp_bitmap.c b/rdp/rdp_bitmap.c
new file mode 100644
index 00000000..f5eade66
--- /dev/null
+++ b/rdp/rdp_bitmap.c
@@ -0,0 +1,917 @@
+/*
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ xrdp: A Remote Desktop Protocol server.
+ Copyright (C) Jay Sorg 2005
+
+ librdp bitmap routines
+
+*/
+
+#include "rdp.h"
+
+/******************************************************************************/
+#define CVAL(p) ((unsigned char)(*(p++)))
+
+/******************************************************************************/
+#define REPEAT(statement) \
+{ \
+ while ((count > 0) && (x < width)) \
+ { \
+ statement; \
+ count--; \
+ x++; \
+ } \
+}
+
+/******************************************************************************/
+#define MASK_UPDATE \
+{ \
+ mixmask <<= 1; \
+ if ((mixmask & 0xff) == 0) \
+ { \
+ mask = fom_mask ? fom_mask : CVAL(input); \
+ mixmask = 1; \
+ } \
+}
+
+/******************************************************************************/
+/* 1 byte bitmap decompress */
+/* returns boolean */
+static int APP_CC
+bitmap_decompress1(char* output, int width, int height, char* input, int size)
+{
+ char* prevline;
+ char* line;
+ char* end;
+ char color1;
+ char color2;
+ char mix;
+ int code;
+ int mixmask;
+ int mask;
+ int opcode;
+ int count;
+ int offset;
+ int isfillormix;
+ int x;
+ int lastopcode;
+ int insertmix;
+ int bicolor;
+ int fom_mask;
+
+ end = input + size;
+ prevline = 0;
+ line = 0;
+ x = width;
+ lastopcode = -1;
+ insertmix = 0;
+ bicolor = 0;
+ color1 = 0;
+ color2 = 0;
+ mix = 0xff;
+ mask = 0;
+ fom_mask = 0;
+
+ while (input < end)
+ {
+ fom_mask = 0;
+ code = CVAL(input);
+ opcode = code >> 4;
+ /* Handle different opcode forms */
+ switch (opcode)
+ {
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ opcode -= 6;
+ count = code & 0xf;
+ offset = 16;
+ break;
+ case 0xf:
+ opcode = code & 0xf;
+ if (opcode < 9)
+ {
+ count = CVAL(input);
+ count |= CVAL(input) << 8;
+ }
+ else
+ {
+ count = (opcode < 0xb) ? 8 : 1;
+ }
+ offset = 0;
+ break;
+ default:
+ opcode >>= 1;
+ count = code & 0x1f;
+ offset = 32;
+ break;
+ }
+ /* Handle strange cases for counts */
+ if (offset != 0)
+ {
+ isfillormix = ((opcode == 2) || (opcode == 7));
+ if (count == 0)
+ {
+ if (isfillormix)
+ {
+ count = CVAL(input) + 1;
+ }
+ else
+ {
+ count = CVAL(input) + offset;
+ }
+ }
+ else if (isfillormix)
+ {
+ count <<= 3;
+ }
+ }
+ /* Read preliminary data */
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if ((lastopcode == opcode) && !((x == width) && (prevline == 0)))
+ {
+ insertmix = 1;
+ }
+ break;
+ case 8: /* Bicolor */
+ color1 = CVAL(input);
+ case 3: /* Color */
+ color2 = CVAL(input);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ mix = CVAL(input);
+ opcode -= 5;
+ break;
+ case 9: /* FillOrMix_1 */
+ mask = 0x03;
+ opcode = 0x02;
+ fom_mask = 3;
+ break;
+ case 0x0a: /* FillOrMix_2 */
+ mask = 0x05;
+ opcode = 0x02;
+ fom_mask = 5;
+ break;
+ }
+ lastopcode = opcode;
+ mixmask = 0;
+ /* Output body */
+ while (count > 0)
+ {
+ if (x >= width)
+ {
+ if (height <= 0)
+ {
+ return 0;
+ }
+ x = 0;
+ height--;
+ prevline = line;
+ line = output + height * width;
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == 0)
+ {
+ line[x] = mix;
+ }
+ else
+ {
+ line[x] = prevline[x] ^ mix;
+ }
+ insertmix = 0;
+ count--;
+ x++;
+ }
+ if (prevline == 0)
+ {
+ REPEAT(line[x] = 0)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x])
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == 0)
+ {
+ REPEAT(line[x] = mix)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x] ^ mix)
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x] = mix;
+ }
+ else
+ {
+ line[x] = 0;
+ }
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x] = prevline[x] ^ mix;
+ }
+ else
+ {
+ line[x] = prevline[x];
+ }
+ )
+ }
+ break;
+ case 3: /* Color */
+ REPEAT(line[x] = color2)
+ break;
+ case 4: /* Copy */
+ REPEAT(line[x] = CVAL(input))
+ break;
+ case 8: /* Bicolor */
+ REPEAT
+ (
+ if (bicolor)
+ {
+ line[x] = color2;
+ bicolor = 0;
+ }
+ else
+ {
+ line[x] = color1;
+ bicolor = 1;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT(line[x] = 0xff)
+ break;
+ case 0xe: /* Black */
+ REPEAT(line[x] = 0)
+ break;
+ default:
+ return 0;
+ break;
+ }
+ }
+ }
+ return 1;
+}
+
+/******************************************************************************/
+/* 2 byte bitmap decompress */
+/* returns boolean */
+static int APP_CC
+bitmap_decompress2(char* output, int width, int height, char* input, int size)
+{
+ char* prevline;
+ char* line;
+ char* end;
+ char color1[2];
+ char color2[2];
+ char mix[2];
+ int code;
+ int mixmask;
+ int mask;
+ int opcode;
+ int count;
+ int offset;
+ int isfillormix;
+ int x;
+ int lastopcode;
+ int insertmix;
+ int bicolor;
+ int fom_mask;
+
+ end = input + size;
+ prevline = 0;
+ line = 0;
+ x = width;
+ lastopcode = -1;
+ insertmix = 0;
+ bicolor = 0;
+ color1[0] = 0;
+ color1[1] = 0;
+ color2[0] = 0;
+ color2[1] = 0;
+ mix[0] = 0xff;
+ mix[1] = 0xff;
+ mask = 0;
+ fom_mask = 0;
+
+ while (input < end)
+ {
+ fom_mask = 0;
+ code = CVAL(input);
+ opcode = code >> 4;
+ /* Handle different opcode forms */
+ switch (opcode)
+ {
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ opcode -= 6;
+ count = code & 0xf;
+ offset = 16;
+ break;
+ case 0xf:
+ opcode = code & 0xf;
+ if (opcode < 9)
+ {
+ count = CVAL(input);
+ count |= CVAL(input) << 8;
+ }
+ else
+ {
+ count = (opcode < 0xb) ? 8 : 1;
+ }
+ offset = 0;
+ break;
+ default:
+ opcode >>= 1;
+ count = code & 0x1f;
+ offset = 32;
+ break;
+ }
+ /* Handle strange cases for counts */
+ if (offset != 0)
+ {
+ isfillormix = ((opcode == 2) || (opcode == 7));
+ if (count == 0)
+ {
+ if (isfillormix)
+ {
+ count = CVAL(input) + 1;
+ }
+ else
+ {
+ count = CVAL(input) + offset;
+ }
+ }
+ else if (isfillormix)
+ {
+ count <<= 3;
+ }
+ }
+ /* Read preliminary data */
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if ((lastopcode == opcode) && !((x == width) && (prevline == 0)))
+ {
+ insertmix = 1;
+ }
+ break;
+ case 8: /* Bicolor */
+ color1[0] = CVAL(input);
+ color1[1] = CVAL(input);
+ case 3: /* Color */
+ color2[0] = CVAL(input);
+ color2[1] = CVAL(input);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ mix[0] = CVAL(input);
+ mix[1] = CVAL(input);
+ opcode -= 5;
+ break;
+ case 9: /* FillOrMix_1 */
+ mask = 0x03;
+ opcode = 0x02;
+ fom_mask = 3;
+ break;
+ case 0x0a: /* FillOrMix_2 */
+ mask = 0x05;
+ opcode = 0x02;
+ fom_mask = 5;
+ break;
+ }
+ lastopcode = opcode;
+ mixmask = 0;
+ /* Output body */
+ while (count > 0)
+ {
+ if (x >= width)
+ {
+ if (height <= 0)
+ {
+ return 0;
+ }
+ x = 0;
+ height--;
+ prevline = line;
+ line = output + height * (width * 2);
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == 0)
+ {
+ line[x * 2 + 0] = mix[0];
+ line[x * 2 + 1] = mix[1];
+ }
+ else
+ {
+ line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0];
+ line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1];
+ }
+ insertmix = 0;
+ count--;
+ x++;
+ }
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ line[x * 2 + 0] = 0;
+ line[x * 2 + 1] = 0;
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 2 + 0] = prevline[x * 2 + 0];
+ line[x * 2 + 1] = prevline[x * 2 + 1];
+ )
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ line[x * 2 + 0] = mix[0];
+ line[x * 2 + 1] = mix[1];
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0];
+ line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1];
+ )
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x * 2 + 0] = mix[0];
+ line[x * 2 + 1] = mix[1];
+ }
+ else
+ {
+ line[x * 2 + 0] = 0;
+ line[x * 2 + 1] = 0;
+ }
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x * 2 + 0] = prevline[x * 2 + 0] ^ mix[0];
+ line[x * 2 + 1] = prevline[x * 2 + 1] ^ mix[1];
+ }
+ else
+ {
+ line[x * 2 + 0] = prevline[x * 2 + 0];
+ line[x * 2 + 1] = prevline[x * 2 + 1];
+ }
+ )
+ }
+ break;
+ case 3: /* Color */
+ REPEAT
+ (
+ line[x * 2 + 0] = color2[0];
+ line[x * 2 + 1] = color2[1];
+ )
+ break;
+ case 4: /* Copy */
+ REPEAT
+ (
+ line[x * 2 + 0] = CVAL(input);
+ line[x * 2 + 1] = CVAL(input);
+ )
+ break;
+ case 8: /* Bicolor */
+ REPEAT
+ (
+ if (bicolor)
+ {
+ line[x * 2 + 0] = color2[0];
+ line[x * 2 + 1] = color2[1];
+ bicolor = 0;
+ }
+ else
+ {
+ line[x * 2 + 0] = color1[0];
+ line[x * 2 + 1] = color1[1];
+ bicolor = 1;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT
+ (
+ line[x * 2 + 0] = 0xff;
+ line[x * 2 + 1] = 0xff;
+ )
+ break;
+ case 0xe: /* Black */
+ REPEAT
+ (
+ line[x * 2 + 0] = 0;
+ line[x * 2 + 1] = 0;
+ )
+ break;
+ default:
+ return 0;
+ break;
+ }
+ }
+ }
+ return 1;
+}
+
+/******************************************************************************/
+/* 3 byte bitmap decompress */
+/* returns boolean */
+static int APP_CC
+bitmap_decompress3(char* output, int width, int height, char* input, int size)
+{
+ char* prevline;
+ char* line;
+ char* end;
+ char color1[3];
+ char color2[3];
+ char mix[3];
+ int code;
+ int mixmask;
+ int mask;
+ int opcode;
+ int count;
+ int offset;
+ int isfillormix;
+ int x;
+ int lastopcode;
+ int insertmix;
+ int bicolor;
+ int fom_mask;
+
+ end = input + size;
+ prevline = 0;
+ line = 0;
+ x = width;
+ lastopcode = -1;
+ insertmix = 0;
+ bicolor = 0;
+ color1[0] = 0;
+ color1[1] = 0;
+ color1[2] = 0;
+ color2[0] = 0;
+ color2[1] = 0;
+ color2[2] = 0;
+ mix[0] = 0xff;
+ mix[1] = 0xff;
+ mix[2] = 0xff;
+ mask = 0;
+ fom_mask = 0;
+
+ while (input < end)
+ {
+ fom_mask = 0;
+ code = CVAL(input);
+ opcode = code >> 4;
+ /* Handle different opcode forms */
+ switch (opcode)
+ {
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ opcode -= 6;
+ count = code & 0xf;
+ offset = 16;
+ break;
+ case 0xf:
+ opcode = code & 0xf;
+ if (opcode < 9)
+ {
+ count = CVAL(input);
+ count |= CVAL(input) << 8;
+ }
+ else
+ {
+ count = (opcode < 0xb) ? 8 : 1;
+ }
+ offset = 0;
+ break;
+ default:
+ opcode >>= 1;
+ count = code & 0x1f;
+ offset = 32;
+ break;
+ }
+ /* Handle strange cases for counts */
+ if (offset != 0)
+ {
+ isfillormix = ((opcode == 2) || (opcode == 7));
+ if (count == 0)
+ {
+ if (isfillormix)
+ {
+ count = CVAL(input) + 1;
+ }
+ else
+ {
+ count = CVAL(input) + offset;
+ }
+ }
+ else if (isfillormix)
+ {
+ count <<= 3;
+ }
+ }
+ /* Read preliminary data */
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if ((lastopcode == opcode) && !((x == width) && (prevline == 0)))
+ {
+ insertmix = 1;
+ }
+ break;
+ case 8: /* Bicolor */
+ color1[0] = CVAL(input);
+ color1[1] = CVAL(input);
+ color1[2] = CVAL(input);
+ case 3: /* Color */
+ color2[0] = CVAL(input);
+ color2[1] = CVAL(input);
+ color2[2] = CVAL(input);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ mix[0] = CVAL(input);
+ mix[1] = CVAL(input);
+ mix[2] = CVAL(input);
+ opcode -= 5;
+ break;
+ case 9: /* FillOrMix_1 */
+ mask = 0x03;
+ opcode = 0x02;
+ fom_mask = 3;
+ break;
+ case 0x0a: /* FillOrMix_2 */
+ mask = 0x05;
+ opcode = 0x02;
+ fom_mask = 5;
+ break;
+ }
+ lastopcode = opcode;
+ mixmask = 0;
+ /* Output body */
+ while (count > 0)
+ {
+ if (x >= width)
+ {
+ if (height <= 0)
+ {
+ return 0;
+ }
+ x = 0;
+ height--;
+ prevline = line;
+ line = output + height * (width * 3);
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == 0)
+ {
+ line[x * 3 + 0] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ }
+ else
+ {
+ line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0];
+ line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1];
+ line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2];
+ }
+ insertmix = 0;
+ count--;
+ x++;
+ }
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ line[x * 3 + 0] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 3 + 0] = prevline[x * 3 + 0];
+ line[x * 3 + 1] = prevline[x * 3 + 1];
+ line[x * 3 + 2] = prevline[x * 3 + 2];
+ )
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ line[x * 3 + 0] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0];
+ line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1];
+ line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2];
+ )
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == 0)
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x * 3 + 0] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ }
+ else
+ {
+ line[x * 3 + 0] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ }
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE;
+ if (mask & mixmask)
+ {
+ line[x * 3 + 0] = prevline[x * 3 + 0] ^ mix[0];
+ line[x * 3 + 1] = prevline[x * 3 + 1] ^ mix[1];
+ line[x * 3 + 2] = prevline[x * 3 + 2] ^ mix[2];
+ }
+ else
+ {
+ line[x * 3 + 0] = prevline[x * 3 + 0];
+ line[x * 3 + 1] = prevline[x * 3 + 1];
+ line[x * 3 + 2] = prevline[x * 3 + 2];
+ }
+ )
+ }
+ break;
+ case 3: /* Color */
+ REPEAT
+ (
+ line[x * 3 + 0] = color2[0];
+ line[x * 3 + 1] = color2[1];
+ line[x * 3 + 2] = color2[2];
+ )
+ break;
+ case 4: /* Copy */
+ REPEAT
+ (
+ line[x * 3 + 0] = CVAL(input);
+ line[x * 3 + 1] = CVAL(input);
+ line[x * 3 + 2] = CVAL(input);
+ )
+ break;
+ case 8: /* Bicolor */
+ REPEAT
+ (
+ if (bicolor)
+ {
+ line[x * 3 + 0] = color2[0];
+ line[x * 3 + 1] = color2[1];
+ line[x * 3 + 2] = color2[2];
+ bicolor = 0;
+ }
+ else
+ {
+ line[x * 3 + 0] = color1[0];
+ line[x * 3 + 1] = color1[1];
+ line[x * 3 + 2] = color1[2];
+ bicolor = 1;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT
+ (
+ line[x * 3 + 0] = 0xff;
+ line[x * 3 + 1] = 0xff;
+ line[x * 3 + 2] = 0xff;
+ )
+ break;
+ case 0xe: /* Black */
+ REPEAT
+ (
+ line[x * 3 + 0] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ )
+ break;
+ default:
+ return 0;
+ break;
+ }
+ }
+ }
+ return 1;
+}
+
+/*****************************************************************************/
+/* returns boolean */
+int APP_CC
+rdp_bitmap_decompress(char* output, int width, int height, char* input,
+ int size, int Bpp)
+{
+ int rv;
+
+ switch (Bpp)
+ {
+ case 1:
+ rv = bitmap_decompress1(output, width, height, input, size);
+ break;
+ case 2:
+ rv = bitmap_decompress2(output, width, height, input, size);
+ break;
+ case 3:
+ rv = bitmap_decompress3(output, width, height, input, size);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+ return rv;
+}