--- sourceforge.net/trunk/rdesktop/orders.c 2003/01/30 11:15:00 299 +++ sourceforge.net/trunk/rdesktop/orders.c 2004/06/30 17:59:40 732 @@ -1,4 +1,4 @@ -/* +/* -*- c-basic-offset: 8 -*- rdesktop: A Remote Desktop Protocol client. RDP order processing Copyright (C) Matthew Chapman 1999-2002 @@ -21,8 +21,9 @@ #include "rdesktop.h" #include "orders.h" -extern uint8 *next_packet; -static RDP_ORDER_STATE order_state; +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 @@ -54,7 +55,7 @@ /* Read a co-ordinate (16-bit, or 8-bit delta) */ static void -rdp_in_coord(STREAM s, uint16 * coord, BOOL delta) +rdp_in_coord(STREAM s, sint16 * coord, BOOL delta) { sint8 change; @@ -71,10 +72,15 @@ /* 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 */ @@ -263,7 +269,7 @@ rdp_parse_pen(s, &os->pen, present >> 7); - DEBUG(("LINE(op=0x%x,sx=%d,sy=%d,dx=%d,dx=%d,fg=0x%x)\n", + 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) @@ -279,6 +285,7 @@ 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 +299,22 @@ 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)); @@ -584,6 +606,10 @@ if (present & 0x002000) in_uint16_le(s, os->boxbottom); + if (present & 0x004000) /* fix for connecting to a server that */ + in_uint8s(s, 10); /* was disconnected with mstsc.exe */ + /* 0x008000, 0x020000, and 0x040000 are present too ??? */ + if (present & 0x080000) in_uint16_le(s, os->x); @@ -620,7 +646,7 @@ { HBITMAP bitmap; uint16 cache_idx, bufsize; - uint8 cache_id, width, height, bpp; + uint8 cache_id, width, height, bpp, Bpp; uint8 *data, *inverted; int y; @@ -629,20 +655,22 @@ 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 = xmalloc(width * height); + inverted = (uint8 *) xmalloc(width * height * Bpp); for (y = 0; y < height; y++) { - memcpy(&inverted[(height - y - 1) * width], &data[y * width], width); + 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); + cache_put_bitmap(cache_id, cache_idx, bitmap, 0); } /* Process a bitmap cache order */ @@ -651,29 +679,131 @@ { HBITMAP bitmap; uint16 cache_idx, size; - uint8 cache_id, width, height, bpp; + 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_uint8s(s, 1); /* pad */ + in_uint8(s, pad1); /* pad */ in_uint8(s, width); in_uint8(s, height); in_uint8(s, bpp); - in_uint8s(s, 2); /* bufsize */ + Bpp = (bpp + 7) / 8; + in_uint16_le(s, bufsize); /* bufsize */ in_uint16_le(s, cache_idx); - in_uint8s(s, 2); /* pad */ - in_uint16_le(s, size); - in_uint8s(s, 4); /* row_size, final_size */ + + 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)\n", width, height, cache_id, cache_idx)); + 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 = xmalloc(width * height); + bmpdata = (uint8 *) xmalloc(width * height * Bpp); - 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); + cache_put_bitmap(cache_id, cache_idx, bitmap, 0); + } + 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, 0); + if (flags & PERSIST) + pstcache_put_bitmap(cache_id, cache_idx, bitmap_id, width, height, + width * height * Bpp, bmpdata); + } + else + { + DEBUG(("process_bmpcache2: ui_create_bitmap failed\n")); } xfree(bmpdata); @@ -692,7 +822,7 @@ in_uint8(s, cache_id); in_uint16_le(s, map.ncolours); - map.colours = xmalloc(3 * map.ncolours); + map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours); for (i = 0; i < map.ncolours; i++) { @@ -746,15 +876,19 @@ 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_uint8s(s, 2); /* flags */ + in_uint16_le(s, flags); /* used by bmpcache2 */ in_uint8(s, type); - next_order = s->p + length + 7; + next_order = s->p + (sint16)length + 7; switch (type) { @@ -774,6 +908,14 @@ 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); } @@ -783,19 +925,14 @@ /* Process an order PDU */ void -process_orders(STREAM s) +process_orders(STREAM s, uint16 num_orders) { - RDP_ORDER_STATE *os = &order_state; + RDP_ORDER_STATE *os = &g_order_state; uint32 present; - uint16 num_orders; uint8 order_flags; int size, processed = 0; BOOL delta; - in_uint8s(s, 2); /* pad */ - in_uint16_le(s, num_orders); - in_uint8s(s, 2); /* pad */ - while (processed < num_orders) { in_uint8(s, order_flags); @@ -903,15 +1040,18 @@ 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 - if (s->p != next_packet) - error("%d bytes remaining\n", (int) (next_packet - s->p)); } /* Reset order state */ void reset_order_state(void) { - memset(&order_state, 0, sizeof(order_state)); - order_state.order_type = RDP_ORDER_PATBLT; + memset(&g_order_state, 0, sizeof(g_order_state)); + g_order_state.order_type = RDP_ORDER_PATBLT; }