1
/* -*- c-basic-offset: 8 -*-
2
rdesktop: A Remote Desktop Protocol client.
4
Copyright (C) Matthew Chapman 1999-2002
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
extern uint8 *g_next_packet;
25
static RDP_ORDER_STATE g_order_state;
26
extern BOOL g_use_rdp5;
28
/* Read field indicating which parameters are present */
30
rdp_in_present(STREAM s, uint32 * present, uint8 flags, int size)
35
if (flags & RDP_ORDER_SMALL)
40
if (flags & RDP_ORDER_TINY)
49
for (i = 0; i < size; i++)
52
*present |= bits << (i * 8);
56
/* Read a co-ordinate (16-bit, or 8-bit delta) */
58
rdp_in_coord(STREAM s, sint16 * coord, BOOL delta)
69
in_uint16_le(s, *coord);
73
/* Read a colour entry */
75
rdp_in_colour(STREAM s, uint32 * colour)
86
/* Parse bounds information */
88
rdp_parse_bounds(STREAM s, BOUNDS * bounds)
95
rdp_in_coord(s, &bounds->left, False);
96
else if (present & 16)
97
rdp_in_coord(s, &bounds->left, True);
100
rdp_in_coord(s, &bounds->top, False);
101
else if (present & 32)
102
rdp_in_coord(s, &bounds->top, True);
105
rdp_in_coord(s, &bounds->right, False);
106
else if (present & 64)
107
rdp_in_coord(s, &bounds->right, True);
110
rdp_in_coord(s, &bounds->bottom, False);
111
else if (present & 128)
112
rdp_in_coord(s, &bounds->bottom, True);
119
rdp_parse_pen(STREAM s, PEN * pen, uint32 present)
122
in_uint8(s, pen->style);
125
in_uint8(s, pen->width);
128
rdp_in_colour(s, &pen->colour);
135
rdp_parse_brush(STREAM s, BRUSH * brush, uint32 present)
138
in_uint8(s, brush->xorigin);
141
in_uint8(s, brush->yorigin);
144
in_uint8(s, brush->style);
147
in_uint8(s, brush->pattern[0]);
150
in_uint8a(s, &brush->pattern[1], 7);
155
/* Process a destination blt order */
157
process_destblt(STREAM s, DESTBLT_ORDER * os, uint32 present, BOOL delta)
160
rdp_in_coord(s, &os->x, delta);
163
rdp_in_coord(s, &os->y, delta);
166
rdp_in_coord(s, &os->cx, delta);
169
rdp_in_coord(s, &os->cy, delta);
172
in_uint8(s, os->opcode);
174
DEBUG(("DESTBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d)\n",
175
os->opcode, os->x, os->y, os->cx, os->cy));
177
ui_destblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy);
180
/* Process a pattern blt order */
182
process_patblt(STREAM s, PATBLT_ORDER * os, uint32 present, BOOL delta)
184
if (present & 0x0001)
185
rdp_in_coord(s, &os->x, delta);
187
if (present & 0x0002)
188
rdp_in_coord(s, &os->y, delta);
190
if (present & 0x0004)
191
rdp_in_coord(s, &os->cx, delta);
193
if (present & 0x0008)
194
rdp_in_coord(s, &os->cy, delta);
196
if (present & 0x0010)
197
in_uint8(s, os->opcode);
199
if (present & 0x0020)
200
rdp_in_colour(s, &os->bgcolour);
202
if (present & 0x0040)
203
rdp_in_colour(s, &os->fgcolour);
205
rdp_parse_brush(s, &os->brush, present >> 7);
207
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,
208
os->y, os->cx, os->cy, os->brush.style, os->bgcolour, os->fgcolour));
210
ui_patblt(ROP2_P(os->opcode), os->x, os->y, os->cx, os->cy,
211
&os->brush, os->bgcolour, os->fgcolour);
214
/* Process a screen blt order */
216
process_screenblt(STREAM s, SCREENBLT_ORDER * os, uint32 present, BOOL delta)
218
if (present & 0x0001)
219
rdp_in_coord(s, &os->x, delta);
221
if (present & 0x0002)
222
rdp_in_coord(s, &os->y, delta);
224
if (present & 0x0004)
225
rdp_in_coord(s, &os->cx, delta);
227
if (present & 0x0008)
228
rdp_in_coord(s, &os->cy, delta);
230
if (present & 0x0010)
231
in_uint8(s, os->opcode);
233
if (present & 0x0020)
234
rdp_in_coord(s, &os->srcx, delta);
236
if (present & 0x0040)
237
rdp_in_coord(s, &os->srcy, delta);
239
DEBUG(("SCREENBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,srcx=%d,srcy=%d)\n",
240
os->opcode, os->x, os->y, os->cx, os->cy, os->srcx, os->srcy));
242
ui_screenblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, os->srcx, os->srcy);
245
/* Process a line order */
247
process_line(STREAM s, LINE_ORDER * os, uint32 present, BOOL delta)
249
if (present & 0x0001)
250
in_uint16_le(s, os->mixmode);
252
if (present & 0x0002)
253
rdp_in_coord(s, &os->startx, delta);
255
if (present & 0x0004)
256
rdp_in_coord(s, &os->starty, delta);
258
if (present & 0x0008)
259
rdp_in_coord(s, &os->endx, delta);
261
if (present & 0x0010)
262
rdp_in_coord(s, &os->endy, delta);
264
if (present & 0x0020)
265
rdp_in_colour(s, &os->bgcolour);
267
if (present & 0x0040)
268
in_uint8(s, os->opcode);
270
rdp_parse_pen(s, &os->pen, present >> 7);
272
DEBUG(("LINE(op=0x%x,sx=%d,sy=%d,dx=%d,dx=%d,fg=0x%x)\n",
273
os->opcode, os->startx, os->starty, os->endx, os->endy, os->pen.colour));
275
if (os->opcode < 0x01 || os->opcode > 0x10)
277
error("bad ROP2 0x%x\n", os->opcode);
281
ui_line(os->opcode - 1, os->startx, os->starty, os->endx, os->endy, &os->pen);
284
/* Process an opaque rectangle order */
286
process_rect(STREAM s, RECT_ORDER * os, uint32 present, BOOL delta)
290
rdp_in_coord(s, &os->x, delta);
293
rdp_in_coord(s, &os->y, delta);
296
rdp_in_coord(s, &os->cx, delta);
299
rdp_in_coord(s, &os->cy, delta);
304
os->colour = (os->colour & 0xffffff00) | i;
310
os->colour = (os->colour & 0xffff00ff) | (i << 8);
316
os->colour = (os->colour & 0xff00ffff) | (i << 16);
319
DEBUG(("RECT(x=%d,y=%d,cx=%d,cy=%d,fg=0x%x)\n", os->x, os->y, os->cx, os->cy, os->colour));
321
ui_rect(os->x, os->y, os->cx, os->cy, os->colour);
324
/* Process a desktop save order */
326
process_desksave(STREAM s, DESKSAVE_ORDER * os, uint32 present, BOOL delta)
331
in_uint32_le(s, os->offset);
334
rdp_in_coord(s, &os->left, delta);
337
rdp_in_coord(s, &os->top, delta);
340
rdp_in_coord(s, &os->right, delta);
343
rdp_in_coord(s, &os->bottom, delta);
346
in_uint8(s, os->action);
348
DEBUG(("DESKSAVE(l=%d,t=%d,r=%d,b=%d,off=%d,op=%d)\n",
349
os->left, os->top, os->right, os->bottom, os->offset, os->action));
351
width = os->right - os->left + 1;
352
height = os->bottom - os->top + 1;
355
ui_desktop_save(os->offset, os->left, os->top, width, height);
357
ui_desktop_restore(os->offset, os->left, os->top, width, height);
360
/* Process a memory blt order */
362
process_memblt(STREAM s, MEMBLT_ORDER * os, uint32 present, BOOL delta)
366
if (present & 0x0001)
368
in_uint8(s, os->cache_id);
369
in_uint8(s, os->colour_table);
372
if (present & 0x0002)
373
rdp_in_coord(s, &os->x, delta);
375
if (present & 0x0004)
376
rdp_in_coord(s, &os->y, delta);
378
if (present & 0x0008)
379
rdp_in_coord(s, &os->cx, delta);
381
if (present & 0x0010)
382
rdp_in_coord(s, &os->cy, delta);
384
if (present & 0x0020)
385
in_uint8(s, os->opcode);
387
if (present & 0x0040)
388
rdp_in_coord(s, &os->srcx, delta);
390
if (present & 0x0080)
391
rdp_in_coord(s, &os->srcy, delta);
393
if (present & 0x0100)
394
in_uint16_le(s, os->cache_idx);
396
DEBUG(("MEMBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d)\n",
397
os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx));
399
bitmap = cache_get_bitmap(os->cache_id, os->cache_idx);
403
ui_memblt(ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, bitmap, os->srcx, os->srcy);
406
/* Process a 3-way blt order */
408
process_triblt(STREAM s, TRIBLT_ORDER * os, uint32 present, BOOL delta)
412
if (present & 0x000001)
414
in_uint8(s, os->cache_id);
415
in_uint8(s, os->colour_table);
418
if (present & 0x000002)
419
rdp_in_coord(s, &os->x, delta);
421
if (present & 0x000004)
422
rdp_in_coord(s, &os->y, delta);
424
if (present & 0x000008)
425
rdp_in_coord(s, &os->cx, delta);
427
if (present & 0x000010)
428
rdp_in_coord(s, &os->cy, delta);
430
if (present & 0x000020)
431
in_uint8(s, os->opcode);
433
if (present & 0x000040)
434
rdp_in_coord(s, &os->srcx, delta);
436
if (present & 0x000080)
437
rdp_in_coord(s, &os->srcy, delta);
439
if (present & 0x000100)
440
rdp_in_colour(s, &os->bgcolour);
442
if (present & 0x000200)
443
rdp_in_colour(s, &os->fgcolour);
445
rdp_parse_brush(s, &os->brush, present >> 10);
447
if (present & 0x008000)
448
in_uint16_le(s, os->cache_idx);
450
if (present & 0x010000)
451
in_uint16_le(s, os->unknown);
453
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",
454
os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx,
455
os->brush.style, os->bgcolour, os->fgcolour));
457
bitmap = cache_get_bitmap(os->cache_id, os->cache_idx);
461
ui_triblt(os->opcode, os->x, os->y, os->cx, os->cy,
462
bitmap, os->srcx, os->srcy, &os->brush, os->bgcolour, os->fgcolour);
465
/* Parse a delta co-ordinate in polyline order form */
467
parse_delta(uint8 * buffer, int *offset)
469
int value = buffer[(*offset)++];
470
int two_byte = value & 0x80;
472
if (value & 0x40) /* sign bit */
478
value = (value << 8) | buffer[(*offset)++];
483
/* Process a polyline order */
485
process_polyline(STREAM s, POLYLINE_ORDER * os, uint32 present, BOOL delta)
487
int index, line, data;
488
int x, y, xfrom, yfrom;
494
rdp_in_coord(s, &os->x, delta);
497
rdp_in_coord(s, &os->y, delta);
500
in_uint8(s, os->opcode);
503
rdp_in_colour(s, &os->fgcolour);
506
in_uint8(s, os->lines);
510
in_uint8(s, os->datasize);
511
in_uint8a(s, os->data, os->datasize);
514
DEBUG(("POLYLINE(x=%d,y=%d,op=0x%x,fg=0x%x,n=%d,sz=%d)\n",
515
os->x, os->y, os->opcode, os->fgcolour, os->lines, os->datasize));
519
for (index = 0; index < os->datasize; index++)
520
DEBUG(("%02x ", os->data[index]));
524
if (os->opcode < 0x01 || os->opcode > 0x10)
526
error("bad ROP2 0x%x\n", os->opcode);
530
opcode = os->opcode - 1;
533
pen.style = pen.width = 0;
534
pen.colour = os->fgcolour;
537
data = ((os->lines - 1) / 4) + 1;
538
for (line = 0; (line < os->lines) && (data < os->datasize); line++)
544
flags = os->data[index++];
546
if ((flags & 0xc0) == 0)
547
flags |= 0xc0; /* none = both */
550
x += parse_delta(os->data, &data);
553
y += parse_delta(os->data, &data);
555
ui_line(opcode, xfrom, yfrom, x, y, &pen);
561
/* Process a text order */
563
process_text2(STREAM s, TEXT2_ORDER * os, uint32 present, BOOL delta)
567
if (present & 0x000001)
568
in_uint8(s, os->font);
570
if (present & 0x000002)
571
in_uint8(s, os->flags);
573
if (present & 0x000004)
574
in_uint8(s, os->unknown);
576
if (present & 0x000008)
577
in_uint8(s, os->mixmode);
579
if (present & 0x000010)
580
rdp_in_colour(s, &os->fgcolour);
582
if (present & 0x000020)
583
rdp_in_colour(s, &os->bgcolour);
585
if (present & 0x000040)
586
in_uint16_le(s, os->clipleft);
588
if (present & 0x000080)
589
in_uint16_le(s, os->cliptop);
591
if (present & 0x000100)
592
in_uint16_le(s, os->clipright);
594
if (present & 0x000200)
595
in_uint16_le(s, os->clipbottom);
597
if (present & 0x000400)
598
in_uint16_le(s, os->boxleft);
600
if (present & 0x000800)
601
in_uint16_le(s, os->boxtop);
603
if (present & 0x001000)
604
in_uint16_le(s, os->boxright);
606
if (present & 0x002000)
607
in_uint16_le(s, os->boxbottom);
609
if (present & 0x004000) /* fix for connecting to a server that */
610
in_uint8s(s, 10); /* was disconnected with mstsc.exe */
611
/* 0x008000, 0x020000, and 0x040000 are present too ??? */
613
if (present & 0x080000)
614
in_uint16_le(s, os->x);
616
if (present & 0x100000)
617
in_uint16_le(s, os->y);
619
if (present & 0x200000)
621
in_uint8(s, os->length);
622
in_uint8a(s, os->text, os->length);
625
DEBUG(("TEXT2(x=%d,y=%d,cl=%d,ct=%d,cr=%d,cb=%d,bl=%d,bt=%d,bb=%d,br=%d,fg=0x%x,bg=0x%x,font=%d,fl=0x%x,mix=%d,unk=0x%x,n=%d)\n", os->x, os->y, os->clipleft, os->cliptop, os->clipright, os->clipbottom, os->boxleft, os->boxtop, os->boxright, os->boxbottom, os->fgcolour, os->bgcolour, os->font, os->flags, os->mixmode, os->unknown, os->length));
629
for (i = 0; i < os->length; i++)
630
DEBUG(("%02x ", os->text[i]));
634
ui_draw_text(os->font, os->flags, os->mixmode, os->x, os->y,
635
os->clipleft, os->cliptop,
636
os->clipright - os->clipleft,
637
os->clipbottom - os->cliptop,
638
os->boxleft, os->boxtop,
639
os->boxright - os->boxleft,
640
os->boxbottom - os->boxtop, os->bgcolour, os->fgcolour, os->text, os->length);
643
/* Process a raw bitmap cache order */
645
process_raw_bmpcache(STREAM s)
648
uint16 cache_idx, bufsize;
649
uint8 cache_id, width, height, bpp, Bpp;
650
uint8 *data, *inverted;
653
in_uint8(s, cache_id);
654
in_uint8s(s, 1); /* pad */
659
in_uint16_le(s, bufsize);
660
in_uint16_le(s, cache_idx);
661
in_uint8p(s, data, bufsize);
663
DEBUG(("RAW_BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", width, height, cache_id, cache_idx));
664
inverted = (uint8 *) xmalloc(width * height * Bpp);
665
for (y = 0; y < height; y++)
667
memcpy(&inverted[(height - y - 1) * (width * Bpp)], &data[y * (width * Bpp)],
671
bitmap = ui_create_bitmap(width, height, inverted);
673
cache_put_bitmap(cache_id, cache_idx, bitmap);
676
/* Process a bitmap cache order */
678
process_bmpcache(STREAM s)
681
uint16 cache_idx, size;
682
uint8 cache_id, width, height, bpp, Bpp;
683
uint8 *data, *bmpdata;
684
uint16 bufsize, pad2, row_size, final_size;
687
pad2 = row_size = final_size = 0xffff; /* Shut the compiler up */
689
in_uint8(s, cache_id);
690
in_uint8(s, pad1); /* pad */
695
in_uint16_le(s, bufsize); /* bufsize */
696
in_uint16_le(s, cache_idx);
701
/* Begin compressedBitmapData */
702
in_uint16_le(s, pad2); /* pad */
703
in_uint16_le(s, size);
704
/* in_uint8s(s, 4); *//* row_size, final_size */
705
in_uint16_le(s, row_size);
706
in_uint16_le(s, final_size);
713
in_uint8p(s, data, size);
715
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));
717
bmpdata = (uint8 *) xmalloc(width * height * Bpp);
719
if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
721
bitmap = ui_create_bitmap(width, height, bmpdata);
722
cache_put_bitmap(cache_id, cache_idx, bitmap);
726
DEBUG(("Failed to decompress bitmap data\n"));
732
/* Process a colourmap cache order */
734
process_colcache(STREAM s)
742
in_uint8(s, cache_id);
743
in_uint16_le(s, map.ncolours);
745
map.colours = (COLOURENTRY *) xmalloc(sizeof(COLOURENTRY) * map.ncolours);
747
for (i = 0; i < map.ncolours; i++)
749
entry = &map.colours[i];
750
in_uint8(s, entry->blue);
751
in_uint8(s, entry->green);
752
in_uint8(s, entry->red);
753
in_uint8s(s, 1); /* pad */
756
DEBUG(("COLCACHE(id=%d,n=%d)\n", cache_id, map.ncolours));
758
hmap = ui_create_colourmap(&map);
759
ui_set_colourmap(hmap);
764
/* Process a font cache order */
766
process_fontcache(STREAM s)
770
uint16 character, offset, baseline, width, height;
775
in_uint8(s, nglyphs);
777
DEBUG(("FONTCACHE(font=%d,n=%d)\n", font, nglyphs));
779
for (i = 0; i < nglyphs; i++)
781
in_uint16_le(s, character);
782
in_uint16_le(s, offset);
783
in_uint16_le(s, baseline);
784
in_uint16_le(s, width);
785
in_uint16_le(s, height);
787
datasize = (height * ((width + 7) / 8) + 3) & ~3;
788
in_uint8p(s, data, datasize);
790
bitmap = ui_create_glyph(width, height, data);
791
cache_put_font(font, character, offset, baseline, width, height, bitmap);
795
/* Process a secondary order */
797
process_secondary_order(STREAM s)
803
in_uint16_le(s, length);
804
in_uint8s(s, 2); /* flags */
807
next_order = s->p + length + 7;
811
case RDP_ORDER_RAW_BMPCACHE:
812
process_raw_bmpcache(s);
815
case RDP_ORDER_COLCACHE:
819
case RDP_ORDER_BMPCACHE:
823
case RDP_ORDER_FONTCACHE:
824
process_fontcache(s);
828
unimpl("secondary order %d\n", type);
834
/* Process an order PDU */
836
process_orders(STREAM s, uint16 num_orders)
838
RDP_ORDER_STATE *os = &g_order_state;
841
int size, processed = 0;
844
while (processed < num_orders)
846
in_uint8(s, order_flags);
848
if (!(order_flags & RDP_ORDER_STANDARD))
850
error("order parsing failed\n");
854
if (order_flags & RDP_ORDER_SECONDARY)
856
process_secondary_order(s);
860
if (order_flags & RDP_ORDER_CHANGE)
862
in_uint8(s, os->order_type);
865
switch (os->order_type)
867
case RDP_ORDER_TRIBLT:
868
case RDP_ORDER_TEXT2:
872
case RDP_ORDER_PATBLT:
873
case RDP_ORDER_MEMBLT:
882
rdp_in_present(s, &present, order_flags, size);
884
if (order_flags & RDP_ORDER_BOUNDS)
886
if (!(order_flags & RDP_ORDER_LASTBOUNDS))
887
rdp_parse_bounds(s, &os->bounds);
889
ui_set_clip(os->bounds.left,
893
os->bounds.bottom - os->bounds.top + 1);
896
delta = order_flags & RDP_ORDER_DELTA;
898
switch (os->order_type)
900
case RDP_ORDER_DESTBLT:
901
process_destblt(s, &os->destblt, present, delta);
904
case RDP_ORDER_PATBLT:
905
process_patblt(s, &os->patblt, present, delta);
908
case RDP_ORDER_SCREENBLT:
909
process_screenblt(s, &os->screenblt, present, delta);
913
process_line(s, &os->line, present, delta);
917
process_rect(s, &os->rect, present, delta);
920
case RDP_ORDER_DESKSAVE:
921
process_desksave(s, &os->desksave, present, delta);
924
case RDP_ORDER_MEMBLT:
925
process_memblt(s, &os->memblt, present, delta);
928
case RDP_ORDER_TRIBLT:
929
process_triblt(s, &os->triblt, present, delta);
932
case RDP_ORDER_POLYLINE:
933
process_polyline(s, &os->polyline, present, delta);
936
case RDP_ORDER_TEXT2:
937
process_text2(s, &os->text2, present, delta);
941
unimpl("order %d\n", os->order_type);
945
if (order_flags & RDP_ORDER_BOUNDS)
952
if (s->p != g_next_packet)
953
error("%d bytes remaining\n", (int) (g_next_packet - s->p));
956
/* Reset order state */
958
reset_order_state(void)
960
memset(&g_order_state, 0, sizeof(g_order_state));
961
g_order_state.order_type = RDP_ORDER_PATBLT;