1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    RDP order processing
4    Copyright (C) Matthew Chapman 1999-2005
5 
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.
10 
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.
15 
16    You should have received a copy of the GNU General Public License along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20 
21 #include "rdesktop.h"
22 #include "orders.h"
23 
24 /* Read field indicating which parameters are present */
25 static void
26 rdp_in_present(STREAM s, uint32 * present, uint8 flags, int size)
27 {
28 	uint8 bits;
29 	int i;
30 
31 	if (flags & RDP_ORDER_SMALL)
32 	{
33 		size--;
34 	}
35 
36 	if (flags & RDP_ORDER_TINY)
37 	{
38 		if (size < 2)
39 			size = 0;
40 		else
41 			size -= 2;
42 	}
43 
44 	*present = 0;
45 	for (i = 0; i < size; i++)
46 	{
47 		in_uint8(s, bits);
48 		*present |= bits << (i * 8);
49 	}
50 }
51 
52 /* Read a co-ordinate (16-bit, or 8-bit delta) */
53 static void
54 rdp_in_coord(STREAM s, sint16 * coord, BOOL delta)
55 {
56 	sint8 change;
57 
58 	if (delta)
59 	{
60 		in_uint8(s, change);
61 		*coord += change;
62 	}
63 	else
64 	{
65 		in_uint16_le(s, *coord);
66 	}
67 }
68 
69 /* Parse a delta co-ordinate in polyline/polygon order form */
70 static int
71 parse_delta(uint8 * buffer, int *offset)
72 {
73 	int value = buffer[(*offset)++];
74 	int two_byte = value & 0x80;
75 
76 	if (value & 0x40)	/* sign bit */
77 		value |= ~0x3f;
78 	else
79 		value &= 0x3f;
80 
81 	if (two_byte)
82 		value = (value << 8) | buffer[(*offset)++];
83 
84 	return value;
85 }
86 
87 /* Read a colour entry */
88 static void
89 rdp_in_colour(STREAM s, uint32 * colour)
90 {
91 	uint32 i;
92 	in_uint8(s, i);
93 	*colour = i;
94 	in_uint8(s, i);
95 	*colour |= i << 8;
96 	in_uint8(s, i);
97 	*colour |= i << 16;
98 }
99 
100 /* Parse bounds information */
101 static BOOL
102 rdp_parse_bounds(STREAM s, BOUNDS * bounds)
103 {
104 	uint8 present;
105 
106 	in_uint8(s, present);
107 
108 	if (present & 1)
109 		rdp_in_coord(s, &bounds->left, False);
110 	else if (present & 16)
111 		rdp_in_coord(s, &bounds->left, True);
112 
113 	if (present & 2)
114 		rdp_in_coord(s, &bounds->top, False);
115 	else if (present & 32)
116 		rdp_in_coord(s, &bounds->top, True);
117 
118 	if (present & 4)
119 		rdp_in_coord(s, &bounds->right, False);
120 	else if (present & 64)
121 		rdp_in_coord(s, &bounds->right, True);
122 
123 	if (present & 8)
124 		rdp_in_coord(s, &bounds->bottom, False);
125 	else if (present & 128)
126 		rdp_in_coord(s, &bounds->bottom, True);
127 
128 	return s_check(s);
129 }
130 
131 /* Parse a pen */
132 static BOOL
133 rdp_parse_pen(STREAM s, PEN * pen, uint32 present)
134 {
135 	if (present & 1)
136 		in_uint8(s, pen->style);
137 
138 	if (present & 2)
139 		in_uint8(s, pen->width);
140 
141 	if (present & 4)
142 		rdp_in_colour(s, &pen->colour);
143 
144 	return s_check(s);
145 }
146 
147 /* Parse a brush */
148 static BOOL
149 rdp_parse_brush(STREAM s, BRUSH * brush, uint32 present)
150 {
151 	if (present & 1)
152 		in_uint8(s, brush->xorigin);
153 
154 	if (present & 2)
155 		in_uint8(s, brush->yorigin);
156 
157 	if (present & 4)
158 		in_uint8(s, brush->style);
159 
160 	if (present & 8)
161 		in_uint8(s, brush->pattern[0]);
162 
163 	if (present & 16)
164 		in_uint8a(s, &brush->pattern[1], 7);
165 
166 	return s_check(s);
167 }
168 
169 /* Process a destination blt order */
170 static void
171 process_destblt(RDPCLIENT * This, STREAM s, DESTBLT_ORDER * os, uint32 present, BOOL delta)
172 {
173 	if (present & 0x01)
174 		rdp_in_coord(s, &os->x, delta);
175 
176 	if (present & 0x02)
177 		rdp_in_coord(s, &os->y, delta);
178 
179 	if (present & 0x04)
180 		rdp_in_coord(s, &os->cx, delta);
181 
182 	if (present & 0x08)
183 		rdp_in_coord(s, &os->cy, delta);
184 
185 	if (present & 0x10)
186 		in_uint8(s, os->opcode);
187 
188 	DEBUG(("DESTBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d)\n",
189 	       os->opcode, os->x, os->y, os->cx, os->cy));
190 
191 #if 0
192 	ui_destblt(This, ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy);
193 #else
194 	ui_destblt(This, os->opcode, os->x, os->y, os->cx, os->cy);
195 #endif
196 }
197 
198 /* Process a pattern blt order */
199 static void
200 process_patblt(RDPCLIENT * This, STREAM s, PATBLT_ORDER * os, uint32 present, BOOL delta)
201 {
202 	if (present & 0x0001)
203 		rdp_in_coord(s, &os->x, delta);
204 
205 	if (present & 0x0002)
206 		rdp_in_coord(s, &os->y, delta);
207 
208 	if (present & 0x0004)
209 		rdp_in_coord(s, &os->cx, delta);
210 
211 	if (present & 0x0008)
212 		rdp_in_coord(s, &os->cy, delta);
213 
214 	if (present & 0x0010)
215 		in_uint8(s, os->opcode);
216 
217 	if (present & 0x0020)
218 		rdp_in_colour(s, &os->bgcolour);
219 
220 	if (present & 0x0040)
221 		rdp_in_colour(s, &os->fgcolour);
222 
223 	rdp_parse_brush(s, &os->brush, present >> 7);
224 
225 	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,
226 	       os->y, os->cx, os->cy, os->brush.style, os->bgcolour, os->fgcolour));
227 
228 #if 0
229 	ui_patblt(This, ROP2_P(os->opcode), os->x, os->y, os->cx, os->cy,
230 		  &os->brush, os->bgcolour, os->fgcolour);
231 #else
232 	ui_patblt(This, os->opcode, os->x, os->y, os->cx, os->cy,
233 		  &os->brush, os->bgcolour, os->fgcolour);
234 #endif
235 }
236 
237 /* Process a screen blt order */
238 static void
239 process_screenblt(RDPCLIENT * This, STREAM s, SCREENBLT_ORDER * os, uint32 present, BOOL delta)
240 {
241 	if (present & 0x0001)
242 		rdp_in_coord(s, &os->x, delta);
243 
244 	if (present & 0x0002)
245 		rdp_in_coord(s, &os->y, delta);
246 
247 	if (present & 0x0004)
248 		rdp_in_coord(s, &os->cx, delta);
249 
250 	if (present & 0x0008)
251 		rdp_in_coord(s, &os->cy, delta);
252 
253 	if (present & 0x0010)
254 		in_uint8(s, os->opcode);
255 
256 	if (present & 0x0020)
257 		rdp_in_coord(s, &os->srcx, delta);
258 
259 	if (present & 0x0040)
260 		rdp_in_coord(s, &os->srcy, delta);
261 
262 	DEBUG(("SCREENBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,srcx=%d,srcy=%d)\n",
263 	       os->opcode, os->x, os->y, os->cx, os->cy, os->srcx, os->srcy));
264 
265 #if 0
266 	ui_screenblt(This, ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, os->srcx, os->srcy);
267 #else
268 	ui_screenblt(This, os->opcode, os->x, os->y, os->cx, os->cy, os->srcx, os->srcy);
269 #endif
270 }
271 
272 /* Process a line order */
273 static void
274 process_line(RDPCLIENT * This, STREAM s, LINE_ORDER * os, uint32 present, BOOL delta)
275 {
276 	if (present & 0x0001)
277 		in_uint16_le(s, os->mixmode);
278 
279 	if (present & 0x0002)
280 		rdp_in_coord(s, &os->startx, delta);
281 
282 	if (present & 0x0004)
283 		rdp_in_coord(s, &os->starty, delta);
284 
285 	if (present & 0x0008)
286 		rdp_in_coord(s, &os->endx, delta);
287 
288 	if (present & 0x0010)
289 		rdp_in_coord(s, &os->endy, delta);
290 
291 	if (present & 0x0020)
292 		rdp_in_colour(s, &os->bgcolour);
293 
294 	if (present & 0x0040)
295 		in_uint8(s, os->opcode);
296 
297 	rdp_parse_pen(s, &os->pen, present >> 7);
298 
299 	DEBUG(("LINE(op=0x%x,sx=%d,sy=%d,dx=%d,dy=%d,fg=0x%x)\n",
300 	       os->opcode, os->startx, os->starty, os->endx, os->endy, os->pen.colour));
301 
302 	if (os->opcode < 0x01 || os->opcode > 0x10)
303 	{
304 		error("bad ROP2 0x%x\n", os->opcode);
305 		return;
306 	}
307 
308 #if 0
309 	ui_line(This, os->opcode - 1, os->startx, os->starty, os->endx, os->endy, &os->pen);
310 #else
311 	ui_line(This, os->opcode, os->startx, os->starty, os->endx, os->endy, &os->pen);
312 #endif
313 }
314 
315 /* Process an opaque rectangle order */
316 static void
317 process_rect(RDPCLIENT * This, STREAM s, RECT_ORDER * os, uint32 present, BOOL delta)
318 {
319 	uint32 i;
320 	if (present & 0x01)
321 		rdp_in_coord(s, &os->x, delta);
322 
323 	if (present & 0x02)
324 		rdp_in_coord(s, &os->y, delta);
325 
326 	if (present & 0x04)
327 		rdp_in_coord(s, &os->cx, delta);
328 
329 	if (present & 0x08)
330 		rdp_in_coord(s, &os->cy, delta);
331 
332 	if (present & 0x10)
333 	{
334 		in_uint8(s, i);
335 		os->colour = (os->colour & 0xffffff00) | i;
336 	}
337 
338 	if (present & 0x20)
339 	{
340 		in_uint8(s, i);
341 		os->colour = (os->colour & 0xffff00ff) | (i << 8);
342 	}
343 
344 	if (present & 0x40)
345 	{
346 		in_uint8(s, i);
347 		os->colour = (os->colour & 0xff00ffff) | (i << 16);
348 	}
349 
350 	DEBUG(("RECT(x=%d,y=%d,cx=%d,cy=%d,fg=0x%x)\n", os->x, os->y, os->cx, os->cy, os->colour));
351 
352 	ui_rect(This, os->x, os->y, os->cx, os->cy, os->colour);
353 }
354 
355 /* Process a desktop save order */
356 static void
357 process_desksave(RDPCLIENT * This, STREAM s, DESKSAVE_ORDER * os, uint32 present, BOOL delta)
358 {
359 	int width, height;
360 
361 	if (present & 0x01)
362 		in_uint32_le(s, os->offset);
363 
364 	if (present & 0x02)
365 		rdp_in_coord(s, &os->left, delta);
366 
367 	if (present & 0x04)
368 		rdp_in_coord(s, &os->top, delta);
369 
370 	if (present & 0x08)
371 		rdp_in_coord(s, &os->right, delta);
372 
373 	if (present & 0x10)
374 		rdp_in_coord(s, &os->bottom, delta);
375 
376 	if (present & 0x20)
377 		in_uint8(s, os->action);
378 
379 	DEBUG(("DESKSAVE(l=%d,t=%d,r=%d,b=%d,off=%d,op=%d)\n",
380 	       os->left, os->top, os->right, os->bottom, os->offset, os->action));
381 
382 	width = os->right - os->left + 1;
383 	height = os->bottom - os->top + 1;
384 
385 	if (os->action == 0)
386 		ui_desktop_save(This, os->offset, os->left, os->top, width, height);
387 	else
388 		ui_desktop_restore(This, os->offset, os->left, os->top, width, height);
389 }
390 
391 /* Process a memory blt order */
392 static void
393 process_memblt(RDPCLIENT * This, STREAM s, MEMBLT_ORDER * os, uint32 present, BOOL delta)
394 {
395 	HBITMAP bitmap;
396 
397 	if (present & 0x0001)
398 	{
399 		in_uint8(s, os->cache_id);
400 		in_uint8(s, os->colour_table);
401 	}
402 
403 	if (present & 0x0002)
404 		rdp_in_coord(s, &os->x, delta);
405 
406 	if (present & 0x0004)
407 		rdp_in_coord(s, &os->y, delta);
408 
409 	if (present & 0x0008)
410 		rdp_in_coord(s, &os->cx, delta);
411 
412 	if (present & 0x0010)
413 		rdp_in_coord(s, &os->cy, delta);
414 
415 	if (present & 0x0020)
416 		in_uint8(s, os->opcode);
417 
418 	if (present & 0x0040)
419 		rdp_in_coord(s, &os->srcx, delta);
420 
421 	if (present & 0x0080)
422 		rdp_in_coord(s, &os->srcy, delta);
423 
424 	if (present & 0x0100)
425 		in_uint16_le(s, os->cache_idx);
426 
427 	DEBUG(("MEMBLT(op=0x%x,x=%d,y=%d,cx=%d,cy=%d,id=%d,idx=%d)\n",
428 	       os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx));
429 
430 	bitmap = cache_get_bitmap(This, os->cache_id, os->cache_idx);
431 	if (bitmap == NULL)
432 		return;
433 
434 #if 0
435 	ui_memblt(This, ROP2_S(os->opcode), os->x, os->y, os->cx, os->cy, bitmap, os->srcx, os->srcy);
436 #else
437 	ui_memblt(This, os->opcode, os->x, os->y, os->cx, os->cy, bitmap, os->srcx, os->srcy);
438 #endif
439 }
440 
441 /* Process a 3-way blt order */
442 static void
443 process_triblt(RDPCLIENT * This, STREAM s, TRIBLT_ORDER * os, uint32 present, BOOL delta)
444 {
445 	HBITMAP bitmap;
446 
447 	if (present & 0x000001)
448 	{
449 		in_uint8(s, os->cache_id);
450 		in_uint8(s, os->colour_table);
451 	}
452 
453 	if (present & 0x000002)
454 		rdp_in_coord(s, &os->x, delta);
455 
456 	if (present & 0x000004)
457 		rdp_in_coord(s, &os->y, delta);
458 
459 	if (present & 0x000008)
460 		rdp_in_coord(s, &os->cx, delta);
461 
462 	if (present & 0x000010)
463 		rdp_in_coord(s, &os->cy, delta);
464 
465 	if (present & 0x000020)
466 		in_uint8(s, os->opcode);
467 
468 	if (present & 0x000040)
469 		rdp_in_coord(s, &os->srcx, delta);
470 
471 	if (present & 0x000080)
472 		rdp_in_coord(s, &os->srcy, delta);
473 
474 	if (present & 0x000100)
475 		rdp_in_colour(s, &os->bgcolour);
476 
477 	if (present & 0x000200)
478 		rdp_in_colour(s, &os->fgcolour);
479 
480 	rdp_parse_brush(s, &os->brush, present >> 10);
481 
482 	if (present & 0x008000)
483 		in_uint16_le(s, os->cache_idx);
484 
485 	if (present & 0x010000)
486 		in_uint16_le(s, os->unknown);
487 
488 	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",
489 	       os->opcode, os->x, os->y, os->cx, os->cy, os->cache_id, os->cache_idx,
490 	       os->brush.style, os->bgcolour, os->fgcolour));
491 
492 	bitmap = cache_get_bitmap(This, os->cache_id, os->cache_idx);
493 	if (bitmap == NULL)
494 		return;
495 
496 	ui_triblt(This, os->opcode, os->x, os->y, os->cx, os->cy,
497 		  bitmap, os->srcx, os->srcy, &os->brush, os->bgcolour, os->fgcolour);
498 }
499 
500 /* Process a polygon order */
501 static void
502 process_polygon(RDPCLIENT * This, STREAM s, POLYGON_ORDER * os, uint32 present, BOOL delta)
503 {
504 	int index, data, next;
505 	uint8 flags = 0;
506 	POINT *points;
507 
508 	if (present & 0x01)
509 		rdp_in_coord(s, &os->x, delta);
510 
511 	if (present & 0x02)
512 		rdp_in_coord(s, &os->y, delta);
513 
514 	if (present & 0x04)
515 		in_uint8(s, os->opcode);
516 
517 	if (present & 0x08)
518 		in_uint8(s, os->fillmode);
519 
520 	if (present & 0x10)
521 		rdp_in_colour(s, &os->fgcolour);
522 
523 	if (present & 0x20)
524 		in_uint8(s, os->npoints);
525 
526 	if (present & 0x40)
527 	{
528 		in_uint8(s, os->datasize);
529 		in_uint8a(s, os->data, os->datasize);
530 	}
531 
532 	DEBUG(("POLYGON(x=%d,y=%d,op=0x%x,fm=%d,fg=0x%x,n=%d,sz=%d)\n",
533 	       os->x, os->y, os->opcode, os->fillmode, os->fgcolour, os->npoints, os->datasize));
534 
535 	DEBUG(("Data: "));
536 
537 	for (index = 0; index < os->datasize; index++)
538 		DEBUG(("%02x ", os->data[index]));
539 
540 	DEBUG(("\n"));
541 
542 	if (os->opcode < 0x01 || os->opcode > 0x10)
543 	{
544 		error("bad ROP2 0x%x\n", os->opcode);
545 		return;
546 	}
547 
548 	points = (POINT *) malloc((os->npoints + 1) * sizeof(POINT));
549 
550 	if(points == NULL)
551 		return;
552 
553 	memset(points, 0, (os->npoints + 1) * sizeof(POINT));
554 
555 	points[0].x = os->x;
556 	points[0].y = os->y;
557 
558 	index = 0;
559 	data = ((os->npoints - 1) / 4) + 1;
560 	for (next = 1; (next <= os->npoints) && (next < 256) && (data < os->datasize); next++)
561 	{
562 		if ((next - 1) % 4 == 0)
563 			flags = os->data[index++];
564 
565 		if (~flags & 0x80)
566 			points[next].x = parse_delta(os->data, &data);
567 
568 		if (~flags & 0x40)
569 			points[next].y = parse_delta(os->data, &data);
570 
571 		flags <<= 2;
572 	}
573 
574 	if (next - 1 == os->npoints)
575 #if 0
576 		ui_polygon(This, os->opcode - 1, os->fillmode, points, os->npoints + 1, NULL, 0,
577 			   os->fgcolour);
578 #else
579 		ui_polygon(This, os->opcode, os->fillmode, points, os->npoints + 1, NULL, 0,
580 			   os->fgcolour);
581 #endif
582 	else
583 		error("polygon parse error\n");
584 
585 	free(points);
586 }
587 
588 /* Process a polygon2 order */
589 static void
590 process_polygon2(RDPCLIENT * This, STREAM s, POLYGON2_ORDER * os, uint32 present, BOOL delta)
591 {
592 	int index, data, next;
593 	uint8 flags = 0;
594 	POINT *points;
595 
596 	if (present & 0x0001)
597 		rdp_in_coord(s, &os->x, delta);
598 
599 	if (present & 0x0002)
600 		rdp_in_coord(s, &os->y, delta);
601 
602 	if (present & 0x0004)
603 		in_uint8(s, os->opcode);
604 
605 	if (present & 0x0008)
606 		in_uint8(s, os->fillmode);
607 
608 	if (present & 0x0010)
609 		rdp_in_colour(s, &os->bgcolour);
610 
611 	if (present & 0x0020)
612 		rdp_in_colour(s, &os->fgcolour);
613 
614 	rdp_parse_brush(s, &os->brush, present >> 6);
615 
616 	if (present & 0x0800)
617 		in_uint8(s, os->npoints);
618 
619 	if (present & 0x1000)
620 	{
621 		in_uint8(s, os->datasize);
622 		in_uint8a(s, os->data, os->datasize);
623 	}
624 
625 	DEBUG(("POLYGON2(x=%d,y=%d,op=0x%x,fm=%d,bs=%d,bg=0x%x,fg=0x%x,n=%d,sz=%d)\n",
626 	       os->x, os->y, os->opcode, os->fillmode, os->brush.style, os->bgcolour, os->fgcolour,
627 	       os->npoints, os->datasize));
628 
629 	DEBUG(("Data: "));
630 
631 	for (index = 0; index < os->datasize; index++)
632 		DEBUG(("%02x ", os->data[index]));
633 
634 	DEBUG(("\n"));
635 
636 	if (os->opcode < 0x01 || os->opcode > 0x10)
637 	{
638 		error("bad ROP2 0x%x\n", os->opcode);
639 		return;
640 	}
641 
642 	points = (POINT *) malloc((os->npoints + 1) * sizeof(POINT));
643 
644 	if(points == NULL)
645 		return;
646 
647 	memset(points, 0, (os->npoints + 1) * sizeof(POINT));
648 
649 	points[0].x = os->x;
650 	points[0].y = os->y;
651 
652 	index = 0;
653 	data = ((os->npoints - 1) / 4) + 1;
654 	for (next = 1; (next <= os->npoints) && (next < 256) && (data < os->datasize); next++)
655 	{
656 		if ((next - 1) % 4 == 0)
657 			flags = os->data[index++];
658 
659 		if (~flags & 0x80)
660 			points[next].x = parse_delta(os->data, &data);
661 
662 		if (~flags & 0x40)
663 			points[next].y = parse_delta(os->data, &data);
664 
665 		flags <<= 2;
666 	}
667 
668 	if (next - 1 == os->npoints)
669 #if 0
670 		ui_polygon(This, os->opcode - 1, os->fillmode, points, os->npoints + 1,
671 			   &os->brush, os->bgcolour, os->fgcolour);
672 #else
673 		ui_polygon(This, os->opcode, os->fillmode, points, os->npoints + 1,
674 			   &os->brush, os->bgcolour, os->fgcolour);
675 #endif
676 	else
677 		error("polygon2 parse error\n");
678 
679 	free(points);
680 }
681 
682 /* Process a polyline order */
683 static void
684 process_polyline(RDPCLIENT * This, STREAM s, POLYLINE_ORDER * os, uint32 present, BOOL delta)
685 {
686 	int index, next, data;
687 	uint8 flags = 0;
688 	PEN pen;
689 	POINT *points;
690 
691 	if (present & 0x01)
692 		rdp_in_coord(s, &os->x, delta);
693 
694 	if (present & 0x02)
695 		rdp_in_coord(s, &os->y, delta);
696 
697 	if (present & 0x04)
698 		in_uint8(s, os->opcode);
699 
700 	if (present & 0x10)
701 		rdp_in_colour(s, &os->fgcolour);
702 
703 	if (present & 0x20)
704 		in_uint8(s, os->lines);
705 
706 	if (present & 0x40)
707 	{
708 		in_uint8(s, os->datasize);
709 		in_uint8a(s, os->data, os->datasize);
710 	}
711 
712 	DEBUG(("POLYLINE(x=%d,y=%d,op=0x%x,fg=0x%x,n=%d,sz=%d)\n",
713 	       os->x, os->y, os->opcode, os->fgcolour, os->lines, os->datasize));
714 
715 	DEBUG(("Data: "));
716 
717 	for (index = 0; index < os->datasize; index++)
718 		DEBUG(("%02x ", os->data[index]));
719 
720 	DEBUG(("\n"));
721 
722 	if (os->opcode < 0x01 || os->opcode > 0x10)
723 	{
724 		error("bad ROP2 0x%x\n", os->opcode);
725 		return;
726 	}
727 
728 	points = (POINT *) malloc((os->lines + 1) * sizeof(POINT));
729 
730 	if(points == NULL)
731 		return;
732 
733 	memset(points, 0, (os->lines + 1) * sizeof(POINT));
734 
735 	points[0].x = os->x;
736 	points[0].y = os->y;
737 	pen.style = pen.width = 0;
738 	pen.colour = os->fgcolour;
739 
740 	index = 0;
741 	data = ((os->lines - 1) / 4) + 1;
742 	for (next = 1; (next <= os->lines) && (data < os->datasize); next++)
743 	{
744 		if ((next - 1) % 4 == 0)
745 			flags = os->data[index++];
746 
747 		if (~flags & 0x80)
748 			points[next].x = parse_delta(os->data, &data);
749 
750 		if (~flags & 0x40)
751 			points[next].y = parse_delta(os->data, &data);
752 
753 		flags <<= 2;
754 	}
755 
756 	if (next - 1 == os->lines)
757 #if 0
758 		ui_polyline(This, os->opcode - 1, points, os->lines + 1, &pen);
759 #else
760 		ui_polyline(This, os->opcode, points, os->lines + 1, &pen);
761 #endif
762 	else
763 		error("polyline parse error\n");
764 
765 	free(points);
766 }
767 
768 /* Process an ellipse order */
769 static void
770 process_ellipse(RDPCLIENT * This, STREAM s, ELLIPSE_ORDER * os, uint32 present, BOOL delta)
771 {
772 	if (present & 0x01)
773 		rdp_in_coord(s, &os->left, delta);
774 
775 	if (present & 0x02)
776 		rdp_in_coord(s, &os->top, delta);
777 
778 	if (present & 0x04)
779 		rdp_in_coord(s, &os->right, delta);
780 
781 	if (present & 0x08)
782 		rdp_in_coord(s, &os->bottom, delta);
783 
784 	if (present & 0x10)
785 		in_uint8(s, os->opcode);
786 
787 	if (present & 0x20)
788 		in_uint8(s, os->fillmode);
789 
790 	if (present & 0x40)
791 		rdp_in_colour(s, &os->fgcolour);
792 
793 	DEBUG(("ELLIPSE(l=%d,t=%d,r=%d,b=%d,op=0x%x,fm=%d,fg=0x%x)\n", os->left, os->top,
794 	       os->right, os->bottom, os->opcode, os->fillmode, os->fgcolour));
795 
796 #if 0
797 	ui_ellipse(This, os->opcode - 1, os->fillmode, os->left, os->top, os->right - os->left,
798 		   os->bottom - os->top, NULL, 0, os->fgcolour);
799 #else
800 	ui_ellipse(This, os->opcode, os->fillmode, os->left, os->top, os->right - os->left,
801 		   os->bottom - os->top, NULL, 0, os->fgcolour);
802 #endif
803 }
804 
805 /* Process an ellipse2 order */
806 static void
807 process_ellipse2(RDPCLIENT * This, STREAM s, ELLIPSE2_ORDER * os, uint32 present, BOOL delta)
808 {
809 	if (present & 0x0001)
810 		rdp_in_coord(s, &os->left, delta);
811 
812 	if (present & 0x0002)
813 		rdp_in_coord(s, &os->top, delta);
814 
815 	if (present & 0x0004)
816 		rdp_in_coord(s, &os->right, delta);
817 
818 	if (present & 0x0008)
819 		rdp_in_coord(s, &os->bottom, delta);
820 
821 	if (present & 0x0010)
822 		in_uint8(s, os->opcode);
823 
824 	if (present & 0x0020)
825 		in_uint8(s, os->fillmode);
826 
827 	if (present & 0x0040)
828 		rdp_in_colour(s, &os->bgcolour);
829 
830 	if (present & 0x0080)
831 		rdp_in_colour(s, &os->fgcolour);
832 
833 	rdp_parse_brush(s, &os->brush, present >> 8);
834 
835 	DEBUG(("ELLIPSE2(l=%d,t=%d,r=%d,b=%d,op=0x%x,fm=%d,bs=%d,bg=0x%x,fg=0x%x)\n",
836 	       os->left, os->top, os->right, os->bottom, os->opcode, os->fillmode, os->brush.style,
837 	       os->bgcolour, os->fgcolour));
838 
839 #if 0
840 	ui_ellipse(This, os->opcode - 1, os->fillmode, os->left, os->top, os->right - os->left,
841 		   os->bottom - os->top, &os->brush, os->bgcolour, os->fgcolour);
842 #else
843 	ui_ellipse(This, os->opcode, os->fillmode, os->left, os->top, os->right - os->left,
844 		   os->bottom - os->top, &os->brush, os->bgcolour, os->fgcolour);
845 #endif
846 }
847 
848 /* Process a text order */
849 static void
850 process_text2(RDPCLIENT * This, STREAM s, TEXT2_ORDER * os, uint32 present, BOOL delta)
851 {
852 	int i;
853 
854 	if (present & 0x000001)
855 		in_uint8(s, os->font);
856 
857 	if (present & 0x000002)
858 		in_uint8(s, os->flags);
859 
860 	if (present & 0x000004)
861 		in_uint8(s, os->opcode);
862 
863 	if (present & 0x000008)
864 		in_uint8(s, os->mixmode);
865 
866 	if (present & 0x000010)
867 		rdp_in_colour(s, &os->fgcolour);
868 
869 	if (present & 0x000020)
870 		rdp_in_colour(s, &os->bgcolour);
871 
872 	if (present & 0x000040)
873 		in_uint16_le(s, os->clipleft);
874 
875 	if (present & 0x000080)
876 		in_uint16_le(s, os->cliptop);
877 
878 	if (present & 0x000100)
879 		in_uint16_le(s, os->clipright);
880 
881 	if (present & 0x000200)
882 		in_uint16_le(s, os->clipbottom);
883 
884 	if (present & 0x000400)
885 		in_uint16_le(s, os->boxleft);
886 
887 	if (present & 0x000800)
888 		in_uint16_le(s, os->boxtop);
889 
890 	if (present & 0x001000)
891 		in_uint16_le(s, os->boxright);
892 
893 	if (present & 0x002000)
894 		in_uint16_le(s, os->boxbottom);
895 
896 	rdp_parse_brush(s, &os->brush, present >> 14);
897 
898 	if (present & 0x080000)
899 		in_uint16_le(s, os->x);
900 
901 	if (present & 0x100000)
902 		in_uint16_le(s, os->y);
903 
904 	if (present & 0x200000)
905 	{
906 		in_uint8(s, os->length);
907 		in_uint8a(s, os->text, os->length);
908 	}
909 
910 	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));
911 
912 	DEBUG(("Text: "));
913 
914 	for (i = 0; i < os->length; i++)
915 		DEBUG(("%02x ", os->text[i]));
916 
917 	DEBUG(("\n"));
918 
919 #if 0
920 	ui_draw_text(This, os->font, os->flags, os->opcode - 1, os->mixmode, os->x, os->y,
921 		     os->clipleft, os->cliptop, os->clipright - os->clipleft,
922 		     os->clipbottom - os->cliptop, os->boxleft, os->boxtop,
923 		     os->boxright - os->boxleft, os->boxbottom - os->boxtop,
924 		     &os->brush, os->bgcolour, os->fgcolour, os->text, os->length);
925 #else
926 	ui_draw_text(This, os->font, os->flags, os->opcode, os->mixmode, os->x, os->y,
927 		     os->clipleft, os->cliptop, os->clipright - os->clipleft,
928 		     os->clipbottom - os->cliptop, os->boxleft, os->boxtop,
929 		     os->boxright - os->boxleft, os->boxbottom - os->boxtop,
930 		     &os->brush, os->bgcolour, os->fgcolour, os->text, os->length);
931 #endif
932 }
933 
934 /* Process a raw bitmap cache order */
935 static void
936 process_raw_bmpcache(RDPCLIENT * This, STREAM s)
937 {
938 	HBITMAP bitmap;
939 	uint16 cache_idx, bufsize;
940 	uint8 cache_id, width, height, bpp, Bpp;
941 	uint8 *data;
942 
943 	in_uint8(s, cache_id);
944 	in_uint8s(s, 1);	/* pad */
945 	in_uint8(s, width);
946 	in_uint8(s, height);
947 	in_uint8(s, bpp);
948 	Bpp = (bpp + 7) / 8;
949 	in_uint16_le(s, bufsize);
950 	in_uint16_le(s, cache_idx);
951 	in_uint8p(s, data, bufsize);
952 
953 	DEBUG(("RAW_BMPCACHE(cx=%d,cy=%d,id=%d,idx=%d)\n", width, height, cache_id, cache_idx));
954 #if 0
955 	inverted = (uint8 *) xmalloc(width * height * Bpp);
956 	for (y = 0; y < height; y++)
957 	{
958 		memcpy(&inverted[(height - y - 1) * (width * Bpp)], &data[y * (width * Bpp)],
959 		       width * Bpp);
960 	}
961 #endif
962 
963 #if 0
964 	bitmap = ui_create_bitmap(This, width, height, inverted);
965 	xfree(inverted);
966 #else
967 	bitmap = ui_create_bitmap(This, width, height, data);
968 #endif
969 
970 	cache_put_bitmap(This, cache_id, cache_idx, bitmap);
971 }
972 
973 /* Process a bitmap cache order */
974 static void
975 process_bmpcache(RDPCLIENT * This, STREAM s)
976 {
977 	HBITMAP bitmap;
978 	uint16 cache_idx, size;
979 	uint8 cache_id, width, height, bpp, Bpp;
980 	uint8 *data, *bmpdata;
981 	uint16 bufsize, pad2, row_size, final_size;
982 	uint8 pad1;
983 
984 	pad2 = row_size = final_size = 0xffff;	/* Shut the compiler up */
985 
986 	in_uint8(s, cache_id);
987 	in_uint8(s, pad1);	/* pad */
988 	in_uint8(s, width);
989 	in_uint8(s, height);
990 	in_uint8(s, bpp);
991 	Bpp = (bpp + 7) / 8;
992 	in_uint16_le(s, bufsize);	/* bufsize */
993 	in_uint16_le(s, cache_idx);
994 
995 	if (This->use_rdp5)
996 	{
997 		size = bufsize;
998 	}
999 	else
1000 	{
1001 
1002 		/* Begin compressedBitmapData */
1003 		in_uint16_le(s, pad2);	/* pad */
1004 		in_uint16_le(s, size);
1005 		/*      in_uint8s(s, 4);  *//* row_size, final_size */
1006 		in_uint16_le(s, row_size);
1007 		in_uint16_le(s, final_size);
1008 
1009 	}
1010 	in_uint8p(s, data, size);
1011 
1012 	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));
1013 
1014 	bmpdata = (uint8 *) malloc(width * height * Bpp);
1015 
1016 	if(bmpdata == NULL)
1017 		return;
1018 
1019 	if (bitmap_decompress(bmpdata, width, height, data, size, Bpp))
1020 	{
1021 		bitmap = ui_create_bitmap(This, width, height, bmpdata);
1022 		cache_put_bitmap(This, cache_id, cache_idx, bitmap);
1023 	}
1024 	else
1025 	{
1026 		DEBUG(("Failed to decompress bitmap data\n"));
1027 	}
1028 
1029 	free(bmpdata);
1030 }
1031 
1032 /* Process a bitmap cache v2 order */
1033 static void
1034 process_bmpcache2(RDPCLIENT * This, STREAM s, uint16 flags, BOOL compressed)
1035 {
1036 	HBITMAP bitmap;
1037 	uint8 cache_id, cache_idx_low, width, height, Bpp;
1038 	uint16 cache_idx, bufsize;
1039 	uint8 *data, *bmpdata, *bitmap_id;
1040 
1041 	bitmap_id = NULL;	/* prevent compiler warning */
1042 	cache_id = flags & ID_MASK;
1043 	Bpp = ((flags & MODE_MASK) >> MODE_SHIFT) - 2;
1044 
1045 	if (flags & PERSIST)
1046 	{
1047 		in_uint8p(s, bitmap_id, 8);
1048 	}
1049 
1050 	if (flags & SQUARE)
1051 	{
1052 		in_uint8(s, width);
1053 		height = width;
1054 	}
1055 	else
1056 	{
1057 		in_uint8(s, width);
1058 		in_uint8(s, height);
1059 	}
1060 
1061 	in_uint16_be(s, bufsize);
1062 	bufsize &= BUFSIZE_MASK;
1063 	in_uint8(s, cache_idx);
1064 
1065 	if (cache_idx & LONG_FORMAT)
1066 	{
1067 		in_uint8(s, cache_idx_low);
1068 		cache_idx = ((cache_idx ^ LONG_FORMAT) << 8) + cache_idx_low;
1069 	}
1070 
1071 	in_uint8p(s, data, bufsize);
1072 
1073 	DEBUG(("BMPCACHE2(compr=%d,flags=%x,cx=%d,cy=%d,id=%d,idx=%d,Bpp=%d,bs=%d)\n",
1074 	       compressed, flags, width, height, cache_id, cache_idx, Bpp, bufsize));
1075 
1076 	if (compressed)
1077 	{
1078 		bmpdata = (uint8 *) malloc(width * height * Bpp);
1079 
1080 		if(bmpdata == NULL)
1081 			return;
1082 
1083 		if (!bitmap_decompress(bmpdata, width, height, data, bufsize, Bpp))
1084 		{
1085 			DEBUG(("Failed to decompress bitmap data\n"));
1086 			free(bmpdata);
1087 			return;
1088 		}
1089 	}
1090 	else
1091 	{
1092 #if 0
1093 		for (y = 0; y < height; y++)
1094 			memcpy(&bmpdata[(height - y - 1) * (width * Bpp)],
1095 			       &data[y * (width * Bpp)], width * Bpp);
1096 #else
1097 		bmpdata = data;
1098 #endif
1099 	}
1100 
1101 	bitmap = ui_create_bitmap(This, width, height, bmpdata);
1102 
1103 	if (bitmap)
1104 	{
1105 		cache_put_bitmap(This, cache_id, cache_idx, bitmap);
1106 		if (flags & PERSIST)
1107 			pstcache_save_bitmap(This, cache_id, cache_idx, bitmap_id, width, height,
1108 					     width * height * Bpp, bmpdata);
1109 	}
1110 	else
1111 	{
1112 		DEBUG(("process_bmpcache2: ui_create_bitmap failed\n"));
1113 	}
1114 
1115 	if (compressed)
1116 		free(bmpdata);
1117 }
1118 
1119 /* Process a colourmap cache order */
1120 static void
1121 process_colcache(RDPCLIENT * This, STREAM s)
1122 {
1123 	COLOURENTRY *entry;
1124 	COLOURMAP map;
1125 	HCOLOURMAP hmap;
1126 	uint8 cache_id;
1127 	int i;
1128 
1129 	in_uint8(s, cache_id);
1130 	in_uint16_le(s, map.ncolours);
1131 
1132 	map.colours = (COLOURENTRY *) malloc(sizeof(COLOURENTRY) * map.ncolours);
1133 
1134 	if(map.colours == NULL)
1135 	{
1136 		in_uint8s(s, map.ncolours * 4);
1137 		return;
1138 	}
1139 
1140 	for (i = 0; i < map.ncolours; i++)
1141 	{
1142 		entry = &map.colours[i];
1143 		in_uint8(s, entry->blue);
1144 		in_uint8(s, entry->green);
1145 		in_uint8(s, entry->red);
1146 		in_uint8s(s, 1);	/* pad */
1147 	}
1148 
1149 	DEBUG(("COLCACHE(id=%d,n=%d)\n", cache_id, map.ncolours));
1150 
1151 	hmap = ui_create_colourmap(This, &map);
1152 
1153 	if (cache_id)
1154 		ui_set_colourmap(This, hmap);
1155 
1156 	free(map.colours);
1157 }
1158 
1159 /* Process a font cache order */
1160 static void
1161 process_fontcache(RDPCLIENT * This, STREAM s)
1162 {
1163 	HGLYPH bitmap;
1164 	uint8 font, nglyphs;
1165 	uint16 character, offset, baseline, width, height;
1166 	int i, datasize;
1167 	uint8 *data;
1168 
1169 	in_uint8(s, font);
1170 	in_uint8(s, nglyphs);
1171 
1172 	DEBUG(("FONTCACHE(font=%d,n=%d)\n", font, nglyphs));
1173 
1174 	for (i = 0; i < nglyphs; i++)
1175 	{
1176 		in_uint16_le(s, character);
1177 		in_uint16_le(s, offset);
1178 		in_uint16_le(s, baseline);
1179 		in_uint16_le(s, width);
1180 		in_uint16_le(s, height);
1181 
1182 		datasize = (height * ((width + 7) / 8) + 3) & ~3;
1183 		in_uint8p(s, data, datasize);
1184 
1185 		bitmap = ui_create_glyph(This, width, height, data);
1186 		cache_put_font(This, font, character, offset, baseline, width, height, bitmap);
1187 	}
1188 }
1189 
1190 /* Process a secondary order */
1191 static void
1192 process_secondary_order(RDPCLIENT * This, STREAM s)
1193 {
1194 	/* The length isn't calculated correctly by the server.
1195 	 * For very compact orders the length becomes negative
1196 	 * so a signed integer must be used. */
1197 	uint16 length;
1198 	uint16 flags;
1199 	uint8 type;
1200 	uint8 *next_order;
1201 
1202 	in_uint16_le(s, length);
1203 	in_uint16_le(s, flags);	/* used by bmpcache2 */
1204 	in_uint8(s, type);
1205 
1206 	next_order = s->p + (sint16) length + 7;
1207 
1208 	switch (type)
1209 	{
1210 		case RDP_ORDER_RAW_BMPCACHE:
1211 			process_raw_bmpcache(This, s);
1212 			break;
1213 
1214 		case RDP_ORDER_COLCACHE:
1215 			process_colcache(This, s);
1216 			break;
1217 
1218 		case RDP_ORDER_BMPCACHE:
1219 			process_bmpcache(This, s);
1220 			break;
1221 
1222 		case RDP_ORDER_FONTCACHE:
1223 			process_fontcache(This, s);
1224 			break;
1225 
1226 		case RDP_ORDER_RAW_BMPCACHE2:
1227 			process_bmpcache2(This, s, flags, False);	/* uncompressed */
1228 			break;
1229 
1230 		case RDP_ORDER_BMPCACHE2:
1231 			process_bmpcache2(This, s, flags, True);	/* compressed */
1232 			break;
1233 
1234 		default:
1235 			unimpl("secondary order %d\n", type);
1236 	}
1237 
1238 	s->p = next_order;
1239 }
1240 
1241 /* Process an order PDU */
1242 void
1243 process_orders(RDPCLIENT * This, STREAM s, uint16 num_orders)
1244 {
1245 	RDP_ORDER_STATE *os = &This->orders.order_state;
1246 	uint32 present;
1247 	uint8 order_flags;
1248 	int size, processed = 0;
1249 	BOOL delta;
1250 
1251 	while (processed < num_orders)
1252 	{
1253 		in_uint8(s, order_flags);
1254 
1255 		if (!(order_flags & RDP_ORDER_STANDARD))
1256 		{
1257 			error("order parsing failed\n");
1258 			break;
1259 		}
1260 
1261 		if (order_flags & RDP_ORDER_SECONDARY)
1262 		{
1263 			process_secondary_order(This, s);
1264 		}
1265 		else
1266 		{
1267 			if (order_flags & RDP_ORDER_CHANGE)
1268 			{
1269 				in_uint8(s, os->order_type);
1270 			}
1271 
1272 			switch (os->order_type)
1273 			{
1274 				case RDP_ORDER_TRIBLT:
1275 				case RDP_ORDER_TEXT2:
1276 					size = 3;
1277 					break;
1278 
1279 				case RDP_ORDER_PATBLT:
1280 				case RDP_ORDER_MEMBLT:
1281 				case RDP_ORDER_LINE:
1282 				case RDP_ORDER_POLYGON2:
1283 				case RDP_ORDER_ELLIPSE2:
1284 					size = 2;
1285 					break;
1286 
1287 				default:
1288 					size = 1;
1289 			}
1290 
1291 			rdp_in_present(s, &present, order_flags, size);
1292 
1293 			if (order_flags & RDP_ORDER_BOUNDS)
1294 			{
1295 				if (!(order_flags & RDP_ORDER_LASTBOUNDS))
1296 					rdp_parse_bounds(s, &os->bounds);
1297 
1298 				ui_set_clip(This, os->bounds.left,
1299 					    os->bounds.top,
1300 					    os->bounds.right -
1301 					    os->bounds.left + 1,
1302 					    os->bounds.bottom - os->bounds.top + 1);
1303 			}
1304 
1305 			delta = order_flags & RDP_ORDER_DELTA;
1306 
1307 			switch (os->order_type)
1308 			{
1309 				case RDP_ORDER_DESTBLT:
1310 					process_destblt(This, s, &os->destblt, present, delta);
1311 					break;
1312 
1313 				case RDP_ORDER_PATBLT:
1314 					process_patblt(This, s, &os->patblt, present, delta);
1315 					break;
1316 
1317 				case RDP_ORDER_SCREENBLT:
1318 					process_screenblt(This, s, &os->screenblt, present, delta);
1319 					break;
1320 
1321 				case RDP_ORDER_LINE:
1322 					process_line(This, s, &os->line, present, delta);
1323 					break;
1324 
1325 				case RDP_ORDER_RECT:
1326 					process_rect(This, s, &os->rect, present, delta);
1327 					break;
1328 
1329 				case RDP_ORDER_DESKSAVE:
1330 					process_desksave(This, s, &os->desksave, present, delta);
1331 					break;
1332 
1333 				case RDP_ORDER_MEMBLT:
1334 					process_memblt(This, s, &os->memblt, present, delta);
1335 					break;
1336 
1337 				case RDP_ORDER_TRIBLT:
1338 					process_triblt(This, s, &os->triblt, present, delta);
1339 					break;
1340 
1341 				case RDP_ORDER_POLYGON:
1342 					process_polygon(This, s, &os->polygon, present, delta);
1343 					break;
1344 
1345 				case RDP_ORDER_POLYGON2:
1346 					process_polygon2(This, s, &os->polygon2, present, delta);
1347 					break;
1348 
1349 				case RDP_ORDER_POLYLINE:
1350 					process_polyline(This, s, &os->polyline, present, delta);
1351 					break;
1352 
1353 				case RDP_ORDER_ELLIPSE:
1354 					process_ellipse(This, s, &os->ellipse, present, delta);
1355 					break;
1356 
1357 				case RDP_ORDER_ELLIPSE2:
1358 					process_ellipse2(This, s, &os->ellipse2, present, delta);
1359 					break;
1360 
1361 				case RDP_ORDER_TEXT2:
1362 					process_text2(This, s, &os->text2, present, delta);
1363 					break;
1364 
1365 				default:
1366 					unimpl("order %d\n", os->order_type);
1367 					return;
1368 			}
1369 
1370 			if (order_flags & RDP_ORDER_BOUNDS)
1371 				ui_reset_clip(This);
1372 		}
1373 
1374 		processed++;
1375 	}
1376 #if 0
1377 	/* not true when RDP_COMPRESSION is set */
1378 	if (s->p != This->next_packet)
1379 		error("%d bytes remaining\n", (int) (This->next_packet - s->p));
1380 #endif
1381 
1382 }
1383 
1384 /* Reset order state */
1385 void
1386 reset_order_state(RDPCLIENT * This)
1387 {
1388 	memset(&This->orders.order_state, 0, sizeof(This->orders.order_state));
1389 	This->orders.order_state.order_type = RDP_ORDER_PATBLT;
1390 }
1391