FreeRDP
Loading...
Searching...
No Matches
orders.c
1
22#include <freerdp/config.h>
23
24#include "settings.h"
25
26#include <winpr/wtypes.h>
27#include <winpr/crt.h>
28#include <winpr/assert.h>
29#include <winpr/cast.h>
30
31#include <freerdp/api.h>
32#include <freerdp/log.h>
33#include <freerdp/graphics.h>
34#include <freerdp/codec/bitmap.h>
35#include <freerdp/gdi/gdi.h>
36
37#include "orders.h"
38#include "window.h"
39
40#include "../cache/glyph.h"
41#include "../cache/bitmap.h"
42#include "../cache/brush.h"
43#include "../cache/cache.h"
44
45#define TAG FREERDP_TAG("core.orders")
46
47/* Exposed type definitions in public headers have the wrong type.
48 * assert to the correct types internally to trigger the ci checkers on wrong data passed */
49#define get_checked_uint16(value) get_checked_uint16_int((value), __FILE__, __func__, __LINE__)
50static inline UINT16 get_checked_uint16_int(UINT32 value, WINPR_ATTR_UNUSED const char* file,
51 WINPR_ATTR_UNUSED const char* fkt,
52 WINPR_ATTR_UNUSED size_t line)
53{
54 WINPR_ASSERT_AT(value <= UINT16_MAX, file, fkt, line);
55 return (UINT16)value;
56}
57
58#define get_checked_uint8(value) get_checked_uint8_int((value), __FILE__, __func__, __LINE__)
59static inline UINT8 get_checked_uint8_int(UINT32 value, WINPR_ATTR_UNUSED const char* file,
60 WINPR_ATTR_UNUSED const char* fkt,
61 WINPR_ATTR_UNUSED size_t line)
62{
63 WINPR_ASSERT_AT(value <= UINT8_MAX, file, fkt, line);
64 return (UINT8)value;
65}
66
67#define get_checked_int16(value) get_checked_int16_int((value), __FILE__, __func__, __LINE__)
68static inline INT16 get_checked_int16_int(INT32 value, WINPR_ATTR_UNUSED const char* file,
69 WINPR_ATTR_UNUSED const char* fkt,
70 WINPR_ATTR_UNUSED size_t line)
71{
72 WINPR_ASSERT_AT(value <= INT16_MAX, file, fkt, line);
73 WINPR_ASSERT_AT(value >= INT16_MIN, file, fkt, line);
74 return (INT16)value;
75}
76
77#define check_val_fits_int16(value) check_val_fits_int16_int((value), __FILE__, __func__, __LINE__)
78static inline BOOL check_val_fits_int16_int(INT32 value, WINPR_ATTR_UNUSED const char* file,
79 WINPR_ATTR_UNUSED const char* fkt,
80 WINPR_ATTR_UNUSED size_t line)
81{
82 const DWORD level = WLOG_WARN;
83 static wLog* log = nullptr;
84 if (!log)
85 log = WLog_Get(TAG);
86
87 if (value < INT16_MIN)
88 {
89 if (WLog_IsLevelActive(log, level))
90 WLog_PrintTextMessage(log, level, line, file, fkt, "value %" PRId32 " < %d", INT16_MIN,
91 value);
92 return FALSE;
93 }
94
95 if (value > INT16_MAX)
96 {
97 if (WLog_IsLevelActive(log, level))
98 WLog_PrintTextMessage(log, level, line, file, fkt, "value %" PRId32 " > %d", INT16_MAX,
99 value);
100 return FALSE;
101 }
102
103 return TRUE;
104}
105
106#define gdi_rob3_code_string_checked(value) \
107 gdi_rob3_code_string_checked_int((value), __FILE__, __func__, __LINE__)
108static inline const char* gdi_rob3_code_string_checked_int(UINT32 rob,
109 WINPR_ATTR_UNUSED const char* file,
110 WINPR_ATTR_UNUSED const char* fkt,
111 WINPR_ATTR_UNUSED size_t line)
112{
113 WINPR_ASSERT_AT((rob) <= UINT8_MAX, file, fkt, line);
114 return gdi_rop3_code_string((BYTE)rob);
115}
116
117#define gdi_rop3_code_checked(value) \
118 gdi_rop3_code_checked_int((value), __FILE__, __func__, __LINE__)
119static inline DWORD gdi_rop3_code_checked_int(UINT32 code, WINPR_ATTR_UNUSED const char* file,
120 WINPR_ATTR_UNUSED const char* fkt,
121 WINPR_ATTR_UNUSED size_t line)
122{
123 WINPR_ASSERT_AT(code <= UINT8_MAX, file, fkt, line);
124 return gdi_rop3_code((UINT8)code);
125}
126
127static const char primary_order_str[] = "Primary Drawing Order";
128static const char secondary_order_str[] = "Secondary Drawing Order";
129static const char alt_sec_order_str[] = "Alternate Secondary Drawing Order";
130
131BYTE get_primary_drawing_order_field_bytes(UINT32 orderType, BOOL* pValid)
132{
133 if (pValid)
134 *pValid = TRUE;
135 switch (orderType)
136 {
137 case 0:
138 return DSTBLT_ORDER_FIELD_BYTES;
139 case 1:
140 return PATBLT_ORDER_FIELD_BYTES;
141 case 2:
142 return SCRBLT_ORDER_FIELD_BYTES;
143 case 3:
144 return 0;
145 case 4:
146 return 0;
147 case 5:
148 return 0;
149 case 6:
150 return 0;
151 case 7:
152 return DRAW_NINE_GRID_ORDER_FIELD_BYTES;
153 case 8:
154 return MULTI_DRAW_NINE_GRID_ORDER_FIELD_BYTES;
155 case 9:
156 return LINE_TO_ORDER_FIELD_BYTES;
157 case 10:
158 return OPAQUE_RECT_ORDER_FIELD_BYTES;
159 case 11:
160 return SAVE_BITMAP_ORDER_FIELD_BYTES;
161 case 12:
162 return 0;
163 case 13:
164 return MEMBLT_ORDER_FIELD_BYTES;
165 case 14:
166 return MEM3BLT_ORDER_FIELD_BYTES;
167 case 15:
168 return MULTI_DSTBLT_ORDER_FIELD_BYTES;
169 case 16:
170 return MULTI_PATBLT_ORDER_FIELD_BYTES;
171 case 17:
172 return MULTI_SCRBLT_ORDER_FIELD_BYTES;
173 case 18:
174 return MULTI_OPAQUE_RECT_ORDER_FIELD_BYTES;
175 case 19:
176 return FAST_INDEX_ORDER_FIELD_BYTES;
177 case 20:
178 return POLYGON_SC_ORDER_FIELD_BYTES;
179 case 21:
180 return POLYGON_CB_ORDER_FIELD_BYTES;
181 case 22:
182 return POLYLINE_ORDER_FIELD_BYTES;
183 case 23:
184 return 0;
185 case 24:
186 return FAST_GLYPH_ORDER_FIELD_BYTES;
187 case 25:
188 return ELLIPSE_SC_ORDER_FIELD_BYTES;
189 case 26:
190 return ELLIPSE_CB_ORDER_FIELD_BYTES;
191 case 27:
192 return GLYPH_INDEX_ORDER_FIELD_BYTES;
193 default:
194 if (pValid)
195 *pValid = FALSE;
196 WLog_WARN(TAG, "Invalid orderType 0x%08X received", orderType);
197 return 0;
198 }
199}
200
201static BYTE get_cbr2_bpp(UINT32 bpp, BOOL* pValid)
202{
203 if (pValid)
204 *pValid = TRUE;
205 switch (bpp)
206 {
207 case 3:
208 return 8;
209 case 4:
210 return 16;
211 case 5:
212 return 24;
213 case 6:
214 return 32;
215 default:
216 WLog_WARN(TAG, "Invalid bpp %" PRIu32, bpp);
217 if (pValid)
218 *pValid = FALSE;
219 return 0;
220 }
221}
222
223static BYTE get_bmf_bpp(UINT32 bmf, BOOL* pValid)
224{
225 if (pValid)
226 *pValid = TRUE;
227 /* Mask out highest bit */
228 switch (bmf & (uint32_t)(~CACHED_BRUSH))
229 {
230 case 1:
231 return 1;
232 case 3:
233 return 8;
234 case 4:
235 return 16;
236 case 5:
237 return 24;
238 case 6:
239 return 32;
240 default:
241 WLog_WARN(TAG, "Invalid bmf %" PRIu32, bmf);
242 if (pValid)
243 *pValid = FALSE;
244 return 0;
245 }
246}
247static BYTE get_bpp_bmf(UINT32 bpp, BOOL* pValid)
248{
249 if (pValid)
250 *pValid = TRUE;
251 switch (bpp)
252 {
253 case 1:
254 return 1;
255 case 8:
256 return 3;
257 case 16:
258 return 4;
259 case 24:
260 return 5;
261 case 32:
262 return 6;
263 default:
264 WLog_WARN(TAG, "Invalid color depth %" PRIu32, bpp);
265 if (pValid)
266 *pValid = FALSE;
267 return 0;
268 }
269}
270
271static BOOL check_order_activated(wLog* log, const rdpSettings* settings, const char* orderName,
272 BOOL condition, const char* extendedMessage)
273{
274 if (!condition)
275 {
276 if (settings->AllowUnanouncedOrdersFromServer)
277 {
278 WLog_Print(log, WLOG_WARN,
279 "%s - SERVER BUG: The support for this feature was not announced!",
280 orderName);
281 if (extendedMessage)
282 WLog_Print(log, WLOG_WARN, "%s", extendedMessage);
283 return TRUE;
284 }
285 else
286 {
287 WLog_Print(log, WLOG_ERROR,
288 "%s - SERVER BUG: The support for this feature was not announced! Use "
289 "/relax-order-checks to ignore",
290 orderName);
291 if (extendedMessage)
292 WLog_Print(log, WLOG_WARN, "%s", extendedMessage);
293 return FALSE;
294 }
295 }
296
297 return TRUE;
298}
299
300static BOOL check_alt_order_supported(wLog* log, rdpSettings* settings, BYTE orderType,
301 const char* orderName)
302{
303 const char* extendedMessage = nullptr;
304 BOOL condition = FALSE;
305
306 switch (orderType)
307 {
308 case ORDER_TYPE_CREATE_OFFSCREEN_BITMAP:
309 case ORDER_TYPE_SWITCH_SURFACE:
310 condition = settings->OffscreenSupportLevel != 0;
311 extendedMessage = "Adding /cache:offscreen might mitigate";
312 break;
313
314 case ORDER_TYPE_CREATE_NINE_GRID_BITMAP:
315 condition = settings->DrawNineGridEnabled;
316 break;
317
318 case ORDER_TYPE_FRAME_MARKER:
319 condition = settings->FrameMarkerCommandEnabled;
320 break;
321
322 case ORDER_TYPE_GDIPLUS_FIRST:
323 case ORDER_TYPE_GDIPLUS_NEXT:
324 case ORDER_TYPE_GDIPLUS_END:
325 case ORDER_TYPE_GDIPLUS_CACHE_FIRST:
326 case ORDER_TYPE_GDIPLUS_CACHE_NEXT:
327 case ORDER_TYPE_GDIPLUS_CACHE_END:
328 condition = settings->DrawGdiPlusCacheEnabled;
329 break;
330
331 case ORDER_TYPE_WINDOW:
332 condition = settings->RemoteWndSupportLevel != WINDOW_LEVEL_NOT_SUPPORTED;
333 break;
334
335 case ORDER_TYPE_STREAM_BITMAP_FIRST:
336 case ORDER_TYPE_STREAM_BITMAP_NEXT:
337 case ORDER_TYPE_COMPDESK_FIRST:
338 condition = TRUE;
339 break;
340
341 default:
342 WLog_Print(log, WLOG_WARN, "%s - %s UNKNOWN", orderName, alt_sec_order_str);
343 condition = FALSE;
344 break;
345 }
346
347 return check_order_activated(log, settings, orderName, condition, extendedMessage);
348}
349
350static BOOL check_secondary_order_supported(wLog* log, rdpSettings* settings, BYTE orderType,
351 const char* orderName)
352{
353 const char* extendedMessage = nullptr;
354 BOOL condition = FALSE;
355
356 switch (orderType)
357 {
358 case ORDER_TYPE_BITMAP_UNCOMPRESSED:
359 case ORDER_TYPE_CACHE_BITMAP_COMPRESSED:
360 condition = settings->BitmapCacheEnabled;
361 extendedMessage = "Adding /cache:bitmap might mitigate";
362 break;
363
364 case ORDER_TYPE_BITMAP_UNCOMPRESSED_V2:
365 case ORDER_TYPE_BITMAP_COMPRESSED_V2:
366 condition = settings->BitmapCacheEnabled;
367 extendedMessage = "Adding /cache:bitmap might mitigate";
368 break;
369
370 case ORDER_TYPE_BITMAP_COMPRESSED_V3:
371 condition = settings->BitmapCacheV3Enabled;
372 extendedMessage = "Adding /cache:bitmap might mitigate";
373 break;
374
375 case ORDER_TYPE_CACHE_COLOR_TABLE:
376 condition = (settings->OrderSupport[NEG_MEMBLT_INDEX] ||
377 settings->OrderSupport[NEG_MEM3BLT_INDEX]);
378 break;
379
380 case ORDER_TYPE_CACHE_GLYPH:
381 {
382 switch (settings->GlyphSupportLevel)
383 {
384 case GLYPH_SUPPORT_PARTIAL:
385 case GLYPH_SUPPORT_FULL:
386 case GLYPH_SUPPORT_ENCODE:
387 condition = TRUE;
388 break;
389
390 case GLYPH_SUPPORT_NONE:
391 default:
392 condition = FALSE;
393 break;
394 }
395 }
396 break;
397
398 case ORDER_TYPE_CACHE_BRUSH:
399 condition = TRUE;
400 break;
401
402 default:
403 WLog_Print(log, WLOG_WARN, "SECONDARY ORDER %s not supported", orderName);
404 break;
405 }
406
407 return check_order_activated(log, settings, orderName, condition, extendedMessage);
408}
409
410static BOOL check_primary_order_supported(wLog* log, const rdpSettings* settings, UINT32 orderType,
411 const char* orderName)
412{
413 const char* extendedMessage = nullptr;
414 BOOL condition = FALSE;
415
416 switch (orderType)
417 {
418 case ORDER_TYPE_DSTBLT:
419 condition = settings->OrderSupport[NEG_DSTBLT_INDEX];
420 break;
421
422 case ORDER_TYPE_SCRBLT:
423 condition = settings->OrderSupport[NEG_SCRBLT_INDEX];
424 break;
425
426 case ORDER_TYPE_DRAW_NINE_GRID:
427 condition = settings->OrderSupport[NEG_DRAWNINEGRID_INDEX];
428 break;
429
430 case ORDER_TYPE_MULTI_DRAW_NINE_GRID:
431 condition = settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX];
432 break;
433
434 case ORDER_TYPE_LINE_TO:
435 condition = settings->OrderSupport[NEG_LINETO_INDEX];
436 break;
437
438 /* [MS-RDPEGDI] 2.2.2.2.1.1.2.5 OpaqueRect (OPAQUERECT_ORDER)
439 * suggests that PatBlt and OpaqueRect imply each other. */
440 case ORDER_TYPE_PATBLT:
441 case ORDER_TYPE_OPAQUE_RECT:
442 condition = settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] ||
443 settings->OrderSupport[NEG_PATBLT_INDEX];
444 break;
445
446 case ORDER_TYPE_SAVE_BITMAP:
447 condition = settings->OrderSupport[NEG_SAVEBITMAP_INDEX];
448 break;
449
450 case ORDER_TYPE_MEMBLT:
451 condition = settings->OrderSupport[NEG_MEMBLT_INDEX];
452 break;
453
454 case ORDER_TYPE_MEM3BLT:
455 condition = settings->OrderSupport[NEG_MEM3BLT_INDEX];
456 break;
457
458 case ORDER_TYPE_MULTI_DSTBLT:
459 condition = settings->OrderSupport[NEG_MULTIDSTBLT_INDEX];
460 break;
461
462 case ORDER_TYPE_MULTI_PATBLT:
463 condition = settings->OrderSupport[NEG_MULTIPATBLT_INDEX];
464 break;
465
466 case ORDER_TYPE_MULTI_SCRBLT:
467 condition = settings->OrderSupport[NEG_MULTIDSTBLT_INDEX];
468 break;
469
470 case ORDER_TYPE_MULTI_OPAQUE_RECT:
471 condition = settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX];
472 break;
473
474 case ORDER_TYPE_FAST_INDEX:
475 condition = settings->OrderSupport[NEG_FAST_INDEX_INDEX];
476 break;
477
478 case ORDER_TYPE_POLYGON_SC:
479 condition = settings->OrderSupport[NEG_POLYGON_SC_INDEX];
480 break;
481
482 case ORDER_TYPE_POLYGON_CB:
483 condition = settings->OrderSupport[NEG_POLYGON_CB_INDEX];
484 break;
485
486 case ORDER_TYPE_POLYLINE:
487 condition = settings->OrderSupport[NEG_POLYLINE_INDEX];
488 break;
489
490 case ORDER_TYPE_FAST_GLYPH:
491 condition = settings->OrderSupport[NEG_FAST_GLYPH_INDEX];
492 break;
493
494 case ORDER_TYPE_ELLIPSE_SC:
495 condition = settings->OrderSupport[NEG_ELLIPSE_SC_INDEX];
496 break;
497
498 case ORDER_TYPE_ELLIPSE_CB:
499 condition = settings->OrderSupport[NEG_ELLIPSE_CB_INDEX];
500 break;
501
502 case ORDER_TYPE_GLYPH_INDEX:
503 condition = settings->OrderSupport[NEG_GLYPH_INDEX_INDEX];
504 break;
505
506 default:
507 WLog_Print(log, WLOG_ERROR, "%s %s not supported", orderName, primary_order_str);
508 break;
509 }
510
511 return check_order_activated(log, settings, orderName, condition, extendedMessage);
512}
513
514WINPR_PRAGMA_DIAG_PUSH
515WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL
516const char* primary_order_string(UINT32 orderType, char* buffer, size_t len)
517{
518 const char* orders[] = { "[0x%02" PRIx8 "] DstBlt",
519 "[0x%02" PRIx8 "] PatBlt",
520 "[0x%02" PRIx8 "] ScrBlt",
521 "[0x%02" PRIx8 "] UNUSED",
522 "[0x%02" PRIx8 "] UNUSED",
523 "[0x%02" PRIx8 "] UNUSED",
524 "[0x%02" PRIx8 "] UNUSED",
525 "[0x%02" PRIx8 "] DrawNineGrid",
526 "[0x%02" PRIx8 "] MultiDrawNineGrid",
527 "[0x%02" PRIx8 "] LineTo",
528 "[0x%02" PRIx8 "] OpaqueRect",
529 "[0x%02" PRIx8 "] SaveBitmap",
530 "[0x%02" PRIx8 "] UNUSED",
531 "[0x%02" PRIx8 "] MemBlt",
532 "[0x%02" PRIx8 "] Mem3Blt",
533 "[0x%02" PRIx8 "] MultiDstBlt",
534 "[0x%02" PRIx8 "] MultiPatBlt",
535 "[0x%02" PRIx8 "] MultiScrBlt",
536 "[0x%02" PRIx8 "] MultiOpaqueRect",
537 "[0x%02" PRIx8 "] FastIndex",
538 "[0x%02" PRIx8 "] PolygonSC",
539 "[0x%02" PRIx8 "] PolygonCB",
540 "[0x%02" PRIx8 "] Polyline",
541 "[0x%02" PRIx8 "] UNUSED",
542 "[0x%02" PRIx8 "] FastGlyph",
543 "[0x%02" PRIx8 "] EllipseSC",
544 "[0x%02" PRIx8 "] EllipseCB",
545 "[0x%02" PRIx8 "] GlyphIndex" };
546 const char* fmt = "[0x%02" PRIx8 "] UNKNOWN";
547
548 if (orderType < ARRAYSIZE(orders))
549 fmt = orders[orderType];
550
551 (void)sprintf_s(buffer, len, fmt, orderType);
552 return buffer;
553}
554
555const char* secondary_order_string(UINT32 orderType, char* buffer, size_t len)
556{
557 const char* orders[] = { "[0x%02" PRIx8 "] Cache Bitmap",
558 "[0x%02" PRIx8 "] Cache Color Table",
559 "[0x%02" PRIx8 "] Cache Bitmap (Compressed)",
560 "[0x%02" PRIx8 "] Cache Glyph",
561 "[0x%02" PRIx8 "] Cache Bitmap V2",
562 "[0x%02" PRIx8 "] Cache Bitmap V2 (Compressed)",
563 "[0x%02" PRIx8 "] UNUSED",
564 "[0x%02" PRIx8 "] Cache Brush",
565 "[0x%02" PRIx8 "] Cache Bitmap V3" };
566 const char* fmt = "[0x%02" PRIx8 "] UNKNOWN";
567
568 if (orderType < ARRAYSIZE(orders))
569 fmt = orders[orderType];
570
571 (void)sprintf_s(buffer, len, fmt, orderType);
572 return buffer;
573}
574
575const char* altsec_order_string(BYTE orderType, char* buffer, size_t len)
576{
577 const char* orders[] = {
578 "[0x%02" PRIx8 "] Switch Surface", "[0x%02" PRIx8 "] Create Offscreen Bitmap",
579 "[0x%02" PRIx8 "] Stream Bitmap First", "[0x%02" PRIx8 "] Stream Bitmap Next",
580 "[0x%02" PRIx8 "] Create NineGrid Bitmap", "[0x%02" PRIx8 "] Draw GDI+ First",
581 "[0x%02" PRIx8 "] Draw GDI+ Next", "[0x%02" PRIx8 "] Draw GDI+ End",
582 "[0x%02" PRIx8 "] Draw GDI+ Cache First", "[0x%02" PRIx8 "] Draw GDI+ Cache Next",
583 "[0x%02" PRIx8 "] Draw GDI+ Cache End", "[0x%02" PRIx8 "] Windowing",
584 "[0x%02" PRIx8 "] Desktop Composition", "[0x%02" PRIx8 "] Frame Marker"
585 };
586 const char* fmt = "[0x%02" PRIx8 "] UNKNOWN";
587
588 if (orderType < ARRAYSIZE(orders))
589 fmt = orders[orderType];
590
591 (void)sprintf_s(buffer, len, fmt, orderType);
592 return buffer;
593}
594WINPR_PRAGMA_DIAG_POP
595
596static inline BOOL update_read_coord(wStream* s, INT32* coord, BOOL delta)
597{
598 INT8 lsi8 = 0;
599 INT16 lsi16 = 0;
600
601 if (delta)
602 {
603 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
604 return FALSE;
605
606 Stream_Read_INT8(s, lsi8);
607
608 /* [MS-RDPEGDI] 2.2.2.2.1.1.1.1 Coord Field (COORD_FIELD) is a signed 16 bit value,
609 * do not let deltas accumulate beyond that range. */
610 const INT32 value = *coord + lsi8;
611 if ((value > INT16_MAX) || (value < INT16_MIN))
612 {
613 WLog_WARN(TAG,
614 "[MS-RDPEGDI] 2.2.2.2.1.1.1.1 Coord Field (COORD_FIELD): out of range delta "
615 "update: %d <= %d <= %d. Clamping to limits.",
616 INT16_MIN, value, INT16_MAX);
617 }
618
619 *coord = MIN(MAX(value, INT16_MIN), INT16_MAX);
620 }
621 else
622 {
623 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
624 return FALSE;
625
626 Stream_Read_INT16(s, lsi16);
627 *coord = lsi16;
628 }
629
630 return TRUE;
631}
632
633#define update_write_coord(s, coord) \
634 update_write_coord_int((s), (coord), #coord, __FILE__, __func__, __LINE__)
635
636static inline BOOL update_write_coord_int(wStream* s, INT32 coord, const char* name,
637 const char* file, const char* fkt, size_t line)
638{
639 if ((coord < 0) || (coord > UINT16_MAX))
640 {
641 const DWORD level = WLOG_WARN;
642 wLog* log = WLog_Get(TAG);
643 if (WLog_IsLevelActive(log, level))
644 {
645 WLog_PrintTextMessage(log, level, line, file, fkt, "[%s] 0 <= %" PRId32 " <= %d", name,
646 coord, UINT16_MAX);
647 }
648 return FALSE;
649 }
650
651 Stream_Write_UINT16(s, (UINT16)coord);
652 return TRUE;
653}
654static inline BOOL update_read_color(wStream* s, UINT32* color)
655{
656 BYTE byte = 0;
657
658 if (!Stream_CheckAndLogRequiredLength(TAG, s, 3))
659 return FALSE;
660
661 *color = 0;
662 Stream_Read_UINT8(s, byte);
663 *color = (UINT32)byte;
664 Stream_Read_UINT8(s, byte);
665 *color |= ((UINT32)byte << 8) & 0xFF00;
666 Stream_Read_UINT8(s, byte);
667 *color |= ((UINT32)byte << 16) & 0xFF0000;
668 return TRUE;
669}
670static inline BOOL update_write_color(wStream* s, UINT32 color)
671{
672 BYTE byte = 0;
673 byte = (color & 0xFF);
674 Stream_Write_UINT8(s, byte);
675 byte = ((color >> 8) & 0xFF);
676 Stream_Write_UINT8(s, byte);
677 byte = ((color >> 16) & 0xFF);
678 Stream_Write_UINT8(s, byte);
679 return TRUE;
680}
681static inline BOOL update_read_colorref(wStream* s, UINT32* color)
682{
683 BYTE byte = 0;
684
685 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
686 return FALSE;
687
688 *color = 0;
689 Stream_Read_UINT8(s, byte);
690 *color = byte;
691 Stream_Read_UINT8(s, byte);
692 *color |= ((UINT32)byte << 8);
693 Stream_Read_UINT8(s, byte);
694 *color |= ((UINT32)byte << 16);
695 Stream_Seek_UINT8(s);
696 return TRUE;
697}
698static inline BOOL update_read_color_quad(wStream* s, UINT32* color)
699{
700 return update_read_colorref(s, color);
701}
702static inline void update_write_color_quad(wStream* s, UINT32 color)
703{
704 BYTE byte = 0;
705 byte = (color >> 16) & 0xFF;
706 Stream_Write_UINT8(s, byte);
707 byte = (color >> 8) & 0xFF;
708 Stream_Write_UINT8(s, byte);
709 byte = color & 0xFF;
710 Stream_Write_UINT8(s, byte);
711}
712static inline BOOL update_read_2byte_unsigned(wStream* s, UINT32* value)
713{
714 BYTE byte = 0;
715
716 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
717 return FALSE;
718
719 Stream_Read_UINT8(s, byte);
720
721 if (byte & 0x80)
722 {
723 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
724 return FALSE;
725
726 *value = ((byte & 0x7F) << 8) & 0xFFFF;
727 Stream_Read_UINT8(s, byte);
728 *value |= byte;
729 }
730 else
731 {
732 *value = (byte & 0x7F);
733 }
734
735 return TRUE;
736}
737static inline BOOL update_write_2byte_unsigned(wStream* s, UINT32 value)
738{
739 BYTE byte = 0;
740
741 if (value > 0x7FFF)
742 return FALSE;
743
744 if (value >= 0x7F)
745 {
746 byte = ((value & 0x7F00) >> 8);
747 Stream_Write_UINT8(s, byte | 0x80);
748 byte = (value & 0xFF);
749 Stream_Write_UINT8(s, byte);
750 }
751 else
752 {
753 byte = (value & 0x7F);
754 Stream_Write_UINT8(s, byte);
755 }
756
757 return TRUE;
758}
759static inline BOOL update_read_2byte_signed(wStream* s, INT32* value)
760{
761 BYTE byte = 0;
762 BOOL negative = 0;
763
764 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
765 return FALSE;
766
767 Stream_Read_UINT8(s, byte);
768 negative = (byte & 0x40) != 0;
769 *value = (byte & 0x3F);
770
771 if (byte & 0x80)
772 {
773 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
774 return FALSE;
775
776 Stream_Read_UINT8(s, byte);
777 *value = (*value << 8) | byte;
778 }
779
780 if (negative)
781 *value *= -1;
782
783 return TRUE;
784}
785static inline BOOL update_write_2byte_signed(wStream* s, INT32 value)
786{
787 BYTE byte = 0;
788 BOOL negative = FALSE;
789
790 if (value < 0)
791 {
792 negative = TRUE;
793 value *= -1;
794 }
795
796 if (value > 0x3FFF)
797 return FALSE;
798
799 if (value >= 0x3F)
800 {
801 byte = ((value & 0x3F00) >> 8);
802
803 if (negative)
804 byte |= 0x40;
805
806 Stream_Write_UINT8(s, byte | 0x80);
807 byte = (value & 0xFF);
808 Stream_Write_UINT8(s, byte);
809 }
810 else
811 {
812 byte = (value & 0x3F);
813
814 if (negative)
815 byte |= 0x40;
816
817 Stream_Write_UINT8(s, byte);
818 }
819
820 return TRUE;
821}
822static inline BOOL update_read_4byte_unsigned(wStream* s, UINT32* value)
823{
824 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
825 return FALSE;
826
827 const UINT32 byte = Stream_Get_UINT8(s);
828 const BYTE count = WINPR_ASSERTING_INT_CAST(uint8_t, (byte & 0xC0) >> 6);
829
830 if (!Stream_CheckAndLogRequiredLength(TAG, s, count))
831 return FALSE;
832
833 switch (count)
834 {
835 case 0:
836 *value = (byte & 0x3F);
837 break;
838
839 case 1:
840 *value = ((byte & 0x3F) << 8) & 0xFFFF;
841 *value |= Stream_Get_UINT8(s);
842 break;
843
844 case 2:
845 *value = ((byte & 0x3F) << 16) & 0xFFFFFF;
846 *value |= ((Stream_Get_UINT8(s) << 8)) & 0xFFFF;
847 *value |= Stream_Get_UINT8(s);
848 break;
849
850 case 3:
851 *value = ((byte & 0x3F) << 24) & 0xFF000000;
852 *value |= ((Stream_Get_UINT8(s) << 16)) & 0xFF0000;
853 *value |= ((Stream_Get_UINT8(s) << 8)) & 0xFF00;
854 *value |= Stream_Get_UINT8(s);
855 break;
856
857 default:
858 break;
859 }
860
861 return TRUE;
862}
863static inline BOOL update_write_4byte_unsigned(wStream* s, UINT32 value)
864{
865 BYTE byte = 0;
866
867 if (value <= 0x3F)
868 {
869 Stream_Write_UINT8(s, (UINT8)value);
870 }
871 else if (value <= 0x3FFF)
872 {
873 byte = (value >> 8) & 0x3F;
874 Stream_Write_UINT8(s, byte | 0x40);
875 byte = (value & 0xFF);
876 Stream_Write_UINT8(s, byte);
877 }
878 else if (value <= 0x3FFFFF)
879 {
880 byte = (value >> 16) & 0x3F;
881 Stream_Write_UINT8(s, byte | 0x80);
882 byte = (value >> 8) & 0xFF;
883 Stream_Write_UINT8(s, byte);
884 byte = (value & 0xFF);
885 Stream_Write_UINT8(s, byte);
886 }
887 else if (value <= 0x3FFFFFFF)
888 {
889 byte = (value >> 24) & 0x3F;
890 Stream_Write_UINT8(s, byte | 0xC0);
891 byte = (value >> 16) & 0xFF;
892 Stream_Write_UINT8(s, byte);
893 byte = (value >> 8) & 0xFF;
894 Stream_Write_UINT8(s, byte);
895 byte = (value & 0xFF);
896 Stream_Write_UINT8(s, byte);
897 }
898 else
899 return FALSE;
900
901 return TRUE;
902}
903
904static inline BOOL update_read_delta(wStream* s, INT32* value)
905{
906 BYTE byte = 0;
907 UINT32 uvalue = 0;
908
909 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
910 return FALSE;
911
912 Stream_Read_UINT8(s, byte);
913
914 if (byte & 0x40)
915 uvalue = WINPR_CXX_COMPAT_CAST(UINT32, (byte | ~0x3F));
916 else
917 uvalue = (byte & 0x3F);
918
919 if (byte & 0x80)
920 {
921 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
922 return FALSE;
923
924 Stream_Read_UINT8(s, byte);
925 uvalue = (uvalue << 8) | byte;
926 }
927 *value = (INT32)uvalue;
928
929 return TRUE;
930}
931
932static inline BOOL update_read_brush(wStream* s, rdpBrush* brush, BYTE fieldFlags)
933{
934 if (fieldFlags & ORDER_FIELD_01)
935 {
936 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
937 return FALSE;
938
939 Stream_Read_UINT8(s, brush->x);
940 }
941
942 if (fieldFlags & ORDER_FIELD_02)
943 {
944 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
945 return FALSE;
946
947 Stream_Read_UINT8(s, brush->y);
948 }
949
950 if (fieldFlags & ORDER_FIELD_03)
951 {
952 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
953 return FALSE;
954
955 Stream_Read_UINT8(s, brush->style);
956 }
957
958 if (fieldFlags & ORDER_FIELD_04)
959 {
960 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
961 return FALSE;
962
963 Stream_Read_UINT8(s, brush->hatch);
964 }
965
966 if (brush->style & CACHED_BRUSH)
967 {
968 BOOL rc = 0;
969 brush->index = brush->hatch;
970 brush->bpp = get_bmf_bpp(brush->style, &rc);
971 if (!rc)
972 return FALSE;
973 if (brush->bpp == 0)
974 brush->bpp = 1;
975 }
976
977 if (fieldFlags & ORDER_FIELD_05)
978 {
979 if (!Stream_CheckAndLogRequiredLength(TAG, s, 7))
980 return FALSE;
981
982 brush->data = (BYTE*)brush->p8x8;
983 Stream_Read_UINT8(s, brush->data[7]);
984 Stream_Read_UINT8(s, brush->data[6]);
985 Stream_Read_UINT8(s, brush->data[5]);
986 Stream_Read_UINT8(s, brush->data[4]);
987 Stream_Read_UINT8(s, brush->data[3]);
988 Stream_Read_UINT8(s, brush->data[2]);
989 Stream_Read_UINT8(s, brush->data[1]);
990 brush->data[0] = get_checked_uint8(brush->hatch);
991 }
992
993 return TRUE;
994}
995static inline BOOL update_write_brush(wStream* s, rdpBrush* brush, BYTE fieldFlags)
996{
997 if (fieldFlags & ORDER_FIELD_01)
998 {
999 if (!Stream_EnsureRemainingCapacity(s, 1))
1000 return FALSE;
1001 Stream_Write_UINT8(s, get_checked_uint8(brush->x));
1002 }
1003
1004 if (fieldFlags & ORDER_FIELD_02)
1005 {
1006 if (!Stream_EnsureRemainingCapacity(s, 1))
1007 return FALSE;
1008 Stream_Write_UINT8(s, get_checked_uint8(brush->y));
1009 }
1010
1011 if (fieldFlags & ORDER_FIELD_03)
1012 {
1013 if (!Stream_EnsureRemainingCapacity(s, 1))
1014 return FALSE;
1015 Stream_Write_UINT8(s, get_checked_uint8(brush->style));
1016 }
1017
1018 if (brush->style & CACHED_BRUSH)
1019 {
1020 BOOL rc = 0;
1021 brush->hatch = brush->index;
1022 brush->bpp = get_bmf_bpp(brush->style, &rc);
1023 if (!rc)
1024 return FALSE;
1025 if (brush->bpp == 0)
1026 brush->bpp = 1;
1027 }
1028
1029 if (fieldFlags & ORDER_FIELD_04)
1030 {
1031 if (!Stream_EnsureRemainingCapacity(s, 1))
1032 return FALSE;
1033 Stream_Write_UINT8(s, get_checked_uint8(brush->hatch));
1034 }
1035
1036 if (fieldFlags & ORDER_FIELD_05)
1037 {
1038 brush->data = (BYTE*)brush->p8x8;
1039 if (!Stream_EnsureRemainingCapacity(s, 7))
1040 return FALSE;
1041 Stream_Write_UINT8(s, brush->data[7]);
1042 Stream_Write_UINT8(s, brush->data[6]);
1043 Stream_Write_UINT8(s, brush->data[5]);
1044 Stream_Write_UINT8(s, brush->data[4]);
1045 Stream_Write_UINT8(s, brush->data[3]);
1046 Stream_Write_UINT8(s, brush->data[2]);
1047 Stream_Write_UINT8(s, brush->data[1]);
1048 brush->data[0] = get_checked_uint8(brush->hatch);
1049 }
1050
1051 return TRUE;
1052}
1053static inline BOOL update_read_delta_rects(wStream* s, DELTA_RECT* rectangles, const UINT32* nr)
1054{
1055 UINT32 number = *nr;
1056 BYTE flags = 0;
1057 UINT32 zeroBitsSize = 0;
1058
1059 if (number > 45)
1060 {
1061 WLog_WARN(TAG, "Invalid number of delta rectangles %" PRIu32, number);
1062 return FALSE;
1063 }
1064
1065 zeroBitsSize = ((number + 1) / 2);
1066
1067 if (!Stream_CheckAndLogRequiredLength(TAG, s, zeroBitsSize))
1068 return FALSE;
1069
1070 BYTE* zeroBits = Stream_PointerAs(s, BYTE);
1071 Stream_Seek(s, zeroBitsSize);
1072 ZeroMemory(rectangles, sizeof(DELTA_RECT) * number);
1073
1074 for (UINT32 i = 0; i < number; i++)
1075 {
1076 if (i % 2 == 0)
1077 flags = zeroBits[i / 2];
1078
1079 if ((~flags & 0x80) && !update_read_delta(s, &rectangles[i].left))
1080 return FALSE;
1081
1082 if ((~flags & 0x40) && !update_read_delta(s, &rectangles[i].top))
1083 return FALSE;
1084
1085 if (~flags & 0x20)
1086 {
1087 if (!update_read_delta(s, &rectangles[i].width))
1088 return FALSE;
1089 }
1090 else if (i > 0)
1091 rectangles[i].width = rectangles[i - 1].width;
1092 else
1093 rectangles[i].width = 0;
1094
1095 if (~flags & 0x10)
1096 {
1097 if (!update_read_delta(s, &rectangles[i].height))
1098 return FALSE;
1099 }
1100 else if (i > 0)
1101 rectangles[i].height = rectangles[i - 1].height;
1102 else
1103 rectangles[i].height = 0;
1104
1105 if (i > 0)
1106 {
1107 rectangles[i].left += rectangles[i - 1].left;
1108 rectangles[i].top += rectangles[i - 1].top;
1109 }
1110
1111 flags <<= 4;
1112 }
1113
1114 return TRUE;
1115}
1116
1117static inline BOOL update_read_delta_points(wStream* s, DELTA_POINT** points, UINT32 number,
1118 WINPR_ATTR_UNUSED INT16 x, WINPR_ATTR_UNUSED INT16 y)
1119{
1120 BYTE flags = 0;
1121 UINT32 zeroBitsSize = ((number + 3) / 4);
1122
1123 if (SIZE_MAX / number <= sizeof(DELTA_POINT))
1124 return FALSE;
1125
1126 WINPR_ASSERT(points);
1127 DELTA_POINT* newpoints = (DELTA_POINT*)realloc(*points, sizeof(DELTA_POINT) * number);
1128
1129 if (!newpoints)
1130 return FALSE;
1131 *points = newpoints;
1132
1133 if (!Stream_CheckAndLogRequiredLength(TAG, s, zeroBitsSize))
1134 return FALSE;
1135
1136 BYTE* zeroBits = Stream_PointerAs(s, BYTE);
1137 Stream_Seek(s, zeroBitsSize);
1138 ZeroMemory(*points, sizeof(DELTA_POINT) * number);
1139
1140 for (UINT32 i = 0; i < number; i++)
1141 {
1142 if (i % 4 == 0)
1143 flags = zeroBits[i / 4];
1144
1145 if ((~flags & 0x80) && !update_read_delta(s, &newpoints[i].x))
1146 {
1147 WLog_ERR(TAG, "update_read_delta(x) failed");
1148 return FALSE;
1149 }
1150
1151 if ((~flags & 0x40) && !update_read_delta(s, &newpoints[i].y))
1152 {
1153 WLog_ERR(TAG, "update_read_delta(y) failed");
1154 return FALSE;
1155 }
1156
1157 flags <<= 2;
1158 }
1159
1160 return TRUE;
1161}
1162
1163static BOOL order_field_flag_is_set(const ORDER_INFO* orderInfo, BYTE number)
1164{
1165 const UINT32 mask = (UINT32)(1UL << ((UINT32)number - 1UL));
1166 const BOOL set = (orderInfo->fieldFlags & mask) != 0;
1167 return set;
1168}
1169
1170static inline BOOL read_order_field_byte(const char* orderName, const ORDER_INFO* orderInfo,
1171 wStream* s, BYTE number, UINT32* target, BOOL optional)
1172{
1173 WINPR_ASSERT(orderName);
1174 WINPR_ASSERT(orderInfo);
1175 WINPR_ASSERT(target);
1176
1177 if (!order_field_flag_is_set(orderInfo, number))
1178 {
1179 WLog_DBG(TAG, "order %s field %" PRIu8 " not found [optional:%d]", orderName, number,
1180 optional);
1181 return TRUE;
1182 }
1183 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1184 return FALSE;
1185 Stream_Read_UINT8(s, *target);
1186 return TRUE;
1187}
1188
1189static inline BOOL read_order_field_2bytes(const char* orderName, const ORDER_INFO* orderInfo,
1190 wStream* s, BYTE number, UINT32* target1,
1191 UINT32* target2, BOOL optional)
1192{
1193 WINPR_ASSERT(orderName);
1194 WINPR_ASSERT(orderInfo);
1195 WINPR_ASSERT(target1);
1196 WINPR_ASSERT(target2);
1197
1198 if (!order_field_flag_is_set(orderInfo, number))
1199 {
1200 WLog_DBG(TAG, "order %s field %" PRIu8 " not found [optional:%d]", orderName, number,
1201 optional);
1202 return TRUE;
1203 }
1204 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1205 return FALSE;
1206 Stream_Read_UINT8(s, *target1);
1207 Stream_Read_UINT8(s, *target2);
1208 return TRUE;
1209}
1210
1211static inline BOOL read_order_field_uint16(const char* orderName, const ORDER_INFO* orderInfo,
1212 wStream* s, BYTE number, UINT32* target, BOOL optional)
1213{
1214 WINPR_ASSERT(orderName);
1215 WINPR_ASSERT(orderInfo);
1216 WINPR_ASSERT(target);
1217
1218 if (!order_field_flag_is_set(orderInfo, number))
1219 {
1220 WLog_DBG(TAG, "order %s field %" PRIu8 " not found [optional:%d]", orderName, number,
1221 optional);
1222 return TRUE;
1223 }
1224
1225 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1226 return FALSE;
1227
1228 Stream_Read_UINT16(s, *target);
1229 return TRUE;
1230}
1231
1232static inline BOOL read_order_field_int16(const char* orderName, const ORDER_INFO* orderInfo,
1233 wStream* s, BYTE number, INT32* target, BOOL optional)
1234{
1235 WINPR_ASSERT(orderName);
1236 WINPR_ASSERT(orderInfo);
1237 WINPR_ASSERT(target);
1238
1239 if (!order_field_flag_is_set(orderInfo, number))
1240 {
1241 WLog_DBG(TAG, "order %s field %" PRIu8 " not found [optional:%d]", orderName, number,
1242 optional);
1243 return TRUE;
1244 }
1245
1246 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1247 return FALSE;
1248
1249 Stream_Read_INT16(s, *target);
1250 return TRUE;
1251}
1252
1253static inline BOOL read_order_field_uint32(const char* orderName, const ORDER_INFO* orderInfo,
1254 wStream* s, BYTE number, UINT32* target, BOOL optional)
1255{
1256 WINPR_ASSERT(orderName);
1257 WINPR_ASSERT(orderInfo);
1258 WINPR_ASSERT(target);
1259
1260 if (!order_field_flag_is_set(orderInfo, number))
1261 {
1262 WLog_DBG(TAG, "order %s field %" PRIu8 " not found [optional:%d]", orderName, number,
1263 optional);
1264 return TRUE;
1265 }
1266
1267 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1268 return FALSE;
1269
1270 Stream_Read_UINT32(s, *target);
1271 return TRUE;
1272}
1273
1274static inline BOOL read_order_field_coord(const char* orderName, const ORDER_INFO* orderInfo,
1275 wStream* s, UINT32 NO, INT32* TARGET, BOOL optional)
1276{
1277 WINPR_ASSERT(orderName);
1278 WINPR_ASSERT(orderInfo);
1279 WINPR_ASSERT(TARGET);
1280
1281 if (!order_field_flag_is_set(orderInfo, get_checked_uint8(NO)))
1282 {
1283 WLog_DBG(TAG, "order %s field %" PRIu8 " not found [optional:%d]", orderName,
1284 get_checked_uint8(NO), optional);
1285 return TRUE;
1286 }
1287
1288 return update_read_coord(s, TARGET, orderInfo->deltaCoordinates);
1289}
1290
1291static inline BOOL read_order_field_color(const char* orderName, const ORDER_INFO* orderInfo,
1292 wStream* s, UINT32 NO, UINT32* TARGET, BOOL optional)
1293{
1294 WINPR_ASSERT(orderName);
1295 WINPR_ASSERT(orderInfo);
1296 WINPR_ASSERT(TARGET);
1297
1298 if (!order_field_flag_is_set(orderInfo, get_checked_uint8(NO)))
1299 {
1300 WLog_DBG(TAG, "order %s field %" PRIu8 " not found [optional:%d]", orderName,
1301 get_checked_uint8(NO), optional);
1302 return TRUE;
1303 }
1304
1305 if (!update_read_color(s, TARGET))
1306 return FALSE;
1307
1308 return TRUE;
1309}
1310static inline BOOL FIELD_SKIP_BUFFER16(wStream* s, UINT32 TARGET_LEN)
1311{
1312 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1313 return FALSE;
1314
1315 Stream_Read_UINT16(s, TARGET_LEN);
1316
1317 if (!Stream_SafeSeek(s, TARGET_LEN))
1318 {
1319 WLog_ERR(TAG, "error skipping %" PRIu32 " bytes", TARGET_LEN);
1320 return FALSE;
1321 }
1322
1323 return TRUE;
1324}
1325/* Primary Drawing Orders */
1326static BOOL update_read_dstblt_order(const char* orderName, wStream* s, const ORDER_INFO* orderInfo,
1327 DSTBLT_ORDER* dstblt)
1328{
1329 return (read_order_field_coord(orderName, orderInfo, s, 1, &dstblt->nLeftRect, FALSE) &&
1330 read_order_field_coord(orderName, orderInfo, s, 2, &dstblt->nTopRect, FALSE) &&
1331 read_order_field_coord(orderName, orderInfo, s, 3, &dstblt->nWidth, FALSE) &&
1332 read_order_field_coord(orderName, orderInfo, s, 4, &dstblt->nHeight, FALSE) &&
1333 read_order_field_byte(orderName, orderInfo, s, 5, &dstblt->bRop, TRUE));
1334}
1335
1336size_t update_approximate_dstblt_order(ORDER_INFO* orderInfo, const DSTBLT_ORDER* dstblt)
1337{
1338 WINPR_UNUSED(orderInfo);
1339 WINPR_UNUSED(dstblt);
1340 return 32;
1341}
1342
1343BOOL update_write_dstblt_order(wStream* s, ORDER_INFO* orderInfo, const DSTBLT_ORDER* dstblt)
1344{
1345 if (!Stream_EnsureRemainingCapacity(s, update_approximate_dstblt_order(orderInfo, dstblt)))
1346 return FALSE;
1347
1348 orderInfo->fieldFlags = 0;
1349 orderInfo->fieldFlags |= ORDER_FIELD_01;
1350 if (!update_write_coord(s, dstblt->nLeftRect))
1351 return FALSE;
1352 orderInfo->fieldFlags |= ORDER_FIELD_02;
1353 if (!update_write_coord(s, dstblt->nTopRect))
1354 return FALSE;
1355 orderInfo->fieldFlags |= ORDER_FIELD_03;
1356 if (!update_write_coord(s, dstblt->nWidth))
1357 return FALSE;
1358 orderInfo->fieldFlags |= ORDER_FIELD_04;
1359 if (!update_write_coord(s, dstblt->nHeight))
1360 return FALSE;
1361 orderInfo->fieldFlags |= ORDER_FIELD_05;
1362 Stream_Write_UINT8(s, get_checked_uint8(dstblt->bRop));
1363 return TRUE;
1364}
1365
1366static BOOL update_read_patblt_order(const char* orderName, wStream* s, const ORDER_INFO* orderInfo,
1367 PATBLT_ORDER* patblt)
1368{
1369 return (read_order_field_coord(orderName, orderInfo, s, 1, &patblt->nLeftRect, FALSE) &&
1370 read_order_field_coord(orderName, orderInfo, s, 2, &patblt->nTopRect, FALSE) &&
1371 read_order_field_coord(orderName, orderInfo, s, 3, &patblt->nWidth, FALSE) &&
1372 read_order_field_coord(orderName, orderInfo, s, 4, &patblt->nHeight, FALSE) &&
1373 read_order_field_byte(orderName, orderInfo, s, 5, &patblt->bRop, TRUE) &&
1374 read_order_field_color(orderName, orderInfo, s, 6, &patblt->backColor, TRUE) &&
1375 read_order_field_color(orderName, orderInfo, s, 7, &patblt->foreColor, TRUE) &&
1376 update_read_brush(s, &patblt->brush,
1377 get_checked_uint8((orderInfo->fieldFlags >> 7) & 0x1F)));
1378}
1379
1380size_t update_approximate_patblt_order(ORDER_INFO* orderInfo, PATBLT_ORDER* patblt)
1381{
1382 WINPR_UNUSED(orderInfo);
1383 WINPR_UNUSED(patblt);
1384 return 32;
1385}
1386
1387BOOL update_write_patblt_order(wStream* s, ORDER_INFO* orderInfo, PATBLT_ORDER* patblt)
1388{
1389 if (!Stream_EnsureRemainingCapacity(s, update_approximate_patblt_order(orderInfo, patblt)))
1390 return FALSE;
1391
1392 orderInfo->fieldFlags = 0;
1393 orderInfo->fieldFlags |= ORDER_FIELD_01;
1394 if (!update_write_coord(s, patblt->nLeftRect))
1395 return FALSE;
1396 orderInfo->fieldFlags |= ORDER_FIELD_02;
1397 if (!update_write_coord(s, patblt->nTopRect))
1398 return FALSE;
1399 orderInfo->fieldFlags |= ORDER_FIELD_03;
1400 if (!update_write_coord(s, patblt->nWidth))
1401 return FALSE;
1402 orderInfo->fieldFlags |= ORDER_FIELD_04;
1403 if (!update_write_coord(s, patblt->nHeight))
1404 return FALSE;
1405 orderInfo->fieldFlags |= ORDER_FIELD_05;
1406 Stream_Write_UINT8(s, get_checked_uint8(patblt->bRop));
1407 orderInfo->fieldFlags |= ORDER_FIELD_06;
1408 update_write_color(s, patblt->backColor);
1409 orderInfo->fieldFlags |= ORDER_FIELD_07;
1410 update_write_color(s, patblt->foreColor);
1411 orderInfo->fieldFlags |= ORDER_FIELD_08;
1412 orderInfo->fieldFlags |= ORDER_FIELD_09;
1413 orderInfo->fieldFlags |= ORDER_FIELD_10;
1414 orderInfo->fieldFlags |= ORDER_FIELD_11;
1415 orderInfo->fieldFlags |= ORDER_FIELD_12;
1416 update_write_brush(s, &patblt->brush, get_checked_uint8((orderInfo->fieldFlags >> 7) & 0x1F));
1417 return TRUE;
1418}
1419
1420static BOOL update_read_scrblt_order(const char* orderName, wStream* s, const ORDER_INFO* orderInfo,
1421 SCRBLT_ORDER* scrblt)
1422{
1423 WINPR_ASSERT(orderInfo);
1424 WINPR_ASSERT(scrblt);
1425 return (read_order_field_coord(orderName, orderInfo, s, 1, &scrblt->nLeftRect, FALSE) &&
1426 read_order_field_coord(orderName, orderInfo, s, 2, &scrblt->nTopRect, FALSE) &&
1427 read_order_field_coord(orderName, orderInfo, s, 3, &scrblt->nWidth, FALSE) &&
1428 read_order_field_coord(orderName, orderInfo, s, 4, &scrblt->nHeight, FALSE) &&
1429 read_order_field_byte(orderName, orderInfo, s, 5, &scrblt->bRop, TRUE) &&
1430 read_order_field_coord(orderName, orderInfo, s, 6, &scrblt->nXSrc, FALSE) &&
1431 read_order_field_coord(orderName, orderInfo, s, 7, &scrblt->nYSrc, FALSE));
1432}
1433
1434size_t update_approximate_scrblt_order(ORDER_INFO* orderInfo, const SCRBLT_ORDER* scrblt)
1435{
1436 WINPR_ASSERT(orderInfo);
1437 WINPR_ASSERT(scrblt);
1438 WINPR_UNUSED(orderInfo);
1439 WINPR_UNUSED(scrblt);
1440 return 32;
1441}
1442
1443BOOL update_write_scrblt_order(wStream* s, ORDER_INFO* orderInfo, const SCRBLT_ORDER* scrblt)
1444{
1445 WINPR_ASSERT(orderInfo);
1446 WINPR_ASSERT(scrblt);
1447 if (!Stream_EnsureRemainingCapacity(s, update_approximate_scrblt_order(orderInfo, scrblt)))
1448 return FALSE;
1449
1450 orderInfo->fieldFlags = 0;
1451 orderInfo->fieldFlags |= ORDER_FIELD_01;
1452 if (!update_write_coord(s, scrblt->nLeftRect))
1453 return FALSE;
1454 orderInfo->fieldFlags |= ORDER_FIELD_02;
1455 if (!update_write_coord(s, scrblt->nTopRect))
1456 return FALSE;
1457 orderInfo->fieldFlags |= ORDER_FIELD_03;
1458 if (!update_write_coord(s, scrblt->nWidth))
1459 return FALSE;
1460 orderInfo->fieldFlags |= ORDER_FIELD_04;
1461 if (!update_write_coord(s, scrblt->nHeight))
1462 return FALSE;
1463 orderInfo->fieldFlags |= ORDER_FIELD_05;
1464 WINPR_ASSERT(scrblt->bRop <= UINT8_MAX);
1465 Stream_Write_UINT8(s, (UINT8)scrblt->bRop);
1466 orderInfo->fieldFlags |= ORDER_FIELD_06;
1467 if (!update_write_coord(s, scrblt->nXSrc))
1468 return FALSE;
1469 orderInfo->fieldFlags |= ORDER_FIELD_07;
1470 return (update_write_coord(s, scrblt->nYSrc));
1471}
1472static BOOL update_read_opaque_rect_order(const char* orderName, wStream* s,
1473 const ORDER_INFO* orderInfo,
1474 OPAQUE_RECT_ORDER* opaque_rect)
1475{
1476 BYTE byte = 0;
1477 if (!read_order_field_coord(orderName, orderInfo, s, 1, &opaque_rect->nLeftRect, FALSE) ||
1478 !read_order_field_coord(orderName, orderInfo, s, 2, &opaque_rect->nTopRect, FALSE) ||
1479 !read_order_field_coord(orderName, orderInfo, s, 3, &opaque_rect->nWidth, FALSE) ||
1480 !read_order_field_coord(orderName, orderInfo, s, 4, &opaque_rect->nHeight, FALSE))
1481 return FALSE;
1482
1483 if ((orderInfo->fieldFlags & ORDER_FIELD_05) != 0)
1484 {
1485 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1486 return FALSE;
1487
1488 Stream_Read_UINT8(s, byte);
1489 opaque_rect->color = (opaque_rect->color & 0x00FFFF00) | ((UINT32)byte);
1490 }
1491
1492 if ((orderInfo->fieldFlags & ORDER_FIELD_06) != 0)
1493 {
1494 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1495 return FALSE;
1496
1497 Stream_Read_UINT8(s, byte);
1498 opaque_rect->color = (opaque_rect->color & 0x00FF00FF) | ((UINT32)byte << 8);
1499 }
1500
1501 if ((orderInfo->fieldFlags & ORDER_FIELD_07) != 0)
1502 {
1503 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1504 return FALSE;
1505
1506 Stream_Read_UINT8(s, byte);
1507 opaque_rect->color = (opaque_rect->color & 0x0000FFFF) | ((UINT32)byte << 16);
1508 }
1509
1510 return TRUE;
1511}
1512
1513size_t update_approximate_opaque_rect_order(ORDER_INFO* orderInfo,
1514 const OPAQUE_RECT_ORDER* opaque_rect)
1515{
1516 WINPR_UNUSED(orderInfo);
1517 WINPR_UNUSED(opaque_rect);
1518 return 32;
1519}
1520
1521BOOL update_write_opaque_rect_order(wStream* s, ORDER_INFO* orderInfo,
1522 const OPAQUE_RECT_ORDER* opaque_rect)
1523{
1524 BYTE byte = 0;
1525 size_t inf = update_approximate_opaque_rect_order(orderInfo, opaque_rect);
1526
1527 if (!Stream_EnsureRemainingCapacity(s, inf))
1528 return FALSE;
1529
1530 // TODO: Color format conversion
1531 orderInfo->fieldFlags = 0;
1532 orderInfo->fieldFlags |= ORDER_FIELD_01;
1533 if (!update_write_coord(s, opaque_rect->nLeftRect))
1534 return FALSE;
1535 orderInfo->fieldFlags |= ORDER_FIELD_02;
1536 if (!update_write_coord(s, opaque_rect->nTopRect))
1537 return FALSE;
1538 orderInfo->fieldFlags |= ORDER_FIELD_03;
1539 if (!update_write_coord(s, opaque_rect->nWidth))
1540 return FALSE;
1541 orderInfo->fieldFlags |= ORDER_FIELD_04;
1542 if (!update_write_coord(s, opaque_rect->nHeight))
1543 return FALSE;
1544 orderInfo->fieldFlags |= ORDER_FIELD_05;
1545 byte = opaque_rect->color & 0x000000FF;
1546 Stream_Write_UINT8(s, byte);
1547 orderInfo->fieldFlags |= ORDER_FIELD_06;
1548 byte = (opaque_rect->color & 0x0000FF00) >> 8;
1549 Stream_Write_UINT8(s, byte);
1550 orderInfo->fieldFlags |= ORDER_FIELD_07;
1551 byte = (opaque_rect->color & 0x00FF0000) >> 16;
1552 Stream_Write_UINT8(s, byte);
1553 return TRUE;
1554}
1555
1556static BOOL update_read_draw_nine_grid_order(const char* orderName, wStream* s,
1557 const ORDER_INFO* orderInfo,
1558 DRAW_NINE_GRID_ORDER* draw_nine_grid)
1559{
1560 return (read_order_field_coord(orderName, orderInfo, s, 1, &draw_nine_grid->srcLeft, FALSE) &&
1561 read_order_field_coord(orderName, orderInfo, s, 2, &draw_nine_grid->srcTop, FALSE) &&
1562 read_order_field_coord(orderName, orderInfo, s, 3, &draw_nine_grid->srcRight, FALSE) &&
1563 read_order_field_coord(orderName, orderInfo, s, 4, &draw_nine_grid->srcBottom, FALSE) &&
1564 read_order_field_uint16(orderName, orderInfo, s, 5, &draw_nine_grid->bitmapId, FALSE));
1565}
1566
1567static BOOL update_read_multi_dstblt_order(const char* orderName, wStream* s,
1568 const ORDER_INFO* orderInfo,
1569 MULTI_DSTBLT_ORDER* multi_dstblt)
1570{
1571 UINT32 numRectangles = multi_dstblt->numRectangles;
1572 if (!read_order_field_coord(orderName, orderInfo, s, 1, &multi_dstblt->nLeftRect, FALSE) ||
1573 !read_order_field_coord(orderName, orderInfo, s, 2, &multi_dstblt->nTopRect, FALSE) ||
1574 !read_order_field_coord(orderName, orderInfo, s, 3, &multi_dstblt->nWidth, FALSE) ||
1575 !read_order_field_coord(orderName, orderInfo, s, 4, &multi_dstblt->nHeight, FALSE) ||
1576 !read_order_field_byte(orderName, orderInfo, s, 5, &multi_dstblt->bRop, TRUE) ||
1577 !read_order_field_byte(orderName, orderInfo, s, 6, &numRectangles, TRUE))
1578 return FALSE;
1579
1580 if ((orderInfo->fieldFlags & ORDER_FIELD_07) != 0)
1581 {
1582 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1583 return FALSE;
1584
1585 multi_dstblt->numRectangles = numRectangles;
1586 Stream_Read_UINT16(s, multi_dstblt->cbData);
1587 return update_read_delta_rects(s, multi_dstblt->rectangles, &multi_dstblt->numRectangles);
1588 }
1589 if (numRectangles > multi_dstblt->numRectangles)
1590 {
1591 WLog_ERR(TAG, "%s numRectangles %" PRIu32 " > %" PRIu32, orderName, numRectangles,
1592 multi_dstblt->numRectangles);
1593 return FALSE;
1594 }
1595 multi_dstblt->numRectangles = numRectangles;
1596 return TRUE;
1597}
1598
1599static BOOL update_read_multi_patblt_order(const char* orderName, wStream* s,
1600 const ORDER_INFO* orderInfo,
1601 MULTI_PATBLT_ORDER* multi_patblt)
1602{
1603 if (!read_order_field_coord(orderName, orderInfo, s, 1, &multi_patblt->nLeftRect, FALSE) ||
1604 !read_order_field_coord(orderName, orderInfo, s, 2, &multi_patblt->nTopRect, FALSE) ||
1605 !read_order_field_coord(orderName, orderInfo, s, 3, &multi_patblt->nWidth, FALSE) ||
1606 !read_order_field_coord(orderName, orderInfo, s, 4, &multi_patblt->nHeight, FALSE) ||
1607 !read_order_field_byte(orderName, orderInfo, s, 5, &multi_patblt->bRop, TRUE) ||
1608 !read_order_field_color(orderName, orderInfo, s, 6, &multi_patblt->backColor, TRUE) ||
1609 !read_order_field_color(orderName, orderInfo, s, 7, &multi_patblt->foreColor, TRUE))
1610 return FALSE;
1611
1612 if (!update_read_brush(s, &multi_patblt->brush,
1613 get_checked_uint8((orderInfo->fieldFlags >> 7) & 0x1F)))
1614 return FALSE;
1615
1616 UINT32 numRectangles = multi_patblt->numRectangles;
1617 if (!read_order_field_byte(orderName, orderInfo, s, 13, &numRectangles, TRUE))
1618 return FALSE;
1619
1620 if ((orderInfo->fieldFlags & ORDER_FIELD_14) != 0)
1621 {
1622 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1623 return FALSE;
1624
1625 multi_patblt->numRectangles = numRectangles;
1626 Stream_Read_UINT16(s, multi_patblt->cbData);
1627
1628 if (!update_read_delta_rects(s, multi_patblt->rectangles, &multi_patblt->numRectangles))
1629 return FALSE;
1630 }
1631
1632 if (numRectangles > multi_patblt->numRectangles)
1633 {
1634 WLog_ERR(TAG, "%s numRectangles %" PRIu32 " > %" PRIu32, orderName, numRectangles,
1635 multi_patblt->numRectangles);
1636 return FALSE;
1637 }
1638 multi_patblt->numRectangles = numRectangles;
1639
1640 return TRUE;
1641}
1642
1643static BOOL update_read_multi_scrblt_order(const char* orderName, wStream* s,
1644 const ORDER_INFO* orderInfo,
1645 MULTI_SCRBLT_ORDER* multi_scrblt)
1646{
1647 WINPR_ASSERT(orderInfo);
1648 WINPR_ASSERT(multi_scrblt);
1649
1650 UINT32 numRectangles = multi_scrblt->numRectangles;
1651 if (!read_order_field_coord(orderName, orderInfo, s, 1, &multi_scrblt->nLeftRect, FALSE) ||
1652 !read_order_field_coord(orderName, orderInfo, s, 2, &multi_scrblt->nTopRect, FALSE) ||
1653 !read_order_field_coord(orderName, orderInfo, s, 3, &multi_scrblt->nWidth, FALSE) ||
1654 !read_order_field_coord(orderName, orderInfo, s, 4, &multi_scrblt->nHeight, FALSE) ||
1655 !read_order_field_byte(orderName, orderInfo, s, 5, &multi_scrblt->bRop, TRUE) ||
1656 !read_order_field_coord(orderName, orderInfo, s, 6, &multi_scrblt->nXSrc, FALSE) ||
1657 !read_order_field_coord(orderName, orderInfo, s, 7, &multi_scrblt->nYSrc, FALSE) ||
1658 !read_order_field_byte(orderName, orderInfo, s, 8, &numRectangles, TRUE))
1659 return FALSE;
1660
1661 if ((orderInfo->fieldFlags & ORDER_FIELD_09) != 0)
1662 {
1663 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1664 return FALSE;
1665
1666 multi_scrblt->numRectangles = numRectangles;
1667 Stream_Read_UINT16(s, multi_scrblt->cbData);
1668 return update_read_delta_rects(s, multi_scrblt->rectangles, &multi_scrblt->numRectangles);
1669 }
1670
1671 if (numRectangles > multi_scrblt->numRectangles)
1672 {
1673 WLog_ERR(TAG, "%s numRectangles %" PRIu32 " > %" PRIu32, orderName, numRectangles,
1674 multi_scrblt->numRectangles);
1675 return FALSE;
1676 }
1677 multi_scrblt->numRectangles = numRectangles;
1678
1679 return TRUE;
1680}
1681
1682static BOOL update_read_multi_opaque_rect_order(const char* orderName, wStream* s,
1683 const ORDER_INFO* orderInfo,
1684 MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
1685{
1686 BYTE byte = 0;
1687 if (!read_order_field_coord(orderName, orderInfo, s, 1, &multi_opaque_rect->nLeftRect, FALSE) ||
1688 !read_order_field_coord(orderName, orderInfo, s, 2, &multi_opaque_rect->nTopRect, FALSE) ||
1689 !read_order_field_coord(orderName, orderInfo, s, 3, &multi_opaque_rect->nWidth, FALSE) ||
1690 !read_order_field_coord(orderName, orderInfo, s, 4, &multi_opaque_rect->nHeight, FALSE))
1691 return FALSE;
1692
1693 if ((orderInfo->fieldFlags & ORDER_FIELD_05) != 0)
1694 {
1695 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1696 return FALSE;
1697
1698 Stream_Read_UINT8(s, byte);
1699 multi_opaque_rect->color = (multi_opaque_rect->color & 0x00FFFF00) | ((UINT32)byte);
1700 }
1701
1702 if ((orderInfo->fieldFlags & ORDER_FIELD_06) != 0)
1703 {
1704 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1705 return FALSE;
1706
1707 Stream_Read_UINT8(s, byte);
1708 multi_opaque_rect->color = (multi_opaque_rect->color & 0x00FF00FF) | ((UINT32)byte << 8);
1709 }
1710
1711 if ((orderInfo->fieldFlags & ORDER_FIELD_07) != 0)
1712 {
1713 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1714 return FALSE;
1715
1716 Stream_Read_UINT8(s, byte);
1717 multi_opaque_rect->color = (multi_opaque_rect->color & 0x0000FFFF) | ((UINT32)byte << 16);
1718 }
1719
1720 UINT32 numRectangles = multi_opaque_rect->numRectangles;
1721 if (!read_order_field_byte(orderName, orderInfo, s, 8, &numRectangles, TRUE))
1722 return FALSE;
1723
1724 if ((orderInfo->fieldFlags & ORDER_FIELD_09) != 0)
1725 {
1726 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1727 return FALSE;
1728
1729 multi_opaque_rect->numRectangles = numRectangles;
1730 Stream_Read_UINT16(s, multi_opaque_rect->cbData);
1731 return update_read_delta_rects(s, multi_opaque_rect->rectangles,
1732 &multi_opaque_rect->numRectangles);
1733 }
1734 if (numRectangles > multi_opaque_rect->numRectangles)
1735 {
1736 WLog_ERR(TAG, "%s numRectangles %" PRIu32 " > %" PRIu32, orderName, numRectangles,
1737 multi_opaque_rect->numRectangles);
1738 return FALSE;
1739 }
1740 multi_opaque_rect->numRectangles = numRectangles;
1741
1742 return TRUE;
1743}
1744
1745static BOOL update_read_multi_draw_nine_grid_order(const char* orderName, wStream* s,
1746 const ORDER_INFO* orderInfo,
1747 MULTI_DRAW_NINE_GRID_ORDER* multi_draw_nine_grid)
1748{
1749 UINT32 nDeltaEntries = multi_draw_nine_grid->nDeltaEntries;
1750 if (!read_order_field_coord(orderName, orderInfo, s, 1, &multi_draw_nine_grid->srcLeft,
1751 FALSE) ||
1752 !read_order_field_coord(orderName, orderInfo, s, 2, &multi_draw_nine_grid->srcTop, FALSE) ||
1753 !read_order_field_coord(orderName, orderInfo, s, 3, &multi_draw_nine_grid->srcRight,
1754 FALSE) ||
1755 !read_order_field_coord(orderName, orderInfo, s, 4, &multi_draw_nine_grid->srcBottom,
1756 FALSE) ||
1757 !read_order_field_uint16(orderName, orderInfo, s, 5, &multi_draw_nine_grid->bitmapId,
1758 TRUE) ||
1759 !read_order_field_byte(orderName, orderInfo, s, 6, &nDeltaEntries, TRUE))
1760 return FALSE;
1761
1762 if ((orderInfo->fieldFlags & ORDER_FIELD_07) != 0)
1763 {
1764 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1765 return FALSE;
1766
1767 multi_draw_nine_grid->nDeltaEntries = nDeltaEntries;
1768 Stream_Read_UINT16(s, multi_draw_nine_grid->cbData);
1769 return update_read_delta_rects(s, multi_draw_nine_grid->rectangles,
1770 &multi_draw_nine_grid->nDeltaEntries);
1771 }
1772
1773 if (nDeltaEntries > multi_draw_nine_grid->nDeltaEntries)
1774 {
1775 WLog_ERR(TAG, "%s nDeltaEntries %" PRIu32 " > %" PRIu32, orderName, nDeltaEntries,
1776 multi_draw_nine_grid->nDeltaEntries);
1777 return FALSE;
1778 }
1779 multi_draw_nine_grid->nDeltaEntries = nDeltaEntries;
1780
1781 return TRUE;
1782}
1783static BOOL update_read_line_to_order(const char* orderName, wStream* s,
1784 const ORDER_INFO* orderInfo, LINE_TO_ORDER* line_to)
1785{
1786 return (read_order_field_uint16(orderName, orderInfo, s, 1, &line_to->backMode, TRUE) &&
1787 read_order_field_coord(orderName, orderInfo, s, 2, &line_to->nXStart, FALSE) &&
1788 read_order_field_coord(orderName, orderInfo, s, 3, &line_to->nYStart, FALSE) &&
1789 read_order_field_coord(orderName, orderInfo, s, 4, &line_to->nXEnd, FALSE) &&
1790 read_order_field_coord(orderName, orderInfo, s, 5, &line_to->nYEnd, FALSE) &&
1791 read_order_field_color(orderName, orderInfo, s, 6, &line_to->backColor, TRUE) &&
1792 read_order_field_byte(orderName, orderInfo, s, 7, &line_to->bRop2, TRUE) &&
1793 read_order_field_byte(orderName, orderInfo, s, 8, &line_to->penStyle, TRUE) &&
1794 read_order_field_byte(orderName, orderInfo, s, 9, &line_to->penWidth, TRUE) &&
1795 read_order_field_color(orderName, orderInfo, s, 10, &line_to->penColor, TRUE));
1796}
1797
1798size_t update_approximate_line_to_order(ORDER_INFO* orderInfo, const LINE_TO_ORDER* line_to)
1799{
1800 WINPR_UNUSED(orderInfo);
1801 WINPR_UNUSED(line_to);
1802 return 32;
1803}
1804
1805BOOL update_write_line_to_order(wStream* s, ORDER_INFO* orderInfo, const LINE_TO_ORDER* line_to)
1806{
1807 if (!Stream_EnsureRemainingCapacity(s, update_approximate_line_to_order(orderInfo, line_to)))
1808 return FALSE;
1809
1810 orderInfo->fieldFlags = 0;
1811 orderInfo->fieldFlags |= ORDER_FIELD_01;
1812 Stream_Write_UINT16(s, get_checked_uint16(line_to->backMode));
1813 orderInfo->fieldFlags |= ORDER_FIELD_02;
1814 if (!update_write_coord(s, line_to->nXStart))
1815 return FALSE;
1816 orderInfo->fieldFlags |= ORDER_FIELD_03;
1817 if (!update_write_coord(s, line_to->nYStart))
1818 return FALSE;
1819 orderInfo->fieldFlags |= ORDER_FIELD_04;
1820 if (!update_write_coord(s, line_to->nXEnd))
1821 return FALSE;
1822 orderInfo->fieldFlags |= ORDER_FIELD_05;
1823 if (!update_write_coord(s, line_to->nYEnd))
1824 return FALSE;
1825 orderInfo->fieldFlags |= ORDER_FIELD_06;
1826 update_write_color(s, line_to->backColor);
1827 orderInfo->fieldFlags |= ORDER_FIELD_07;
1828 Stream_Write_UINT8(s, get_checked_uint8(line_to->bRop2));
1829 orderInfo->fieldFlags |= ORDER_FIELD_08;
1830 Stream_Write_UINT8(s, get_checked_uint8(line_to->penStyle));
1831 orderInfo->fieldFlags |= ORDER_FIELD_09;
1832 Stream_Write_UINT8(s, get_checked_uint8(line_to->penWidth));
1833 orderInfo->fieldFlags |= ORDER_FIELD_10;
1834 update_write_color(s, line_to->penColor);
1835 return TRUE;
1836}
1837
1838static BOOL update_read_polyline_order(const char* orderName, wStream* s,
1839 const ORDER_INFO* orderInfo, POLYLINE_ORDER* polyline)
1840{
1841 UINT32 word = 0;
1842 UINT32 new_num = polyline->numDeltaEntries;
1843 if (!read_order_field_coord(orderName, orderInfo, s, 1, &polyline->xStart, FALSE) ||
1844 !read_order_field_coord(orderName, orderInfo, s, 2, &polyline->yStart, FALSE) ||
1845 !read_order_field_byte(orderName, orderInfo, s, 3, &polyline->bRop2, TRUE) ||
1846 !read_order_field_uint16(orderName, orderInfo, s, 4, &word, TRUE) ||
1847 !read_order_field_color(orderName, orderInfo, s, 5, &polyline->penColor, TRUE) ||
1848 !read_order_field_byte(orderName, orderInfo, s, 6, &new_num, TRUE))
1849 return FALSE;
1850
1851 if ((orderInfo->fieldFlags & ORDER_FIELD_07) != 0)
1852 {
1853 if (new_num == 0)
1854 return FALSE;
1855
1856 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1857 return FALSE;
1858
1859 Stream_Read_UINT8(s, polyline->cbData);
1860
1861 if (!check_val_fits_int16(polyline->xStart) || !check_val_fits_int16(polyline->yStart))
1862 return FALSE;
1863
1864 polyline->numDeltaEntries = new_num;
1865 return update_read_delta_points(s, &polyline->points, polyline->numDeltaEntries,
1866 get_checked_int16(polyline->xStart),
1867 get_checked_int16(polyline->yStart));
1868 }
1869 if (new_num > polyline->numDeltaEntries)
1870 {
1871 WLog_ERR(TAG, "%s numDeltaEntries %" PRIu32 " > %" PRIu32, orderName, new_num,
1872 polyline->numDeltaEntries);
1873 return FALSE;
1874 }
1875 polyline->numDeltaEntries = new_num;
1876
1877 return TRUE;
1878}
1879
1880static BOOL update_read_memblt_order(const char* orderName, wStream* s, const ORDER_INFO* orderInfo,
1881 MEMBLT_ORDER* memblt)
1882{
1883 if (!s || !orderInfo || !memblt)
1884 return FALSE;
1885
1886 if (!read_order_field_uint16(orderName, orderInfo, s, 1, &memblt->cacheId, TRUE) ||
1887 !read_order_field_coord(orderName, orderInfo, s, 2, &memblt->nLeftRect, FALSE) ||
1888 !read_order_field_coord(orderName, orderInfo, s, 3, &memblt->nTopRect, FALSE) ||
1889 !read_order_field_coord(orderName, orderInfo, s, 4, &memblt->nWidth, FALSE) ||
1890 !read_order_field_coord(orderName, orderInfo, s, 5, &memblt->nHeight, FALSE) ||
1891 !read_order_field_byte(orderName, orderInfo, s, 6, &memblt->bRop, TRUE) ||
1892 !read_order_field_coord(orderName, orderInfo, s, 7, &memblt->nXSrc, FALSE) ||
1893 !read_order_field_coord(orderName, orderInfo, s, 8, &memblt->nYSrc, FALSE) ||
1894 !read_order_field_uint16(orderName, orderInfo, s, 9, &memblt->cacheIndex, TRUE))
1895 return FALSE;
1896 memblt->colorIndex = (memblt->cacheId >> 8);
1897 memblt->cacheId = (memblt->cacheId & 0xFF);
1898 memblt->bitmap = nullptr;
1899 return TRUE;
1900}
1901
1902size_t update_approximate_memblt_order(ORDER_INFO* orderInfo, const MEMBLT_ORDER* memblt)
1903{
1904 WINPR_UNUSED(orderInfo);
1905 WINPR_UNUSED(memblt);
1906 return 64;
1907}
1908
1909BOOL update_write_memblt_order(wStream* s, ORDER_INFO* orderInfo, const MEMBLT_ORDER* memblt)
1910{
1911 if (!Stream_EnsureRemainingCapacity(s, update_approximate_memblt_order(orderInfo, memblt)))
1912 return FALSE;
1913
1914 const UINT16 cacheId = (UINT16)((memblt->cacheId & 0xFF) | ((memblt->colorIndex & 0xFF) << 8));
1915 orderInfo->fieldFlags |= ORDER_FIELD_01;
1916 Stream_Write_UINT16(s, cacheId);
1917 orderInfo->fieldFlags |= ORDER_FIELD_02;
1918 if (!update_write_coord(s, memblt->nLeftRect))
1919 return FALSE;
1920 orderInfo->fieldFlags |= ORDER_FIELD_03;
1921 if (!update_write_coord(s, memblt->nTopRect))
1922 return FALSE;
1923 orderInfo->fieldFlags |= ORDER_FIELD_04;
1924 if (!update_write_coord(s, memblt->nWidth))
1925 return FALSE;
1926 orderInfo->fieldFlags |= ORDER_FIELD_05;
1927 if (!update_write_coord(s, memblt->nHeight))
1928 return FALSE;
1929 orderInfo->fieldFlags |= ORDER_FIELD_06;
1930 Stream_Write_UINT8(s, get_checked_uint8(memblt->bRop));
1931 orderInfo->fieldFlags |= ORDER_FIELD_07;
1932 if (!update_write_coord(s, memblt->nXSrc))
1933 return FALSE;
1934 orderInfo->fieldFlags |= ORDER_FIELD_08;
1935 if (!update_write_coord(s, memblt->nYSrc))
1936 return FALSE;
1937 orderInfo->fieldFlags |= ORDER_FIELD_09;
1938 Stream_Write_UINT16(s, get_checked_uint16(memblt->cacheIndex));
1939 return TRUE;
1940}
1941static BOOL update_read_mem3blt_order(const char* orderName, wStream* s,
1942 const ORDER_INFO* orderInfo, MEM3BLT_ORDER* mem3blt)
1943{
1944 if (!read_order_field_uint16(orderName, orderInfo, s, 1, &mem3blt->cacheId, TRUE) ||
1945 !read_order_field_coord(orderName, orderInfo, s, 2, &mem3blt->nLeftRect, FALSE) ||
1946 !read_order_field_coord(orderName, orderInfo, s, 3, &mem3blt->nTopRect, FALSE) ||
1947 !read_order_field_coord(orderName, orderInfo, s, 4, &mem3blt->nWidth, FALSE) ||
1948 !read_order_field_coord(orderName, orderInfo, s, 5, &mem3blt->nHeight, FALSE) ||
1949 !read_order_field_byte(orderName, orderInfo, s, 6, &mem3blt->bRop, TRUE) ||
1950 !read_order_field_coord(orderName, orderInfo, s, 7, &mem3blt->nXSrc, FALSE) ||
1951 !read_order_field_coord(orderName, orderInfo, s, 8, &mem3blt->nYSrc, FALSE) ||
1952 !read_order_field_color(orderName, orderInfo, s, 9, &mem3blt->backColor, TRUE) ||
1953 !read_order_field_color(orderName, orderInfo, s, 10, &mem3blt->foreColor, TRUE))
1954 return FALSE;
1955
1956 if (!update_read_brush(s, &mem3blt->brush,
1957 get_checked_uint8((orderInfo->fieldFlags >> 10) & 0x1F)) ||
1958 !read_order_field_uint16(orderName, orderInfo, s, 16, &mem3blt->cacheIndex, TRUE))
1959 return FALSE;
1960 mem3blt->colorIndex = (mem3blt->cacheId >> 8);
1961 mem3blt->cacheId = (mem3blt->cacheId & 0xFF);
1962 mem3blt->bitmap = nullptr;
1963 return TRUE;
1964}
1965static BOOL update_read_save_bitmap_order(const char* orderName, wStream* s,
1966 const ORDER_INFO* orderInfo,
1967 SAVE_BITMAP_ORDER* save_bitmap)
1968{
1969 return (read_order_field_uint32(orderName, orderInfo, s, 1, &save_bitmap->savedBitmapPosition,
1970 TRUE) &&
1971 read_order_field_coord(orderName, orderInfo, s, 2, &save_bitmap->nLeftRect, FALSE) &&
1972 read_order_field_coord(orderName, orderInfo, s, 3, &save_bitmap->nTopRect, FALSE) &&
1973 read_order_field_coord(orderName, orderInfo, s, 4, &save_bitmap->nRightRect, FALSE) &&
1974 read_order_field_coord(orderName, orderInfo, s, 5, &save_bitmap->nBottomRect, FALSE) &&
1975 read_order_field_byte(orderName, orderInfo, s, 6, &save_bitmap->operation, TRUE));
1976}
1977static BOOL update_read_glyph_index_order(const char* orderName, wStream* s,
1978 const ORDER_INFO* orderInfo,
1979 GLYPH_INDEX_ORDER* glyph_index)
1980{
1981 if (!read_order_field_byte(orderName, orderInfo, s, 1, &glyph_index->cacheId, TRUE) ||
1982 !read_order_field_byte(orderName, orderInfo, s, 2, &glyph_index->flAccel, TRUE) ||
1983 !read_order_field_byte(orderName, orderInfo, s, 3, &glyph_index->ulCharInc, TRUE) ||
1984 !read_order_field_byte(orderName, orderInfo, s, 4, &glyph_index->fOpRedundant, TRUE) ||
1985 !read_order_field_color(orderName, orderInfo, s, 5, &glyph_index->backColor, TRUE) ||
1986 !read_order_field_color(orderName, orderInfo, s, 6, &glyph_index->foreColor, TRUE) ||
1987 !read_order_field_int16(orderName, orderInfo, s, 7, &glyph_index->bkLeft, TRUE) ||
1988 !read_order_field_int16(orderName, orderInfo, s, 8, &glyph_index->bkTop, TRUE) ||
1989 !read_order_field_int16(orderName, orderInfo, s, 9, &glyph_index->bkRight, TRUE) ||
1990 !read_order_field_int16(orderName, orderInfo, s, 10, &glyph_index->bkBottom, TRUE) ||
1991 !read_order_field_int16(orderName, orderInfo, s, 11, &glyph_index->opLeft, TRUE) ||
1992 !read_order_field_int16(orderName, orderInfo, s, 12, &glyph_index->opTop, TRUE) ||
1993 !read_order_field_int16(orderName, orderInfo, s, 13, &glyph_index->opRight, TRUE) ||
1994 !read_order_field_int16(orderName, orderInfo, s, 14, &glyph_index->opBottom, TRUE) ||
1995 !update_read_brush(s, &glyph_index->brush,
1996 get_checked_uint8((orderInfo->fieldFlags >> 14) & 0x1F)) ||
1997 !read_order_field_int16(orderName, orderInfo, s, 20, &glyph_index->x, TRUE) ||
1998 !read_order_field_int16(orderName, orderInfo, s, 21, &glyph_index->y, TRUE))
1999 return FALSE;
2000
2001 if ((orderInfo->fieldFlags & ORDER_FIELD_22) != 0)
2002 {
2003 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
2004 return FALSE;
2005
2006 Stream_Read_UINT8(s, glyph_index->cbData);
2007
2008 if (!Stream_CheckAndLogRequiredLength(TAG, s, glyph_index->cbData))
2009 return FALSE;
2010
2011 CopyMemory(glyph_index->data, Stream_ConstPointer(s), glyph_index->cbData);
2012 Stream_Seek(s, glyph_index->cbData);
2013 }
2014
2015 return TRUE;
2016}
2017
2018size_t update_approximate_glyph_index_order(ORDER_INFO* orderInfo,
2019 const GLYPH_INDEX_ORDER* glyph_index)
2020{
2021 WINPR_UNUSED(orderInfo);
2022 WINPR_UNUSED(glyph_index);
2023 return 64;
2024}
2025
2026BOOL update_write_glyph_index_order(wStream* s, ORDER_INFO* orderInfo,
2027 GLYPH_INDEX_ORDER* glyph_index)
2028{
2029 size_t inf = update_approximate_glyph_index_order(orderInfo, glyph_index);
2030
2031 if (!Stream_EnsureRemainingCapacity(s, inf))
2032 return FALSE;
2033
2034 if (!Stream_EnsureRemainingCapacity(s, 4))
2035 return FALSE;
2036 orderInfo->fieldFlags = 0;
2037 orderInfo->fieldFlags |= ORDER_FIELD_01;
2038 Stream_Write_UINT8(s, get_checked_uint8(glyph_index->cacheId));
2039 orderInfo->fieldFlags |= ORDER_FIELD_02;
2040 Stream_Write_UINT8(s, get_checked_uint8(glyph_index->flAccel));
2041 orderInfo->fieldFlags |= ORDER_FIELD_03;
2042 Stream_Write_UINT8(s, get_checked_uint8(glyph_index->ulCharInc));
2043 orderInfo->fieldFlags |= ORDER_FIELD_04;
2044 Stream_Write_UINT8(s, get_checked_uint8(glyph_index->fOpRedundant));
2045 orderInfo->fieldFlags |= ORDER_FIELD_05;
2046 if (!update_write_color(s, get_checked_uint8(glyph_index->backColor)))
2047 return FALSE;
2048 orderInfo->fieldFlags |= ORDER_FIELD_06;
2049 if (!update_write_color(s, glyph_index->foreColor))
2050 return FALSE;
2051
2052 if (!Stream_EnsureRemainingCapacity(s, 14))
2053 return FALSE;
2054 orderInfo->fieldFlags |= ORDER_FIELD_07;
2055 Stream_Write_INT16(s, get_checked_int16(glyph_index->bkLeft));
2056 orderInfo->fieldFlags |= ORDER_FIELD_08;
2057 Stream_Write_INT16(s, get_checked_int16(glyph_index->bkTop));
2058 orderInfo->fieldFlags |= ORDER_FIELD_09;
2059 Stream_Write_INT16(s, get_checked_int16(glyph_index->bkRight));
2060 orderInfo->fieldFlags |= ORDER_FIELD_10;
2061 Stream_Write_INT16(s, get_checked_int16(glyph_index->bkBottom));
2062 orderInfo->fieldFlags |= ORDER_FIELD_11;
2063 Stream_Write_INT16(s, get_checked_int16(glyph_index->opLeft));
2064 orderInfo->fieldFlags |= ORDER_FIELD_12;
2065 Stream_Write_INT16(s, get_checked_int16(glyph_index->opTop));
2066 orderInfo->fieldFlags |= ORDER_FIELD_13;
2067 Stream_Write_INT16(s, get_checked_int16(glyph_index->opRight));
2068 orderInfo->fieldFlags |= ORDER_FIELD_14;
2069 Stream_Write_INT16(s, get_checked_int16(glyph_index->opBottom));
2070 orderInfo->fieldFlags |= ORDER_FIELD_15;
2071 orderInfo->fieldFlags |= ORDER_FIELD_16;
2072 orderInfo->fieldFlags |= ORDER_FIELD_17;
2073 orderInfo->fieldFlags |= ORDER_FIELD_18;
2074 orderInfo->fieldFlags |= ORDER_FIELD_19;
2075 if (!update_write_brush(s, &glyph_index->brush,
2076 get_checked_uint8((orderInfo->fieldFlags >> 14) & 0x1F)))
2077 return FALSE;
2078
2079 if (!Stream_EnsureRemainingCapacity(s, 5ULL + glyph_index->cbData))
2080 return FALSE;
2081 orderInfo->fieldFlags |= ORDER_FIELD_20;
2082 Stream_Write_INT16(s, get_checked_int16(glyph_index->x));
2083 orderInfo->fieldFlags |= ORDER_FIELD_21;
2084 Stream_Write_INT16(s, get_checked_int16(glyph_index->y));
2085 orderInfo->fieldFlags |= ORDER_FIELD_22;
2086 Stream_Write_UINT8(s, get_checked_uint8(glyph_index->cbData));
2087 Stream_Write(s, glyph_index->data, glyph_index->cbData);
2088 return TRUE;
2089}
2090static BOOL update_read_fast_index_order(const char* orderName, wStream* s,
2091 const ORDER_INFO* orderInfo, FAST_INDEX_ORDER* fast_index)
2092{
2093 if (!read_order_field_byte(orderName, orderInfo, s, 1, &fast_index->cacheId, TRUE) ||
2094 !read_order_field_2bytes(orderName, orderInfo, s, 2, &fast_index->ulCharInc,
2095 &fast_index->flAccel, TRUE) ||
2096 !read_order_field_color(orderName, orderInfo, s, 3, &fast_index->backColor, TRUE) ||
2097 !read_order_field_color(orderName, orderInfo, s, 4, &fast_index->foreColor, TRUE) ||
2098 !read_order_field_coord(orderName, orderInfo, s, 5, &fast_index->bkLeft, FALSE) ||
2099 !read_order_field_coord(orderName, orderInfo, s, 6, &fast_index->bkTop, FALSE) ||
2100 !read_order_field_coord(orderName, orderInfo, s, 7, &fast_index->bkRight, FALSE) ||
2101 !read_order_field_coord(orderName, orderInfo, s, 8, &fast_index->bkBottom, FALSE) ||
2102 !read_order_field_coord(orderName, orderInfo, s, 9, &fast_index->opLeft, FALSE) ||
2103 !read_order_field_coord(orderName, orderInfo, s, 10, &fast_index->opTop, FALSE) ||
2104 !read_order_field_coord(orderName, orderInfo, s, 11, &fast_index->opRight, FALSE) ||
2105 !read_order_field_coord(orderName, orderInfo, s, 12, &fast_index->opBottom, FALSE) ||
2106 !read_order_field_coord(orderName, orderInfo, s, 13, &fast_index->x, FALSE) ||
2107 !read_order_field_coord(orderName, orderInfo, s, 14, &fast_index->y, FALSE))
2108 return FALSE;
2109
2110 if ((orderInfo->fieldFlags & ORDER_FIELD_15) != 0)
2111 {
2112 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
2113 return FALSE;
2114
2115 Stream_Read_UINT8(s, fast_index->cbData);
2116
2117 if (!Stream_CheckAndLogRequiredLength(TAG, s, fast_index->cbData))
2118 return FALSE;
2119
2120 CopyMemory(fast_index->data, Stream_ConstPointer(s), fast_index->cbData);
2121 Stream_Seek(s, fast_index->cbData);
2122 }
2123
2124 return TRUE;
2125}
2126static BOOL update_read_fast_glyph_order(const char* orderName, wStream* s,
2127 const ORDER_INFO* orderInfo, FAST_GLYPH_ORDER* fastGlyph)
2128{
2129 GLYPH_DATA_V2* glyph = &fastGlyph->glyphData;
2130 if (!read_order_field_byte(orderName, orderInfo, s, 1, &fastGlyph->cacheId, TRUE))
2131 return FALSE;
2132 if (fastGlyph->cacheId > 9)
2133 return FALSE;
2134 if (!read_order_field_2bytes(orderName, orderInfo, s, 2, &fastGlyph->ulCharInc,
2135 &fastGlyph->flAccel, TRUE) ||
2136 !read_order_field_color(orderName, orderInfo, s, 3, &fastGlyph->backColor, TRUE) ||
2137 !read_order_field_color(orderName, orderInfo, s, 4, &fastGlyph->foreColor, TRUE) ||
2138 !read_order_field_coord(orderName, orderInfo, s, 5, &fastGlyph->bkLeft, FALSE) ||
2139 !read_order_field_coord(orderName, orderInfo, s, 6, &fastGlyph->bkTop, FALSE) ||
2140 !read_order_field_coord(orderName, orderInfo, s, 7, &fastGlyph->bkRight, FALSE) ||
2141 !read_order_field_coord(orderName, orderInfo, s, 8, &fastGlyph->bkBottom, FALSE) ||
2142 !read_order_field_coord(orderName, orderInfo, s, 9, &fastGlyph->opLeft, FALSE) ||
2143 !read_order_field_coord(orderName, orderInfo, s, 10, &fastGlyph->opTop, FALSE) ||
2144 !read_order_field_coord(orderName, orderInfo, s, 11, &fastGlyph->opRight, FALSE) ||
2145 !read_order_field_coord(orderName, orderInfo, s, 12, &fastGlyph->opBottom, FALSE) ||
2146 !read_order_field_coord(orderName, orderInfo, s, 13, &fastGlyph->x, FALSE) ||
2147 !read_order_field_coord(orderName, orderInfo, s, 14, &fastGlyph->y, FALSE))
2148 return FALSE;
2149
2150 if ((orderInfo->fieldFlags & ORDER_FIELD_15) != 0)
2151 {
2152 const BYTE* src = nullptr;
2153 wStream subbuffer;
2154 wStream* sub = nullptr;
2155 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
2156 return FALSE;
2157
2158 Stream_Read_UINT8(s, fastGlyph->cbData);
2159
2160 src = Stream_ConstPointer(s);
2161 if (!Stream_SafeSeek(s, fastGlyph->cbData) || (fastGlyph->cbData == 0))
2162 return FALSE;
2163
2164 CopyMemory(fastGlyph->data, src, fastGlyph->cbData);
2165 sub = Stream_StaticInit(&subbuffer, fastGlyph->data, fastGlyph->cbData);
2166
2167 Stream_Read_UINT8(sub, glyph->cacheIndex);
2168
2169 if (fastGlyph->cbData > 1)
2170 {
2171 if (!update_read_2byte_signed(sub, &glyph->x) ||
2172 !update_read_2byte_signed(sub, &glyph->y) ||
2173 !update_read_2byte_unsigned(sub, &glyph->cx) ||
2174 !update_read_2byte_unsigned(sub, &glyph->cy))
2175 return FALSE;
2176
2177 if ((glyph->cx == 0) || (glyph->cy == 0))
2178 {
2179 WLog_ERR(TAG, "GLYPH_DATA_V2::cx=%" PRIu32 ", GLYPH_DATA_V2::cy=%" PRIu32,
2180 glyph->cx, glyph->cy);
2181 return FALSE;
2182 }
2183
2184 const size_t slen = Stream_GetRemainingLength(sub);
2185 if (slen > UINT32_MAX)
2186 return FALSE;
2187 glyph->cb = (UINT32)slen;
2188 if (glyph->cb > 0)
2189 {
2190 BYTE* new_aj = (BYTE*)realloc(glyph->aj, glyph->cb);
2191
2192 if (!new_aj)
2193 return FALSE;
2194
2195 glyph->aj = new_aj;
2196 Stream_Read(sub, glyph->aj, glyph->cb);
2197 }
2198 else
2199 {
2200 free(glyph->aj);
2201 glyph->aj = nullptr;
2202 }
2203 }
2204 }
2205
2206 return TRUE;
2207}
2208
2209static BOOL update_read_polygon_sc_order(const char* orderName, wStream* s,
2210 const ORDER_INFO* orderInfo, POLYGON_SC_ORDER* polygon_sc)
2211{
2212 UINT32 num = polygon_sc->numPoints;
2213 if (!read_order_field_coord(orderName, orderInfo, s, 1, &polygon_sc->xStart, FALSE) ||
2214 !read_order_field_coord(orderName, orderInfo, s, 2, &polygon_sc->yStart, FALSE) ||
2215 !read_order_field_byte(orderName, orderInfo, s, 3, &polygon_sc->bRop2, TRUE) ||
2216 !read_order_field_byte(orderName, orderInfo, s, 4, &polygon_sc->fillMode, TRUE) ||
2217 !read_order_field_color(orderName, orderInfo, s, 5, &polygon_sc->brushColor, TRUE) ||
2218 !read_order_field_byte(orderName, orderInfo, s, 6, &num, TRUE))
2219 return FALSE;
2220
2221 if ((orderInfo->fieldFlags & ORDER_FIELD_07) != 0)
2222 {
2223 if (num == 0)
2224 return FALSE;
2225
2226 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
2227 return FALSE;
2228
2229 Stream_Read_UINT8(s, polygon_sc->cbData);
2230
2231 if (!check_val_fits_int16(polygon_sc->xStart) || !check_val_fits_int16(polygon_sc->yStart))
2232 return FALSE;
2233
2234 polygon_sc->numPoints = num;
2235 return update_read_delta_points(s, &polygon_sc->points, polygon_sc->numPoints,
2236 get_checked_int16(polygon_sc->xStart),
2237 get_checked_int16(polygon_sc->yStart));
2238 }
2239 if (num > polygon_sc->numPoints)
2240 {
2241 WLog_ERR(TAG, "%s numPoints %" PRIu32 " > %" PRIu32, orderName, num, polygon_sc->numPoints);
2242 return FALSE;
2243 }
2244 polygon_sc->numPoints = num;
2245
2246 return TRUE;
2247}
2248static BOOL update_read_polygon_cb_order(const char* orderName, wStream* s,
2249 const ORDER_INFO* orderInfo, POLYGON_CB_ORDER* polygon_cb)
2250{
2251 UINT32 num = polygon_cb->numPoints;
2252 if (!read_order_field_coord(orderName, orderInfo, s, 1, &polygon_cb->xStart, FALSE) ||
2253 !read_order_field_coord(orderName, orderInfo, s, 2, &polygon_cb->yStart, FALSE) ||
2254 !read_order_field_byte(orderName, orderInfo, s, 3, &polygon_cb->bRop2, TRUE) ||
2255 !read_order_field_byte(orderName, orderInfo, s, 4, &polygon_cb->fillMode, TRUE) ||
2256 !read_order_field_color(orderName, orderInfo, s, 5, &polygon_cb->backColor, TRUE) ||
2257 !read_order_field_color(orderName, orderInfo, s, 6, &polygon_cb->foreColor, TRUE))
2258 return FALSE;
2259
2260 if (!update_read_brush(s, &polygon_cb->brush,
2261 get_checked_uint8((orderInfo->fieldFlags >> 6) & 0x1F)))
2262 return FALSE;
2263
2264 if (!read_order_field_byte(orderName, orderInfo, s, 12, &num, TRUE))
2265 return FALSE;
2266
2267 if ((orderInfo->fieldFlags & ORDER_FIELD_13) != 0)
2268 {
2269 if (num == 0)
2270 return FALSE;
2271
2272 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
2273 return FALSE;
2274
2275 Stream_Read_UINT8(s, polygon_cb->cbData);
2276 polygon_cb->numPoints = num;
2277
2278 if (!check_val_fits_int16(polygon_cb->xStart) || !check_val_fits_int16(polygon_cb->yStart))
2279 return FALSE;
2280
2281 if (!update_read_delta_points(s, &polygon_cb->points, polygon_cb->numPoints,
2282 get_checked_int16(polygon_cb->xStart),
2283 get_checked_int16(polygon_cb->yStart)))
2284 return FALSE;
2285 }
2286
2287 if (num > polygon_cb->numPoints)
2288 {
2289 WLog_ERR(TAG, "%s numPoints %" PRIu32 " > %" PRIu32, orderName, num, polygon_cb->numPoints);
2290 return FALSE;
2291 }
2292 polygon_cb->numPoints = num;
2293
2294 polygon_cb->backMode = (polygon_cb->bRop2 & 0x80) ? BACKMODE_TRANSPARENT : BACKMODE_OPAQUE;
2295 polygon_cb->bRop2 = (polygon_cb->bRop2 & 0x1F);
2296 return TRUE;
2297}
2298static BOOL update_read_ellipse_sc_order(const char* orderName, wStream* s,
2299 const ORDER_INFO* orderInfo, ELLIPSE_SC_ORDER* ellipse_sc)
2300{
2301 return (read_order_field_coord(orderName, orderInfo, s, 1, &ellipse_sc->leftRect, FALSE) &&
2302 read_order_field_coord(orderName, orderInfo, s, 2, &ellipse_sc->topRect, FALSE) &&
2303 read_order_field_coord(orderName, orderInfo, s, 3, &ellipse_sc->rightRect, FALSE) &&
2304 read_order_field_coord(orderName, orderInfo, s, 4, &ellipse_sc->bottomRect, FALSE) &&
2305 read_order_field_byte(orderName, orderInfo, s, 5, &ellipse_sc->bRop2, TRUE) &&
2306 read_order_field_byte(orderName, orderInfo, s, 6, &ellipse_sc->fillMode, TRUE) &&
2307 read_order_field_color(orderName, orderInfo, s, 7, &ellipse_sc->color, TRUE));
2308}
2309static BOOL update_read_ellipse_cb_order(const char* orderName, wStream* s,
2310 const ORDER_INFO* orderInfo, ELLIPSE_CB_ORDER* ellipse_cb)
2311{
2312 return (read_order_field_coord(orderName, orderInfo, s, 1, &ellipse_cb->leftRect, FALSE) &&
2313 read_order_field_coord(orderName, orderInfo, s, 2, &ellipse_cb->topRect, FALSE) &&
2314 read_order_field_coord(orderName, orderInfo, s, 3, &ellipse_cb->rightRect, FALSE) &&
2315 read_order_field_coord(orderName, orderInfo, s, 4, &ellipse_cb->bottomRect, FALSE) &&
2316 read_order_field_byte(orderName, orderInfo, s, 5, &ellipse_cb->bRop2, TRUE) &&
2317 read_order_field_byte(orderName, orderInfo, s, 6, &ellipse_cb->fillMode, TRUE) &&
2318 read_order_field_color(orderName, orderInfo, s, 7, &ellipse_cb->backColor, TRUE) &&
2319 read_order_field_color(orderName, orderInfo, s, 8, &ellipse_cb->foreColor, TRUE) &&
2320 update_read_brush(s, &ellipse_cb->brush,
2321 get_checked_uint8((orderInfo->fieldFlags >> 8) & 0x1F)));
2322}
2323
2324/* Secondary Drawing Orders */
2325WINPR_ATTR_MALLOC(free_cache_bitmap_order, 2)
2326static CACHE_BITMAP_ORDER* update_read_cache_bitmap_order(rdpUpdate* update, wStream* s,
2327 BOOL compressed, UINT16 flags)
2328{
2329 CACHE_BITMAP_ORDER* cache_bitmap = nullptr;
2330 rdp_update_internal* up = update_cast(update);
2331
2332 if (!update || !s)
2333 return nullptr;
2334
2335 cache_bitmap = calloc(1, sizeof(CACHE_BITMAP_ORDER));
2336
2337 if (!cache_bitmap)
2338 goto fail;
2339
2340 if (!Stream_CheckAndLogRequiredLength(TAG, s, 9))
2341 goto fail;
2342
2343 Stream_Read_UINT8(s, cache_bitmap->cacheId); /* cacheId (1 byte) */
2344 Stream_Seek_UINT8(s); /* pad1Octet (1 byte) */
2345 Stream_Read_UINT8(s, cache_bitmap->bitmapWidth); /* bitmapWidth (1 byte) */
2346 Stream_Read_UINT8(s, cache_bitmap->bitmapHeight); /* bitmapHeight (1 byte) */
2347 Stream_Read_UINT8(s, cache_bitmap->bitmapBpp); /* bitmapBpp (1 byte) */
2348
2349 if ((cache_bitmap->bitmapBpp < 1) || (cache_bitmap->bitmapBpp > 32))
2350 {
2351 WLog_Print(up->log, WLOG_ERROR, "invalid bitmap bpp %" PRIu32 "", cache_bitmap->bitmapBpp);
2352 goto fail;
2353 }
2354
2355 Stream_Read_UINT16(s, cache_bitmap->bitmapLength); /* bitmapLength (2 bytes) */
2356 Stream_Read_UINT16(s, cache_bitmap->cacheIndex); /* cacheIndex (2 bytes) */
2357
2358 if (compressed)
2359 {
2360 if ((flags & NO_BITMAP_COMPRESSION_HDR) == 0)
2361 {
2362 BYTE* bitmapComprHdr = (BYTE*)&(cache_bitmap->bitmapComprHdr);
2363
2364 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
2365 goto fail;
2366
2367 Stream_Read(s, bitmapComprHdr, 8); /* bitmapComprHdr (8 bytes) */
2368 if (cache_bitmap->bitmapLength < 8)
2369 goto fail;
2370 cache_bitmap->bitmapLength -= 8;
2371 }
2372 }
2373
2374 if (cache_bitmap->bitmapLength == 0)
2375 goto fail;
2376
2377 if (!Stream_CheckAndLogRequiredLength(TAG, s, cache_bitmap->bitmapLength))
2378 goto fail;
2379
2380 cache_bitmap->bitmapDataStream = malloc(cache_bitmap->bitmapLength);
2381
2382 if (!cache_bitmap->bitmapDataStream)
2383 goto fail;
2384
2385 Stream_Read(s, cache_bitmap->bitmapDataStream, cache_bitmap->bitmapLength);
2386 cache_bitmap->compressed = compressed;
2387 return cache_bitmap;
2388fail:
2389 WINPR_PRAGMA_DIAG_PUSH
2390 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2391 free_cache_bitmap_order(update->context, cache_bitmap);
2392 WINPR_PRAGMA_DIAG_POP
2393 return nullptr;
2394}
2395
2396size_t update_approximate_cache_bitmap_order(const CACHE_BITMAP_ORDER* cache_bitmap,
2397 BOOL compressed, const UINT16* flags)
2398{
2399 WINPR_ASSERT(cache_bitmap);
2400 WINPR_UNUSED(compressed);
2401 WINPR_UNUSED(flags);
2402 return 64 + cache_bitmap->bitmapLength;
2403}
2404
2405BOOL update_write_cache_bitmap_order(wStream* s, const CACHE_BITMAP_ORDER* cache_bitmap,
2406 BOOL compressed, UINT16* flags)
2407{
2408 UINT32 bitmapLength = cache_bitmap->bitmapLength;
2409 size_t inf = update_approximate_cache_bitmap_order(cache_bitmap, compressed, flags);
2410
2411 if (!Stream_EnsureRemainingCapacity(s, inf))
2412 return FALSE;
2413
2414 *flags = NO_BITMAP_COMPRESSION_HDR;
2415
2416 if ((*flags & NO_BITMAP_COMPRESSION_HDR) == 0)
2417 bitmapLength += 8;
2418
2419 Stream_Write_UINT8(s, get_checked_uint8(cache_bitmap->cacheId)); /* cacheId (1 byte) */
2420 Stream_Write_UINT8(s, 0); /* pad1Octet (1 byte) */
2421 Stream_Write_UINT8(s, get_checked_uint8(cache_bitmap->bitmapWidth)); /* bitmapWidth (1 byte) */
2422 Stream_Write_UINT8(s,
2423 get_checked_uint8(cache_bitmap->bitmapHeight)); /* bitmapHeight (1 byte) */
2424 Stream_Write_UINT8(s, get_checked_uint8(cache_bitmap->bitmapBpp)); /* bitmapBpp (1 byte) */
2425 Stream_Write_UINT16(s, get_checked_uint16(bitmapLength)); /* bitmapLength (2 bytes) */
2426 Stream_Write_UINT16(s, get_checked_uint16(cache_bitmap->cacheIndex)); /* cacheIndex (2 bytes) */
2427
2428 if (compressed)
2429 {
2430 if ((*flags & NO_BITMAP_COMPRESSION_HDR) == 0)
2431 {
2432 const BYTE* bitmapComprHdr = (const BYTE*)&(cache_bitmap->bitmapComprHdr);
2433 Stream_Write(s, bitmapComprHdr, 8); /* bitmapComprHdr (8 bytes) */
2434 bitmapLength -= 8;
2435 }
2436
2437 Stream_Write(s, cache_bitmap->bitmapDataStream, bitmapLength);
2438 }
2439 else
2440 {
2441 Stream_Write(s, cache_bitmap->bitmapDataStream, bitmapLength);
2442 }
2443
2444 return TRUE;
2445}
2446
2447WINPR_ATTR_MALLOC(free_cache_bitmap_v2_order, 2)
2448WINPR_ATTR_NODISCARD
2449static CACHE_BITMAP_V2_ORDER* update_read_cache_bitmap_v2_order(rdpUpdate* update, wStream* s,
2450 BOOL compressed, UINT16 flags)
2451{
2452 BOOL rc = 0;
2453 BYTE bitsPerPixelId = 0;
2454 CACHE_BITMAP_V2_ORDER* cache_bitmap_v2 = nullptr;
2455
2456 if (!update || !s)
2457 return nullptr;
2458
2459 cache_bitmap_v2 = calloc(1, sizeof(CACHE_BITMAP_V2_ORDER));
2460
2461 if (!cache_bitmap_v2)
2462 goto fail;
2463
2464 cache_bitmap_v2->cacheId = flags & 0x0007;
2465 cache_bitmap_v2->flags = (flags & 0xFF80) >> 7;
2466 bitsPerPixelId = (flags & 0x0078) >> 3;
2467 cache_bitmap_v2->bitmapBpp = get_cbr2_bpp(bitsPerPixelId, &rc);
2468 if (!rc)
2469 goto fail;
2470
2471 if (cache_bitmap_v2->flags & CBR2_PERSISTENT_KEY_PRESENT)
2472 {
2473 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
2474 goto fail;
2475
2476 Stream_Read_UINT32(s, cache_bitmap_v2->key1); /* key1 (4 bytes) */
2477 Stream_Read_UINT32(s, cache_bitmap_v2->key2); /* key2 (4 bytes) */
2478 }
2479
2480 if (cache_bitmap_v2->flags & CBR2_HEIGHT_SAME_AS_WIDTH)
2481 {
2482 if (!update_read_2byte_unsigned(s, &cache_bitmap_v2->bitmapWidth)) /* bitmapWidth */
2483 goto fail;
2484
2485 cache_bitmap_v2->bitmapHeight = cache_bitmap_v2->bitmapWidth;
2486 }
2487 else
2488 {
2489 if (!update_read_2byte_unsigned(s, &cache_bitmap_v2->bitmapWidth) || /* bitmapWidth */
2490 !update_read_2byte_unsigned(s, &cache_bitmap_v2->bitmapHeight)) /* bitmapHeight */
2491 goto fail;
2492 }
2493
2494 if (!update_read_4byte_unsigned(s, &cache_bitmap_v2->bitmapLength) || /* bitmapLength */
2495 !update_read_2byte_unsigned(s, &cache_bitmap_v2->cacheIndex)) /* cacheIndex */
2496 goto fail;
2497
2498 if (cache_bitmap_v2->flags & CBR2_DO_NOT_CACHE)
2499 cache_bitmap_v2->cacheIndex = BITMAP_CACHE_WAITING_LIST_INDEX;
2500
2501 if (compressed)
2502 {
2503 if (!(cache_bitmap_v2->flags & CBR2_NO_BITMAP_COMPRESSION_HDR))
2504 {
2505 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
2506 goto fail;
2507
2508 Stream_Read_UINT16(
2509 s, cache_bitmap_v2->cbCompFirstRowSize); /* cbCompFirstRowSize (2 bytes) */
2510 Stream_Read_UINT16(
2511 s, cache_bitmap_v2->cbCompMainBodySize); /* cbCompMainBodySize (2 bytes) */
2512 Stream_Read_UINT16(s, cache_bitmap_v2->cbScanWidth); /* cbScanWidth (2 bytes) */
2513 Stream_Read_UINT16(
2514 s, cache_bitmap_v2->cbUncompressedSize); /* cbUncompressedSize (2 bytes) */
2515 cache_bitmap_v2->bitmapLength = cache_bitmap_v2->cbCompMainBodySize;
2516 }
2517 }
2518
2519 if (cache_bitmap_v2->bitmapLength == 0)
2520 goto fail;
2521
2522 if (!Stream_CheckAndLogRequiredLength(TAG, s, cache_bitmap_v2->bitmapLength))
2523 goto fail;
2524
2525 if (cache_bitmap_v2->bitmapLength == 0)
2526 goto fail;
2527
2528 cache_bitmap_v2->bitmapDataStream = malloc(cache_bitmap_v2->bitmapLength);
2529
2530 if (!cache_bitmap_v2->bitmapDataStream)
2531 goto fail;
2532
2533 Stream_Read(s, cache_bitmap_v2->bitmapDataStream, cache_bitmap_v2->bitmapLength);
2534 cache_bitmap_v2->compressed = compressed;
2535 return cache_bitmap_v2;
2536fail:
2537 WINPR_PRAGMA_DIAG_PUSH
2538 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2539 free_cache_bitmap_v2_order(update->context, cache_bitmap_v2);
2540 WINPR_PRAGMA_DIAG_POP
2541 return nullptr;
2542}
2543
2544size_t update_approximate_cache_bitmap_v2_order(CACHE_BITMAP_V2_ORDER* cache_bitmap_v2,
2545 BOOL compressed, const UINT16* flags)
2546{
2547 WINPR_ASSERT(cache_bitmap_v2);
2548 WINPR_UNUSED(flags);
2549 WINPR_UNUSED(compressed);
2550
2551 return 64 + cache_bitmap_v2->bitmapLength;
2552}
2553
2554BOOL update_write_cache_bitmap_v2_order(wStream* s, CACHE_BITMAP_V2_ORDER* cache_bitmap_v2,
2555 BOOL compressed, UINT16* flags)
2556{
2557 BOOL rc = 0;
2558 BYTE bitsPerPixelId = 0;
2559
2560 if (!Stream_EnsureRemainingCapacity(
2561 s, update_approximate_cache_bitmap_v2_order(cache_bitmap_v2, compressed, flags)))
2562 return FALSE;
2563
2564 bitsPerPixelId = get_bpp_bmf(cache_bitmap_v2->bitmapBpp, &rc);
2565 if (!rc)
2566 return FALSE;
2567 WINPR_ASSERT(cache_bitmap_v2->cacheId <= 3);
2568 WINPR_ASSERT(bitsPerPixelId <= 0x0f);
2569 WINPR_ASSERT(cache_bitmap_v2->flags <= 0x1FF);
2570 *flags = (UINT16)((cache_bitmap_v2->cacheId & 0x0003) | ((bitsPerPixelId << 3) & 0xFFFF) |
2571 ((cache_bitmap_v2->flags << 7) & 0xFF80));
2572
2573 if (cache_bitmap_v2->flags & CBR2_PERSISTENT_KEY_PRESENT)
2574 {
2575 Stream_Write_UINT32(s, cache_bitmap_v2->key1); /* key1 (4 bytes) */
2576 Stream_Write_UINT32(s, cache_bitmap_v2->key2); /* key2 (4 bytes) */
2577 }
2578
2579 if (cache_bitmap_v2->flags & CBR2_HEIGHT_SAME_AS_WIDTH)
2580 {
2581 if (!update_write_2byte_unsigned(s, cache_bitmap_v2->bitmapWidth)) /* bitmapWidth */
2582 return FALSE;
2583 }
2584 else
2585 {
2586 if (!update_write_2byte_unsigned(s, cache_bitmap_v2->bitmapWidth) || /* bitmapWidth */
2587 !update_write_2byte_unsigned(s, cache_bitmap_v2->bitmapHeight)) /* bitmapHeight */
2588 return FALSE;
2589 }
2590
2591 if (cache_bitmap_v2->flags & CBR2_DO_NOT_CACHE)
2592 cache_bitmap_v2->cacheIndex = BITMAP_CACHE_WAITING_LIST_INDEX;
2593
2594 if (!update_write_4byte_unsigned(s, cache_bitmap_v2->bitmapLength) || /* bitmapLength */
2595 !update_write_2byte_unsigned(s, cache_bitmap_v2->cacheIndex)) /* cacheIndex */
2596 return FALSE;
2597
2598 if (compressed)
2599 {
2600 if (!(cache_bitmap_v2->flags & CBR2_NO_BITMAP_COMPRESSION_HDR))
2601 {
2602 Stream_Write_UINT16(
2603 s, get_checked_uint16(
2604 cache_bitmap_v2->cbCompFirstRowSize)); /* cbCompFirstRowSize (2 bytes) */
2605 Stream_Write_UINT16(
2606 s, get_checked_uint16(
2607 cache_bitmap_v2->cbCompMainBodySize)); /* cbCompMainBodySize (2 bytes) */
2608 Stream_Write_UINT16(
2609 s, get_checked_uint16(cache_bitmap_v2->cbScanWidth)); /* cbScanWidth (2 bytes) */
2610 Stream_Write_UINT16(
2611 s, get_checked_uint16(
2612 cache_bitmap_v2->cbUncompressedSize)); /* cbUncompressedSize (2 bytes) */
2613 cache_bitmap_v2->bitmapLength = cache_bitmap_v2->cbCompMainBodySize;
2614 }
2615
2616 if (!Stream_EnsureRemainingCapacity(s, cache_bitmap_v2->bitmapLength))
2617 return FALSE;
2618
2619 Stream_Write(s, cache_bitmap_v2->bitmapDataStream, cache_bitmap_v2->bitmapLength);
2620 }
2621 else
2622 {
2623 if (!Stream_EnsureRemainingCapacity(s, cache_bitmap_v2->bitmapLength))
2624 return FALSE;
2625
2626 Stream_Write(s, cache_bitmap_v2->bitmapDataStream, cache_bitmap_v2->bitmapLength);
2627 }
2628
2629 cache_bitmap_v2->compressed = compressed;
2630 return TRUE;
2631}
2632
2633WINPR_ATTR_MALLOC(free_cache_bitmap_v3_order, 2)
2634static CACHE_BITMAP_V3_ORDER* update_read_cache_bitmap_v3_order(rdpUpdate* update, wStream* s,
2635 UINT16 flags)
2636{
2637 BOOL rc = 0;
2638 UINT32 new_len = 0;
2639 BYTE* new_data = nullptr;
2640 rdp_update_internal* up = update_cast(update);
2641
2642 if (!update || !s)
2643 return nullptr;
2644
2645 WINPR_ASSERT(update->context);
2646
2647 const rdpSettings* settings = update->context->settings;
2648 WINPR_ASSERT(settings);
2649
2650 if (!freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheV3Enabled))
2651 {
2652 WLog_Print(up->log, WLOG_ERROR, "BitmapCacheV3 not enabled for this connection, aborting");
2653 return nullptr;
2654 }
2655
2656 CACHE_BITMAP_V3_ORDER* cache_bitmap_v3 = calloc(1, sizeof(CACHE_BITMAP_V3_ORDER));
2657
2658 if (!cache_bitmap_v3)
2659 goto fail;
2660
2661 cache_bitmap_v3->cacheId = flags & 0x00000007;
2662 const UINT32 NumCellCaches =
2663 freerdp_settings_get_uint32(settings, FreeRDP_BitmapCacheV2NumCells);
2664 if (cache_bitmap_v3->cacheId >= NumCellCaches)
2665 {
2666 WLog_Print(up->log, WLOG_ERROR,
2667 "BitmapCacheV3::cacheId %" PRIu32 " > NumCellCaches %" PRIu32,
2668 cache_bitmap_v3->cacheId, NumCellCaches);
2669 goto fail;
2670 }
2671 cache_bitmap_v3->flags = (flags >> 7) & 0x000001FF;
2672
2673 const BYTE bitsPerPixelId = (flags >> 3) & 0x000000F;
2674 cache_bitmap_v3->bpp = get_cbr2_bpp(bitsPerPixelId, &rc);
2675
2676 if (!Stream_CheckAndLogRequiredLength(TAG, s, 21))
2677 goto fail;
2678
2679 Stream_Read_UINT16(s, cache_bitmap_v3->cacheIndex); /* cacheIndex (2 bytes) */
2680 Stream_Read_UINT32(s, cache_bitmap_v3->key1); /* key1 (4 bytes) */
2681 Stream_Read_UINT32(s, cache_bitmap_v3->key2); /* key2 (4 bytes) */
2682
2683 if ((cache_bitmap_v3->flags & CBR3_DO_NOT_CACHE) != 0)
2684 {
2685 rdpCache* cache = update->context->cache;
2686 WINPR_ASSERT(cache);
2687
2688 if (cache_bitmap_v3->cacheId >= cache->bitmap->maxCells)
2689 goto fail;
2690
2691 BITMAP_V2_CELL* cell = &cache->bitmap->cells[cache_bitmap_v3->cacheId];
2692 cache_bitmap_v3->cacheIndex = cell->number;
2693 }
2694
2695 BITMAP_DATA_EX* bitmapData = &cache_bitmap_v3->bitmapData;
2696 Stream_Read_UINT8(s, bitmapData->bpp);
2697
2698 if ((bitmapData->bpp < 1) || (bitmapData->bpp > 32))
2699 {
2700 WLog_Print(up->log, WLOG_ERROR, "invalid bpp value %" PRIu32 "", bitmapData->bpp);
2701 goto fail;
2702 }
2703
2704 /* [MS-RDPEGDI] 2.2.2.2.1.2.8 Cache Bitmap - Revision 3 (CACHE_BITMAP_REV3_ORDER)
2705 * tells this should not be 0, but it is for some windows versions.
2706 * fall back to setting color depth from bitmapData
2707 */
2708 if (!rc)
2709 cache_bitmap_v3->bpp = bitmapData->bpp;
2710
2711 Stream_Seek_UINT8(s); /* reserved1 (1 byte) */
2712 Stream_Seek_UINT8(s); /* reserved2 (1 byte) */
2713 Stream_Read_UINT8(s, bitmapData->codecID); /* codecID (1 byte) */
2714 Stream_Read_UINT16(s, bitmapData->width); /* width (2 bytes) */
2715 Stream_Read_UINT16(s, bitmapData->height); /* height (2 bytes) */
2716 Stream_Read_UINT32(s, new_len); /* length (4 bytes) */
2717
2718 switch (bitmapData->codecID)
2719 {
2720 case RDP_CODEC_ID_IMAGE_REMOTEFX:
2721 if (!freerdp_settings_get_bool(settings, FreeRDP_RemoteFxImageCodec))
2722 {
2723 WLog_Print(up->log, WLOG_ERROR,
2724 "codecID RDP_CODEC_ID_IMAGE_REMOTEFX not enabled for this "
2725 "connection, aborting");
2726 goto fail;
2727 }
2728 break;
2729 case RDP_CODEC_ID_REMOTEFX:
2730 if (!freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec))
2731 {
2732 WLog_ERR(TAG,
2733 "codecID RDP_CODEC_ID_REMOTEFX not enabled for this connection, aborting");
2734 goto fail;
2735 }
2736 break;
2737 case RDP_CODEC_ID_NSCODEC:
2738 if (!freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
2739 {
2740 WLog_ERR(TAG,
2741 "codecID RDP_CODEC_ID_NSCODEC not enabled for this connection, aborting");
2742 goto fail;
2743 }
2744 break;
2745 case RDP_CODEC_ID_NONE:
2746 break;
2747 default:
2748 WLog_ERR(TAG, "Unsupported codecID 0x%08" PRIx32, bitmapData->codecID);
2749 goto fail;
2750 }
2751
2752 if ((new_len == 0) || (!Stream_CheckAndLogRequiredLength(TAG, s, new_len)))
2753 goto fail;
2754
2755 new_data = (BYTE*)realloc(bitmapData->data, new_len);
2756
2757 if (!new_data)
2758 goto fail;
2759
2760 bitmapData->data = new_data;
2761 bitmapData->length = new_len;
2762 Stream_Read(s, bitmapData->data, bitmapData->length);
2763 return cache_bitmap_v3;
2764fail:
2765 WINPR_PRAGMA_DIAG_PUSH
2766 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2767 free_cache_bitmap_v3_order(update->context, cache_bitmap_v3);
2768 WINPR_PRAGMA_DIAG_POP
2769 return nullptr;
2770}
2771
2772size_t update_approximate_cache_bitmap_v3_order(CACHE_BITMAP_V3_ORDER* cache_bitmap_v3,
2773 WINPR_ATTR_UNUSED UINT16* flags)
2774{
2775 BITMAP_DATA_EX* bitmapData = &cache_bitmap_v3->bitmapData;
2776 return 64 + bitmapData->length;
2777}
2778
2779BOOL update_write_cache_bitmap_v3_order(wStream* s, CACHE_BITMAP_V3_ORDER* cache_bitmap_v3,
2780 UINT16* flags)
2781{
2782 BOOL rc = 0;
2783 BYTE bitsPerPixelId = 0;
2784 BITMAP_DATA_EX* bitmapData = nullptr;
2785
2786 if (!Stream_EnsureRemainingCapacity(
2787 s, update_approximate_cache_bitmap_v3_order(cache_bitmap_v3, flags)))
2788 return FALSE;
2789
2790 bitmapData = &cache_bitmap_v3->bitmapData;
2791 bitsPerPixelId = get_bpp_bmf(cache_bitmap_v3->bpp, &rc);
2792 if (!rc)
2793 return FALSE;
2794 *flags = (cache_bitmap_v3->cacheId & 0x00000007) |
2795 ((cache_bitmap_v3->flags << 7) & 0x0000FF80) | ((bitsPerPixelId << 3) & 0x00000078);
2796 Stream_Write_UINT16(s,
2797 get_checked_uint16(cache_bitmap_v3->cacheIndex)); /* cacheIndex (2 bytes) */
2798 Stream_Write_UINT32(s, cache_bitmap_v3->key1); /* key1 (4 bytes) */
2799 Stream_Write_UINT32(s, cache_bitmap_v3->key2); /* key2 (4 bytes) */
2800 Stream_Write_UINT8(s, get_checked_uint8(bitmapData->bpp));
2801 Stream_Write_UINT8(s, 0); /* reserved1 (1 byte) */
2802 Stream_Write_UINT8(s, 0); /* reserved2 (1 byte) */
2803 Stream_Write_UINT8(s, get_checked_uint8(bitmapData->codecID)); /* codecID (1 byte) */
2804 Stream_Write_UINT16(s, get_checked_uint16(bitmapData->width)); /* width (2 bytes) */
2805 Stream_Write_UINT16(s, get_checked_uint16(bitmapData->height)); /* height (2 bytes) */
2806 Stream_Write_UINT32(s, bitmapData->length); /* length (4 bytes) */
2807 Stream_Write(s, bitmapData->data, bitmapData->length);
2808 return TRUE;
2809}
2810
2811WINPR_ATTR_MALLOC(free_cache_color_table_order, 2)
2812WINPR_ATTR_NODISCARD
2813static CACHE_COLOR_TABLE_ORDER* update_read_cache_color_table_order(rdpUpdate* update, wStream* s,
2814 WINPR_ATTR_UNUSED UINT16 flags)
2815{
2816 UINT32* colorTable = nullptr;
2817 CACHE_COLOR_TABLE_ORDER* cache_color_table = calloc(1, sizeof(CACHE_COLOR_TABLE_ORDER));
2818
2819 if (!cache_color_table)
2820 goto fail;
2821
2822 if (!Stream_CheckAndLogRequiredLength(TAG, s, 3))
2823 goto fail;
2824
2825 Stream_Read_UINT8(s, cache_color_table->cacheIndex); /* cacheIndex (1 byte) */
2826 Stream_Read_UINT16(s, cache_color_table->numberColors); /* numberColors (2 bytes) */
2827
2828 if (cache_color_table->numberColors != 256)
2829 {
2830 /* This field MUST be set to 256 */
2831 goto fail;
2832 }
2833
2834 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, cache_color_table->numberColors, 4ull))
2835 goto fail;
2836
2837 colorTable = (UINT32*)&cache_color_table->colorTable;
2838
2839 for (UINT32 i = 0; i < cache_color_table->numberColors; i++)
2840 update_read_color_quad(s, &colorTable[i]);
2841
2842 return cache_color_table;
2843fail:
2844 WINPR_PRAGMA_DIAG_PUSH
2845 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2846 free_cache_color_table_order(update->context, cache_color_table);
2847 WINPR_PRAGMA_DIAG_POP
2848 return nullptr;
2849}
2850
2851size_t update_approximate_cache_color_table_order(const CACHE_COLOR_TABLE_ORDER* cache_color_table,
2852 const UINT16* flags)
2853{
2854 WINPR_UNUSED(cache_color_table);
2855 WINPR_UNUSED(flags);
2856
2857 return 16 + (256 * 4);
2858}
2859
2860BOOL update_write_cache_color_table_order(wStream* s,
2861 const CACHE_COLOR_TABLE_ORDER* cache_color_table,
2862 UINT16* flags)
2863{
2864 size_t inf = 0;
2865 const UINT32* colorTable = nullptr;
2866
2867 if (cache_color_table->numberColors != 256)
2868 return FALSE;
2869
2870 inf = update_approximate_cache_color_table_order(cache_color_table, flags);
2871
2872 if (!Stream_EnsureRemainingCapacity(s, inf))
2873 return FALSE;
2874
2875 Stream_Write_UINT8(s,
2876 get_checked_uint8(cache_color_table->cacheIndex)); /* cacheIndex (1 byte) */
2877 Stream_Write_UINT16(
2878 s, get_checked_uint16(cache_color_table->numberColors)); /* numberColors (2 bytes) */
2879 colorTable = (const UINT32*)&cache_color_table->colorTable;
2880
2881 for (size_t i = 0; i < cache_color_table->numberColors; i++)
2882 {
2883 update_write_color_quad(s, colorTable[i]);
2884 }
2885
2886 return TRUE;
2887}
2888static CACHE_GLYPH_ORDER* update_read_cache_glyph_order(rdpUpdate* update, wStream* s, UINT16 flags)
2889{
2890 CACHE_GLYPH_ORDER* cache_glyph_order = calloc(1, sizeof(CACHE_GLYPH_ORDER));
2891
2892 WINPR_ASSERT(update);
2893 WINPR_ASSERT(s);
2894
2895 if (!cache_glyph_order)
2896 goto fail;
2897
2898 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
2899 goto fail;
2900
2901 Stream_Read_UINT8(s, cache_glyph_order->cacheId); /* cacheId (1 byte) */
2902 Stream_Read_UINT8(s, cache_glyph_order->cGlyphs); /* cGlyphs (1 byte) */
2903
2904 for (UINT32 i = 0; i < cache_glyph_order->cGlyphs; i++)
2905 {
2906 GLYPH_DATA* glyph = &cache_glyph_order->glyphData[i];
2907
2908 if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
2909 goto fail;
2910
2911 Stream_Read_UINT16(s, glyph->cacheIndex);
2912 Stream_Read_INT16(s, glyph->x);
2913 Stream_Read_INT16(s, glyph->y);
2914 Stream_Read_UINT16(s, glyph->cx);
2915 Stream_Read_UINT16(s, glyph->cy);
2916 glyph->cb = ((glyph->cx + 7) / 8) * glyph->cy;
2917 glyph->cb += ((glyph->cb % 4) > 0) ? 4 - (glyph->cb % 4) : 0;
2918
2919 if (!Stream_CheckAndLogRequiredLength(TAG, s, glyph->cb))
2920 goto fail;
2921
2922 glyph->aj = (BYTE*)malloc(glyph->cb);
2923
2924 if (!glyph->aj)
2925 goto fail;
2926
2927 Stream_Read(s, glyph->aj, glyph->cb);
2928 }
2929
2930 if ((flags & CG_GLYPH_UNICODE_PRESENT) && (cache_glyph_order->cGlyphs > 0))
2931 {
2932 cache_glyph_order->unicodeCharacters = calloc(cache_glyph_order->cGlyphs, sizeof(WCHAR));
2933
2934 if (!cache_glyph_order->unicodeCharacters)
2935 goto fail;
2936
2937 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, cache_glyph_order->cGlyphs,
2938 sizeof(WCHAR)))
2939 goto fail;
2940
2941 if (!Stream_Read_UTF16_String(s, cache_glyph_order->unicodeCharacters,
2942 cache_glyph_order->cGlyphs))
2943 goto fail;
2944 }
2945
2946 return cache_glyph_order;
2947fail:
2948 free_cache_glyph_order(update->context, cache_glyph_order);
2949 return nullptr;
2950}
2951
2952size_t update_approximate_cache_glyph_order(const CACHE_GLYPH_ORDER* cache_glyph,
2953 const UINT16* flags)
2954{
2955 WINPR_ASSERT(cache_glyph);
2956 WINPR_UNUSED(flags);
2957 return 2 + cache_glyph->cGlyphs * 32;
2958}
2959
2960BOOL update_write_cache_glyph_order(wStream* s, const CACHE_GLYPH_ORDER* cache_glyph, UINT16* flags)
2961{
2962 const GLYPH_DATA* glyph = nullptr;
2963 size_t inf = update_approximate_cache_glyph_order(cache_glyph, flags);
2964
2965 if (!Stream_EnsureRemainingCapacity(s, inf))
2966 return FALSE;
2967
2968 Stream_Write_UINT8(s, get_checked_uint8(cache_glyph->cacheId)); /* cacheId (1 byte) */
2969 Stream_Write_UINT8(s, get_checked_uint8(cache_glyph->cGlyphs)); /* cGlyphs (1 byte) */
2970
2971 for (UINT32 i = 0; i < cache_glyph->cGlyphs; i++)
2972 {
2973 UINT32 cb = 0;
2974 glyph = &cache_glyph->glyphData[i];
2975 Stream_Write_UINT16(s, get_checked_uint16(glyph->cacheIndex)); /* cacheIndex (2 bytes) */
2976 Stream_Write_INT16(s, glyph->x); /* x (2 bytes) */
2977 Stream_Write_INT16(s, glyph->y); /* y (2 bytes) */
2978 Stream_Write_UINT16(s, get_checked_uint16(glyph->cx)); /* cx (2 bytes) */
2979 Stream_Write_UINT16(s, get_checked_uint16(glyph->cy)); /* cy (2 bytes) */
2980 cb = ((glyph->cx + 7) / 8) * glyph->cy;
2981 cb += ((cb % 4) > 0) ? 4 - (cb % 4) : 0;
2982 Stream_Write(s, glyph->aj, cb);
2983 }
2984
2985 if (*flags & CG_GLYPH_UNICODE_PRESENT)
2986 {
2987 Stream_Zero(s, 2ULL * cache_glyph->cGlyphs);
2988 }
2989
2990 return TRUE;
2991}
2992
2993static CACHE_GLYPH_V2_ORDER* update_read_cache_glyph_v2_order(rdpUpdate* update, wStream* s,
2994 UINT16 flags)
2995{
2996 CACHE_GLYPH_V2_ORDER* cache_glyph_v2 = calloc(1, sizeof(CACHE_GLYPH_V2_ORDER));
2997
2998 if (!cache_glyph_v2)
2999 goto fail;
3000
3001 cache_glyph_v2->cacheId = (flags & 0x000F);
3002 cache_glyph_v2->flags = (flags & 0x00F0) >> 4;
3003 cache_glyph_v2->cGlyphs = (flags & 0xFF00) >> 8;
3004
3005 for (UINT32 i = 0; i < cache_glyph_v2->cGlyphs; i++)
3006 {
3007 GLYPH_DATA_V2* glyph = &cache_glyph_v2->glyphData[i];
3008
3009 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
3010 goto fail;
3011
3012 Stream_Read_UINT8(s, glyph->cacheIndex);
3013
3014 if (!update_read_2byte_signed(s, &glyph->x) || !update_read_2byte_signed(s, &glyph->y) ||
3015 !update_read_2byte_unsigned(s, &glyph->cx) ||
3016 !update_read_2byte_unsigned(s, &glyph->cy))
3017 {
3018 goto fail;
3019 }
3020
3021 glyph->cb = ((glyph->cx + 7) / 8) * glyph->cy;
3022 glyph->cb += ((glyph->cb % 4) > 0) ? 4 - (glyph->cb % 4) : 0;
3023
3024 if (!Stream_CheckAndLogRequiredLength(TAG, s, glyph->cb))
3025 goto fail;
3026
3027 glyph->aj = (BYTE*)malloc(glyph->cb);
3028
3029 if (!glyph->aj)
3030 goto fail;
3031
3032 Stream_Read(s, glyph->aj, glyph->cb);
3033 }
3034
3035 if ((flags & CG_GLYPH_UNICODE_PRESENT) && (cache_glyph_v2->cGlyphs > 0))
3036 {
3037 cache_glyph_v2->unicodeCharacters = calloc(cache_glyph_v2->cGlyphs, sizeof(WCHAR));
3038
3039 if (!cache_glyph_v2->unicodeCharacters)
3040 goto fail;
3041
3042 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, cache_glyph_v2->cGlyphs, sizeof(WCHAR)))
3043 goto fail;
3044
3045 if (!Stream_Read_UTF16_String(s, cache_glyph_v2->unicodeCharacters,
3046 cache_glyph_v2->cGlyphs))
3047 goto fail;
3048 }
3049
3050 return cache_glyph_v2;
3051fail:
3052 free_cache_glyph_v2_order(update->context, cache_glyph_v2);
3053 return nullptr;
3054}
3055
3056size_t update_approximate_cache_glyph_v2_order(const CACHE_GLYPH_V2_ORDER* cache_glyph_v2,
3057 const UINT16* flags)
3058{
3059 WINPR_ASSERT(cache_glyph_v2);
3060 WINPR_UNUSED(flags);
3061 return 8 + cache_glyph_v2->cGlyphs * 32;
3062}
3063
3064BOOL update_write_cache_glyph_v2_order(wStream* s, const CACHE_GLYPH_V2_ORDER* cache_glyph_v2,
3065 UINT16* flags)
3066{
3067 size_t inf = update_approximate_cache_glyph_v2_order(cache_glyph_v2, flags);
3068
3069 if (!Stream_EnsureRemainingCapacity(s, inf))
3070 return FALSE;
3071
3072 WINPR_ASSERT(cache_glyph_v2->cacheId <= 0x0F);
3073 WINPR_ASSERT(cache_glyph_v2->flags <= 0x0F);
3074 WINPR_ASSERT(cache_glyph_v2->cGlyphs <= 0xFF);
3075 *flags = (UINT16)((cache_glyph_v2->cacheId & 0x000F) | ((cache_glyph_v2->flags & 0x000F) << 4) |
3076 ((cache_glyph_v2->cGlyphs & 0x00FF) << 8));
3077
3078 for (UINT32 i = 0; i < cache_glyph_v2->cGlyphs; i++)
3079 {
3080 UINT32 cb = 0;
3081 const GLYPH_DATA_V2* glyph = &cache_glyph_v2->glyphData[i];
3082 Stream_Write_UINT8(s, get_checked_uint8(glyph->cacheIndex));
3083
3084 if (!update_write_2byte_signed(s, glyph->x) || !update_write_2byte_signed(s, glyph->y) ||
3085 !update_write_2byte_unsigned(s, glyph->cx) ||
3086 !update_write_2byte_unsigned(s, glyph->cy))
3087 {
3088 return FALSE;
3089 }
3090
3091 cb = ((glyph->cx + 7) / 8) * glyph->cy;
3092 cb += ((cb % 4) > 0) ? 4 - (cb % 4) : 0;
3093 Stream_Write(s, glyph->aj, cb);
3094 }
3095
3096 if (*flags & CG_GLYPH_UNICODE_PRESENT)
3097 {
3098 Stream_Zero(s, 2ULL * cache_glyph_v2->cGlyphs);
3099 }
3100
3101 return TRUE;
3102}
3103static BOOL update_decompress_brush(wStream* s, BYTE* output, size_t outSize, BYTE bpp)
3104{
3105 BYTE byte = 0;
3106 const BYTE* palette = Stream_PointerAs(s, const BYTE) + 16;
3107 const size_t bytesPerPixel = ((bpp + 1) / 8);
3108
3109 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, 4ULL + bytesPerPixel, 4ULL))
3110 return FALSE;
3111
3112 for (size_t y = 0; y < 8; y++)
3113 {
3114 for (size_t x = 0; x < 8; x++)
3115 {
3116 if ((x % 4) == 0)
3117 Stream_Read_UINT8(s, byte);
3118
3119 const uint32_t index = ((byte >> ((3 - (x % 4)) * 2)) & 0x03);
3120
3121 for (size_t k = 0; k < bytesPerPixel; k++)
3122 {
3123 const size_t dstIndex = ((8ULL * (7ULL - y) + x) * bytesPerPixel) + k;
3124 const size_t srcIndex = (index * bytesPerPixel) + k;
3125 if (dstIndex >= outSize)
3126 return FALSE;
3127 output[dstIndex] = palette[srcIndex];
3128 }
3129 }
3130 }
3131
3132 return TRUE;
3133}
3134static BOOL update_compress_brush(WINPR_ATTR_UNUSED wStream* s, WINPR_ATTR_UNUSED const BYTE* input,
3135 WINPR_ATTR_UNUSED BYTE bpp)
3136{
3137 return FALSE;
3138}
3139static CACHE_BRUSH_ORDER* update_read_cache_brush_order(rdpUpdate* update, wStream* s,
3140 WINPR_ATTR_UNUSED UINT16 flags)
3141{
3142 BOOL rc = 0;
3143 BYTE iBitmapFormat = 0;
3144 BOOL compressed = FALSE;
3145 rdp_update_internal* up = update_cast(update);
3146 CACHE_BRUSH_ORDER* cache_brush = calloc(1, sizeof(CACHE_BRUSH_ORDER));
3147
3148 if (!cache_brush)
3149 goto fail;
3150
3151 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
3152 goto fail;
3153
3154 Stream_Read_UINT8(s, cache_brush->index); /* cacheEntry (1 byte) */
3155 Stream_Read_UINT8(s, iBitmapFormat); /* iBitmapFormat (1 byte) */
3156
3157 cache_brush->bpp = get_bmf_bpp(iBitmapFormat, &rc);
3158 if (!rc)
3159 goto fail;
3160
3161 Stream_Read_UINT8(s, cache_brush->cx); /* cx (1 byte) */
3162 Stream_Read_UINT8(s, cache_brush->cy); /* cy (1 byte) */
3163 /* according to Section 2.2.2.2.1.2.7 errata the windows implementation sets this filed is set
3164 * to 0x00 */
3165 Stream_Read_UINT8(s, cache_brush->style); /* style (1 byte) */
3166 Stream_Read_UINT8(s, cache_brush->length); /* iBytes (1 byte) */
3167
3168 if ((cache_brush->cx == 8) && (cache_brush->cy == 8))
3169 {
3170 if (cache_brush->bpp == 1)
3171 {
3172 if (cache_brush->length != 8)
3173 {
3174 WLog_Print(up->log, WLOG_ERROR, "incompatible 1bpp brush of length:%" PRIu32 "",
3175 cache_brush->length);
3176 goto fail;
3177 }
3178
3179 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
3180 goto fail;
3181
3182 /* rows are encoded in reverse order */
3183 for (int i = 7; i >= 0; i--)
3184 Stream_Read_UINT8(s, cache_brush->data[i]);
3185 }
3186 else
3187 {
3188 if ((iBitmapFormat == BMF_8BPP) && (cache_brush->length == 20))
3189 compressed = TRUE;
3190 else if ((iBitmapFormat == BMF_16BPP) && (cache_brush->length == 24))
3191 compressed = TRUE;
3192 else if ((iBitmapFormat == BMF_24BPP) && (cache_brush->length == 28))
3193 compressed = TRUE;
3194 else if ((iBitmapFormat == BMF_32BPP) && (cache_brush->length == 32))
3195 compressed = TRUE;
3196
3197 if (compressed != FALSE)
3198 {
3199 /* compressed brush */
3200 if (!update_decompress_brush(s, cache_brush->data, sizeof(cache_brush->data),
3201 get_checked_uint8(cache_brush->bpp)))
3202 goto fail;
3203 }
3204 else
3205 {
3206 /* uncompressed brush */
3207 UINT32 scanline = (cache_brush->bpp / 8) * 8;
3208
3209 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, scanline, 8ull))
3210 goto fail;
3211
3212 for (int i = 7; i >= 0; i--)
3213 {
3214 Stream_Read(s, &cache_brush->data[1LL * i * scanline], scanline);
3215 }
3216 }
3217 }
3218 }
3219
3220 return cache_brush;
3221fail:
3222 free_cache_brush_order(update->context, cache_brush);
3223 return nullptr;
3224}
3225
3226size_t update_approximate_cache_brush_order(const CACHE_BRUSH_ORDER* cache_brush,
3227 const UINT16* flags)
3228{
3229 WINPR_UNUSED(cache_brush);
3230 WINPR_UNUSED(flags);
3231
3232 return 64;
3233}
3234
3235BOOL update_write_cache_brush_order(wStream* s, const CACHE_BRUSH_ORDER* cache_brush, UINT16* flags)
3236{
3237 BYTE iBitmapFormat = 0;
3238 BOOL rc = 0;
3239 BOOL compressed = FALSE;
3240
3241 if (!Stream_EnsureRemainingCapacity(s,
3242 update_approximate_cache_brush_order(cache_brush, flags)))
3243 return FALSE;
3244
3245 iBitmapFormat = get_bpp_bmf(cache_brush->bpp, &rc);
3246 if (!rc)
3247 return FALSE;
3248 Stream_Write_UINT8(s, get_checked_uint8(cache_brush->index)); /* cacheEntry (1 byte) */
3249 Stream_Write_UINT8(s, iBitmapFormat); /* iBitmapFormat (1 byte) */
3250 Stream_Write_UINT8(s, get_checked_uint8(cache_brush->cx)); /* cx (1 byte) */
3251 Stream_Write_UINT8(s, get_checked_uint8(cache_brush->cy)); /* cy (1 byte) */
3252 Stream_Write_UINT8(s, get_checked_uint8(cache_brush->style)); /* style (1 byte) */
3253 Stream_Write_UINT8(s, get_checked_uint8(cache_brush->length)); /* iBytes (1 byte) */
3254
3255 if ((cache_brush->cx == 8) && (cache_brush->cy == 8))
3256 {
3257 if (cache_brush->bpp == 1)
3258 {
3259 if (cache_brush->length != 8)
3260 {
3261 WLog_ERR(TAG, "incompatible 1bpp brush of length:%" PRIu32 "", cache_brush->length);
3262 return FALSE;
3263 }
3264
3265 for (int i = 7; i >= 0; i--)
3266 {
3267 Stream_Write_UINT8(s, cache_brush->data[i]);
3268 }
3269 }
3270 else
3271 {
3272 if ((iBitmapFormat == BMF_8BPP) && (cache_brush->length == 20))
3273 compressed = TRUE;
3274 else if ((iBitmapFormat == BMF_16BPP) && (cache_brush->length == 24))
3275 compressed = TRUE;
3276 else if ((iBitmapFormat == BMF_32BPP) && (cache_brush->length == 32))
3277 compressed = TRUE;
3278
3279 if (compressed != FALSE)
3280 {
3281 /* compressed brush */
3282 if (!update_compress_brush(s, cache_brush->data,
3283 get_checked_uint8(cache_brush->bpp)))
3284 return FALSE;
3285 }
3286 else
3287 {
3288 /* uncompressed brush */
3289 const size_t scanline = 8ULL * (cache_brush->bpp / 8);
3290
3291 for (size_t i = 0; i <= 7; i++)
3292 {
3293 Stream_Write(s, &cache_brush->data[1LL * (7 - i) * scanline], scanline);
3294 }
3295 }
3296 }
3297 }
3298
3299 return TRUE;
3300}
3301/* Alternate Secondary Drawing Orders */
3302static BOOL
3303update_read_create_offscreen_bitmap_order(wStream* s,
3304 CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
3305{
3306 UINT16 flags = 0;
3307 BOOL deleteListPresent = 0;
3308 OFFSCREEN_DELETE_LIST* deleteList = nullptr;
3309
3310 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
3311 return FALSE;
3312
3313 Stream_Read_UINT16(s, flags); /* flags (2 bytes) */
3314 create_offscreen_bitmap->id = flags & 0x7FFF;
3315 deleteListPresent = (flags & 0x8000) != 0;
3316 Stream_Read_UINT16(s, create_offscreen_bitmap->cx); /* cx (2 bytes) */
3317 Stream_Read_UINT16(s, create_offscreen_bitmap->cy); /* cy (2 bytes) */
3318 deleteList = &(create_offscreen_bitmap->deleteList);
3319
3320 if ((create_offscreen_bitmap->cx == 0) || (create_offscreen_bitmap->cy == 0))
3321 {
3322 WLog_ERR(TAG, "Invalid OFFSCREEN_DELETE_LIST: cx=%" PRIu16 ", cy=%" PRIu16,
3323 create_offscreen_bitmap->cx, create_offscreen_bitmap->cy);
3324 return FALSE;
3325 }
3326
3327 if (deleteListPresent)
3328 {
3329 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
3330 return FALSE;
3331
3332 Stream_Read_UINT16(s, deleteList->cIndices);
3333
3334 if (deleteList->cIndices > deleteList->sIndices)
3335 {
3336 UINT16* new_indices = nullptr;
3337 new_indices = (UINT16*)realloc(deleteList->indices, 2ULL * deleteList->cIndices);
3338
3339 if (!new_indices)
3340 return FALSE;
3341
3342 deleteList->sIndices = deleteList->cIndices;
3343 deleteList->indices = new_indices;
3344 }
3345
3346 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, deleteList->cIndices, 2ull))
3347 return FALSE;
3348
3349 for (UINT32 i = 0; i < deleteList->cIndices; i++)
3350 {
3351 Stream_Read_UINT16(s, deleteList->indices[i]);
3352 }
3353 }
3354 else
3355 {
3356 deleteList->cIndices = 0;
3357 }
3358
3359 return TRUE;
3360}
3361
3362size_t update_approximate_create_offscreen_bitmap_order(
3363 const CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
3364{
3365 const OFFSCREEN_DELETE_LIST* deleteList = nullptr;
3366
3367 WINPR_ASSERT(create_offscreen_bitmap);
3368
3369 deleteList = &(create_offscreen_bitmap->deleteList);
3370 WINPR_ASSERT(deleteList);
3371
3372 return 32ull + deleteList->cIndices * 2ull;
3373}
3374
3375BOOL update_write_create_offscreen_bitmap_order(
3376 wStream* s, const CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
3377{
3378 UINT16 flags = 0;
3379 BOOL deleteListPresent = 0;
3380 const OFFSCREEN_DELETE_LIST* deleteList = nullptr;
3381
3382 if (!Stream_EnsureRemainingCapacity(
3383 s, update_approximate_create_offscreen_bitmap_order(create_offscreen_bitmap)))
3384 return FALSE;
3385
3386 deleteList = &(create_offscreen_bitmap->deleteList);
3387 flags = create_offscreen_bitmap->id & 0x7FFF;
3388 deleteListPresent = (deleteList->cIndices > 0);
3389
3390 if (deleteListPresent)
3391 flags |= 0x8000;
3392
3393 Stream_Write_UINT16(s, flags); /* flags (2 bytes) */
3394 Stream_Write_UINT16(s, get_checked_uint16(create_offscreen_bitmap->cx)); /* cx (2 bytes) */
3395 Stream_Write_UINT16(s, get_checked_uint16(create_offscreen_bitmap->cy)); /* cy (2 bytes) */
3396
3397 if (deleteListPresent)
3398 {
3399 Stream_Write_UINT16(s, get_checked_uint16(deleteList->cIndices));
3400
3401 for (size_t i = 0; i < deleteList->cIndices; i++)
3402 {
3403 Stream_Write_UINT16(s, deleteList->indices[i]);
3404 }
3405 }
3406
3407 return TRUE;
3408}
3409static BOOL update_read_switch_surface_order(wStream* s, SWITCH_SURFACE_ORDER* switch_surface)
3410{
3411 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
3412 return FALSE;
3413
3414 Stream_Read_UINT16(s, switch_surface->bitmapId); /* bitmapId (2 bytes) */
3415 return TRUE;
3416}
3417size_t update_approximate_switch_surface_order(
3418 WINPR_ATTR_UNUSED const SWITCH_SURFACE_ORDER* switch_surface)
3419{
3420 return 2;
3421}
3422BOOL update_write_switch_surface_order(wStream* s, const SWITCH_SURFACE_ORDER* switch_surface)
3423{
3424 size_t inf = update_approximate_switch_surface_order(switch_surface);
3425
3426 if (!Stream_EnsureRemainingCapacity(s, inf))
3427 return FALSE;
3428
3429 WINPR_ASSERT(switch_surface->bitmapId <= UINT16_MAX);
3430 Stream_Write_UINT16(s, (UINT16)switch_surface->bitmapId); /* bitmapId (2 bytes) */
3431 return TRUE;
3432}
3433static BOOL
3434update_read_create_nine_grid_bitmap_order(wStream* s,
3435 CREATE_NINE_GRID_BITMAP_ORDER* create_nine_grid_bitmap)
3436{
3437 NINE_GRID_BITMAP_INFO* nineGridInfo = nullptr;
3438
3439 if (!Stream_CheckAndLogRequiredLength(TAG, s, 19))
3440 return FALSE;
3441
3442 Stream_Read_UINT8(s, create_nine_grid_bitmap->bitmapBpp); /* bitmapBpp (1 byte) */
3443
3444 if ((create_nine_grid_bitmap->bitmapBpp < 1) || (create_nine_grid_bitmap->bitmapBpp > 32))
3445 {
3446 WLog_ERR(TAG, "invalid bpp value %" PRIu32 "", create_nine_grid_bitmap->bitmapBpp);
3447 return FALSE;
3448 }
3449
3450 Stream_Read_UINT16(s, create_nine_grid_bitmap->bitmapId); /* bitmapId (2 bytes) */
3451 nineGridInfo = &(create_nine_grid_bitmap->nineGridInfo);
3452 Stream_Read_UINT32(s, nineGridInfo->flFlags); /* flFlags (4 bytes) */
3453 Stream_Read_UINT16(s, nineGridInfo->ulLeftWidth); /* ulLeftWidth (2 bytes) */
3454 Stream_Read_UINT16(s, nineGridInfo->ulRightWidth); /* ulRightWidth (2 bytes) */
3455 Stream_Read_UINT16(s, nineGridInfo->ulTopHeight); /* ulTopHeight (2 bytes) */
3456 Stream_Read_UINT16(s, nineGridInfo->ulBottomHeight); /* ulBottomHeight (2 bytes) */
3457 update_read_colorref(s, &nineGridInfo->crTransparent); /* crTransparent (4 bytes) */
3458 return TRUE;
3459}
3460static BOOL update_read_frame_marker_order(wStream* s, FRAME_MARKER_ORDER* frame_marker)
3461{
3462 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
3463 return FALSE;
3464
3465 Stream_Read_UINT32(s, frame_marker->action); /* action (4 bytes) */
3466 return TRUE;
3467}
3468static BOOL update_read_stream_bitmap_first_order(wStream* s,
3469 STREAM_BITMAP_FIRST_ORDER* stream_bitmap_first)
3470{
3471 if (!Stream_CheckAndLogRequiredLength(TAG, s, 10)) // 8 + 2 at least
3472 return FALSE;
3473
3474 Stream_Read_UINT8(s, stream_bitmap_first->bitmapFlags); /* bitmapFlags (1 byte) */
3475 Stream_Read_UINT8(s, stream_bitmap_first->bitmapBpp); /* bitmapBpp (1 byte) */
3476
3477 if ((stream_bitmap_first->bitmapBpp < 1) || (stream_bitmap_first->bitmapBpp > 32))
3478 {
3479 WLog_ERR(TAG, "invalid bpp value %" PRIu32 "", stream_bitmap_first->bitmapBpp);
3480 return FALSE;
3481 }
3482
3483 Stream_Read_UINT16(s, stream_bitmap_first->bitmapType); /* bitmapType (2 bytes) */
3484 Stream_Read_UINT16(s, stream_bitmap_first->bitmapWidth); /* bitmapWidth (2 bytes) */
3485 Stream_Read_UINT16(s, stream_bitmap_first->bitmapHeight); /* bitmapHeight (2 bytes) */
3486
3487 if (stream_bitmap_first->bitmapFlags & STREAM_BITMAP_V2)
3488 {
3489 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
3490 return FALSE;
3491
3492 Stream_Read_UINT32(s, stream_bitmap_first->bitmapSize); /* bitmapSize (4 bytes) */
3493 }
3494 else
3495 {
3496 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
3497 return FALSE;
3498
3499 Stream_Read_UINT16(s, stream_bitmap_first->bitmapSize); /* bitmapSize (2 bytes) */
3500 }
3501
3502 FIELD_SKIP_BUFFER16(
3503 s, stream_bitmap_first->bitmapBlockSize); /* bitmapBlockSize(2 bytes) + bitmapBlock */
3504 return TRUE;
3505}
3506static BOOL update_read_stream_bitmap_next_order(wStream* s,
3507 STREAM_BITMAP_NEXT_ORDER* stream_bitmap_next)
3508{
3509 if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
3510 return FALSE;
3511
3512 Stream_Read_UINT8(s, stream_bitmap_next->bitmapFlags); /* bitmapFlags (1 byte) */
3513 Stream_Read_UINT16(s, stream_bitmap_next->bitmapType); /* bitmapType (2 bytes) */
3514 FIELD_SKIP_BUFFER16(
3515 s, stream_bitmap_next->bitmapBlockSize); /* bitmapBlockSize(2 bytes) + bitmapBlock */
3516 return TRUE;
3517}
3518static BOOL update_read_draw_gdiplus_first_order(wStream* s,
3519 DRAW_GDIPLUS_FIRST_ORDER* draw_gdiplus_first)
3520{
3521 if (!Stream_CheckAndLogRequiredLength(TAG, s, 11))
3522 return FALSE;
3523
3524 Stream_Seek_UINT8(s); /* pad1Octet (1 byte) */
3525 Stream_Read_UINT16(s, draw_gdiplus_first->cbSize); /* cbSize (2 bytes) */
3526 Stream_Read_UINT32(s, draw_gdiplus_first->cbTotalSize); /* cbTotalSize (4 bytes) */
3527 Stream_Read_UINT32(s, draw_gdiplus_first->cbTotalEmfSize); /* cbTotalEmfSize (4 bytes) */
3528 return Stream_SafeSeek(s, draw_gdiplus_first->cbSize); /* emfRecords */
3529}
3530static BOOL update_read_draw_gdiplus_next_order(wStream* s,
3531 DRAW_GDIPLUS_NEXT_ORDER* draw_gdiplus_next)
3532{
3533 if (!Stream_CheckAndLogRequiredLength(TAG, s, 3))
3534 return FALSE;
3535
3536 Stream_Seek_UINT8(s); /* pad1Octet (1 byte) */
3537 FIELD_SKIP_BUFFER16(s, draw_gdiplus_next->cbSize); /* cbSize(2 bytes) + emfRecords */
3538 return TRUE;
3539}
3540static BOOL update_read_draw_gdiplus_end_order(wStream* s, DRAW_GDIPLUS_END_ORDER* draw_gdiplus_end)
3541{
3542 if (!Stream_CheckAndLogRequiredLength(TAG, s, 11))
3543 return FALSE;
3544
3545 Stream_Seek_UINT8(s); /* pad1Octet (1 byte) */
3546 Stream_Read_UINT16(s, draw_gdiplus_end->cbSize); /* cbSize (2 bytes) */
3547 Stream_Read_UINT32(s, draw_gdiplus_end->cbTotalSize); /* cbTotalSize (4 bytes) */
3548 Stream_Read_UINT32(s, draw_gdiplus_end->cbTotalEmfSize); /* cbTotalEmfSize (4 bytes) */
3549 return Stream_SafeSeek(s, draw_gdiplus_end->cbSize); /* emfRecords */
3550}
3551static BOOL
3552update_read_draw_gdiplus_cache_first_order(wStream* s,
3553 DRAW_GDIPLUS_CACHE_FIRST_ORDER* draw_gdiplus_cache_first)
3554{
3555 if (!Stream_CheckAndLogRequiredLength(TAG, s, 11))
3556 return FALSE;
3557
3558 Stream_Read_UINT8(s, draw_gdiplus_cache_first->flags); /* flags (1 byte) */
3559 Stream_Read_UINT16(s, draw_gdiplus_cache_first->cacheType); /* cacheType (2 bytes) */
3560 Stream_Read_UINT16(s, draw_gdiplus_cache_first->cacheIndex); /* cacheIndex (2 bytes) */
3561 Stream_Read_UINT16(s, draw_gdiplus_cache_first->cbSize); /* cbSize (2 bytes) */
3562 Stream_Read_UINT32(s, draw_gdiplus_cache_first->cbTotalSize); /* cbTotalSize (4 bytes) */
3563 return Stream_SafeSeek(s, draw_gdiplus_cache_first->cbSize); /* emfRecords */
3564}
3565static BOOL
3566update_read_draw_gdiplus_cache_next_order(wStream* s,
3567 DRAW_GDIPLUS_CACHE_NEXT_ORDER* draw_gdiplus_cache_next)
3568{
3569 if (!Stream_CheckAndLogRequiredLength(TAG, s, 7))
3570 return FALSE;
3571
3572 Stream_Read_UINT8(s, draw_gdiplus_cache_next->flags); /* flags (1 byte) */
3573 Stream_Read_UINT16(s, draw_gdiplus_cache_next->cacheType); /* cacheType (2 bytes) */
3574 Stream_Read_UINT16(s, draw_gdiplus_cache_next->cacheIndex); /* cacheIndex (2 bytes) */
3575 FIELD_SKIP_BUFFER16(s, draw_gdiplus_cache_next->cbSize); /* cbSize(2 bytes) + emfRecords */
3576 return TRUE;
3577}
3578static BOOL
3579update_read_draw_gdiplus_cache_end_order(wStream* s,
3580 DRAW_GDIPLUS_CACHE_END_ORDER* draw_gdiplus_cache_end)
3581{
3582 if (!Stream_CheckAndLogRequiredLength(TAG, s, 11))
3583 return FALSE;
3584
3585 Stream_Read_UINT8(s, draw_gdiplus_cache_end->flags); /* flags (1 byte) */
3586 Stream_Read_UINT16(s, draw_gdiplus_cache_end->cacheType); /* cacheType (2 bytes) */
3587 Stream_Read_UINT16(s, draw_gdiplus_cache_end->cacheIndex); /* cacheIndex (2 bytes) */
3588 Stream_Read_UINT16(s, draw_gdiplus_cache_end->cbSize); /* cbSize (2 bytes) */
3589 Stream_Read_UINT32(s, draw_gdiplus_cache_end->cbTotalSize); /* cbTotalSize (4 bytes) */
3590 return Stream_SafeSeek(s, draw_gdiplus_cache_end->cbSize); /* emfRecords */
3591}
3592static BOOL update_read_field_flags(wStream* s, UINT32* fieldFlags, BYTE flags, BYTE fieldBytes)
3593{
3594 if (flags & ORDER_ZERO_FIELD_BYTE_BIT0)
3595 fieldBytes--;
3596
3597 if (flags & ORDER_ZERO_FIELD_BYTE_BIT1)
3598 {
3599 if (fieldBytes > 1)
3600 fieldBytes -= 2;
3601 else
3602 fieldBytes = 0;
3603 }
3604
3605 if (!Stream_CheckAndLogRequiredLength(TAG, s, fieldBytes))
3606 return FALSE;
3607
3608 *fieldFlags = 0;
3609
3610 for (size_t i = 0; i < fieldBytes; i++)
3611 {
3612 const UINT32 byte = Stream_Get_UINT8(s);
3613 *fieldFlags |= (byte << (i * 8ULL)) & 0xFFFFFFFF;
3614 }
3615
3616 return TRUE;
3617}
3618BOOL update_write_field_flags(wStream* s, UINT32 fieldFlags, WINPR_ATTR_UNUSED BYTE flags,
3619 BYTE fieldBytes)
3620{
3621 BYTE byte = 0;
3622
3623 if (fieldBytes == 1)
3624 {
3625 byte = fieldFlags & 0xFF;
3626 Stream_Write_UINT8(s, byte);
3627 }
3628 else if (fieldBytes == 2)
3629 {
3630 byte = fieldFlags & 0xFF;
3631 Stream_Write_UINT8(s, byte);
3632 byte = (fieldFlags >> 8) & 0xFF;
3633 Stream_Write_UINT8(s, byte);
3634 }
3635 else if (fieldBytes == 3)
3636 {
3637 byte = fieldFlags & 0xFF;
3638 Stream_Write_UINT8(s, byte);
3639 byte = (fieldFlags >> 8) & 0xFF;
3640 Stream_Write_UINT8(s, byte);
3641 byte = (fieldFlags >> 16) & 0xFF;
3642 Stream_Write_UINT8(s, byte);
3643 }
3644 else
3645 {
3646 return FALSE;
3647 }
3648
3649 return TRUE;
3650}
3651static BOOL update_read_bounds(wStream* s, rdpBounds* bounds)
3652{
3653 BYTE flags = 0;
3654
3655 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
3656 return FALSE;
3657
3658 Stream_Read_UINT8(s, flags); /* field flags */
3659
3660 if (flags & BOUND_LEFT)
3661 {
3662 if (!update_read_coord(s, &bounds->left, FALSE))
3663 return FALSE;
3664 }
3665 else if (flags & BOUND_DELTA_LEFT)
3666 {
3667 if (!update_read_coord(s, &bounds->left, TRUE))
3668 return FALSE;
3669 }
3670
3671 if (flags & BOUND_TOP)
3672 {
3673 if (!update_read_coord(s, &bounds->top, FALSE))
3674 return FALSE;
3675 }
3676 else if (flags & BOUND_DELTA_TOP)
3677 {
3678 if (!update_read_coord(s, &bounds->top, TRUE))
3679 return FALSE;
3680 }
3681
3682 if (flags & BOUND_RIGHT)
3683 {
3684 if (!update_read_coord(s, &bounds->right, FALSE))
3685 return FALSE;
3686 }
3687 else if (flags & BOUND_DELTA_RIGHT)
3688 {
3689 if (!update_read_coord(s, &bounds->right, TRUE))
3690 return FALSE;
3691 }
3692
3693 if (flags & BOUND_BOTTOM)
3694 {
3695 if (!update_read_coord(s, &bounds->bottom, FALSE))
3696 return FALSE;
3697 }
3698 else if (flags & BOUND_DELTA_BOTTOM)
3699 {
3700 if (!update_read_coord(s, &bounds->bottom, TRUE))
3701 return FALSE;
3702 }
3703
3704 if (bounds->left > bounds->right)
3705 return FALSE;
3706 if (bounds->top > bounds->bottom)
3707 return FALSE;
3708 const INT64 w = 1ll * bounds->right - bounds->left;
3709 if ((w <= INT32_MIN) || (w >= INT32_MAX))
3710 return FALSE;
3711 const INT64 h = 1ll * bounds->bottom - bounds->top;
3712 return !((h <= INT32_MIN) || (h >= INT32_MAX));
3713}
3714BOOL update_write_bounds(wStream* s, const ORDER_INFO* orderInfo)
3715{
3716 WINPR_ASSERT(orderInfo);
3717
3718 if (!(orderInfo->controlFlags & ORDER_BOUNDS))
3719 return TRUE;
3720
3721 if (orderInfo->controlFlags & ORDER_ZERO_BOUNDS_DELTAS)
3722 return TRUE;
3723
3724 Stream_Write_UINT8(s, get_checked_uint8(orderInfo->boundsFlags)); /* field flags */
3725
3726 if (orderInfo->boundsFlags & BOUND_LEFT)
3727 {
3728 if (!update_write_coord(s, orderInfo->bounds.left))
3729 return FALSE;
3730 }
3731 else if (orderInfo->boundsFlags & BOUND_DELTA_LEFT)
3732 {
3733 }
3734
3735 if (orderInfo->boundsFlags & BOUND_TOP)
3736 {
3737 if (!update_write_coord(s, orderInfo->bounds.top))
3738 return FALSE;
3739 }
3740 else if (orderInfo->boundsFlags & BOUND_DELTA_TOP)
3741 {
3742 }
3743
3744 if (orderInfo->boundsFlags & BOUND_RIGHT)
3745 {
3746 if (!update_write_coord(s, orderInfo->bounds.right))
3747 return FALSE;
3748 }
3749 else if (orderInfo->boundsFlags & BOUND_DELTA_RIGHT)
3750 {
3751 }
3752
3753 if (orderInfo->boundsFlags & BOUND_BOTTOM)
3754 {
3755 if (!update_write_coord(s, orderInfo->bounds.bottom))
3756 return FALSE;
3757 }
3758 else if (orderInfo->boundsFlags & BOUND_DELTA_BOTTOM)
3759 {
3760 }
3761
3762 return TRUE;
3763}
3764
3765static BOOL read_primary_order(wLog* log, const char* orderName, wStream* s,
3766 const ORDER_INFO* orderInfo, rdpPrimaryUpdate* primary_pub)
3767{
3768 BOOL rc = FALSE;
3769 rdp_primary_update_internal* primary = primary_update_cast(primary_pub);
3770
3771 if (!s || !orderInfo || !orderName)
3772 return FALSE;
3773
3774 switch (orderInfo->orderType)
3775 {
3776 case ORDER_TYPE_DSTBLT:
3777 rc = update_read_dstblt_order(orderName, s, orderInfo, &(primary->dstblt));
3778 break;
3779
3780 case ORDER_TYPE_PATBLT:
3781 rc = update_read_patblt_order(orderName, s, orderInfo, &(primary->patblt));
3782 break;
3783
3784 case ORDER_TYPE_SCRBLT:
3785 rc = update_read_scrblt_order(orderName, s, orderInfo, &(primary->scrblt));
3786 break;
3787
3788 case ORDER_TYPE_OPAQUE_RECT:
3789 rc = update_read_opaque_rect_order(orderName, s, orderInfo, &(primary->opaque_rect));
3790 break;
3791
3792 case ORDER_TYPE_DRAW_NINE_GRID:
3793 rc = update_read_draw_nine_grid_order(orderName, s, orderInfo,
3794 &(primary->draw_nine_grid));
3795 break;
3796
3797 case ORDER_TYPE_MULTI_DSTBLT:
3798 rc = update_read_multi_dstblt_order(orderName, s, orderInfo, &(primary->multi_dstblt));
3799 break;
3800
3801 case ORDER_TYPE_MULTI_PATBLT:
3802 rc = update_read_multi_patblt_order(orderName, s, orderInfo, &(primary->multi_patblt));
3803 break;
3804
3805 case ORDER_TYPE_MULTI_SCRBLT:
3806 rc = update_read_multi_scrblt_order(orderName, s, orderInfo, &(primary->multi_scrblt));
3807 break;
3808
3809 case ORDER_TYPE_MULTI_OPAQUE_RECT:
3810 rc = update_read_multi_opaque_rect_order(orderName, s, orderInfo,
3811 &(primary->multi_opaque_rect));
3812 break;
3813
3814 case ORDER_TYPE_MULTI_DRAW_NINE_GRID:
3815 rc = update_read_multi_draw_nine_grid_order(orderName, s, orderInfo,
3816 &(primary->multi_draw_nine_grid));
3817 break;
3818
3819 case ORDER_TYPE_LINE_TO:
3820 rc = update_read_line_to_order(orderName, s, orderInfo, &(primary->line_to));
3821 break;
3822
3823 case ORDER_TYPE_POLYLINE:
3824 rc = update_read_polyline_order(orderName, s, orderInfo, &(primary->polyline));
3825 break;
3826
3827 case ORDER_TYPE_MEMBLT:
3828 rc = update_read_memblt_order(orderName, s, orderInfo, &(primary->memblt));
3829 break;
3830
3831 case ORDER_TYPE_MEM3BLT:
3832 rc = update_read_mem3blt_order(orderName, s, orderInfo, &(primary->mem3blt));
3833 break;
3834
3835 case ORDER_TYPE_SAVE_BITMAP:
3836 rc = update_read_save_bitmap_order(orderName, s, orderInfo, &(primary->save_bitmap));
3837 break;
3838
3839 case ORDER_TYPE_GLYPH_INDEX:
3840 rc = update_read_glyph_index_order(orderName, s, orderInfo, &(primary->glyph_index));
3841 break;
3842
3843 case ORDER_TYPE_FAST_INDEX:
3844 rc = update_read_fast_index_order(orderName, s, orderInfo, &(primary->fast_index));
3845 break;
3846
3847 case ORDER_TYPE_FAST_GLYPH:
3848 rc = update_read_fast_glyph_order(orderName, s, orderInfo, &(primary->fast_glyph));
3849 break;
3850
3851 case ORDER_TYPE_POLYGON_SC:
3852 rc = update_read_polygon_sc_order(orderName, s, orderInfo, &(primary->polygon_sc));
3853 break;
3854
3855 case ORDER_TYPE_POLYGON_CB:
3856 rc = update_read_polygon_cb_order(orderName, s, orderInfo, &(primary->polygon_cb));
3857 break;
3858
3859 case ORDER_TYPE_ELLIPSE_SC:
3860 rc = update_read_ellipse_sc_order(orderName, s, orderInfo, &(primary->ellipse_sc));
3861 break;
3862
3863 case ORDER_TYPE_ELLIPSE_CB:
3864 rc = update_read_ellipse_cb_order(orderName, s, orderInfo, &(primary->ellipse_cb));
3865 break;
3866
3867 default:
3868 WLog_Print(log, WLOG_WARN, "%s %s not supported, ignoring", primary_order_str,
3869 orderName);
3870 rc = TRUE;
3871 break;
3872 }
3873
3874 if (!rc)
3875 {
3876 WLog_Print(log, WLOG_ERROR, "%s %s failed", primary_order_str, orderName);
3877 return FALSE;
3878 }
3879
3880 return TRUE;
3881}
3882
3883static BOOL update_recv_primary_order(rdpUpdate* update, wStream* s, BYTE flags)
3884{
3885 BYTE field = 0;
3886 BOOL rc = FALSE;
3887 rdp_update_internal* up = update_cast(update);
3888 rdpContext* context = update->context;
3889 rdp_primary_update_internal* primary = primary_update_cast(update->primary);
3890
3891 WINPR_ASSERT(s);
3892
3893 ORDER_INFO* orderInfo = &(primary->order_info);
3894 WINPR_ASSERT(orderInfo);
3895 WINPR_ASSERT(context);
3896
3897 const rdpSettings* settings = context->settings;
3898 WINPR_ASSERT(settings);
3899
3900 const BOOL defaultReturn =
3901 freerdp_settings_get_bool(settings, FreeRDP_DeactivateClientDecoding);
3902
3903 if (flags & ORDER_TYPE_CHANGE)
3904 {
3905 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
3906 return FALSE;
3907
3908 Stream_Read_UINT8(s, orderInfo->orderType); /* orderType (1 byte) */
3909 }
3910
3911 up->stats.primary[orderInfo->orderType]++;
3912 char buffer[64] = WINPR_C_ARRAY_INIT;
3913 const char* orderName = primary_order_string(orderInfo->orderType, buffer, sizeof(buffer));
3914 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
3915
3916 if (!check_primary_order_supported(up->log, settings, orderInfo->orderType, orderName))
3917 return FALSE;
3918
3919 field = get_primary_drawing_order_field_bytes(orderInfo->orderType, &rc);
3920 if (!rc)
3921 return FALSE;
3922
3923 if (!update_read_field_flags(s, &(orderInfo->fieldFlags), flags, field))
3924 {
3925 WLog_Print(up->log, WLOG_ERROR, "update_read_field_flags() failed");
3926 return FALSE;
3927 }
3928
3929 if (flags & ORDER_BOUNDS)
3930 {
3931 if (!(flags & ORDER_ZERO_BOUNDS_DELTAS))
3932 {
3933 if (!update_read_bounds(s, &orderInfo->bounds))
3934 {
3935 WLog_Print(up->log, WLOG_ERROR, "update_read_bounds() failed");
3936 return FALSE;
3937 }
3938 }
3939
3940 rc = IFCALLRESULT(defaultReturn, update->SetBounds, context, &orderInfo->bounds);
3941
3942 if (!rc)
3943 return FALSE;
3944 }
3945
3946 orderInfo->deltaCoordinates = (flags & ORDER_DELTA_COORDINATES) != 0;
3947
3948 if (!read_primary_order(up->log, orderName, s, orderInfo, &primary->common))
3949 return FALSE;
3950
3951 rc = IFCALLRESULT(TRUE, primary->common.OrderInfo, context, orderInfo, orderName);
3952 if (!rc)
3953 return FALSE;
3954
3955 switch (orderInfo->orderType)
3956 {
3957 case ORDER_TYPE_DSTBLT:
3958 {
3959 WLog_Print(up->log, WLOG_DEBUG, "%s %s rop=%s [0x%08" PRIx32 "]", primary_order_str,
3960 orderName, gdi_rob3_code_string_checked(primary->dstblt.bRop),
3961 gdi_rop3_code_checked(primary->dstblt.bRop));
3962 rc = IFCALLRESULT(defaultReturn, primary->common.DstBlt, context, &primary->dstblt);
3963 }
3964 break;
3965
3966 case ORDER_TYPE_PATBLT:
3967 {
3968 WINPR_ASSERT(primary->patblt.bRop <= UINT8_MAX);
3969 WLog_Print(up->log, WLOG_DEBUG, "%s %s rop=%s [0x%08" PRIx32 "]", primary_order_str,
3970 orderName, gdi_rob3_code_string_checked(primary->patblt.bRop),
3971 gdi_rop3_code_checked(primary->patblt.bRop));
3972 rc = IFCALLRESULT(defaultReturn, primary->common.PatBlt, context, &primary->patblt);
3973 }
3974 break;
3975
3976 case ORDER_TYPE_SCRBLT:
3977 {
3978 WINPR_ASSERT(primary->scrblt.bRop <= UINT8_MAX);
3979 WLog_Print(up->log, WLOG_DEBUG, "%s %s rop=%s [0x%08" PRIx32 "]", primary_order_str,
3980 orderName, gdi_rob3_code_string_checked((UINT8)primary->scrblt.bRop),
3981 gdi_rop3_code_checked(primary->scrblt.bRop));
3982 rc = IFCALLRESULT(defaultReturn, primary->common.ScrBlt, context, &primary->scrblt);
3983 }
3984 break;
3985
3986 case ORDER_TYPE_OPAQUE_RECT:
3987 {
3988 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
3989 rc = IFCALLRESULT(defaultReturn, primary->common.OpaqueRect, context,
3990 &primary->opaque_rect);
3991 }
3992 break;
3993
3994 case ORDER_TYPE_DRAW_NINE_GRID:
3995 {
3996 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
3997 rc = IFCALLRESULT(defaultReturn, primary->common.DrawNineGrid, context,
3998 &primary->draw_nine_grid);
3999 }
4000 break;
4001
4002 case ORDER_TYPE_MULTI_DSTBLT:
4003 {
4004 WLog_Print(up->log, WLOG_DEBUG, "%s %s rop=%s [0x%08" PRIx32 "]", primary_order_str,
4005 orderName, gdi_rob3_code_string_checked(primary->multi_dstblt.bRop),
4006 gdi_rop3_code_checked(primary->multi_dstblt.bRop));
4007 rc = IFCALLRESULT(defaultReturn, primary->common.MultiDstBlt, context,
4008 &primary->multi_dstblt);
4009 }
4010 break;
4011
4012 case ORDER_TYPE_MULTI_PATBLT:
4013 {
4014 WLog_Print(up->log, WLOG_DEBUG, "%s %s rop=%s [0x%08" PRIx32 "]", primary_order_str,
4015 orderName, gdi_rob3_code_string_checked(primary->multi_patblt.bRop),
4016 gdi_rop3_code_checked(primary->multi_patblt.bRop));
4017 rc = IFCALLRESULT(defaultReturn, primary->common.MultiPatBlt, context,
4018 &primary->multi_patblt);
4019 }
4020 break;
4021
4022 case ORDER_TYPE_MULTI_SCRBLT:
4023 {
4024 WLog_Print(up->log, WLOG_DEBUG, "%s %s rop=%s [0x%08" PRIx32 "]", primary_order_str,
4025 orderName, gdi_rob3_code_string_checked(primary->multi_scrblt.bRop),
4026 gdi_rop3_code_checked(primary->multi_scrblt.bRop));
4027 rc = IFCALLRESULT(defaultReturn, primary->common.MultiScrBlt, context,
4028 &primary->multi_scrblt);
4029 }
4030 break;
4031
4032 case ORDER_TYPE_MULTI_OPAQUE_RECT:
4033 {
4034 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4035 rc = IFCALLRESULT(defaultReturn, primary->common.MultiOpaqueRect, context,
4036 &primary->multi_opaque_rect);
4037 }
4038 break;
4039
4040 case ORDER_TYPE_MULTI_DRAW_NINE_GRID:
4041 {
4042 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4043 rc = IFCALLRESULT(defaultReturn, primary->common.MultiDrawNineGrid, context,
4044 &primary->multi_draw_nine_grid);
4045 }
4046 break;
4047
4048 case ORDER_TYPE_LINE_TO:
4049 {
4050 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4051 rc = IFCALLRESULT(defaultReturn, primary->common.LineTo, context, &primary->line_to);
4052 }
4053 break;
4054
4055 case ORDER_TYPE_POLYLINE:
4056 {
4057 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4058 rc = IFCALLRESULT(defaultReturn, primary->common.Polyline, context, &primary->polyline);
4059 }
4060 break;
4061
4062 case ORDER_TYPE_MEMBLT:
4063 {
4064 WINPR_ASSERT(primary->memblt.bRop <= UINT8_MAX);
4065 WLog_Print(up->log, WLOG_DEBUG, "%s %s rop=%s [0x%08" PRIx32 "]", primary_order_str,
4066 orderName, gdi_rob3_code_string_checked(primary->memblt.bRop),
4067 gdi_rop3_code_checked(primary->memblt.bRop));
4068 rc = IFCALLRESULT(defaultReturn, primary->common.MemBlt, context, &primary->memblt);
4069 }
4070 break;
4071
4072 case ORDER_TYPE_MEM3BLT:
4073 {
4074 WINPR_ASSERT(primary->mem3blt.bRop <= UINT8_MAX);
4075 WLog_Print(up->log, WLOG_DEBUG, "%s %s rop=%s [0x%08" PRIx32 "]", primary_order_str,
4076 orderName, gdi_rob3_code_string_checked(primary->mem3blt.bRop),
4077 gdi_rop3_code_checked(primary->mem3blt.bRop));
4078 rc = IFCALLRESULT(defaultReturn, primary->common.Mem3Blt, context, &primary->mem3blt);
4079 }
4080 break;
4081
4082 case ORDER_TYPE_SAVE_BITMAP:
4083 {
4084 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4085 rc = IFCALLRESULT(defaultReturn, primary->common.SaveBitmap, context,
4086 &primary->save_bitmap);
4087 }
4088 break;
4089
4090 case ORDER_TYPE_GLYPH_INDEX:
4091 {
4092 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4093 rc = IFCALLRESULT(defaultReturn, primary->common.GlyphIndex, context,
4094 &primary->glyph_index);
4095 }
4096 break;
4097
4098 case ORDER_TYPE_FAST_INDEX:
4099 {
4100 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4101 rc = IFCALLRESULT(defaultReturn, primary->common.FastIndex, context,
4102 &primary->fast_index);
4103 }
4104 break;
4105
4106 case ORDER_TYPE_FAST_GLYPH:
4107 {
4108 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4109 rc = IFCALLRESULT(defaultReturn, primary->common.FastGlyph, context,
4110 &primary->fast_glyph);
4111 }
4112 break;
4113
4114 case ORDER_TYPE_POLYGON_SC:
4115 {
4116 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4117 rc = IFCALLRESULT(defaultReturn, primary->common.PolygonSC, context,
4118 &primary->polygon_sc);
4119 }
4120 break;
4121
4122 case ORDER_TYPE_POLYGON_CB:
4123 {
4124 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4125 rc = IFCALLRESULT(defaultReturn, primary->common.PolygonCB, context,
4126 &primary->polygon_cb);
4127 }
4128 break;
4129
4130 case ORDER_TYPE_ELLIPSE_SC:
4131 {
4132 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4133 rc = IFCALLRESULT(defaultReturn, primary->common.EllipseSC, context,
4134 &primary->ellipse_sc);
4135 }
4136 break;
4137
4138 case ORDER_TYPE_ELLIPSE_CB:
4139 {
4140 WLog_Print(up->log, WLOG_DEBUG, "%s %s", primary_order_str, orderName);
4141 rc = IFCALLRESULT(defaultReturn, primary->common.EllipseCB, context,
4142 &primary->ellipse_cb);
4143 }
4144 break;
4145
4146 default:
4147 WLog_Print(up->log, WLOG_WARN, "%s %s not supported", primary_order_str, orderName);
4148 break;
4149 }
4150
4151 if (!rc)
4152 {
4153 WLog_Print(up->log, WLOG_ERROR, "%s %s failed", primary_order_str, orderName);
4154 return FALSE;
4155 }
4156
4157 if (flags & ORDER_BOUNDS)
4158 {
4159 rc = IFCALLRESULT(defaultReturn, update->SetBounds, context, nullptr);
4160 }
4161
4162 return rc;
4163}
4164
4165static BOOL update_recv_secondary_order(rdpUpdate* update, wStream* s, WINPR_ATTR_UNUSED BYTE flags)
4166{
4167 BOOL rc = FALSE;
4168 size_t start = 0;
4169 size_t end = 0;
4170 size_t pos = 0;
4171 size_t diff = 0;
4172 BYTE orderType = 0;
4173 UINT16 extraFlags = 0;
4174 INT16 orderLength = 0;
4175 rdp_update_internal* up = update_cast(update);
4176 rdpContext* context = update->context;
4177 rdpSettings* settings = context->settings;
4178 rdpSecondaryUpdate* secondary = update->secondary;
4179 const char* name = nullptr;
4180 BOOL defaultReturn = 0;
4181
4182 defaultReturn = freerdp_settings_get_bool(settings, FreeRDP_DeactivateClientDecoding);
4183
4184 if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
4185 return FALSE;
4186
4187 Stream_Read_INT16(s, orderLength); /* orderLength (2 bytes signed) */
4188 Stream_Read_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
4189 Stream_Read_UINT8(s, orderType); /* orderType (1 byte) */
4190
4191 start = Stream_GetPosition(s);
4192
4193 char buffer[64] = WINPR_C_ARRAY_INIT;
4194 name = secondary_order_string(orderType, buffer, sizeof(buffer));
4195 WLog_Print(up->log, WLOG_DEBUG, "%s %s", secondary_order_str, name);
4196
4197 up->stats.secondary[orderType]++;
4198 rc = IFCALLRESULT(TRUE, secondary->CacheOrderInfo, context, orderLength, extraFlags, orderType,
4199 name);
4200 if (!rc)
4201 return FALSE;
4202
4203 /*
4204 * According to [MS-RDPEGDI] 2.2.2.2.1.2.1.1 the order length must be increased by 13 bytes
4205 * including the header. As we already read the header 7 left
4206 */
4207
4208 /* orderLength might be negative without the adjusted header data.
4209 * Account for that here so all further checks operate on the correct value.
4210 */
4211 if (orderLength < 0)
4212 {
4213 WLog_Print(up->log, WLOG_ERROR, "orderLength %" PRIu16 " must be >= 7", orderLength);
4214 return FALSE;
4215 }
4216
4217 const size_t orderLengthFull = WINPR_ASSERTING_INT_CAST(size_t, orderLength) + 7ULL;
4218 if (!Stream_CheckAndLogRequiredLength(TAG, s, orderLengthFull))
4219 return FALSE;
4220
4221 if (!check_secondary_order_supported(up->log, settings, orderType, name))
4222 return FALSE;
4223
4224 switch (orderType)
4225 {
4226 case ORDER_TYPE_BITMAP_UNCOMPRESSED:
4227 case ORDER_TYPE_CACHE_BITMAP_COMPRESSED:
4228 {
4229 const BOOL compressed = (orderType == ORDER_TYPE_CACHE_BITMAP_COMPRESSED);
4230 CACHE_BITMAP_ORDER* order =
4231 update_read_cache_bitmap_order(update, s, compressed, extraFlags);
4232
4233 if (order)
4234 {
4235 rc = IFCALLRESULT(defaultReturn, secondary->CacheBitmap, context, order);
4236 free_cache_bitmap_order(context, order);
4237 }
4238 }
4239 break;
4240
4241 case ORDER_TYPE_BITMAP_UNCOMPRESSED_V2:
4242 case ORDER_TYPE_BITMAP_COMPRESSED_V2:
4243 {
4244 const BOOL compressed = (orderType == ORDER_TYPE_BITMAP_COMPRESSED_V2);
4245 CACHE_BITMAP_V2_ORDER* order =
4246 update_read_cache_bitmap_v2_order(update, s, compressed, extraFlags);
4247
4248 if (order)
4249 {
4250 rc = IFCALLRESULT(defaultReturn, secondary->CacheBitmapV2, context, order);
4251 free_cache_bitmap_v2_order(context, order);
4252 }
4253 }
4254 break;
4255
4256 case ORDER_TYPE_BITMAP_COMPRESSED_V3:
4257 {
4258 CACHE_BITMAP_V3_ORDER* order = update_read_cache_bitmap_v3_order(update, s, extraFlags);
4259
4260 if (order)
4261 {
4262 rc = IFCALLRESULT(defaultReturn, secondary->CacheBitmapV3, context, order);
4263 free_cache_bitmap_v3_order(context, order);
4264 }
4265 }
4266 break;
4267
4268 case ORDER_TYPE_CACHE_COLOR_TABLE:
4269 {
4271 update_read_cache_color_table_order(update, s, extraFlags);
4272
4273 if (order)
4274 {
4275 rc = IFCALLRESULT(defaultReturn, secondary->CacheColorTable, context, order);
4276 free_cache_color_table_order(context, order);
4277 }
4278 }
4279 break;
4280
4281 case ORDER_TYPE_CACHE_GLYPH:
4282 {
4283 switch (settings->GlyphSupportLevel)
4284 {
4285 case GLYPH_SUPPORT_PARTIAL:
4286 case GLYPH_SUPPORT_FULL:
4287 {
4288 CACHE_GLYPH_ORDER* order = update_read_cache_glyph_order(update, s, extraFlags);
4289
4290 if (order)
4291 {
4292 rc = IFCALLRESULT(defaultReturn, secondary->CacheGlyph, context, order);
4293 free_cache_glyph_order(context, order);
4294 }
4295 }
4296 break;
4297
4298 case GLYPH_SUPPORT_ENCODE:
4299 {
4300 CACHE_GLYPH_V2_ORDER* order =
4301 update_read_cache_glyph_v2_order(update, s, extraFlags);
4302
4303 if (order)
4304 {
4305 rc = IFCALLRESULT(defaultReturn, secondary->CacheGlyphV2, context, order);
4306 free_cache_glyph_v2_order(context, order);
4307 }
4308 }
4309 break;
4310
4311 case GLYPH_SUPPORT_NONE:
4312 default:
4313 break;
4314 }
4315 }
4316 break;
4317
4318 case ORDER_TYPE_CACHE_BRUSH:
4319 /* [MS-RDPEGDI] 2.2.2.2.1.2.7 Cache Brush (CACHE_BRUSH_ORDER) */
4320 {
4321 CACHE_BRUSH_ORDER* order = update_read_cache_brush_order(update, s, extraFlags);
4322
4323 if (order)
4324 {
4325 rc = IFCALLRESULT(defaultReturn, secondary->CacheBrush, context, order);
4326 free_cache_brush_order(context, order);
4327 }
4328 }
4329 break;
4330
4331 default:
4332 WLog_Print(up->log, WLOG_WARN, "%s %s not supported", secondary_order_str, name);
4333 break;
4334 }
4335
4336 if (!rc)
4337 {
4338 WLog_Print(up->log, WLOG_ERROR, "%s %s failed", secondary_order_str, name);
4339 }
4340
4341 end = start + WINPR_ASSERTING_INT_CAST(size_t, orderLengthFull);
4342 pos = Stream_GetPosition(s);
4343 if (pos > end)
4344 {
4345 WLog_Print(up->log, WLOG_WARN, "%s %s: read %" PRIuz "bytes too much", secondary_order_str,
4346 name, pos - end);
4347 return FALSE;
4348 }
4349 diff = end - pos;
4350 if (diff > 0)
4351 {
4352 WLog_Print(up->log, WLOG_DEBUG, "%s %s: read %" PRIuz "bytes short, skipping",
4353 secondary_order_str, name, diff);
4354 if (!Stream_SafeSeek(s, diff))
4355 return FALSE;
4356 }
4357 return rc;
4358}
4359
4360static BOOL read_altsec_order(wLog* log, wStream* s, BYTE orderType, rdpAltSecUpdate* altsec_pub)
4361{
4362 BOOL rc = FALSE;
4363 rdp_altsec_update_internal* altsec = altsec_update_cast(altsec_pub);
4364
4365 WINPR_ASSERT(s);
4366
4367 switch (orderType)
4368 {
4369 case ORDER_TYPE_CREATE_OFFSCREEN_BITMAP:
4370 rc = update_read_create_offscreen_bitmap_order(s, &(altsec->create_offscreen_bitmap));
4371 break;
4372
4373 case ORDER_TYPE_SWITCH_SURFACE:
4374 rc = update_read_switch_surface_order(s, &(altsec->switch_surface));
4375 break;
4376
4377 case ORDER_TYPE_CREATE_NINE_GRID_BITMAP:
4378 rc = update_read_create_nine_grid_bitmap_order(s, &(altsec->create_nine_grid_bitmap));
4379 break;
4380
4381 case ORDER_TYPE_FRAME_MARKER:
4382 rc = update_read_frame_marker_order(s, &(altsec->frame_marker));
4383 break;
4384
4385 case ORDER_TYPE_STREAM_BITMAP_FIRST:
4386 rc = update_read_stream_bitmap_first_order(s, &(altsec->stream_bitmap_first));
4387 break;
4388
4389 case ORDER_TYPE_STREAM_BITMAP_NEXT:
4390 rc = update_read_stream_bitmap_next_order(s, &(altsec->stream_bitmap_next));
4391 break;
4392
4393 case ORDER_TYPE_GDIPLUS_FIRST:
4394 rc = update_read_draw_gdiplus_first_order(s, &(altsec->draw_gdiplus_first));
4395 break;
4396
4397 case ORDER_TYPE_GDIPLUS_NEXT:
4398 rc = update_read_draw_gdiplus_next_order(s, &(altsec->draw_gdiplus_next));
4399 break;
4400
4401 case ORDER_TYPE_GDIPLUS_END:
4402 rc = update_read_draw_gdiplus_end_order(s, &(altsec->draw_gdiplus_end));
4403 break;
4404
4405 case ORDER_TYPE_GDIPLUS_CACHE_FIRST:
4406 rc = update_read_draw_gdiplus_cache_first_order(s, &(altsec->draw_gdiplus_cache_first));
4407 break;
4408
4409 case ORDER_TYPE_GDIPLUS_CACHE_NEXT:
4410 rc = update_read_draw_gdiplus_cache_next_order(s, &(altsec->draw_gdiplus_cache_next));
4411 break;
4412
4413 case ORDER_TYPE_GDIPLUS_CACHE_END:
4414 rc = update_read_draw_gdiplus_cache_end_order(s, &(altsec->draw_gdiplus_cache_end));
4415 break;
4416
4417 case ORDER_TYPE_WINDOW:
4418 /* This order is handled elsewhere. */
4419 rc = TRUE;
4420 break;
4421
4422 case ORDER_TYPE_COMPDESK_FIRST:
4423 rc = TRUE;
4424 break;
4425
4426 default:
4427 break;
4428 }
4429
4430 if (!rc)
4431 {
4432 char buffer[64] = WINPR_C_ARRAY_INIT;
4433 WLog_Print(log, WLOG_ERROR, "Read %s %s failed", alt_sec_order_str,
4434 altsec_order_string(orderType, buffer, sizeof(buffer)));
4435 }
4436
4437 return rc;
4438}
4439
4440static BOOL update_recv_altsec_order(rdpUpdate* update, wStream* s, BYTE flags)
4441{
4442 BYTE orderType = flags >> 2; /* orderType is in higher 6 bits of flags field */
4443 BOOL rc = FALSE;
4444 rdp_update_internal* up = update_cast(update);
4445 rdpContext* context = update->context;
4446 rdpSettings* settings = context->settings;
4447 rdp_altsec_update_internal* altsec = altsec_update_cast(update->altsec);
4448
4449 char buffer[64] = WINPR_C_ARRAY_INIT;
4450 const char* orderName = altsec_order_string(orderType, buffer, sizeof(buffer));
4451
4452 WINPR_ASSERT(s);
4453 WINPR_ASSERT(context);
4454 WINPR_ASSERT(settings);
4455
4456 WLog_Print(up->log, WLOG_DEBUG, "%s %s", alt_sec_order_str, orderName);
4457
4458 up->stats.altsec[orderType]++;
4459
4460 rc = IFCALLRESULT(TRUE, altsec->common.DrawOrderInfo, context, orderType, orderName);
4461 if (!rc)
4462 return FALSE;
4463
4464 if (!check_alt_order_supported(up->log, settings, orderType, orderName))
4465 return FALSE;
4466
4467 if (!read_altsec_order(up->log, s, orderType, &altsec->common))
4468 return FALSE;
4469
4470 switch (orderType)
4471 {
4472 case ORDER_TYPE_CREATE_OFFSCREEN_BITMAP:
4473 IFCALLRET(altsec->common.CreateOffscreenBitmap, rc, context,
4474 &(altsec->create_offscreen_bitmap));
4475 break;
4476
4477 case ORDER_TYPE_SWITCH_SURFACE:
4478 IFCALLRET(altsec->common.SwitchSurface, rc, context, &(altsec->switch_surface));
4479 break;
4480
4481 case ORDER_TYPE_CREATE_NINE_GRID_BITMAP:
4482 IFCALLRET(altsec->common.CreateNineGridBitmap, rc, context,
4483 &(altsec->create_nine_grid_bitmap));
4484 break;
4485
4486 case ORDER_TYPE_FRAME_MARKER:
4487 IFCALLRET(altsec->common.FrameMarker, rc, context, &(altsec->frame_marker));
4488 break;
4489
4490 case ORDER_TYPE_STREAM_BITMAP_FIRST:
4491 IFCALLRET(altsec->common.StreamBitmapFirst, rc, context,
4492 &(altsec->stream_bitmap_first));
4493 break;
4494
4495 case ORDER_TYPE_STREAM_BITMAP_NEXT:
4496 IFCALLRET(altsec->common.StreamBitmapNext, rc, context, &(altsec->stream_bitmap_next));
4497 break;
4498
4499 case ORDER_TYPE_GDIPLUS_FIRST:
4500 IFCALLRET(altsec->common.DrawGdiPlusFirst, rc, context, &(altsec->draw_gdiplus_first));
4501 break;
4502
4503 case ORDER_TYPE_GDIPLUS_NEXT:
4504 IFCALLRET(altsec->common.DrawGdiPlusNext, rc, context, &(altsec->draw_gdiplus_next));
4505 break;
4506
4507 case ORDER_TYPE_GDIPLUS_END:
4508 IFCALLRET(altsec->common.DrawGdiPlusEnd, rc, context, &(altsec->draw_gdiplus_end));
4509 break;
4510
4511 case ORDER_TYPE_GDIPLUS_CACHE_FIRST:
4512 IFCALLRET(altsec->common.DrawGdiPlusCacheFirst, rc, context,
4513 &(altsec->draw_gdiplus_cache_first));
4514 break;
4515
4516 case ORDER_TYPE_GDIPLUS_CACHE_NEXT:
4517 IFCALLRET(altsec->common.DrawGdiPlusCacheNext, rc, context,
4518 &(altsec->draw_gdiplus_cache_next));
4519 break;
4520
4521 case ORDER_TYPE_GDIPLUS_CACHE_END:
4522 IFCALLRET(altsec->common.DrawGdiPlusCacheEnd, rc, context,
4523 &(altsec->draw_gdiplus_cache_end));
4524 break;
4525
4526 case ORDER_TYPE_WINDOW:
4527 rc = update_recv_altsec_window_order(update, s);
4528 break;
4529
4530 case ORDER_TYPE_COMPDESK_FIRST:
4531 rc = TRUE;
4532 break;
4533
4534 default:
4535 break;
4536 }
4537
4538 if (!rc)
4539 {
4540 WLog_Print(up->log, WLOG_ERROR, "%s %s failed", alt_sec_order_str, orderName);
4541 }
4542
4543 return rc;
4544}
4545BOOL update_recv_order(rdpUpdate* update, wStream* s)
4546{
4547 BOOL rc = 0;
4548 BYTE controlFlags = 0;
4549 rdp_update_internal* up = update_cast(update);
4550
4551 if (!rdp_has_reached_state(update->context->rdp, CONNECTION_STATE_ACTIVE))
4552 return FALSE;
4553
4554 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
4555 return FALSE;
4556
4557 Stream_Read_UINT8(s, controlFlags); /* controlFlags (1 byte) */
4558
4559 if (!(controlFlags & ORDER_STANDARD))
4560 rc = update_recv_altsec_order(update, s, controlFlags);
4561 else if (controlFlags & ORDER_SECONDARY)
4562 rc = update_recv_secondary_order(update, s, controlFlags);
4563 else
4564 rc = update_recv_primary_order(update, s, controlFlags);
4565
4566 if (!rc)
4567 WLog_Print(up->log, WLOG_ERROR, "order flags %02" PRIx8 " failed", controlFlags);
4568
4569 return rc;
4570}
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.