summaryrefslogtreecommitdiffstats
path: root/uirdesktop
diff options
context:
space:
mode:
authorjsorg71 <jsorg71>2006-06-21 03:58:16 +0000
committerjsorg71 <jsorg71>2006-06-21 03:58:16 +0000
commit8c28bc2dec8b920777e9571c7b75e4be1102419a (patch)
treece2045be5b7aa1dc8c086896298ea9e8cfed5282 /uirdesktop
parentfac0e03c03e27563900a1b00625ae12fd9c931f8 (diff)
downloadxrdp-proprietary-8c28bc2dec8b920777e9571c7b75e4be1102419a.tar.gz
xrdp-proprietary-8c28bc2dec8b920777e9571c7b75e4be1102419a.zip
added files from rdesktop
Diffstat (limited to 'uirdesktop')
-rw-r--r--uirdesktop/bitmap.c1021
-rw-r--r--uirdesktop/cache.c432
-rw-r--r--uirdesktop/mppc.c380
-rw-r--r--uirdesktop/orders.c1307
-rw-r--r--uirdesktop/orders.h368
-rw-r--r--uirdesktop/pstcache.c200
6 files changed, 3708 insertions, 0 deletions
diff --git a/uirdesktop/bitmap.c b/uirdesktop/bitmap.c
new file mode 100644
index 00000000..18e0cee7
--- /dev/null
+++ b/uirdesktop/bitmap.c
@@ -0,0 +1,1021 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ Bitmap decompression routines
+ Copyright (C) Matthew Chapman 1999-2005
+
+ 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.
+*/
+
+/* three seperate function for speed when decompressing the bitmaps */
+/* when modifing one function make the change in the others */
+/* comment out #define BITMAP_SPEED_OVER_SIZE below for one slower function */
+/* j@american-data.com */
+
+#define BITMAP_SPEED_OVER_SIZE
+
+/* indent is confused by this file */
+/* *INDENT-OFF* */
+
+#include "rdesktop.h"
+
+#define CVAL(p) (*(p++))
+#ifdef NEED_ALIGN
+#ifdef L_ENDIAN
+#define CVAL2(p, v) { v = (*(p++)); v |= (*(p++)) << 8; }
+#else
+#define CVAL2(p, v) { v = (*(p++)) << 8; v |= (*(p++)); }
+#endif /* L_ENDIAN */
+#else
+#define CVAL2(p, v) { v = (*((uint16*)p)); p += 2; }
+#endif /* NEED_ALIGN */
+
+#define UNROLL8(exp) { exp exp exp exp exp exp exp exp }
+
+#define REPEAT(statement) \
+{ \
+ while((count & ~0x7) && ((x+8) < width)) \
+ UNROLL8( statement; count--; x++; ); \
+ \
+ while((count > 0) && (x < width)) \
+ { \
+ statement; \
+ count--; \
+ x++; \
+ } \
+}
+
+#define MASK_UPDATE() \
+{ \
+ mixmask <<= 1; \
+ if (mixmask == 0) \
+ { \
+ mask = fom_mask ? fom_mask : CVAL(input); \
+ mixmask = 1; \
+ } \
+}
+
+#ifdef BITMAP_SPEED_OVER_SIZE
+
+/* 1 byte bitmap decompress */
+static BOOL
+bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size)
+{
+ uint8 *end = input + size;
+ uint8 *prevline = NULL, *line = NULL;
+ int opcode, count, offset, isfillormix, x = width;
+ int lastopcode = -1, insertmix = False, bicolour = False;
+ uint8 code;
+ uint8 colour1 = 0, colour2 = 0;
+ uint8 mixmask, mask = 0;
+ uint8 mix = 0xff;
+ int 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 == NULL)))
+ insertmix = True;
+ break;
+ case 8: /* Bicolour */
+ colour1 = CVAL(input);
+ case 3: /* Colour */
+ colour2 = 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 False;
+ x = 0;
+ height--;
+ prevline = line;
+ line = output + height * width;
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == NULL)
+ line[x] = mix;
+ else
+ line[x] = prevline[x] ^ mix;
+ insertmix = False;
+ count--;
+ x++;
+ }
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = 0)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x])
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = mix)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x] ^ mix)
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == NULL)
+ {
+ 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: /* Colour */
+ REPEAT(line[x] = colour2)
+ break;
+ case 4: /* Copy */
+ REPEAT(line[x] = CVAL(input))
+ break;
+ case 8: /* Bicolour */
+ REPEAT
+ (
+ if (bicolour)
+ {
+ line[x] = colour2;
+ bicolour = False;
+ }
+ else
+ {
+ line[x] = colour1;
+ bicolour = True; count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT(line[x] = 0xff)
+ break;
+ case 0xe: /* Black */
+ REPEAT(line[x] = 0)
+ break;
+ default:
+ unimpl("bitmap opcode 0x%x\n", opcode);
+ return False;
+ }
+ }
+ }
+ return True;
+}
+
+/* 2 byte bitmap decompress */
+static BOOL
+bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size)
+{
+ uint8 *end = input + size;
+ uint16 *prevline = NULL, *line = NULL;
+ int opcode, count, offset, isfillormix, x = width;
+ int lastopcode = -1, insertmix = False, bicolour = False;
+ uint8 code;
+ uint16 colour1 = 0, colour2 = 0;
+ uint8 mixmask, mask = 0;
+ uint16 mix = 0xffff;
+ int 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 == NULL)))
+ insertmix = True;
+ break;
+ case 8: /* Bicolour */
+ CVAL2(input, colour1);
+ case 3: /* Colour */
+ CVAL2(input, colour2);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ CVAL2(input, mix);
+ 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 False;
+ x = 0;
+ height--;
+ prevline = line;
+ line = ((uint16 *) output) + height * width;
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == NULL)
+ line[x] = mix;
+ else
+ line[x] = prevline[x] ^ mix;
+ insertmix = False;
+ count--;
+ x++;
+ }
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = 0)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x])
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == NULL)
+ {
+ REPEAT(line[x] = mix)
+ }
+ else
+ {
+ REPEAT(line[x] = prevline[x] ^ mix)
+ }
+ break;
+ case 2: /* Fill or Mix */
+ if (prevline == NULL)
+ {
+ 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: /* Colour */
+ REPEAT(line[x] = colour2)
+ break;
+ case 4: /* Copy */
+ REPEAT(CVAL2(input, line[x]))
+ break;
+ case 8: /* Bicolour */
+ REPEAT
+ (
+ if (bicolour)
+ {
+ line[x] = colour2;
+ bicolour = False;
+ }
+ else
+ {
+ line[x] = colour1;
+ bicolour = True;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT(line[x] = 0xffff)
+ break;
+ case 0xe: /* Black */
+ REPEAT(line[x] = 0)
+ break;
+ default:
+ unimpl("bitmap opcode 0x%x\n", opcode);
+ return False;
+ }
+ }
+ }
+ return True;
+}
+
+/* 3 byte bitmap decompress */
+static BOOL
+bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size)
+{
+ uint8 *end = input + size;
+ uint8 *prevline = NULL, *line = NULL;
+ int opcode, count, offset, isfillormix, x = width;
+ int lastopcode = -1, insertmix = False, bicolour = False;
+ uint8 code;
+ uint8 colour1[3] = {0, 0, 0}, colour2[3] = {0, 0, 0};
+ uint8 mixmask, mask = 0;
+ uint8 mix[3] = {0xff, 0xff, 0xff};
+ int 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 == NULL)))
+ insertmix = True;
+ break;
+ case 8: /* Bicolour */
+ colour1[0] = CVAL(input);
+ colour1[1] = CVAL(input);
+ colour1[2] = CVAL(input);
+ case 3: /* Colour */
+ colour2[0] = CVAL(input);
+ colour2[1] = CVAL(input);
+ colour2[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 False;
+ x = 0;
+ height--;
+ prevline = line;
+ line = output + height * (width * 3);
+ }
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == NULL)
+ {
+ line[x * 3] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ }
+ else
+ {
+ line[x * 3] =
+ prevline[x * 3] ^ mix[0];
+ line[x * 3 + 1] =
+ prevline[x * 3 + 1] ^ mix[1];
+ line[x * 3 + 2] =
+ prevline[x * 3 + 2] ^ mix[2];
+ }
+ insertmix = False;
+ count--;
+ x++;
+ }
+ if (prevline == NULL)
+ {
+ REPEAT
+ (
+ line[x * 3] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 3] = prevline[x * 3];
+ line[x * 3 + 1] = prevline[x * 3 + 1];
+ line[x * 3 + 2] = prevline[x * 3 + 2];
+ )
+ }
+ break;
+ case 1: /* Mix */
+ if (prevline == NULL)
+ {
+ REPEAT
+ (
+ line[x * 3] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ line[x * 3] =
+ prevline[x * 3] ^ 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 == NULL)
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ {
+ line[x * 3] = mix[0];
+ line[x * 3 + 1] = mix[1];
+ line[x * 3 + 2] = mix[2];
+ }
+ else
+ {
+ line[x * 3] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ }
+ )
+ }
+ else
+ {
+ REPEAT
+ (
+ MASK_UPDATE();
+ if (mask & mixmask)
+ {
+ line[x * 3] =
+ prevline[x * 3] ^ 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] =
+ prevline[x * 3];
+ line[x * 3 + 1] =
+ prevline[x * 3 + 1];
+ line[x * 3 + 2] =
+ prevline[x * 3 + 2];
+ }
+ )
+ }
+ break;
+ case 3: /* Colour */
+ REPEAT
+ (
+ line[x * 3] = colour2 [0];
+ line[x * 3 + 1] = colour2 [1];
+ line[x * 3 + 2] = colour2 [2];
+ )
+ break;
+ case 4: /* Copy */
+ REPEAT
+ (
+ line[x * 3] = CVAL(input);
+ line[x * 3 + 1] = CVAL(input);
+ line[x * 3 + 2] = CVAL(input);
+ )
+ break;
+ case 8: /* Bicolour */
+ REPEAT
+ (
+ if (bicolour)
+ {
+ line[x * 3] = colour2[0];
+ line[x * 3 + 1] = colour2[1];
+ line[x * 3 + 2] = colour2[2];
+ bicolour = False;
+ }
+ else
+ {
+ line[x * 3] = colour1[0];
+ line[x * 3 + 1] = colour1[1];
+ line[x * 3 + 2] = colour1[2];
+ bicolour = True;
+ count++;
+ }
+ )
+ break;
+ case 0xd: /* White */
+ REPEAT
+ (
+ line[x * 3] = 0xff;
+ line[x * 3 + 1] = 0xff;
+ line[x * 3 + 2] = 0xff;
+ )
+ break;
+ case 0xe: /* Black */
+ REPEAT
+ (
+ line[x * 3] = 0;
+ line[x * 3 + 1] = 0;
+ line[x * 3 + 2] = 0;
+ )
+ break;
+ default:
+ unimpl("bitmap opcode 0x%x\n", opcode);
+ return False;
+ }
+ }
+ }
+ return True;
+}
+
+#else
+
+static uint32
+cvalx(uint8 **input, int Bpp)
+{
+ uint32 rv = 0;
+ memcpy(&rv, *input, Bpp);
+ *input += Bpp;
+ return rv;
+}
+
+static void
+setli(uint8 *input, int offset, uint32 value, int Bpp)
+{
+ input += offset * Bpp;
+ memcpy(input, &value, Bpp);
+}
+
+static uint32
+getli(uint8 *input, int offset, int Bpp)
+{
+ uint32 rv = 0;
+ input += offset * Bpp;
+ memcpy(&rv, input, Bpp);
+ return rv;
+}
+
+static BOOL
+bitmap_decompressx(uint8 *output, int width, int height, uint8 *input, int size, int Bpp)
+{
+ uint8 *end = input + size;
+ uint8 *prevline = NULL, *line = NULL;
+ int opcode, count, offset, isfillormix, x = width;
+ int lastopcode = -1, insertmix = False, bicolour = False;
+ uint8 code;
+ uint32 colour1 = 0, colour2 = 0;
+ uint8 mixmask, mask = 0;
+ uint32 mix = 0xffffffff;
+ int 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 == NULL)))
+ insertmix = True;
+ break;
+ case 8: /* Bicolour */
+ colour1 = cvalx(&input, Bpp);
+ case 3: /* Colour */
+ colour2 = cvalx(&input, Bpp);
+ break;
+ case 6: /* SetMix/Mix */
+ case 7: /* SetMix/FillOrMix */
+ mix = cvalx(&input, Bpp);
+ 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 False;
+
+ x = 0;
+ height--;
+
+ prevline = line;
+ line = output + height * width * Bpp;
+ }
+
+ switch (opcode)
+ {
+ case 0: /* Fill */
+ if (insertmix)
+ {
+ if (prevline == NULL)
+ setli(line, x, mix, Bpp);
+ else
+ setli(line, x,
+ getli(prevline, x, Bpp) ^ mix, Bpp);
+
+ insertmix = False;
+ count--;
+ x++;
+ }
+
+ if (prevline == NULL)
+ {
+ REPEAT(setli(line, x, 0, Bpp))}
+ else
+ {
+ REPEAT(setli
+ (line, x, getli(prevline, x, Bpp), Bpp));
+ }
+ break;
+
+ case 1: /* Mix */
+ if (prevline == NULL)
+ {
+ REPEAT(setli(line, x, mix, Bpp));
+ }
+ else
+ {
+ REPEAT(setli
+ (line, x, getli(prevline, x, Bpp) ^ mix,
+ Bpp));
+ }
+ break;
+
+ case 2: /* Fill or Mix */
+ if (prevline == NULL)
+ {
+ REPEAT(MASK_UPDATE();
+ if (mask & mixmask) setli(line, x, mix, Bpp);
+ else
+ setli(line, x, 0, Bpp););
+ }
+ else
+ {
+ REPEAT(MASK_UPDATE();
+ if (mask & mixmask)
+ setli(line, x, getli(prevline, x, Bpp) ^ mix,
+ Bpp);
+ else
+ setli(line, x, getli(prevline, x, Bpp),
+ Bpp););
+ }
+ break;
+
+ case 3: /* Colour */
+ REPEAT(setli(line, x, colour2, Bpp));
+ break;
+
+ case 4: /* Copy */
+ REPEAT(setli(line, x, cvalx(&input, Bpp), Bpp));
+ break;
+
+ case 8: /* Bicolour */
+ REPEAT(if (bicolour)
+ {
+ setli(line, x, colour2, Bpp); bicolour = False;}
+ else
+ {
+ setli(line, x, colour1, Bpp); bicolour = True;
+ count++;}
+ );
+ break;
+
+ case 0xd: /* White */
+ REPEAT(setli(line, x, 0xffffffff, Bpp));
+ break;
+
+ case 0xe: /* Black */
+ REPEAT(setli(line, x, 0, Bpp));
+ break;
+
+ default:
+ unimpl("bitmap opcode 0x%x\n", opcode);
+ return False;
+ }
+ }
+ }
+
+ return True;
+}
+
+#endif
+
+/* main decompress function */
+BOOL
+bitmap_decompress(uint8 * output, int width, int height, uint8 * input, int size, int Bpp)
+{
+#ifdef BITMAP_SPEED_OVER_SIZE
+ BOOL rv = False;
+ 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;
+ }
+#else
+ BOOL rv;
+ rv = bitmap_decompressx(output, width, height, input, size, Bpp);
+#endif
+ return rv;
+}
+
+/* *INDENT-ON* */
diff --git a/uirdesktop/cache.c b/uirdesktop/cache.c
new file mode 100644
index 00000000..70fcf2cf
--- /dev/null
+++ b/uirdesktop/cache.c
@@ -0,0 +1,432 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ Cache routines
+ Copyright (C) Matthew Chapman 1999-2005
+ Copyright (C) Jeroen Meijer 2005
+
+ 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.
+*/
+
+#include "rdesktop.h"
+
+/* BITMAP CACHE */
+extern int g_pstcache_fd[];
+
+#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
+#define IS_PERSISTENT(id) (g_pstcache_fd[id] > 0)
+#define TO_TOP -1
+#define NOT_SET -1
+#define IS_SET(idx) (idx >= 0)
+
+/*
+ * TODO: Test for optimal value of BUMP_COUNT. TO_TOP gives lowest cpu utilisation but using
+ * a positive value will hopefully result in less frequently used bitmaps having a greater chance
+ * of being evicted from the cache, and therby reducing the need to load bitmaps from disk.
+ * (Jeroen)
+ */
+#define BUMP_COUNT 40
+
+struct bmpcache_entry
+{
+ HBITMAP bitmap;
+ sint16 previous;
+ sint16 next;
+};
+
+static struct bmpcache_entry g_bmpcache[3][0xa00];
+static HBITMAP g_volatile_bc[3];
+
+static int g_bmpcache_lru[3] = { NOT_SET, NOT_SET, NOT_SET };
+static int g_bmpcache_mru[3] = { NOT_SET, NOT_SET, NOT_SET };
+static int g_bmpcache_count[3];
+
+/* Setup the bitmap cache lru/mru linked list */
+void
+cache_rebuild_bmpcache_linked_list(uint8 id, sint16 * idx, int count)
+{
+ int n = count, c = 0;
+ sint16 n_idx;
+
+ /* find top, skip evicted bitmaps */
+ while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
+ if (n < 0)
+ {
+ g_bmpcache_mru[id] = g_bmpcache_lru[id] = NOT_SET;
+ return;
+ }
+
+ g_bmpcache_mru[id] = idx[n];
+ g_bmpcache[id][idx[n]].next = NOT_SET;
+ n_idx = idx[n];
+ c++;
+
+ /* link list */
+ while (n >= 0)
+ {
+ /* skip evicted bitmaps */
+ while (--n >= 0 && g_bmpcache[id][idx[n]].bitmap == NULL);
+
+ if (n < 0)
+ break;
+
+ g_bmpcache[id][n_idx].previous = idx[n];
+ g_bmpcache[id][idx[n]].next = n_idx;
+ n_idx = idx[n];
+ c++;
+ }
+
+ g_bmpcache[id][n_idx].previous = NOT_SET;
+ g_bmpcache_lru[id] = n_idx;
+
+ if (c != g_bmpcache_count[id])
+ {
+ error("Oops. %d in bitmap cache linked list, %d in ui cache...\n", c,
+ g_bmpcache_count[id]);
+ exit(1);
+ }
+}
+
+/* Move a bitmap to a new position in the linked list. */
+void
+cache_bump_bitmap(uint8 id, uint16 idx, int bump)
+{
+ int p_idx, n_idx, n;
+
+ if (!IS_PERSISTENT(id))
+ return;
+
+ if (g_bmpcache_mru[id] == idx)
+ return;
+
+ DEBUG_RDP5(("bump bitmap: id=%d, idx=%d, bump=%d\n", id, idx, bump));
+
+ n_idx = g_bmpcache[id][idx].next;
+ p_idx = g_bmpcache[id][idx].previous;
+
+ if (IS_SET(n_idx))
+ {
+ /* remove */
+ --g_bmpcache_count[id];
+ if (IS_SET(p_idx))
+ g_bmpcache[id][p_idx].next = n_idx;
+ else
+ g_bmpcache_lru[id] = n_idx;
+ if (IS_SET(n_idx))
+ g_bmpcache[id][n_idx].previous = p_idx;
+ else
+ g_bmpcache_mru[id] = p_idx;
+ }
+ else
+ {
+ p_idx = NOT_SET;
+ n_idx = g_bmpcache_lru[id];
+ }
+
+ if (bump >= 0)
+ {
+ for (n = 0; n < bump && IS_SET(n_idx); n++)
+ {
+ p_idx = n_idx;
+ n_idx = g_bmpcache[id][p_idx].next;
+ }
+ }
+ else
+ {
+ p_idx = g_bmpcache_mru[id];
+ n_idx = NOT_SET;
+ }
+
+ /* insert */
+ ++g_bmpcache_count[id];
+ g_bmpcache[id][idx].previous = p_idx;
+ g_bmpcache[id][idx].next = n_idx;
+
+ if (p_idx >= 0)
+ g_bmpcache[id][p_idx].next = idx;
+ else
+ g_bmpcache_lru[id] = idx;
+
+ if (n_idx >= 0)
+ g_bmpcache[id][n_idx].previous = idx;
+ else
+ g_bmpcache_mru[id] = idx;
+}
+
+/* Evict the least-recently used bitmap from the cache */
+void
+cache_evict_bitmap(uint8 id)
+{
+ uint16 idx;
+ int n_idx;
+
+ if (!IS_PERSISTENT(id))
+ return;
+
+ idx = g_bmpcache_lru[id];
+ n_idx = g_bmpcache[id][idx].next;
+ DEBUG_RDP5(("evict bitmap: id=%d idx=%d n_idx=%d bmp=0x%x\n", id, idx, n_idx,
+ g_bmpcache[id][idx].bitmap));
+
+ ui_destroy_bitmap(g_bmpcache[id][idx].bitmap);
+ --g_bmpcache_count[id];
+ g_bmpcache[id][idx].bitmap = 0;
+
+ g_bmpcache_lru[id] = n_idx;
+ g_bmpcache[id][n_idx].previous = NOT_SET;
+
+ pstcache_touch_bitmap(id, idx, 0);
+}
+
+/* Retrieve a bitmap from the cache */
+HBITMAP
+cache_get_bitmap(uint8 id, uint16 idx)
+{
+ if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
+ {
+ if (g_bmpcache[id][idx].bitmap || pstcache_load_bitmap(id, idx))
+ {
+ if (IS_PERSISTENT(id))
+ cache_bump_bitmap(id, idx, BUMP_COUNT);
+
+ return g_bmpcache[id][idx].bitmap;
+ }
+ }
+ else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
+ {
+ return g_volatile_bc[id];
+ }
+
+ error("get bitmap %d:%d\n", id, idx);
+ return NULL;
+}
+
+/* Store a bitmap in the cache */
+void
+cache_put_bitmap(uint8 id, uint16 idx, HBITMAP bitmap)
+{
+ HBITMAP old;
+
+ if ((id < NUM_ELEMENTS(g_bmpcache)) && (idx < NUM_ELEMENTS(g_bmpcache[0])))
+ {
+ old = g_bmpcache[id][idx].bitmap;
+ if (old != NULL)
+ ui_destroy_bitmap(old);
+ g_bmpcache[id][idx].bitmap = bitmap;
+
+ if (IS_PERSISTENT(id))
+ {
+ if (old == NULL)
+ g_bmpcache[id][idx].previous = g_bmpcache[id][idx].next = NOT_SET;
+
+ cache_bump_bitmap(id, idx, TO_TOP);
+ if (g_bmpcache_count[id] > BMPCACHE2_C2_CELLS)
+ cache_evict_bitmap(id);
+ }
+ }
+ else if ((id < NUM_ELEMENTS(g_volatile_bc)) && (idx == 0x7fff))
+ {
+ old = g_volatile_bc[id];
+ if (old != NULL)
+ ui_destroy_bitmap(old);
+ g_volatile_bc[id] = bitmap;
+ }
+ else
+ {
+ error("put bitmap %d:%d\n", id, idx);
+ }
+}
+
+/* Updates the persistent bitmap cache MRU information on exit */
+void
+cache_save_state(void)
+{
+ uint32 id = 0, t = 0;
+ int idx;
+
+ for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++)
+ if (IS_PERSISTENT(id))
+ {
+ DEBUG_RDP5(("Saving cache state for bitmap cache %d...", id));
+ idx = g_bmpcache_lru[id];
+ while (idx >= 0)
+ {
+ pstcache_touch_bitmap(id, idx, ++t);
+ idx = g_bmpcache[id][idx].next;
+ }
+ DEBUG_RDP5((" %d stamps written.\n", t));
+ }
+}
+
+
+/* FONT CACHE */
+static FONTGLYPH g_fontcache[12][256];
+
+/* Retrieve a glyph from the font cache */
+FONTGLYPH *
+cache_get_font(uint8 font, uint16 character)
+{
+ FONTGLYPH *glyph;
+
+ if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
+ {
+ glyph = &g_fontcache[font][character];
+ if (glyph->pixmap != NULL)
+ return glyph;
+ }
+
+ error("get font %d:%d\n", font, character);
+ return NULL;
+}
+
+/* Store a glyph in the font cache */
+void
+cache_put_font(uint8 font, uint16 character, uint16 offset,
+ uint16 baseline, uint16 width, uint16 height, HGLYPH pixmap)
+{
+ FONTGLYPH *glyph;
+
+ if ((font < NUM_ELEMENTS(g_fontcache)) && (character < NUM_ELEMENTS(g_fontcache[0])))
+ {
+ glyph = &g_fontcache[font][character];
+ if (glyph->pixmap != NULL)
+ ui_destroy_glyph(glyph->pixmap);
+
+ glyph->offset = offset;
+ glyph->baseline = baseline;
+ glyph->width = width;
+ glyph->height = height;
+ glyph->pixmap = pixmap;
+ }
+ else
+ {
+ error("put font %d:%d\n", font, character);
+ }
+}
+
+
+/* TEXT CACHE */
+static DATABLOB g_textcache[256];
+
+/* Retrieve a text item from the cache */
+DATABLOB *
+cache_get_text(uint8 cache_id)
+{
+ DATABLOB *text;
+
+ text = &g_textcache[cache_id];
+ return text;
+}
+
+/* Store a text item in the cache */
+void
+cache_put_text(uint8 cache_id, void *data, int length)
+{
+ DATABLOB *text;
+
+ text = &g_textcache[cache_id];
+ if (text->data != NULL)
+ xfree(text->data);
+ text->data = xmalloc(length);
+ text->size = length;
+ memcpy(text->data, data, length);
+}
+
+
+/* DESKTOP CACHE */
+static uint8 g_deskcache[0x38400 * 4];
+
+/* Retrieve desktop data from the cache */
+uint8 *
+cache_get_desktop(uint32 offset, int cx, int cy, int bytes_per_pixel)
+{
+ int length = cx * cy * bytes_per_pixel;
+
+ if (offset > sizeof(g_deskcache))
+ offset = 0;
+
+ if ((offset + length) <= sizeof(g_deskcache))
+ {
+ return &g_deskcache[offset];
+ }
+
+ error("get desktop %d:%d\n", offset, length);
+ return NULL;
+}
+
+/* Store desktop data in the cache */
+void
+cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_per_pixel, uint8 * data)
+{
+ int length = cx * cy * bytes_per_pixel;
+
+ if (offset > sizeof(g_deskcache))
+ offset = 0;
+
+ if ((offset + length) <= sizeof(g_deskcache))
+ {
+ cx *= bytes_per_pixel;
+ while (cy--)
+ {
+ memcpy(&g_deskcache[offset], data, cx);
+ data += scanline;
+ offset += cx;
+ }
+ }
+ else
+ {
+ error("put desktop %d:%d\n", offset, length);
+ }
+}
+
+
+/* CURSOR CACHE */
+static HCURSOR g_cursorcache[0x20];
+
+/* Retrieve cursor from cache */
+HCURSOR
+cache_get_cursor(uint16 cache_idx)
+{
+ HCURSOR cursor;
+
+ if (cache_idx < NUM_ELEMENTS(g_cursorcache))
+ {
+ cursor = g_cursorcache[cache_idx];
+ if (cursor != NULL)
+ return cursor;
+ }
+
+ error("get cursor %d\n", cache_idx);
+ return NULL;
+}
+
+/* Store cursor in cache */
+void
+cache_put_cursor(uint16 cache_idx, HCURSOR cursor)
+{
+ HCURSOR old;
+
+ if (cache_idx < NUM_ELEMENTS(g_cursorcache))
+ {
+ old = g_cursorcache[cache_idx];
+ if (old != NULL)
+ ui_destroy_cursor(old);
+
+ g_cursorcache[cache_idx] = cursor;
+ }
+ else
+ {
+ error("put cursor %d\n", cache_idx);
+ }
+}
diff --git a/uirdesktop/mppc.c b/uirdesktop/mppc.c
new file mode 100644
index 00000000..cc126c15
--- /dev/null
+++ b/uirdesktop/mppc.c
@@ -0,0 +1,380 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ Protocol services - RDP decompression
+ Copyright (C) Matthew Chapman 1999-2005
+
+ 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.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "rdesktop.h"
+
+/* mppc decompression */
+/* http://www.faqs.org/rfcs/rfc2118.html */
+
+/* Contacts: */
+
+/* hifn contact mentioned in the faq is */
+/* Robert Friend rfriend at hifn dot com */
+
+/* if you have questions regarding MPPC */
+/* our contact is */
+/* Guus Dhaeze GDhaeze at hifn dot com */
+
+/* Licensing: */
+
+/* decompression is alright as long as we */
+/* don't compress data */
+
+/* Algorithm: */
+
+/* as the rfc states the algorithm seems to */
+/* be LZ77 with a sliding buffer */
+/* that is empty at init. */
+
+/* the algorithm is called LZS and is */
+/* patented for another couple of years. */
+
+/* more information is available in */
+/* http://www.ietf.org/ietf/IPR/hifn-ipr-draft-friend-tls-lzs-compression.txt */
+
+
+RDPCOMP g_mppc_dict;
+
+int
+mppc_expand(uint8 * data, uint32 clen, uint8 ctype, uint32 * roff, uint32 * rlen)
+{
+ int k, walker_len = 0, walker;
+ uint32 i = 0;
+ int next_offset, match_off;
+ int match_len;
+ int old_offset, match_bits;
+ BOOL big = ctype & RDP_MPPC_BIG ? True : False;
+
+ uint8 *dict = g_mppc_dict.hist;
+
+ if ((ctype & RDP_MPPC_COMPRESSED) == 0)
+ {
+ *roff = 0;
+ *rlen = clen;
+ return 0;
+ }
+
+ if ((ctype & RDP_MPPC_RESET) != 0)
+ {
+ g_mppc_dict.roff = 0;
+ }
+
+ if ((ctype & RDP_MPPC_FLUSH) != 0)
+ {
+ memset(dict, 0, RDP_MPPC_DICT_SIZE);
+ g_mppc_dict.roff = 0;
+ }
+
+ *roff = 0;
+ *rlen = 0;
+
+ walker = g_mppc_dict.roff;
+
+ next_offset = walker;
+ old_offset = next_offset;
+ *roff = old_offset;
+ if (clen == 0)
+ return 0;
+ clen += i;
+
+ do
+ {
+ if (walker_len == 0)
+ {
+ if (i >= clen)
+ break;
+ walker = data[i++] << 24;
+ walker_len = 8;
+ }
+ if (walker >= 0)
+ {
+ if (walker_len < 8)
+ {
+ if (i >= clen)
+ {
+ if (walker != 0)
+ return -1;
+ break;
+ }
+ walker |= (data[i++] & 0xff) << (24 - walker_len);
+ walker_len += 8;
+ }
+ if (next_offset >= RDP_MPPC_DICT_SIZE)
+ return -1;
+ dict[next_offset++] = (((uint32) walker) >> ((uint32) 24));
+ walker <<= 8;
+ walker_len -= 8;
+ continue;
+ }
+ walker <<= 1;
+ /* fetch next 8-bits */
+ if (--walker_len == 0)
+ {
+ if (i >= clen)
+ return -1;
+ walker = data[i++] << 24;
+ walker_len = 8;
+ }
+ /* literal decoding */
+ if (walker >= 0)
+ {
+ if (walker_len < 8)
+ {
+ if (i >= clen)
+ return -1;
+ walker |= (data[i++] & 0xff) << (24 - walker_len);
+ walker_len += 8;
+ }
+ if (next_offset >= RDP_MPPC_DICT_SIZE)
+ return -1;
+ dict[next_offset++] = (uint8) (walker >> 24 | 0x80);
+ walker <<= 8;
+ walker_len -= 8;
+ continue;
+ }
+
+ /* decode offset */
+ /* length pair */
+ walker <<= 1;
+ if (--walker_len < (big ? 3 : 2))
+ {
+ if (i >= clen)
+ return -1;
+ walker |= (data[i++] & 0xff) << (24 - walker_len);
+ walker_len += 8;
+ }
+
+ if (big)
+ {
+ /* offset decoding where offset len is:
+ -63: 11111 followed by the lower 6 bits of the value
+ 64-319: 11110 followed by the lower 8 bits of the value ( value - 64 )
+ 320-2367: 1110 followed by lower 11 bits of the value ( value - 320 )
+ 2368-65535: 110 followed by lower 16 bits of the value ( value - 2368 )
+ */
+ switch (((uint32) walker) >> ((uint32) 29))
+ {
+ case 7: /* - 63 */
+ for (; walker_len < 9; walker_len += 8)
+ {
+ if (i >= clen)
+ return -1;
+ walker |= (data[i++] & 0xff) << (24 - walker_len);
+ }
+ walker <<= 3;
+ match_off = ((uint32) walker) >> ((uint32) 26);
+ walker <<= 6;
+ walker_len -= 9;
+ break;
+
+ case 6: /* 64 - 319 */
+ for (; walker_len < 11; walker_len += 8)
+ {
+ if (i >= clen)
+ return -1;
+ walker |= (data[i++] & 0xff) << (24 - walker_len);
+ }
+
+ walker <<= 3;
+ match_off = (((uint32) walker) >> ((uint32) 24)) + 64;
+ walker <<= 8;
+ walker_len -= 11;
+ break;
+
+ case 5:
+ case 4: /* 320 - 2367 */
+ for (; walker_len < 13; walker_len += 8)
+ {
+ if (i >= clen)
+ return -1;
+ walker |= (data[i++] & 0xff) << (24 - walker_len);
+ }
+
+ walker <<= 2;
+ match_off = (((uint32) walker) >> ((uint32) 21)) + 320;
+ walker <<= 11;
+ walker_len -= 13;
+ break;
+
+ default: /* 2368 - 65535 */
+ for (; walker_len < 17; walker_len += 8)
+ {
+ if (i >= clen)
+ return -1;
+ walker |= (data[i++] & 0xff) << (24 - walker_len);
+ }
+
+ walker <<= 1;
+ match_off = (((uint32) walker) >> ((uint32) 16)) + 2368;
+ walker <<= 16;
+ walker_len -= 17;
+ break;
+ }
+ }
+ else
+ {
+ /* offset decoding where offset len is:
+ -63: 1111 followed by the lower 6 bits of the value
+ 64-319: 1110 followed by the lower 8 bits of the value ( value - 64 )
+ 320-8191: 110 followed by the lower 13 bits of the value ( value - 320 )
+ */
+ switch (((uint32) walker) >> ((uint32) 30))
+ {
+ case 3: /* - 63 */
+ if (walker_len < 8)
+ {
+ if (i >= clen)
+ return -1;
+ walker |= (data[i++] & 0xff) << (24 - walker_len);
+ walker_len += 8;
+ }
+ walker <<= 2;
+ match_off = ((uint32) walker) >> ((uint32) 26);
+ walker <<= 6;
+ walker_len -= 8;
+ break;
+
+ case 2: /* 64 - 319 */
+ for (; walker_len < 10; walker_len += 8)
+ {
+ if (i >= clen)
+ return -1;
+ walker |= (data[i++] & 0xff) << (24 - walker_len);
+ }
+
+ walker <<= 2;
+ match_off = (((uint32) walker) >> ((uint32) 24)) + 64;
+ walker <<= 8;
+ walker_len -= 10;
+ break;
+
+ default: /* 320 - 8191 */
+ for (; walker_len < 14; walker_len += 8)
+ {
+ if (i >= clen)
+ return -1;
+ walker |= (data[i++] & 0xff) << (24 - walker_len);
+ }
+
+ match_off = (walker >> 18) + 320;
+ walker <<= 14;
+ walker_len -= 14;
+ break;
+ }
+ }
+ if (walker_len == 0)
+ {
+ if (i >= clen)
+ return -1;
+ walker = data[i++] << 24;
+ walker_len = 8;
+ }
+
+ /* decode length of match */
+ match_len = 0;
+ if (walker >= 0)
+ { /* special case - length of 3 is in bit 0 */
+ match_len = 3;
+ walker <<= 1;
+ walker_len--;
+ }
+ else
+ {
+ /* this is how it works len of:
+ 4-7: 10 followed by 2 bits of the value
+ 8-15: 110 followed by 3 bits of the value
+ 16-31: 1110 followed by 4 bits of the value
+ 32-63: .... and so forth
+ 64-127:
+ 128-255:
+ 256-511:
+ 512-1023:
+ 1024-2047:
+ 2048-4095:
+ 4096-8191:
+
+ i.e. 4097 is encoded as: 111111111110 000000000001
+ meaning 4096 + 1...
+ */
+ match_bits = big ? 14 : 11; /* 11 or 14 bits of value at most */
+ do
+ {
+ walker <<= 1;
+ if (--walker_len == 0)
+ {
+ if (i >= clen)
+ return -1;
+ walker = data[i++] << 24;
+ walker_len = 8;
+ }
+ if (walker >= 0)
+ break;
+ if (--match_bits == 0)
+ {
+ return -1;
+ }
+ }
+ while (1);
+ match_len = (big ? 16 : 13) - match_bits;
+ walker <<= 1;
+ if (--walker_len < match_len)
+ {
+ for (; walker_len < match_len; walker_len += 8)
+ {
+ if (i >= clen)
+ {
+ return -1;
+ }
+ walker |= (data[i++] & 0xff) << (24 - walker_len);
+ }
+ }
+
+ match_bits = match_len;
+ match_len =
+ ((walker >> (32 - match_bits)) & (~(-1 << match_bits))) | (1 <<
+ match_bits);
+ walker <<= match_bits;
+ walker_len -= match_bits;
+ }
+ if (next_offset + match_len >= RDP_MPPC_DICT_SIZE)
+ {
+ return -1;
+ }
+ /* memory areas can overlap - meaning we can't use memXXX functions */
+ k = (next_offset - match_off) & (big ? 65535 : 8191);
+ do
+ {
+ dict[next_offset++] = dict[k++];
+ }
+ while (--match_len != 0);
+ }
+ while (1);
+
+ /* store history offset */
+ g_mppc_dict.roff = next_offset;
+
+ *roff = old_offset;
+ *rlen = next_offset - old_offset;
+
+ return 0;
+}
diff --git a/uirdesktop/orders.c b/uirdesktop/orders.c
new file mode 100644
index 00000000..418988ba
--- /dev/null
+++ b/uirdesktop/orders.c
@@ -0,0 +1,1307 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ RDP order processing
+ Copyright (C) Matthew Chapman 1999-2005
+
+ 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.
+*/
+
+#include "rdesktop.h"
+#include "orders.h"
+
+extern uint8 *g_next_packet;
+static RDP_ORDER_STATE g_order_state;
+extern BOOL g_use_rdp5;
+
+/* Read field indicating which parameters are present */
+static void
+rdp_in_present(STREAM s, uint32 * present, uint8 flags, int size)
+{
+ uint8 bits;
+ int i;
+
+ if (flags & RDP_ORDER_SMALL)
+ {
+ size--;
+ }
+
+ if (flags & RDP_ORDER_TINY)
+ {
+ if (size < 2)
+ size = 0;
+ else
+ size -= 2;
+ }
+
+ *present = 0;
+ for (i = 0; i < size; i++)
+ {
+ in_uint8(s, bits);
+ *present |= bits << (i * 8);
+ }
+}
+
+/* Read a co-ordinate (16-bit, or 8-bit delta) */
+static void
+rdp_in_coord(STREAM s, sint16 * coord, BOOL delta)
+{
+ sint8 change;
+
+ if (delta)
+ {
+ in_uint8(s, change);
+ *coord += change;
+ }
+ else
+ {
+ in_uint16_le(s, *coord);
+ }
+}
+
+/* Parse a delta co-ordinate in polyline/polygon order form */
+static int
+parse_delta(uint8 * buffer, int *offset)
+{
+ int value = buffer[(*offset)++];
+ int two_byte = value & 0x80;
+
+ if (value & 0x40) /* sign bit */
+ value |= ~0x3f;
+ else
+ value &= 0x3f;
+
+ if (two_byte)
+ value = (value << 8) | buffer[(*offset)++];
+
+ return value;
+}
+
+/* Read a colour entry */
+static void
+rdp_in_colour(STREAM s, uint32 * colour)
+{
+ uint32 i;
+ in_uint8(s, i);
+ *colour = i;
+ in_uint8(s, i);
+ *colour |= i << 8;
+ in_uint8(s, i);
+ *colour |= i << 16;
+}
+
+/* Parse bounds information */
+static BOOL
+rdp_parse_bounds(STREAM s, BOUNDS * bounds)
+{
+ uint8 present;
+
+ in_uint8(s, present);
+
+ if (present & 1)
+ rdp_in_coord(s, &bounds->left, False);
+ else if (present & 16)
+ rdp_in_coord(s, &bounds->left, True);
+
+ if (present & 2)
+ rdp_in_coord(s, &bounds->top, False);
+ else if (present & 32)
+ rdp_in_coord(s, &bounds->top, True);
+
+ if (present & 4)
+ rdp_in_coord(s, &bounds->right, False);
+ else if (present & 64)
+ rdp_in_coord(s, &bounds->right, True);
+
+ if (present & 8)
+ rdp_in_coord(s, &bounds->bottom, False);
+ else if (present & 128)
+ rdp_in_coord(s, &bounds->bottom, True);
+
+ return s_check(s);
+}
+
+/* Parse a pen */
+static BOOL
+rdp_parse_pen(STREAM s, PEN * pen, uint32 present)
+{
+ if (present & 1)
+ in_uint8(s, pen->style);
+
+ if (present & 2)
+ in_uint8(s, pen->width);
+
+ if (present & 4)
+ rdp_in_colour(s, &pen->colour);
+
+ return s_check(s);
+}
+
+/* Parse a brush */
+static BOOL
+rdp_parse_brush(STREAM s, BRUSH * brush, uint32 present)
+{
+ if (present & 1)
+ in_uint8(s, brush->xorigin);
+
+ if (present & 2)
+ in_uint8(s, brush->yorigin);
+
+ if (present & 4)
+ in_uint8(s, brush->style);
+
+ if (present & 8)
+ in_uint8(s, brush->pattern[0]);
+
+ if (present & 16)
+ in_uint8a(s, &brush->pattern[1], 7);
+
+ return s_check(s);
+}
+
+/* Process a destination blt order */
+static void
+process_destblt(STREAM s, DESTBLT_ORDER * os, uint32 present, BOOL delta)
+{
+ if (present & 0x01)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x02)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x04)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x08)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x10)
+ in_uint8(s, os->opcode);
+
+ DEBUG(("DESTBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d)\n",
+ os->opcode, os->x, os->y, os->cx, os->cy));
+
+ ui_destblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy);
+}
+
+/* Process a pattern blt order */
+static void
+process_patblt(STREAM s, PATBLT_ORDER * os, uint32 present, BOOL delta)
+{
+ if (present & 0x0001)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x0002)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x0004)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x0008)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x0010)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x0020)
+ rdp_in_colour(s, &os->bgcolour);
+
+ if (present & 0x0040)
+ rdp_in_colour(s, &os->fgcolour);
+
+ rdp_parse_brush(s, &os->brush, present >> 7);
+
+ DEBUG(("PATBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,bs=%d,bg=0x%x,fg=0x%x)\n", os->opcode, os->x,
+ os->y, os->cx, os->cy, os->brush.style, os->bgcolour, os->fgcolour));
+
+ ui_patblt(ROP2_P(os->opcode), os->x, os->y, os->cx, os->cy,
+ &os->brush, os->bgcolour, os->fgcolour);
+}
+
+/* Process a screen blt order */
+static void
+process_screenblt(STREAM s, SCREENBLT_ORDER * os, uint32 present, BOOL delta)
+{
+ if (present & 0x0001)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x0002)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x0004)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x0008)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x0010)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x0020)
+ rdp_in_coord(s, &os->srcx, delta);
+
+ if (present & 0x0040)
+ rdp_in_coord(s, &os->srcy, delta);
+
+ DEBUG(("SCREENBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,srcx=%d,srcy=%d)\n",
+ os->opcode, os->x, os->y, os->cx, os->cy, os->srcx, os->srcy));
+
+ ui_screenblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, os->srcx, os->srcy);
+}
+
+/* Process a line order */
+static void
+process_line(STREAM s, LINE_ORDER * os, uint32 present, BOOL delta)
+{
+ if (present & 0x0001)
+ in_uint16_le(s, os->mixmode);
+
+ if (present & 0x0002)
+ rdp_in_coord(s, &os->startx, delta);
+
+ if (present & 0x0004)
+ rdp_in_coord(s, &os->starty, delta);
+
+ if (present & 0x0008)
+ rdp_in_coord(s, &os->endx, delta);
+
+ if (present & 0x0010)
+ rdp_in_coord(s, &os->endy, delta);
+
+ if (present & 0x0020)
+ rdp_in_colour(s, &os->bgcolour);
+
+ if (present & 0x0040)
+ in_uint8(s, os->opcode);
+
+ rdp_parse_pen(s, &os->pen, present >> 7);
+
+ DEBUG(("LINE(op=0x%x,sx=%d,sy=%d,dx=%d,dy=%d,fg=0x%x)\n",
+ os->opcode, os->startx, os->starty, os->endx, os->endy, os->pen.colour));
+
+ if (os->opcode < 0x01 || os->opcode > 0x10)
+ {
+ error("bad ROP2 0x%x\n", os->opcode);
+ return;
+ }
+
+ ui_line(os->opcode - 1, os->startx, os->starty, os->endx, os->endy, &os->pen);
+}
+
+/* Process an opaque rectangle order */
+static void
+process_rect(STREAM s, RECT_ORDER * os, uint32 present, BOOL delta)
+{
+ uint32 i;
+ if (present & 0x01)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x02)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x04)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x08)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x10)
+ {
+ in_uint8(s, i);
+ os->colour = (os->colour & 0xffffff00) | i;
+ }
+
+ if (present & 0x20)
+ {
+ in_uint8(s, i);
+ os->colour = (os->colour & 0xffff00ff) | (i << 8);
+ }
+
+ if (present & 0x40)
+ {
+ in_uint8(s, i);
+ os->colour = (os->colour & 0xff00ffff) | (i << 16);
+ }
+
+ DEBUG(("RECT(x=%d,y=%d,cx=%d,cy=%d,fg=0x%x)\n", os->x, os->y, os->cx, os->cy, os->colour));
+
+ ui_rect(os->x, os->y, os->cx, os->cy, os->colour);
+}
+
+/* Process a desktop save order */
+static void
+process_desksave(STREAM s, DESKSAVE_ORDER * os, uint32 present, BOOL delta)
+{
+ int width, height;
+
+ if (present & 0x01)
+ in_uint32_le(s, os->offset);
+
+ if (present & 0x02)
+ rdp_in_coord(s, &os->left, delta);
+
+ if (present & 0x04)
+ rdp_in_coord(s, &os->top, delta);
+
+ if (present & 0x08)
+ rdp_in_coord(s, &os->right, delta);
+
+ if (present & 0x10)
+ rdp_in_coord(s, &os->bottom, delta);
+
+ if (present & 0x20)
+ in_uint8(s, os->action);
+
+ DEBUG(("DESKSAVE(l=%d,t=%d,r=%d,b=%d,off=%d,op=%d)\n",
+ os->left, os->top, os->right, os->bottom, os->offset, os->action));
+
+ width = os->right - os->left + 1;
+ height = os->bottom - os->top + 1;
+
+ if (os->action == 0)
+ ui_desktop_save(os->offset, os->left, os->top, width, height);
+ else
+ ui_desktop_restore(os->offset, os->left, os->top, width, height);
+}
+
+/* Process a memory blt order */
+static void
+process_memblt(STREAM s, MEMBLT_ORDER * os, uint32 present, BOOL delta)
+{
+ HBITMAP bitmap;
+
+ if (present & 0x0001)
+ {
+ in_uint8(s, os->cache_id);
+ in_uint8(s, os->colour_table);
+ }
+
+ if (present & 0x0002)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x0004)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x0008)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x0010)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x0020)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x0040)
+ rdp_in_coord(s, &os->srcx, delta);
+
+ if (present & 0x0080)
+ rdp_in_coord(s, &os->srcy, delta);
+
+ if (present & 0x0100)
+ in_uint16_le(s, os->cache_idx);
+
+ DEBUG(("MEMBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d)\n",
+ os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx));
+
+ bitmap = cache_get_bitmap(os->cache_id, os->cache_idx);
+ if (bitmap == NULL)
+ return;
+
+ ui_memblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, bitmap, os->srcx, os->srcy);
+}
+
+/* Process a 3-way blt order */
+static void
+process_triblt(STREAM s, TRIBLT_ORDER * os, uint32 present, BOOL delta)
+{
+ HBITMAP bitmap;
+
+ if (present & 0x000001)
+ {
+ in_uint8(s, os->cache_id);
+ in_uint8(s, os->colour_table);
+ }
+
+ if (present & 0x000002)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x000004)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x000008)
+ rdp_in_coord(s, &os->cx, delta);
+
+ if (present & 0x000010)
+ rdp_in_coord(s, &os->cy, delta);
+
+ if (present & 0x000020)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x000040)
+ rdp_in_coord(s, &os->srcx, delta);
+
+ if (present & 0x000080)
+ rdp_in_coord(s, &os->srcy, delta);
+
+ if (present & 0x000100)
+ rdp_in_colour(s, &os->bgcolour);
+
+ if (present & 0x000200)
+ rdp_in_colour(s, &os->fgcolour);
+
+ rdp_parse_brush(s, &os->brush, present >> 10);
+
+ if (present & 0x008000)
+ in_uint16_le(s, os->cache_idx);
+
+ if (present & 0x010000)
+ in_uint16_le(s, os->unknown);
+
+ DEBUG(("TRIBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d,bs=%d,bg=0x%x,fg=0x%x)\n",
+ os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx,
+ os->brush.style, os->bgcolour, os->fgcolour));
+
+ bitmap = cache_get_bitmap(os->cache_id, os->cache_idx);
+ if (bitmap == NULL)
+ return;
+
+ ui_triblt(os->opcode, os->x, os->y, os->cx, os->cy,
+ bitmap, os->srcx, os->srcy, &os->brush, os->bgcolour, os->fgcolour);
+}
+
+/* Process a polygon order */
+static void
+process_polygon(STREAM s, POLYGON_ORDER * os, uint32 present, BOOL delta)
+{
+ int index, data, next;
+ uint8 flags = 0;
+ POINT *points;
+
+ if (present & 0x01)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x02)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x04)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x08)
+ in_uint8(s, os->fillmode);
+
+ if (present & 0x10)
+ rdp_in_colour(s, &os->fgcolour);
+
+ if (present & 0x20)
+ in_uint8(s, os->npoints);
+
+ if (present & 0x40)
+ {
+ in_uint8(s, os->datasize);
+ in_uint8a(s, os->data, os->datasize);
+ }
+
+ DEBUG(("POLYGON(x=%d,y=%d,op=0x%x,fm=%d,fg=0x%x,n=%d,sz=%d)\n",
+ os->x, os->y, os->opcode, os->fillmode, os->fgcolour, os->npoints, os->datasize));
+
+ DEBUG(("Data: "));
+
+ for (index = 0; index < os->datasize; index++)
+ DEBUG(("%02x ", os->data[index]));
+
+ DEBUG(("\n"));
+
+ if (os->opcode < 0x01 || os->opcode > 0x10)
+ {
+ error("bad ROP2 0x%x\n", os->opcode);
+ return;
+ }
+
+ points = (POINT *) xmalloc((os->npoints + 1) * sizeof(POINT));
+ memset(points, 0, (os->npoints + 1) * sizeof(POINT));
+
+ points[0].x = os->x;
+ points[0].y = os->y;
+
+ index = 0;
+ data = ((os->npoints - 1) / 4) + 1;
+ for (next = 1; (next <= os->npoints) && (next < 256) && (data < os->datasize); next++)
+ {
+ if ((next - 1) % 4 == 0)
+ flags = os->data[index++];
+
+ if (~flags & 0x80)
+ points[next].x = parse_delta(os->data, &data);
+
+ if (~flags & 0x40)
+ points[next].y = parse_delta(os->data, &data);
+
+ flags <<= 2;
+ }
+
+ if (next - 1 == os->npoints)
+ ui_polygon(os->opcode - 1, os->fillmode, points, os->npoints + 1, NULL, 0,
+ os->fgcolour);
+ else
+ error("polygon parse error\n");
+
+ xfree(points);
+}
+
+/* Process a polygon2 order */
+static void
+process_polygon2(STREAM s, POLYGON2_ORDER * os, uint32 present, BOOL delta)
+{
+ int index, data, next;
+ uint8 flags = 0;
+ POINT *points;
+
+ if (present & 0x0001)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x0002)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x0004)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x0008)
+ in_uint8(s, os->fillmode);
+
+ if (present & 0x0010)
+ rdp_in_colour(s, &os->bgcolour);
+
+ if (present & 0x0020)
+ rdp_in_colour(s, &os->fgcolour);
+
+ rdp_parse_brush(s, &os->brush, present >> 6);
+
+ if (present & 0x0800)
+ in_uint8(s, os->npoints);
+
+ if (present & 0x1000)
+ {
+ in_uint8(s, os->datasize);
+ in_uint8a(s, os->data, os->datasize);
+ }
+
+ DEBUG(("POLYGON2(x=%d,y=%d,op=0x%x,fm=%d,bs=%d,bg=0x%x,fg=0x%x,n=%d,sz=%d)\n",
+ os->x, os->y, os->opcode, os->fillmode, os->brush.style, os->bgcolour, os->fgcolour,
+ os->npoints, os->datasize));
+
+ DEBUG(("Data: "));
+
+ for (index = 0; index < os->datasize; index++)
+ DEBUG(("%02x ", os->data[index]));
+
+ DEBUG(("\n"));
+
+ if (os->opcode < 0x01 || os->opcode > 0x10)
+ {
+ error("bad ROP2 0x%x\n", os->opcode);
+ return;
+ }
+
+ points = (POINT *) xmalloc((os->npoints + 1) * sizeof(POINT));
+ memset(points, 0, (os->npoints + 1) * sizeof(POINT));
+
+ points[0].x = os->x;
+ points[0].y = os->y;
+
+ index = 0;
+ data = ((os->npoints - 1) / 4) + 1;
+ for (next = 1; (next <= os->npoints) && (next < 256) && (data < os->datasize); next++)
+ {
+ if ((next - 1) % 4 == 0)
+ flags = os->data[index++];
+
+ if (~flags & 0x80)
+ points[next].x = parse_delta(os->data, &data);
+
+ if (~flags & 0x40)
+ points[next].y = parse_delta(os->data, &data);
+
+ flags <<= 2;
+ }
+
+ if (next - 1 == os->npoints)
+ ui_polygon(os->opcode - 1, os->fillmode, points, os->npoints + 1,
+ &os->brush, os->bgcolour, os->fgcolour);
+ else
+ error("polygon2 parse error\n");
+
+ xfree(points);
+}
+
+/* Process a polyline order */
+static void
+process_polyline(STREAM s, POLYLINE_ORDER * os, uint32 present, BOOL delta)
+{
+ int index, next, data;
+ uint8 flags = 0;
+ PEN pen;
+ POINT *points;
+
+ if (present & 0x01)
+ rdp_in_coord(s, &os->x, delta);
+
+ if (present & 0x02)
+ rdp_in_coord(s, &os->y, delta);
+
+ if (present & 0x04)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x10)
+ rdp_in_colour(s, &os->fgcolour);
+
+ if (present & 0x20)
+ in_uint8(s, os->lines);
+
+ if (present & 0x40)
+ {
+ in_uint8(s, os->datasize);
+ in_uint8a(s, os->data, os->datasize);
+ }
+
+ DEBUG(("POLYLINE(x=%d,y=%d,op=0x%x,fg=0x%x,n=%d,sz=%d)\n",
+ os->x, os->y, os->opcode, os->fgcolour, os->lines, os->datasize));
+
+ DEBUG(("Data: "));
+
+ for (index = 0; index < os->datasize; index++)
+ DEBUG(("%02x ", os->data[index]));
+
+ DEBUG(("\n"));
+
+ if (os->opcode < 0x01 || os->opcode > 0x10)
+ {
+ error("bad ROP2 0x%x\n", os->opcode);
+ return;
+ }
+
+ points = (POINT *) xmalloc((os->lines + 1) * sizeof(POINT));
+ memset(points, 0, (os->lines + 1) * sizeof(POINT));
+
+ points[0].x = os->x;
+ points[0].y = os->y;
+ pen.style = pen.width = 0;
+ pen.colour = os->fgcolour;
+
+ index = 0;
+ data = ((os->lines - 1) / 4) + 1;
+ for (next = 1; (next <= os->lines) && (data < os->datasize); next++)
+ {
+ if ((next - 1) % 4 == 0)
+ flags = os->data[index++];
+
+ if (~flags & 0x80)
+ points[next].x = parse_delta(os->data, &data);
+
+ if (~flags & 0x40)
+ points[next].y = parse_delta(os->data, &data);
+
+ flags <<= 2;
+ }
+
+ if (next - 1 == os->lines)
+ ui_polyline(os->opcode - 1, points, os->lines + 1, &pen);
+ else
+ error("polyline parse error\n");
+
+ xfree(points);
+}
+
+/* Process an ellipse order */
+static void
+process_ellipse(STREAM s, ELLIPSE_ORDER * os, uint32 present, BOOL delta)
+{
+ if (present & 0x01)
+ rdp_in_coord(s, &os->left, delta);
+
+ if (present & 0x02)
+ rdp_in_coord(s, &os->top, delta);
+
+ if (present & 0x04)
+ rdp_in_coord(s, &os->right, delta);
+
+ if (present & 0x08)
+ rdp_in_coord(s, &os->bottom, delta);
+
+ if (present & 0x10)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x20)
+ in_uint8(s, os->fillmode);
+
+ if (present & 0x40)
+ rdp_in_colour(s, &os->fgcolour);
+
+ DEBUG(("ELLIPSE(l=%d,t=%d,r=%d,b=%d,op=0x%x,fm=%d,fg=0x%x)\n", os->left, os->top,
+ os->right, os->bottom, os->opcode, os->fillmode, os->fgcolour));
+
+ ui_ellipse(os->opcode - 1, os->fillmode, os->left, os->top, os->right - os->left,
+ os->bottom - os->top, NULL, 0, os->fgcolour);
+}
+
+/* Process an ellipse2 order */
+static void
+process_ellipse2(STREAM s, ELLIPSE2_ORDER * os, uint32 present, BOOL delta)
+{
+ if (present & 0x0001)
+ rdp_in_coord(s, &os->left, delta);
+
+ if (present & 0x0002)
+ rdp_in_coord(s, &os->top, delta);
+
+ if (present & 0x0004)
+ rdp_in_coord(s, &os->right, delta);
+
+ if (present & 0x0008)
+ rdp_in_coord(s, &os->bottom, delta);
+
+ if (present & 0x0010)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x0020)
+ in_uint8(s, os->fillmode);
+
+ if (present & 0x0040)
+ rdp_in_colour(s, &os->bgcolour);
+
+ if (present & 0x0080)
+ rdp_in_colour(s, &os->fgcolour);
+
+ rdp_parse_brush(s, &os->brush, present >> 8);
+
+ DEBUG(("ELLIPSE2(l=%d,t=%d,r=%d,b=%d,op=0x%x,fm=%d,bs=%d,bg=0x%x,fg=0x%x)\n",
+ os->left, os->top, os->right, os->bottom, os->opcode, os->fillmode, os->brush.style,
+ os->bgcolour, os->fgcolour));
+
+ ui_ellipse(os->opcode - 1, os->fillmode, os->left, os->top, os->right - os->left,
+ os->bottom - os->top, &os->brush, os->bgcolour, os->fgcolour);
+}
+
+/* Process a text order */
+static void
+process_text2(STREAM s, TEXT2_ORDER * os, uint32 present, BOOL delta)
+{
+ int i;
+
+ if (present & 0x000001)
+ in_uint8(s, os->font);
+
+ if (present & 0x000002)
+ in_uint8(s, os->flags);
+
+ if (present & 0x000004)
+ in_uint8(s, os->opcode);
+
+ if (present & 0x000008)
+ in_uint8(s, os->mixmode);
+
+ if (present & 0x000010)
+ rdp_in_colour(s, &os->fgcolour);
+
+ if (present & 0x000020)
+ rdp_in_colour(s, &os->bgcolour);
+
+ if (present & 0x000040)
+ in_uint16_le(s, os->clipleft);
+
+ if (present & 0x000080)
+ in_uint16_le(s, os->cliptop);
+
+ if (present & 0x000100)
+ in_uint16_le(s, os->clipright);
+
+ if (present & 0x000200)
+ in_uint16_le(s, os->clipbottom);
+
+ if (present & 0x000400)
+ in_uint16_le(s, os->boxleft);
+
+ if (present & 0x000800)
+ in_uint16_le(s, os->boxtop);
+
+ if (present & 0x001000)
+ in_uint16_le(s, os->boxright);
+
+ if (present & 0x002000)
+ in_uint16_le(s, os->boxbottom);
+
+ rdp_parse_brush(s, &os->brush, present >> 14);
+
+ if (present & 0x080000)
+ in_uint16_le(s, os->x);
+
+ if (present & 0x100000)
+ in_uint16_le(s, os->y);
+
+ if (present & 0x200000)
+ {
+ in_uint8(s, os->length);
+ in_uint8a(s, os->text, os->length);
+ }
+
+ DEBUG(("TEXT2(x=%d,y=%d,cl=%d,ct=%d,cr=%d,cb=%d,bl=%d,bt=%d,br=%d,bb=%d,bs=%d,bg=0x%x,fg=0x%x,font=%d,fl=0x%x,op=0x%x,mix=%d,n=%d)\n", os->x, os->y, os->clipleft, os->cliptop, os->clipright, os->clipbottom, os->boxleft, os->boxtop, os->boxright, os->boxbottom, os->brush.style, os->bgcolour, os->fgcolour, os->font, os->flags, os->opcode, os->mixmode, os->length));
+
+ DEBUG(("Text: "));
+
+ for (i = 0; i < os->length; i++)
+ DEBUG(("%02x ", os->text[i]));
+
+ DEBUG(("\n"));
+
+ ui_draw_text(os->font, os->flags, os->opcode - 1, os->mixmode, os->x, os->y,
+ os->clipleft, os->cliptop, os->clipright - os->clipleft,
+ os->clipbottom - os->cliptop, os->boxleft, os->boxtop,
+ os->boxright - os->boxleft, os->boxbottom - os->boxtop,
+ &os->brush, os->bgcolour, os->fgcolour, os->text, os->length);
+}
+
+/* Process a raw bitmap cache order */
+static void
+process_raw_bmpcache(STREAM s)
+{
+ HBITMAP bitmap;
+ uint16 cache_idx, bufsize;
+ uint8 cache_id, width, height, bpp, Bpp;
+ uint8 *data, *inverted;
+ int y;
+
+ in_uint8(s, cache_id);
+ in_uint8s(s, 1); /* pad */
+ in_uint8(s, width);
+ in_uint8(s, height);
+ in_uint8(s, bpp);
+ Bpp = (bpp + 7) / 8;
+ in_uint16_le(s, bufsize);
+ in_uint16_le(s, cache_idx);
+ in_uint8p(s, data, bufsize);
+
+ DEBUG(("RAW_BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", width, height, cache_id, cache_idx));
+ inverted = (uint8 *) xmalloc(width * height * Bpp);
+ for (y = 0; y < height; y++)
+ {
+ memcpy(&inverted[(height - y - 1) * (width * Bpp)], &data[y * (width * Bpp)],
+ width * Bpp);
+ }
+
+ bitmap = ui_create_bitmap(width, height, inverted);
+ xfree(inverted);
+ cache_put_bitmap(cache_id, cache_idx, bitmap);
+}
+
+/* Process a bitmap cache order */
+static void
+process_bmpcache(STREAM s)
+{
+ HBITMAP bitmap;
+ uint16 cache_idx, size;
+ uint8 cache_id, width, height, bpp, Bpp;
+ uint8 *data, *bmpdata;
+ uint16 bufsize, pad2, row_size, final_size;
+ uint8 pad1;
+
+ pad2 = row_size = final_size = 0xffff; /* Shut the compiler up */
+
+ in_uint8(s, cache_id);
+ in_uint8(s, pad1); /* pad */
+ in_uint8(s, width);
+ in_uint8(s, height);
+ in_uint8(s, bpp);
+ Bpp = (bpp + 7) / 8;
+ in_uint16_le(s, bufsize); /* bufsize */
+ in_uint16_le(s, cache_idx);
+
+ if (g_use_rdp5)
+ {
+ size = bufsize;
+ }
+ else
+ {
+
+ /* Begin compressedBitmapData */
+ in_uint16_le(s, pad2); /* pad */
+ in_uint16_le(s, size);
+ /* in_uint8s(s, 4); *//* row_size, final_size */
+ in_uint16_le(s, row_size);
+ in_uint16_le(s, final_size);
+
+ }
+ in_uint8p(s, data, size);
+
+ DEBUG(("BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d,bpp=%d,size=%d,pad1=%d,bufsize=%d,pad2=%d,rs=%d,fs=%d)\n", width, height, cache_id, cache_idx, bpp, size, pad1, bufsize, pad2, row_size, final_size));
+
+ bmpdata = (uint8 *) xmalloc(width * height * Bpp);
+
+ if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
+ {
+ bitmap = ui_create_bitmap(width, height, bmpdata);
+ cache_put_bitmap(cache_id, cache_idx, bitmap);
+ }
+ else
+ {
+ DEBUG(("Failed to decompress bitmap data\n"));
+ }
+
+ xfree(bmpdata);
+}
+
+/* Process a bitmap cache v2 order */
+static void
+process_bmpcache2(STREAM s, uint16 flags, BOOL compressed)
+{
+ HBITMAP bitmap;
+ int y;
+ uint8 cache_id, cache_idx_low, width, height, Bpp;
+ uint16 cache_idx, bufsize;
+ uint8 *data, *bmpdata, *bitmap_id;
+
+ bitmap_id = NULL; /* prevent compiler warning */
+ cache_id = flags & ID_MASK;
+ Bpp = ((flags & MODE_MASK) >> MODE_SHIFT) - 2;
+
+ if (flags & PERSIST)
+ {
+ in_uint8p(s, bitmap_id, 8);
+ }
+
+ if (flags & SQUARE)
+ {
+ in_uint8(s, width);
+ height = width;
+ }
+ else
+ {
+ in_uint8(s, width);
+ in_uint8(s, height);
+ }
+
+ in_uint16_be(s, bufsize);
+ bufsize &= BUFSIZE_MASK;
+ in_uint8(s, cache_idx);
+
+ if (cache_idx & LONG_FORMAT)
+ {
+ in_uint8(s, cache_idx_low);
+ cache_idx = ((cache_idx ^ LONG_FORMAT) << 8) + cache_idx_low;
+ }
+
+ in_uint8p(s, data, bufsize);
+
+ DEBUG(("BMPCACHE2(compr=%d,flags=%x,cx=%d,cy=%d,id=%d,idx=%d,Bpp=%d,bs=%d)\n",
+ compressed, flags, width, height, cache_id, cache_idx, Bpp, bufsize));
+
+ bmpdata = (uint8 *) xmalloc(width * height * Bpp);
+
+ if (compressed)
+ {
+ if (!bitmap_decompress(bmpdata, width, height, data, bufsize, Bpp))
+ {
+ DEBUG(("Failed to decompress bitmap data\n"));
+ xfree(bmpdata);
+ return;
+ }
+ }
+ else
+ {
+ for (y = 0; y < height; y++)
+ memcpy(&bmpdata[(height - y - 1) * (width * Bpp)],
+ &data[y * (width * Bpp)], width * Bpp);
+ }
+
+ bitmap = ui_create_bitmap(width, height, bmpdata);
+
+ if (bitmap)
+ {
+ cache_put_bitmap(cache_id, cache_idx, bitmap);
+ if (flags & PERSIST)
+ pstcache_save_bitmap(cache_id, cache_idx, bitmap_id, width, height,
+ width * height * Bpp, bmpdata);
+ }
+ else
+ {
+ DEBUG(("process_bmpcache2: ui_create_bitmap failed\n"));
+ }
+
+ xfree(bmpdata);
+}
+
+/* Process a colourmap cache order */
+static void
+process_colcache(STREAM s)
+{
+ COLOURENTRY *entry;
+ COLOURMAP map;
+ HCOLOURMAP hmap;
+ uint8 cache_id;
+ int i;
+
+ in_uint8(s, cache_id);
+ in_uint16_le(s, map.ncolours);
+
+ map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours);
+
+ for (i = 0; i < map.ncolours; i++)
+ {
+ entry = &map.colours[i];
+ in_uint8(s, entry->blue);
+ in_uint8(s, entry->green);
+ in_uint8(s, entry->red);
+ in_uint8s(s, 1); /* pad */
+ }
+
+ DEBUG(("COLCACHE(id=%d,n=%d)\n", cache_id, map.ncolours));
+
+ hmap = ui_create_colourmap(&map);
+
+ if (cache_id)
+ ui_set_colourmap(hmap);
+
+ xfree(map.colours);
+}
+
+/* Process a font cache order */
+static void
+process_fontcache(STREAM s)
+{
+ HGLYPH bitmap;
+ uint8 font, nglyphs;
+ uint16 character, offset, baseline, width, height;
+ int i, datasize;
+ uint8 *data;
+
+ in_uint8(s, font);
+ in_uint8(s, nglyphs);
+
+ DEBUG(("FONTCACHE(font=%d,n=%d)\n", font, nglyphs));
+
+ for (i = 0; i < nglyphs; i++)
+ {
+ in_uint16_le(s, character);
+ in_uint16_le(s, offset);
+ in_uint16_le(s, baseline);
+ in_uint16_le(s, width);
+ in_uint16_le(s, height);
+
+ datasize = (height * ((width + 7) / 8) + 3) & ~3;
+ in_uint8p(s, data, datasize);
+
+ bitmap = ui_create_glyph(width, height, data);
+ cache_put_font(font, character, offset, baseline, width, height, bitmap);
+ }
+}
+
+/* Process a secondary order */
+static void
+process_secondary_order(STREAM s)
+{
+ /* The length isn't calculated correctly by the server.
+ * For very compact orders the length becomes negative
+ * so a signed integer must be used. */
+ uint16 length;
+ uint16 flags;
+ uint8 type;
+ uint8 *next_order;
+
+ in_uint16_le(s, length);
+ in_uint16_le(s, flags); /* used by bmpcache2 */
+ in_uint8(s, type);
+
+ next_order = s->p + (sint16) length + 7;
+
+ switch (type)
+ {
+ case RDP_ORDER_RAW_BMPCACHE:
+ process_raw_bmpcache(s);
+ break;
+
+ case RDP_ORDER_COLCACHE:
+ process_colcache(s);
+ break;
+
+ case RDP_ORDER_BMPCACHE:
+ process_bmpcache(s);
+ break;
+
+ case RDP_ORDER_FONTCACHE:
+ process_fontcache(s);
+ break;
+
+ case RDP_ORDER_RAW_BMPCACHE2:
+ process_bmpcache2(s, flags, False); /* uncompressed */
+ break;
+
+ case RDP_ORDER_BMPCACHE2:
+ process_bmpcache2(s, flags, True); /* compressed */
+ break;
+
+ default:
+ unimpl("secondary order %d\n", type);
+ }
+
+ s->p = next_order;
+}
+
+/* Process an order PDU */
+void
+process_orders(STREAM s, uint16 num_orders)
+{
+ RDP_ORDER_STATE *os = &g_order_state;
+ uint32 present;
+ uint8 order_flags;
+ int size, processed = 0;
+ BOOL delta;
+
+ while (processed < num_orders)
+ {
+ in_uint8(s, order_flags);
+
+ if (!(order_flags & RDP_ORDER_STANDARD))
+ {
+ error("order parsing failed\n");
+ break;
+ }
+
+ if (order_flags & RDP_ORDER_SECONDARY)
+ {
+ process_secondary_order(s);
+ }
+ else
+ {
+ if (order_flags & RDP_ORDER_CHANGE)
+ {
+ in_uint8(s, os->order_type);
+ }
+
+ switch (os->order_type)
+ {
+ case RDP_ORDER_TRIBLT:
+ case RDP_ORDER_TEXT2:
+ size = 3;
+ break;
+
+ case RDP_ORDER_PATBLT:
+ case RDP_ORDER_MEMBLT:
+ case RDP_ORDER_LINE:
+ case RDP_ORDER_POLYGON2:
+ case RDP_ORDER_ELLIPSE2:
+ size = 2;
+ break;
+
+ default:
+ size = 1;
+ }
+
+ rdp_in_present(s, &present, order_flags, size);
+
+ if (order_flags & RDP_ORDER_BOUNDS)
+ {
+ if (!(order_flags & RDP_ORDER_LASTBOUNDS))
+ rdp_parse_bounds(s, &os->bounds);
+
+ ui_set_clip(os->bounds.left,
+ os->bounds.top,
+ os->bounds.right -
+ os->bounds.left + 1,
+ os->bounds.bottom - os->bounds.top + 1);
+ }
+
+ delta = order_flags & RDP_ORDER_DELTA;
+
+ switch (os->order_type)
+ {
+ case RDP_ORDER_DESTBLT:
+ process_destblt(s, &os->destblt, present, delta);
+ break;
+
+ case RDP_ORDER_PATBLT:
+ process_patblt(s, &os->patblt, present, delta);
+ break;
+
+ case RDP_ORDER_SCREENBLT:
+ process_screenblt(s, &os->screenblt, present, delta);
+ break;
+
+ case RDP_ORDER_LINE:
+ process_line(s, &os->line, present, delta);
+ break;
+
+ case RDP_ORDER_RECT:
+ process_rect(s, &os->rect, present, delta);
+ break;
+
+ case RDP_ORDER_DESKSAVE:
+ process_desksave(s, &os->desksave, present, delta);
+ break;
+
+ case RDP_ORDER_MEMBLT:
+ process_memblt(s, &os->memblt, present, delta);
+ break;
+
+ case RDP_ORDER_TRIBLT:
+ process_triblt(s, &os->triblt, present, delta);
+ break;
+
+ case RDP_ORDER_POLYGON:
+ process_polygon(s, &os->polygon, present, delta);
+ break;
+
+ case RDP_ORDER_POLYGON2:
+ process_polygon2(s, &os->polygon2, present, delta);
+ break;
+
+ case RDP_ORDER_POLYLINE:
+ process_polyline(s, &os->polyline, present, delta);
+ break;
+
+ case RDP_ORDER_ELLIPSE:
+ process_ellipse(s, &os->ellipse, present, delta);
+ break;
+
+ case RDP_ORDER_ELLIPSE2:
+ process_ellipse2(s, &os->ellipse2, present, delta);
+ break;
+
+ case RDP_ORDER_TEXT2:
+ process_text2(s, &os->text2, present, delta);
+ break;
+
+ default:
+ unimpl("order %d\n", os->order_type);
+ return;
+ }
+
+ if (order_flags & RDP_ORDER_BOUNDS)
+ ui_reset_clip();
+ }
+
+ processed++;
+ }
+#if 0
+ /* not true when RDP_COMPRESSION is set */
+ if (s->p != g_next_packet)
+ error("%d bytes remaining\n", (int) (g_next_packet - s->p));
+#endif
+
+}
+
+/* Reset order state */
+void
+reset_order_state(void)
+{
+ memset(&g_order_state, 0, sizeof(g_order_state));
+ g_order_state.order_type = RDP_ORDER_PATBLT;
+}
diff --git a/uirdesktop/orders.h b/uirdesktop/orders.h
new file mode 100644
index 00000000..b1272822
--- /dev/null
+++ b/uirdesktop/orders.h
@@ -0,0 +1,368 @@
+/*
+ rdesktop: A Remote Desktop Protocol client.
+ RDP order processing
+ Copyright (C) Matthew Chapman 1999-2005
+
+ 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.
+*/
+
+#define RDP_ORDER_STANDARD 0x01
+#define RDP_ORDER_SECONDARY 0x02
+#define RDP_ORDER_BOUNDS 0x04
+#define RDP_ORDER_CHANGE 0x08
+#define RDP_ORDER_DELTA 0x10
+#define RDP_ORDER_LASTBOUNDS 0x20
+#define RDP_ORDER_SMALL 0x40
+#define RDP_ORDER_TINY 0x80
+
+enum RDP_ORDER_TYPE
+{
+ RDP_ORDER_DESTBLT = 0,
+ RDP_ORDER_PATBLT = 1,
+ RDP_ORDER_SCREENBLT = 2,
+ RDP_ORDER_LINE = 9,
+ RDP_ORDER_RECT = 10,
+ RDP_ORDER_DESKSAVE = 11,
+ RDP_ORDER_MEMBLT = 13,
+ RDP_ORDER_TRIBLT = 14,
+ RDP_ORDER_POLYGON = 20,
+ RDP_ORDER_POLYGON2 = 21,
+ RDP_ORDER_POLYLINE = 22,
+ RDP_ORDER_ELLIPSE = 25,
+ RDP_ORDER_ELLIPSE2 = 26,
+ RDP_ORDER_TEXT2 = 27
+};
+
+enum RDP_SECONDARY_ORDER_TYPE
+{
+ RDP_ORDER_RAW_BMPCACHE = 0,
+ RDP_ORDER_COLCACHE = 1,
+ RDP_ORDER_BMPCACHE = 2,
+ RDP_ORDER_FONTCACHE = 3,
+ RDP_ORDER_RAW_BMPCACHE2 = 4,
+ RDP_ORDER_BMPCACHE2 = 5,
+ RDP_ORDER_BRUSHCACHE = 7
+};
+
+typedef struct _DESTBLT_ORDER
+{
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint8 opcode;
+
+}
+DESTBLT_ORDER;
+
+typedef struct _PATBLT_ORDER
+{
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint8 opcode;
+ uint32 bgcolour;
+ uint32 fgcolour;
+ BRUSH brush;
+
+}
+PATBLT_ORDER;
+
+typedef struct _SCREENBLT_ORDER
+{
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint8 opcode;
+ sint16 srcx;
+ sint16 srcy;
+
+}
+SCREENBLT_ORDER;
+
+typedef struct _LINE_ORDER
+{
+ uint16 mixmode;
+ sint16 startx;
+ sint16 starty;
+ sint16 endx;
+ sint16 endy;
+ uint32 bgcolour;
+ uint8 opcode;
+ PEN pen;
+
+}
+LINE_ORDER;
+
+typedef struct _RECT_ORDER
+{
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint32 colour;
+
+}
+RECT_ORDER;
+
+typedef struct _DESKSAVE_ORDER
+{
+ uint32 offset;
+ sint16 left;
+ sint16 top;
+ sint16 right;
+ sint16 bottom;
+ uint8 action;
+
+}
+DESKSAVE_ORDER;
+
+typedef struct _TRIBLT_ORDER
+{
+ uint8 colour_table;
+ uint8 cache_id;
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint8 opcode;
+ sint16 srcx;
+ sint16 srcy;
+ uint32 bgcolour;
+ uint32 fgcolour;
+ BRUSH brush;
+ uint16 cache_idx;
+ uint16 unknown;
+
+}
+TRIBLT_ORDER;
+
+typedef struct _MEMBLT_ORDER
+{
+ uint8 colour_table;
+ uint8 cache_id;
+ sint16 x;
+ sint16 y;
+ sint16 cx;
+ sint16 cy;
+ uint8 opcode;
+ sint16 srcx;
+ sint16 srcy;
+ uint16 cache_idx;
+
+}
+MEMBLT_ORDER;
+
+#define MAX_DATA 256
+
+typedef struct _POLYGON_ORDER
+{
+ sint16 x;
+ sint16 y;
+ uint8 opcode;
+ uint8 fillmode;
+ uint32 fgcolour;
+ uint8 npoints;
+ uint8 datasize;
+ uint8 data[MAX_DATA];
+
+}
+POLYGON_ORDER;
+
+typedef struct _POLYGON2_ORDER
+{
+ sint16 x;
+ sint16 y;
+ uint8 opcode;
+ uint8 fillmode;
+ uint32 bgcolour;
+ uint32 fgcolour;
+ BRUSH brush;
+ uint8 npoints;
+ uint8 datasize;
+ uint8 data[MAX_DATA];
+
+}
+POLYGON2_ORDER;
+
+typedef struct _POLYLINE_ORDER
+{
+ sint16 x;
+ sint16 y;
+ uint8 opcode;
+ uint32 fgcolour;
+ uint8 lines;
+ uint8 datasize;
+ uint8 data[MAX_DATA];
+
+}
+POLYLINE_ORDER;
+
+typedef struct _ELLIPSE_ORDER
+{
+ sint16 left;
+ sint16 top;
+ sint16 right;
+ sint16 bottom;
+ uint8 opcode;
+ uint8 fillmode;
+ uint32 fgcolour;
+
+}
+ELLIPSE_ORDER;
+
+typedef struct _ELLIPSE2_ORDER
+{
+ sint16 left;
+ sint16 top;
+ sint16 right;
+ sint16 bottom;
+ uint8 opcode;
+ uint8 fillmode;
+ BRUSH brush;
+ uint32 bgcolour;
+ uint32 fgcolour;
+
+}
+ELLIPSE2_ORDER;
+
+#define MAX_TEXT 256
+
+typedef struct _TEXT2_ORDER
+{
+ uint8 font;
+ uint8 flags;
+ uint8 opcode;
+ uint8 mixmode;
+ uint32 bgcolour;
+ uint32 fgcolour;
+ sint16 clipleft;
+ sint16 cliptop;
+ sint16 clipright;
+ sint16 clipbottom;
+ sint16 boxleft;
+ sint16 boxtop;
+ sint16 boxright;
+ sint16 boxbottom;
+ BRUSH brush;
+ sint16 x;
+ sint16 y;
+ uint8 length;
+ uint8 text[MAX_TEXT];
+
+}
+TEXT2_ORDER;
+
+typedef struct _RDP_ORDER_STATE
+{
+ uint8 order_type;
+ BOUNDS bounds;
+
+ DESTBLT_ORDER destblt;
+ PATBLT_ORDER patblt;
+ SCREENBLT_ORDER screenblt;
+ LINE_ORDER line;
+ RECT_ORDER rect;
+ DESKSAVE_ORDER desksave;
+ MEMBLT_ORDER memblt;
+ TRIBLT_ORDER triblt;
+ POLYGON_ORDER polygon;
+ POLYGON2_ORDER polygon2;
+ POLYLINE_ORDER polyline;
+ ELLIPSE_ORDER ellipse;
+ ELLIPSE2_ORDER ellipse2;
+ TEXT2_ORDER text2;
+
+}
+RDP_ORDER_STATE;
+
+typedef struct _RDP_RAW_BMPCACHE_ORDER
+{
+ uint8 cache_id;
+ uint8 pad1;
+ uint8 width;
+ uint8 height;
+ uint8 bpp;
+ uint16 bufsize;
+ uint16 cache_idx;
+ uint8 *data;
+
+}
+RDP_RAW_BMPCACHE_ORDER;
+
+typedef struct _RDP_BMPCACHE_ORDER
+{
+ uint8 cache_id;
+ uint8 pad1;
+ uint8 width;
+ uint8 height;
+ uint8 bpp;
+ uint16 bufsize;
+ uint16 cache_idx;
+ uint16 pad2;
+ uint16 size;
+ uint16 row_size;
+ uint16 final_size;
+ uint8 *data;
+
+}
+RDP_BMPCACHE_ORDER;
+
+/* RDP_BMPCACHE2_ORDER */
+#define ID_MASK 0x0007
+#define MODE_MASK 0x0038
+#define SQUARE 0x0080
+#define PERSIST 0x0100
+#define FLAG_51_UNKNOWN 0x0800
+
+#define MODE_SHIFT 3
+
+#define LONG_FORMAT 0x80
+#define BUFSIZE_MASK 0x3FFF /* or 0x1FFF? */
+
+#define MAX_GLYPH 32
+
+typedef struct _RDP_FONT_GLYPH
+{
+ uint16 character;
+ uint16 unknown;
+ uint16 baseline;
+ uint16 width;
+ uint16 height;
+ uint8 data[MAX_GLYPH];
+
+}
+RDP_FONT_GLYPH;
+
+#define MAX_GLYPHS 256
+
+typedef struct _RDP_FONTCACHE_ORDER
+{
+ uint8 font;
+ uint8 nglyphs;
+ RDP_FONT_GLYPH glyphs[MAX_GLYPHS];
+
+}
+RDP_FONTCACHE_ORDER;
+
+typedef struct _RDP_COLCACHE_ORDER
+{
+ uint8 cache_id;
+ COLOURMAP map;
+
+}
+RDP_COLCACHE_ORDER;
diff --git a/uirdesktop/pstcache.c b/uirdesktop/pstcache.c
new file mode 100644
index 00000000..9e6432bd
--- /dev/null
+++ b/uirdesktop/pstcache.c
@@ -0,0 +1,200 @@
+/* -*- c-basic-offset: 8 -*-
+ rdesktop: A Remote Desktop Protocol client.
+ Persistent Bitmap Cache routines
+ Copyright (C) Jeroen Meijer 2004-2005
+
+ 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.
+*/
+
+#include "rdesktop.h"
+
+#define MAX_CELL_SIZE 0x1000 /* pixels */
+
+#define IS_PERSISTENT(id) (id < 8 && g_pstcache_fd[id] > 0)
+
+extern int g_server_depth;
+extern BOOL g_bitmap_cache;
+extern BOOL g_bitmap_cache_persist_enable;
+extern BOOL g_bitmap_cache_precache;
+
+int g_pstcache_fd[8];
+int g_pstcache_Bpp;
+BOOL g_pstcache_enumerated = False;
+uint8 zero_key[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+
+/* Update mru stamp/index for a bitmap */
+void
+pstcache_touch_bitmap(uint8 cache_id, uint16 cache_idx, uint32 stamp)
+{
+ int fd;
+
+ if (!IS_PERSISTENT(cache_id) || cache_idx >= BMPCACHE2_NUM_PSTCELLS)
+ return;
+
+ fd = g_pstcache_fd[cache_id];
+ rd_lseek_file(fd, 12 + cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
+ rd_write_file(fd, &stamp, sizeof(stamp));
+}
+
+/* Load a bitmap from the persistent cache */
+BOOL
+pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx)
+{
+ uint8 *celldata;
+ int fd;
+ CELLHEADER cellhdr;
+ HBITMAP bitmap;
+
+ if (!g_bitmap_cache_persist_enable)
+ return False;
+
+ if (!IS_PERSISTENT(cache_id) || cache_idx >= BMPCACHE2_NUM_PSTCELLS)
+ return False;
+
+ fd = g_pstcache_fd[cache_id];
+ rd_lseek_file(fd, cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
+ rd_read_file(fd, &cellhdr, sizeof(CELLHEADER));
+ celldata = (uint8 *) xmalloc(cellhdr.length);
+ rd_read_file(fd, celldata, cellhdr.length);
+
+ bitmap = ui_create_bitmap(cellhdr.width, cellhdr.height, celldata);
+ DEBUG(("Load bitmap from disk: id=%d, idx=%d, bmp=0x%x)\n", cache_id, cache_idx, bitmap));
+ cache_put_bitmap(cache_id, cache_idx, bitmap);
+
+ xfree(celldata);
+ return True;
+}
+
+/* Store a bitmap in the persistent cache */
+BOOL
+pstcache_save_bitmap(uint8 cache_id, uint16 cache_idx, uint8 * key,
+ uint8 width, uint8 height, uint16 length, uint8 * data)
+{
+ int fd;
+ CELLHEADER cellhdr;
+
+ if (!IS_PERSISTENT(cache_id) || cache_idx >= BMPCACHE2_NUM_PSTCELLS)
+ return False;
+
+ memcpy(cellhdr.key, key, sizeof(HASH_KEY));
+ cellhdr.width = width;
+ cellhdr.height = height;
+ cellhdr.length = length;
+ cellhdr.stamp = 0;
+
+ fd = g_pstcache_fd[cache_id];
+ rd_lseek_file(fd, cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
+ rd_write_file(fd, &cellhdr, sizeof(CELLHEADER));
+ rd_write_file(fd, data, length);
+
+ return True;
+}
+
+/* List the bitmap keys from the persistent cache file */
+int
+pstcache_enumerate(uint8 id, HASH_KEY * keylist)
+{
+ int fd, n;
+ uint16 idx;
+ sint16 mru_idx[0xa00];
+ uint32 mru_stamp[0xa00];
+ CELLHEADER cellhdr;
+
+ if (!(g_bitmap_cache && g_bitmap_cache_persist_enable && IS_PERSISTENT(id)))
+ return 0;
+
+ /* The server disconnects if the bitmap cache content is sent more than once */
+ if (g_pstcache_enumerated)
+ return 0;
+
+ DEBUG_RDP5(("Persistent bitmap cache enumeration... "));
+ for (idx = 0; idx < BMPCACHE2_NUM_PSTCELLS; idx++)
+ {
+ fd = g_pstcache_fd[id];
+ rd_lseek_file(fd, idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
+ if (rd_read_file(fd, &cellhdr, sizeof(CELLHEADER)) <= 0)
+ break;
+
+ if (memcmp(cellhdr.key, zero_key, sizeof(HASH_KEY)) != 0)
+ {
+ memcpy(keylist[idx], cellhdr.key, sizeof(HASH_KEY));
+
+ /* Pre-cache (not possible for 8 bit colour depth cause it needs a colourmap) */
+ if (g_bitmap_cache_precache && cellhdr.stamp && g_server_depth > 8)
+ pstcache_load_bitmap(id, idx);
+
+ /* Sort by stamp */
+ for (n = idx; n > 0 && cellhdr.stamp < mru_stamp[n - 1]; n--)
+ {
+ mru_idx[n] = mru_idx[n - 1];
+ mru_stamp[n] = mru_stamp[n - 1];
+ }
+
+ mru_idx[n] = idx;
+ mru_stamp[n] = cellhdr.stamp;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ DEBUG_RDP5(("%d cached bitmaps.\n", idx));
+
+ cache_rebuild_bmpcache_linked_list(id, mru_idx, idx);
+ g_pstcache_enumerated = True;
+ return idx;
+}
+
+/* initialise the persistent bitmap cache */
+BOOL
+pstcache_init(uint8 cache_id)
+{
+ int fd;
+ char filename[256];
+
+ if (g_pstcache_enumerated)
+ return True;
+
+ g_pstcache_fd[cache_id] = 0;
+
+ if (!(g_bitmap_cache && g_bitmap_cache_persist_enable))
+ return False;
+
+ if (!rd_pstcache_mkdir())
+ {
+ DEBUG(("failed to get/make cache directory!\n"));
+ return False;
+ }
+
+ g_pstcache_Bpp = (g_server_depth + 7) / 8;
+ sprintf(filename, "cache/pstcache_%d_%d", cache_id, g_pstcache_Bpp);
+ DEBUG(("persistent bitmap cache file: %s\n", filename));
+
+ fd = rd_open_file(filename);
+ if (fd == -1)
+ return False;
+
+ if (!rd_lock_file(fd, 0, 0))
+ {
+ warning("Persistent bitmap caching is disabled. (The file is already in use)\n");
+ rd_close_file(fd);
+ return False;
+ }
+
+ g_pstcache_fd[cache_id] = fd;
+ return True;
+}