diff --git a/bitmap.c b/bitmap.c index 9c527d7..4209f7d 100644 --- a/bitmap.c +++ b/bitmap.c @@ -2,17 +2,17 @@ rdesktop: A Remote Desktop Protocol client. Bitmap decompression routines Copyright (C) Matthew Chapman 1999-2002 - + 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. @@ -21,6 +21,7 @@ #include "rdesktop.h" #define CVAL(p) (*(p++)) +#define CVAL16(p) (*(((uint16*)p)++)) #define UNROLL8(exp) { exp exp exp exp exp exp exp exp } @@ -43,7 +44,7 @@ } BOOL -bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size) +bitmap_decompress8(unsigned char *output, int width, int height, unsigned char *input, int size) { unsigned char *end = input + size; unsigned char *prevline = NULL, *line = NULL; @@ -246,3 +247,221 @@ bitmap_decompress(unsigned char *output, int width, int height, unsigned char *i return True; } + +BOOL +bitmap_decompress16(unsigned char *output, int width, int height, unsigned char *input, int size) +{ + unsigned char *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 < 0xd) ? 8 : 1; // was 0xb in 8 bit + } + 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 = CVAL16(input); + case 3: /* Colour */ + colour2 = CVAL16(input); + break; + case 6: /* SetMix/Mix */ + case 7: /* SetMix/FillOrMix */ + mix = CVAL16(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 = (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(line[x] = CVAL16(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] = 0xffff); + break; + + case 0xe: /* Black */ + REPEAT(line[x] = 0x00); + break; + + default: + unimpl("bitmap opcode 0x%x\n", opcode); + return False; + } + } + } + + return True; +} + +BOOL +bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, int size, int bpp) +{ + if (bpp == 8) + return bitmap_decompress8(output, width, height, input, size); + else if (bpp == 16) + return bitmap_decompress16(output, width, height, input, size); + else + return False; +} diff --git a/orders.c b/orders.c index fa4f3d6..ab51881 100644 --- a/orders.c +++ b/orders.c @@ -71,10 +71,15 @@ rdp_in_coord(STREAM s, uint16 * coord, BOOL delta) /* Read a colour entry */ static void -rdp_in_colour(STREAM s, uint8 * colour) +rdp_in_colour(STREAM s, uint32 * colour) { - in_uint8(s, *colour); - s->p += 2; + 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 */ @@ -279,6 +284,7 @@ process_line(STREAM s, LINE_ORDER * os, uint32 present, BOOL delta) 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); @@ -292,7 +298,22 @@ process_rect(STREAM s, RECT_ORDER * os, uint32 present, BOOL delta) rdp_in_coord(s, &os->cy, delta); if (present & 0x10) - in_uint8(s, os->colour); + { + 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)); @@ -632,6 +653,8 @@ process_raw_bmpcache(STREAM s) in_uint16_le(s, bufsize); in_uint16_le(s, cache_idx); in_uint8p(s, data, bufsize); + if (bpp != 8) /* todo */ + return; DEBUG(("RAW_BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", width, height, cache_id, cache_idx)); inverted = xmalloc(width * height); @@ -665,12 +688,14 @@ process_bmpcache(STREAM s) in_uint16_le(s, size); in_uint8s(s, 4); /* row_size, final_size */ in_uint8p(s, data, size); + if (bpp != 8) /* todo */ + return; DEBUG(("BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", width, height, cache_id, cache_idx)); bmpdata = xmalloc(width * height); - if (bitmap_decompress(bmpdata, width, height, data, size)) + if (bitmap_decompress(bmpdata, width, height, data, size, bpp)) { bitmap = ui_create_bitmap(width, height, bmpdata); cache_put_bitmap(cache_id, cache_idx, bitmap); diff --git a/orders.h b/orders.h index a680f11..fb66f4c 100644 --- a/orders.h +++ b/orders.h @@ -67,8 +67,8 @@ typedef struct _PATBLT_ORDER uint16 cx; uint16 cy; uint8 opcode; - uint8 bgcolour; - uint8 fgcolour; + uint32 bgcolour; + uint32 fgcolour; BRUSH brush; } @@ -94,7 +94,7 @@ typedef struct _LINE_ORDER uint16 starty; uint16 endx; uint16 endy; - uint8 bgcolour; + uint32 bgcolour; uint8 opcode; PEN pen; @@ -107,7 +107,7 @@ typedef struct _RECT_ORDER uint16 y; uint16 cx; uint16 cy; - uint8 colour; + uint32 colour; } RECT_ORDER; @@ -135,8 +135,8 @@ typedef struct _TRIBLT_ORDER uint8 opcode; uint16 srcx; uint16 srcy; - uint8 bgcolour; - uint8 fgcolour; + uint32 bgcolour; + uint32 fgcolour; BRUSH brush; uint16 cache_idx; uint16 unknown; @@ -167,7 +167,7 @@ typedef struct _POLYLINE_ORDER uint16 x; uint16 y; uint8 opcode; - uint8 fgcolour; + uint32 fgcolour; uint8 lines; uint8 datasize; uint8 data[MAX_DATA]; @@ -183,8 +183,8 @@ typedef struct _TEXT2_ORDER uint8 flags; uint8 mixmode; uint8 unknown; - uint8 fgcolour; - uint8 bgcolour; + uint32 fgcolour; + uint32 bgcolour; uint16 clipleft; uint16 cliptop; uint16 clipright; diff --git a/proto.h b/proto.h index e8f8c33..7f1fe29 100644 --- a/proto.h +++ b/proto.h @@ -1,6 +1,6 @@ /* bitmap.c */ BOOL bitmap_decompress(unsigned char *output, int width, int height, unsigned char *input, - int size); + int size, int bpp); /* cache.c */ HBITMAP cache_get_bitmap(uint8 cache_id, uint16 cache_idx); void cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap); diff --git a/rdesktop.c b/rdesktop.c index da1d81c..cebd66f 100644 --- a/rdesktop.c +++ b/rdesktop.c @@ -45,10 +45,11 @@ char username[16]; char hostname[16]; char keymapname[16]; int keylayout = 0x409; /* Defaults to US keyboard layout */ -int width = 800; /* If width or height are reset to zero, the geometry will +int width = 800; /* If width or height are reset to zero, the geometry will be fetched from _NET_WORKAREA */ int height = 600; int tcp_port_rdp = TCP_PORT_RDP; +int server_bpp = 8; BOOL bitmap_compression = True; BOOL sendmotion = True; BOOL orders = True; @@ -84,6 +85,7 @@ usage(char *program) fprintf(stderr, " -K: keep window manager key bindings\n"); fprintf(stderr, " -T: window title\n"); fprintf(stderr, " -D: hide window manager decorations\n"); + fprintf(stderr, " -a: server bpp\n"); } static BOOL @@ -144,7 +146,7 @@ main(int argc, char *argv[]) domain[0] = password[0] = shell[0] = directory[0] = 0; strcpy(keymapname, "en-us"); - while ((c = getopt(argc, argv, "u:d:s:c:p:n:k:g:fbemCKT:Dh?")) != -1) + while ((c = getopt(argc, argv, "u:d:s:c:p:n:k:g:a:fbemCKT:Dh?")) != -1) { switch (c) { @@ -239,6 +241,15 @@ main(int argc, char *argv[]) hide_decorations = True; break; + case 'a': + server_bpp = strtol(optarg, NULL, 10); + if (server_bpp != 8 && server_bpp != 16) + { + error("invalid server bpp\n"); + return 1; + } + break; + case 'h': case '?': default: diff --git a/rdp.c b/rdp.c index 9abef59..1589b93 100644 --- a/rdp.c +++ b/rdp.c @@ -579,10 +579,10 @@ process_bitmap_updates(STREAM s) if (!compress) { int y; - bmpdata = xmalloc(width * height); + bmpdata = xmalloc(width * height * (bpp / 8)); for (y = 0; y < height; y++) { - in_uint8a(s, &bmpdata[(height - y - 1) * width], width); + in_uint8a(s, &bmpdata[(height - y - 1) * (width * (bpp / 8))], width * (bpp / 8)); } ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata); xfree(bmpdata); @@ -593,13 +593,11 @@ process_bitmap_updates(STREAM s) in_uint16_le(s, size); in_uint8s(s, 4); /* line_size, final_size */ in_uint8p(s, data, size); - - bmpdata = xmalloc(width * height); - if (bitmap_decompress(bmpdata, width, height, data, size)) + bmpdata = xmalloc(width * height * (bpp / 8)); + if (bitmap_decompress(bmpdata, width, height, data, size, bpp)) { ui_paint_bitmap(left, top, cx, cy, width, height, bmpdata); } - xfree(bmpdata); } } diff --git a/secure.c b/secure.c index cd0a952..af9f2cd 100644 --- a/secure.c +++ b/secure.c @@ -38,6 +38,7 @@ extern int height; extern int keylayout; extern BOOL encryption; extern BOOL licence_issued; +extern int server_bpp; static int rc4_key_len; static RC4_KEY rc4_decrypt_key; @@ -425,7 +426,14 @@ sec_out_mcs_data(STREAM s) out_uint32_le(s, 12); out_uint8s(s, 64); /* reserved? 4 + 12 doublewords */ - out_uint16_le(s, 0xca01); + if (server_bpp == 16) + { + out_uint16_le(s, 0xca03); /* 16 bit */ + } + else + { + out_uint16_le(s, 0xca01); /* 8 bit */ + } out_uint16(s, 0); /* Client encryption settings */ diff --git a/types.h b/types.h index 9954592..979ae5b 100644 --- a/types.h +++ b/types.h @@ -68,7 +68,7 @@ typedef struct _PEN { uint8 style; uint8 width; - uint8 colour; + uint32 colour; } PEN; diff --git a/xwin.c b/xwin.c index a3ad623..b600566 100644 --- a/xwin.c +++ b/xwin.c @@ -31,6 +31,7 @@ extern BOOL fullscreen; extern BOOL grab_keyboard; extern BOOL hide_decorations; extern char title[]; +extern int server_bpp; BOOL enable_compose = False; BOOL focused; BOOL mouse_in_wnd; @@ -88,7 +89,7 @@ BOOL owncolmap = False; static Colormap xcolmap; static uint32 *colmap; -#define TRANSLATE(col) ( owncolmap ? col : translate_colour(colmap[col]) ) +#define TRANSLATE(col) ( server_bpp != 8 ? col : owncolmap ? col : translate_colour(colmap[col]) ) #define SET_FOREGROUND(col) XSetForeground(display, gc, TRANSLATE(col)); #define SET_BACKGROUND(col) XSetBackground(display, gc, TRANSLATE(col)); @@ -749,6 +750,24 @@ ui_paint_bitmap(int x, int y, int cx, int cy, int width, int height, uint8 * dat XImage *image; uint8 *tdata; + if (server_bpp == 16) + { + image = XCreateImage(display, visual, depth, ZPixmap, 0, + (char *) data, width, height, 16, 0); + + if (ownbackstore) + { + XPutImage(display, backstore, gc, image, 0, 0, x, y, cx, cy); + XCopyArea(display, backstore, wnd, gc, x, y, cx, cy, x, y); + } + else + { + XPutImage(display, wnd, gc, image, 0, 0, x, y, cx, cy); + } + + XFree(image); + return; + } tdata = (owncolmap ? data : translate_image(width, height, data)); image = XCreateImage(display, visual, depth, ZPixmap, 0, (char *) tdata, width, height, 8, 0);