FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
update.c
1
22#include <freerdp/config.h>
23
24#include <winpr/crt.h>
25#include <winpr/print.h>
26#include <winpr/synch.h>
27#include <winpr/thread.h>
28#include <winpr/collections.h>
29#include <winpr/assert.h>
30#include <winpr/cast.h>
31
32#include "settings.h"
33#include "update.h"
34#include "surface.h"
35#include "message.h"
36#include "info.h"
37#include "window.h"
38
39#include <freerdp/log.h>
40#include <freerdp/peer.h>
41#include <freerdp/codec/bitmap.h>
42
43#include "../cache/pointer.h"
44#include "../cache/palette.h"
45#include "../cache/bitmap.h"
46
47#define TAG FREERDP_TAG("core.update")
48
49#define FORCE_ASYNC_UPDATE_OFF
50
51static const char* const UPDATE_TYPE_STRINGS[] = { "Orders", "Bitmap", "Palette", "Synchronize" };
52
53static const char* update_type_to_string(UINT16 updateType)
54{
55 if (updateType >= ARRAYSIZE(UPDATE_TYPE_STRINGS))
56 return "UNKNOWN";
57
58 return UPDATE_TYPE_STRINGS[updateType];
59}
60
61static BOOL update_recv_orders(rdpUpdate* update, wStream* s)
62{
63 UINT16 numberOrders = 0;
64
65 WINPR_ASSERT(update);
66
67 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
68 return FALSE;
69
70 Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */
71 Stream_Read_UINT16(s, numberOrders); /* numberOrders (2 bytes) */
72 Stream_Seek_UINT16(s); /* pad2OctetsB (2 bytes) */
73
74 while (numberOrders > 0)
75 {
76 if (!update_recv_order(update, s))
77 {
78 WLog_ERR(TAG, "update_recv_order() failed");
79 return FALSE;
80 }
81
82 numberOrders--;
83 }
84
85 return TRUE;
86}
87
88static BOOL update_read_bitmap_data(rdpUpdate* update, wStream* s, BITMAP_DATA* bitmapData)
89{
90 WINPR_UNUSED(update);
91 WINPR_ASSERT(bitmapData);
92
93 if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
94 return FALSE;
95
96 Stream_Read_UINT16(s, bitmapData->destLeft);
97 Stream_Read_UINT16(s, bitmapData->destTop);
98 Stream_Read_UINT16(s, bitmapData->destRight);
99 Stream_Read_UINT16(s, bitmapData->destBottom);
100 Stream_Read_UINT16(s, bitmapData->width);
101 Stream_Read_UINT16(s, bitmapData->height);
102 Stream_Read_UINT16(s, bitmapData->bitsPerPixel);
103 Stream_Read_UINT16(s, bitmapData->flags);
104 Stream_Read_UINT16(s, bitmapData->bitmapLength);
105
106 if ((bitmapData->width == 0) || (bitmapData->height == 0))
107 {
108 WLog_ERR(TAG, "Invalid BITMAP_DATA: width=%" PRIu16 ", height=%" PRIu16, bitmapData->width,
109 bitmapData->height);
110 return FALSE;
111 }
112
113 if (bitmapData->flags & BITMAP_COMPRESSION)
114 {
115 if (!(bitmapData->flags & NO_BITMAP_COMPRESSION_HDR))
116 {
117 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
118 return FALSE;
119
120 Stream_Read_UINT16(s,
121 bitmapData->cbCompFirstRowSize); /* cbCompFirstRowSize (2 bytes) */
122 Stream_Read_UINT16(s,
123 bitmapData->cbCompMainBodySize); /* cbCompMainBodySize (2 bytes) */
124 Stream_Read_UINT16(s, bitmapData->cbScanWidth); /* cbScanWidth (2 bytes) */
125 Stream_Read_UINT16(s,
126 bitmapData->cbUncompressedSize); /* cbUncompressedSize (2 bytes) */
127 bitmapData->bitmapLength = bitmapData->cbCompMainBodySize;
128 }
129
130 bitmapData->compressed = TRUE;
131 }
132 else
133 bitmapData->compressed = FALSE;
134
135 if (!Stream_CheckAndLogRequiredLength(TAG, s, bitmapData->bitmapLength))
136 return FALSE;
137
138 if (bitmapData->bitmapLength > 0)
139 {
140 bitmapData->bitmapDataStream = malloc(bitmapData->bitmapLength);
141
142 if (!bitmapData->bitmapDataStream)
143 return FALSE;
144
145 memcpy(bitmapData->bitmapDataStream, Stream_ConstPointer(s), bitmapData->bitmapLength);
146 Stream_Seek(s, bitmapData->bitmapLength);
147 }
148
149 return TRUE;
150}
151
152static BOOL update_write_bitmap_data_header(const BITMAP_DATA* bitmapData, wStream* s)
153{
154 WINPR_ASSERT(bitmapData);
155 if (!Stream_EnsureRemainingCapacity(s, 18))
156 return FALSE;
157 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, bitmapData->destLeft));
158 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, bitmapData->destTop));
159 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, bitmapData->destRight));
160 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, bitmapData->destBottom));
161 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, bitmapData->width));
162 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, bitmapData->height));
163 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, bitmapData->bitsPerPixel));
164 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, bitmapData->flags));
165 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, bitmapData->bitmapLength));
166 return TRUE;
167}
168
169static BOOL update_write_bitmap_data_no_comp_header(const BITMAP_DATA* bitmapData, wStream* s)
170{
171 WINPR_ASSERT(bitmapData);
172 if (!Stream_EnsureRemainingCapacity(s, 8))
173 return FALSE;
174
175 Stream_Write_UINT16(
176 s, WINPR_ASSERTING_INT_CAST(
177 uint16_t, bitmapData->cbCompFirstRowSize)); /* cbCompFirstRowSize (2 bytes) */
178 Stream_Write_UINT16(
179 s, WINPR_ASSERTING_INT_CAST(
180 uint16_t, bitmapData->cbCompMainBodySize)); /* cbCompMainBodySize (2 bytes) */
181 Stream_Write_UINT16(
182 s, WINPR_ASSERTING_INT_CAST(uint16_t, bitmapData->cbScanWidth)); /* cbScanWidth (2 bytes) */
183 Stream_Write_UINT16(
184 s, WINPR_ASSERTING_INT_CAST(
185 uint16_t, bitmapData->cbUncompressedSize)); /* cbUncompressedSize (2 bytes) */
186 return TRUE;
187}
188
189static BOOL update_write_bitmap_data(rdpUpdate* update_pub, wStream* s, BITMAP_DATA* bitmapData)
190{
191 rdp_update_internal* update = update_cast(update_pub);
192
193 WINPR_ASSERT(bitmapData);
194
195 if (!Stream_EnsureRemainingCapacity(s, 64 + bitmapData->bitmapLength))
196 return FALSE;
197
198 if (update->common.autoCalculateBitmapData)
199 {
200 bitmapData->flags = 0;
201 bitmapData->cbCompFirstRowSize = 0;
202
203 if (bitmapData->compressed)
204 bitmapData->flags |= BITMAP_COMPRESSION;
205
206 if (update->common.context->settings->NoBitmapCompressionHeader)
207 {
208 bitmapData->flags |= NO_BITMAP_COMPRESSION_HDR;
209 bitmapData->cbCompMainBodySize = bitmapData->bitmapLength;
210 }
211 }
212
213 if (!update_write_bitmap_data_header(bitmapData, s))
214 return FALSE;
215
216 if (bitmapData->flags & BITMAP_COMPRESSION)
217 {
218 if ((bitmapData->flags & NO_BITMAP_COMPRESSION_HDR) == 0)
219 {
220 if (!update_write_bitmap_data_no_comp_header(bitmapData, s))
221 return FALSE;
222 }
223 }
224
225 if (!Stream_EnsureRemainingCapacity(s, bitmapData->bitmapLength))
226 return FALSE;
227 Stream_Write(s, bitmapData->bitmapDataStream, bitmapData->bitmapLength);
228
229 return TRUE;
230}
231
232BITMAP_UPDATE* update_read_bitmap_update(rdpUpdate* update, wStream* s)
233{
234 BITMAP_UPDATE* bitmapUpdate = calloc(1, sizeof(BITMAP_UPDATE));
235 rdp_update_internal* up = update_cast(update);
236
237 if (!bitmapUpdate)
238 goto fail;
239
240 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
241 goto fail;
242
243 Stream_Read_UINT16(s, bitmapUpdate->number); /* numberRectangles (2 bytes) */
244 WLog_Print(up->log, WLOG_TRACE, "BitmapUpdate: %" PRIu32 "", bitmapUpdate->number);
245
246 bitmapUpdate->rectangles = (BITMAP_DATA*)calloc(bitmapUpdate->number, sizeof(BITMAP_DATA));
247
248 if (!bitmapUpdate->rectangles)
249 goto fail;
250
251 /* rectangles */
252 for (UINT32 i = 0; i < bitmapUpdate->number; i++)
253 {
254 if (!update_read_bitmap_data(update, s, &bitmapUpdate->rectangles[i]))
255 goto fail;
256 }
257
258 return bitmapUpdate;
259fail:
260 WINPR_PRAGMA_DIAG_PUSH
261 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
262 free_bitmap_update(update->context, bitmapUpdate);
263 WINPR_PRAGMA_DIAG_POP
264 return NULL;
265}
266
267static BOOL update_write_bitmap_update(rdpUpdate* update, wStream* s,
268 const BITMAP_UPDATE* bitmapUpdate)
269{
270 WINPR_ASSERT(update);
271 WINPR_ASSERT(bitmapUpdate);
272
273 if (!Stream_EnsureRemainingCapacity(s, 32))
274 return FALSE;
275
276 Stream_Write_UINT16(s, UPDATE_TYPE_BITMAP); /* updateType */
277 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(
278 uint16_t, bitmapUpdate->number)); /* numberRectangles (2 bytes) */
279
280 /* rectangles */
281 for (UINT32 i = 0; i < bitmapUpdate->number; i++)
282 {
283 if (!update_write_bitmap_data(update, s, &bitmapUpdate->rectangles[i]))
284 return FALSE;
285 }
286
287 return TRUE;
288}
289
290PALETTE_UPDATE* update_read_palette(rdpUpdate* update, wStream* s)
291{
292 PALETTE_UPDATE* palette_update = calloc(1, sizeof(PALETTE_UPDATE));
293
294 if (!palette_update)
295 goto fail;
296
297 if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
298 goto fail;
299
300 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
301 Stream_Read_UINT32(s, palette_update->number); /* numberColors (4 bytes), must be set to 256 */
302
303 if (palette_update->number > 256)
304 palette_update->number = 256;
305
306 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, palette_update->number, 3ull))
307 goto fail;
308
309 /* paletteEntries */
310 for (UINT32 i = 0; i < palette_update->number; i++)
311 {
312 PALETTE_ENTRY* entry = &palette_update->entries[i];
313 Stream_Read_UINT8(s, entry->red);
314 Stream_Read_UINT8(s, entry->green);
315 Stream_Read_UINT8(s, entry->blue);
316 }
317
318 return palette_update;
319fail:
320 WINPR_PRAGMA_DIAG_PUSH
321 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
322 free_palette_update(update->context, palette_update);
323 WINPR_PRAGMA_DIAG_POP
324 return NULL;
325}
326
327static BOOL update_read_synchronize(rdpUpdate* update, wStream* s)
328{
329 WINPR_UNUSED(update);
330 return Stream_SafeSeek(s, 2); /* pad2Octets (2 bytes) */
335}
336
337static BOOL update_read_play_sound(wStream* s, PLAY_SOUND_UPDATE* play_sound)
338{
339 WINPR_ASSERT(play_sound);
340
341 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
342 return FALSE;
343
344 Stream_Read_UINT32(s, play_sound->duration); /* duration (4 bytes) */
345 Stream_Read_UINT32(s, play_sound->frequency); /* frequency (4 bytes) */
346 return TRUE;
347}
348
349BOOL update_recv_play_sound(rdpUpdate* update, wStream* s)
350{
351 PLAY_SOUND_UPDATE play_sound = { 0 };
352
353 WINPR_ASSERT(update);
354
355 if (!update_read_play_sound(s, &play_sound))
356 return FALSE;
357
358 return IFCALLRESULT(FALSE, update->PlaySound, update->context, &play_sound);
359}
360
361POINTER_POSITION_UPDATE* update_read_pointer_position(rdpUpdate* update, wStream* s)
362{
363 POINTER_POSITION_UPDATE* pointer_position = calloc(1, sizeof(POINTER_POSITION_UPDATE));
364
365 WINPR_ASSERT(update);
366
367 if (!pointer_position)
368 goto fail;
369
370 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
371 goto fail;
372
373 Stream_Read_UINT16(s, pointer_position->xPos); /* xPos (2 bytes) */
374 Stream_Read_UINT16(s, pointer_position->yPos); /* yPos (2 bytes) */
375 return pointer_position;
376fail:
377 WINPR_PRAGMA_DIAG_PUSH
378 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
379 free_pointer_position_update(update->context, pointer_position);
380 WINPR_PRAGMA_DIAG_POP
381 return NULL;
382}
383
384POINTER_SYSTEM_UPDATE* update_read_pointer_system(rdpUpdate* update, wStream* s)
385{
386 POINTER_SYSTEM_UPDATE* pointer_system = calloc(1, sizeof(POINTER_SYSTEM_UPDATE));
387
388 WINPR_ASSERT(update);
389
390 if (!pointer_system)
391 goto fail;
392
393 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
394 goto fail;
395
396 Stream_Read_UINT32(s, pointer_system->type); /* systemPointerType (4 bytes) */
397 return pointer_system;
398fail:
399 WINPR_PRAGMA_DIAG_PUSH
400 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
401 free_pointer_system_update(update->context, pointer_system);
402 WINPR_PRAGMA_DIAG_POP
403 return NULL;
404}
405
406static BOOL s_update_read_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color,
407 BYTE xorBpp, UINT32 flags)
408{
409 BYTE* newMask = NULL;
410 UINT32 scanlineSize = 0;
411 UINT32 max = 32;
412
413 WINPR_ASSERT(pointer_color);
414
415 if (flags & LARGE_POINTER_FLAG_96x96)
416 max = 96;
417
418 if (!pointer_color)
419 goto fail;
420
421 if (!Stream_CheckAndLogRequiredLength(TAG, s, 14))
422 goto fail;
423
424 Stream_Read_UINT16(s, pointer_color->cacheIndex); /* cacheIndex (2 bytes) */
425 Stream_Read_UINT16(s, pointer_color->hotSpotX); /* hotSpot.xPos (2 bytes) */
426 Stream_Read_UINT16(s, pointer_color->hotSpotY); /* hotSpot.yPos (2 bytes) */
436 Stream_Read_UINT16(s, pointer_color->width); /* width (2 bytes) */
437 Stream_Read_UINT16(s, pointer_color->height); /* height (2 bytes) */
438
439 if ((pointer_color->width > max) || (pointer_color->height > max))
440 goto fail;
441
442 Stream_Read_UINT16(s, pointer_color->lengthAndMask); /* lengthAndMask (2 bytes) */
443 Stream_Read_UINT16(s, pointer_color->lengthXorMask); /* lengthXorMask (2 bytes) */
444
451 if (pointer_color->hotSpotX >= pointer_color->width)
452 pointer_color->hotSpotX = 0;
453
454 if (pointer_color->hotSpotY >= pointer_color->height)
455 pointer_color->hotSpotY = 0;
456
457 if (pointer_color->lengthXorMask > 0)
458 {
470 if (!Stream_CheckAndLogRequiredLength(TAG, s, pointer_color->lengthXorMask))
471 goto fail;
472
473 scanlineSize = (7 + xorBpp * pointer_color->width) / 8;
474 scanlineSize = ((scanlineSize + 1) / 2) * 2;
475
476 if (scanlineSize * pointer_color->height != pointer_color->lengthXorMask)
477 {
478 WLog_ERR(TAG,
479 "invalid lengthXorMask: width=%" PRIu32 " height=%" PRIu32 ", %" PRIu32
480 " instead of %" PRIu32 "",
481 pointer_color->width, pointer_color->height, pointer_color->lengthXorMask,
482 scanlineSize * pointer_color->height);
483 goto fail;
484 }
485
486 newMask = realloc(pointer_color->xorMaskData, pointer_color->lengthXorMask);
487
488 if (!newMask)
489 goto fail;
490
491 pointer_color->xorMaskData = newMask;
492 Stream_Read(s, pointer_color->xorMaskData, pointer_color->lengthXorMask);
493 }
494
495 if (pointer_color->lengthAndMask > 0)
496 {
504 if (!Stream_CheckAndLogRequiredLength(TAG, s, pointer_color->lengthAndMask))
505 goto fail;
506
507 scanlineSize = ((7 + pointer_color->width) / 8);
508 scanlineSize = ((1 + scanlineSize) / 2) * 2;
509
510 if (scanlineSize * pointer_color->height != pointer_color->lengthAndMask)
511 {
512 WLog_ERR(TAG, "invalid lengthAndMask: %" PRIu32 " instead of %" PRIu32 "",
513 pointer_color->lengthAndMask, scanlineSize * pointer_color->height);
514 goto fail;
515 }
516
517 newMask = realloc(pointer_color->andMaskData, pointer_color->lengthAndMask);
518
519 if (!newMask)
520 goto fail;
521
522 pointer_color->andMaskData = newMask;
523 Stream_Read(s, pointer_color->andMaskData, pointer_color->lengthAndMask);
524 }
525
526 if (Stream_GetRemainingLength(s) > 0)
527 Stream_Seek_UINT8(s); /* pad (1 byte) */
528
529 return TRUE;
530fail:
531 return FALSE;
532}
533
534POINTER_COLOR_UPDATE* update_read_pointer_color(rdpUpdate* update, wStream* s, BYTE xorBpp)
535{
536 POINTER_COLOR_UPDATE* pointer_color = calloc(1, sizeof(POINTER_COLOR_UPDATE));
537
538 WINPR_ASSERT(update);
539
540 if (!pointer_color)
541 goto fail;
542
543 if (!s_update_read_pointer_color(s, pointer_color, xorBpp,
544 update->context->settings->LargePointerFlag))
545 goto fail;
546
547 return pointer_color;
548fail:
549 WINPR_PRAGMA_DIAG_PUSH
550 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
551 free_pointer_color_update(update->context, pointer_color);
552 WINPR_PRAGMA_DIAG_POP
553 return NULL;
554}
555
556static BOOL s_update_read_pointer_large(wStream* s, POINTER_LARGE_UPDATE* pointer)
557{
558 BYTE* newMask = NULL;
559 UINT32 scanlineSize = 0;
560
561 if (!pointer)
562 goto fail;
563
564 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
565 goto fail;
566
567 Stream_Read_UINT16(s, pointer->xorBpp);
568 Stream_Read_UINT16(s, pointer->cacheIndex); /* cacheIndex (2 bytes) */
569 Stream_Read_UINT16(s, pointer->hotSpotX); /* hotSpot.xPos (2 bytes) */
570 Stream_Read_UINT16(s, pointer->hotSpotY); /* hotSpot.yPos (2 bytes) */
571
572 Stream_Read_UINT16(s, pointer->width); /* width (2 bytes) */
573 Stream_Read_UINT16(s, pointer->height); /* height (2 bytes) */
574
575 if ((pointer->width > 384) || (pointer->height > 384))
576 goto fail;
577
578 Stream_Read_UINT32(s, pointer->lengthAndMask); /* lengthAndMask (4 bytes) */
579 Stream_Read_UINT32(s, pointer->lengthXorMask); /* lengthXorMask (4 bytes) */
580
581 if (pointer->hotSpotX >= pointer->width)
582 pointer->hotSpotX = 0;
583
584 if (pointer->hotSpotY >= pointer->height)
585 pointer->hotSpotY = 0;
586
587 if (pointer->lengthXorMask > 0)
588 {
600 if (!Stream_CheckAndLogRequiredLength(TAG, s, pointer->lengthXorMask))
601 goto fail;
602
603 scanlineSize = (7 + pointer->xorBpp * pointer->width) / 8;
604 scanlineSize = ((scanlineSize + 1) / 2) * 2;
605
606 if (scanlineSize * pointer->height != pointer->lengthXorMask)
607 {
608 WLog_ERR(TAG,
609 "invalid lengthXorMask: width=%" PRIu32 " height=%" PRIu32 ", %" PRIu32
610 " instead of %" PRIu32 "",
611 pointer->width, pointer->height, pointer->lengthXorMask,
612 scanlineSize * pointer->height);
613 goto fail;
614 }
615
616 newMask = realloc(pointer->xorMaskData, pointer->lengthXorMask);
617
618 if (!newMask)
619 goto fail;
620
621 pointer->xorMaskData = newMask;
622 Stream_Read(s, pointer->xorMaskData, pointer->lengthXorMask);
623 }
624
625 if (pointer->lengthAndMask > 0)
626 {
634 if (!Stream_CheckAndLogRequiredLength(TAG, s, pointer->lengthAndMask))
635 goto fail;
636
637 scanlineSize = ((7 + pointer->width) / 8);
638 scanlineSize = ((1 + scanlineSize) / 2) * 2;
639
640 if (scanlineSize * pointer->height != pointer->lengthAndMask)
641 {
642 WLog_ERR(TAG, "invalid lengthAndMask: %" PRIu32 " instead of %" PRIu32 "",
643 pointer->lengthAndMask, scanlineSize * pointer->height);
644 goto fail;
645 }
646
647 newMask = realloc(pointer->andMaskData, pointer->lengthAndMask);
648
649 if (!newMask)
650 goto fail;
651
652 pointer->andMaskData = newMask;
653 Stream_Read(s, pointer->andMaskData, pointer->lengthAndMask);
654 }
655
656 if (Stream_GetRemainingLength(s) > 0)
657 Stream_Seek_UINT8(s); /* pad (1 byte) */
658
659 return TRUE;
660fail:
661 return FALSE;
662}
663
664POINTER_LARGE_UPDATE* update_read_pointer_large(rdpUpdate* update, wStream* s)
665{
666 POINTER_LARGE_UPDATE* pointer = calloc(1, sizeof(POINTER_LARGE_UPDATE));
667
668 WINPR_ASSERT(update);
669
670 if (!pointer)
671 goto fail;
672
673 if (!s_update_read_pointer_large(s, pointer))
674 goto fail;
675
676 return pointer;
677fail:
678 WINPR_PRAGMA_DIAG_PUSH
679 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
680 free_pointer_large_update(update->context, pointer);
681 WINPR_PRAGMA_DIAG_POP
682 return NULL;
683}
684
685POINTER_NEW_UPDATE* update_read_pointer_new(rdpUpdate* update, wStream* s)
686{
687 POINTER_NEW_UPDATE* pointer_new = calloc(1, sizeof(POINTER_NEW_UPDATE));
688
689 WINPR_ASSERT(update);
690
691 if (!pointer_new)
692 goto fail;
693
694 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
695 goto fail;
696
697 Stream_Read_UINT16(s, pointer_new->xorBpp); /* xorBpp (2 bytes) */
698
699 if ((pointer_new->xorBpp < 1) || (pointer_new->xorBpp > 32))
700 {
701 WLog_ERR(TAG, "invalid xorBpp %" PRIu32 "", pointer_new->xorBpp);
702 goto fail;
703 }
704
705 WINPR_ASSERT(pointer_new->xorBpp <= UINT8_MAX);
706 if (!s_update_read_pointer_color(
707 s, &pointer_new->colorPtrAttr, (UINT8)pointer_new->xorBpp,
708 update->context->settings->LargePointerFlag)) /* colorPtrAttr */
709 goto fail;
710
711 return pointer_new;
712fail:
713 WINPR_PRAGMA_DIAG_PUSH
714 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
715 free_pointer_new_update(update->context, pointer_new);
716 WINPR_PRAGMA_DIAG_POP
717 return NULL;
718}
719
720POINTER_CACHED_UPDATE* update_read_pointer_cached(rdpUpdate* update, wStream* s)
721{
722 POINTER_CACHED_UPDATE* pointer = calloc(1, sizeof(POINTER_CACHED_UPDATE));
723
724 WINPR_ASSERT(update);
725
726 if (!pointer)
727 goto fail;
728
729 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
730 goto fail;
731
732 Stream_Read_UINT16(s, pointer->cacheIndex); /* cacheIndex (2 bytes) */
733 return pointer;
734fail:
735 WINPR_PRAGMA_DIAG_PUSH
736 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
737 free_pointer_cached_update(update->context, pointer);
738 WINPR_PRAGMA_DIAG_POP
739 return NULL;
740}
741
742BOOL update_recv_pointer(rdpUpdate* update, wStream* s)
743{
744 BOOL rc = FALSE;
745 UINT16 messageType = 0;
746
747 WINPR_ASSERT(update);
748
749 rdpContext* context = update->context;
750 rdpPointerUpdate* pointer = update->pointer;
751
752 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2 + 2))
753 return FALSE;
754
755 Stream_Read_UINT16(s, messageType); /* messageType (2 bytes) */
756 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
757
758 switch (messageType)
759 {
760 case PTR_MSG_TYPE_POSITION:
761 {
762 POINTER_POSITION_UPDATE* pointer_position = update_read_pointer_position(update, s);
763
764 if (pointer_position)
765 {
766 rc = IFCALLRESULT(FALSE, pointer->PointerPosition, context, pointer_position);
767 free_pointer_position_update(context, pointer_position);
768 }
769 }
770 break;
771
772 case PTR_MSG_TYPE_SYSTEM:
773 {
774 POINTER_SYSTEM_UPDATE* pointer_system = update_read_pointer_system(update, s);
775
776 if (pointer_system)
777 {
778 rc = IFCALLRESULT(FALSE, pointer->PointerSystem, context, pointer_system);
779 free_pointer_system_update(context, pointer_system);
780 }
781 }
782 break;
783
784 case PTR_MSG_TYPE_COLOR:
785 {
786 POINTER_COLOR_UPDATE* pointer_color = update_read_pointer_color(update, s, 24);
787
788 if (pointer_color)
789 {
790 rc = IFCALLRESULT(FALSE, pointer->PointerColor, context, pointer_color);
791 free_pointer_color_update(context, pointer_color);
792 }
793 }
794 break;
795
796 case PTR_MSG_TYPE_POINTER_LARGE:
797 {
798 POINTER_LARGE_UPDATE* pointer_large = update_read_pointer_large(update, s);
799
800 if (pointer_large)
801 {
802 rc = IFCALLRESULT(FALSE, pointer->PointerLarge, context, pointer_large);
803 free_pointer_large_update(context, pointer_large);
804 }
805 }
806 break;
807
808 case PTR_MSG_TYPE_POINTER:
809 {
810 POINTER_NEW_UPDATE* pointer_new = update_read_pointer_new(update, s);
811
812 if (pointer_new)
813 {
814 rc = IFCALLRESULT(FALSE, pointer->PointerNew, context, pointer_new);
815 free_pointer_new_update(context, pointer_new);
816 }
817 }
818 break;
819
820 case PTR_MSG_TYPE_CACHED:
821 {
822 POINTER_CACHED_UPDATE* pointer_cached = update_read_pointer_cached(update, s);
823
824 if (pointer_cached)
825 {
826 rc = IFCALLRESULT(FALSE, pointer->PointerCached, context, pointer_cached);
827 free_pointer_cached_update(context, pointer_cached);
828 }
829 }
830 break;
831
832 default:
833 break;
834 }
835
836 return rc;
837}
838
839BOOL update_recv(rdpUpdate* update, wStream* s)
840{
841 BOOL rc = FALSE;
842 UINT16 updateType = 0;
843 rdp_update_internal* up = update_cast(update);
844 rdpContext* context = update->context;
845
846 WINPR_ASSERT(context);
847
848 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
849 return FALSE;
850
851 Stream_Read_UINT16(s, updateType); /* updateType (2 bytes) */
852 WLog_Print(up->log, WLOG_TRACE, "%s Update Data PDU", update_type_to_string(updateType));
853
854 if (!update_begin_paint(update))
855 goto fail;
856
857 switch (updateType)
858 {
859 case UPDATE_TYPE_ORDERS:
860 rc = update_recv_orders(update, s);
861 break;
862
863 case UPDATE_TYPE_BITMAP:
864 {
865 BITMAP_UPDATE* bitmap_update = update_read_bitmap_update(update, s);
866
867 if (!bitmap_update)
868 {
869 WLog_ERR(TAG, "UPDATE_TYPE_BITMAP - update_read_bitmap_update() failed");
870 goto fail;
871 }
872
873 rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, bitmap_update);
874 free_bitmap_update(context, bitmap_update);
875 }
876 break;
877
878 case UPDATE_TYPE_PALETTE:
879 {
880 PALETTE_UPDATE* palette_update = update_read_palette(update, s);
881
882 if (!palette_update)
883 {
884 WLog_ERR(TAG, "UPDATE_TYPE_PALETTE - update_read_palette() failed");
885 goto fail;
886 }
887
888 rc = IFCALLRESULT(FALSE, update->Palette, context, palette_update);
889 free_palette_update(context, palette_update);
890 }
891 break;
892
893 case UPDATE_TYPE_SYNCHRONIZE:
894 if (!update_read_synchronize(update, s))
895 goto fail;
896 rc = IFCALLRESULT(TRUE, update->Synchronize, context);
897 break;
898
899 default:
900 break;
901 }
902
903fail:
904
905 if (!update_end_paint(update))
906 rc = FALSE;
907
908 if (!rc)
909 {
910 WLog_ERR(TAG, "UPDATE_TYPE %s [%" PRIu16 "] failed", update_type_to_string(updateType),
911 updateType);
912 return FALSE;
913 }
914
915 return TRUE;
916}
917
918void update_reset_state(rdpUpdate* update)
919{
920 rdp_update_internal* up = update_cast(update);
921 rdp_primary_update_internal* primary = primary_update_cast(update->primary);
922
923 WINPR_ASSERT(primary);
924
925 ZeroMemory(&primary->order_info, sizeof(ORDER_INFO));
926 ZeroMemory(&primary->dstblt, sizeof(DSTBLT_ORDER));
927 ZeroMemory(&primary->patblt, sizeof(PATBLT_ORDER));
928 ZeroMemory(&primary->scrblt, sizeof(SCRBLT_ORDER));
929 ZeroMemory(&primary->opaque_rect, sizeof(OPAQUE_RECT_ORDER));
930 ZeroMemory(&primary->draw_nine_grid, sizeof(DRAW_NINE_GRID_ORDER));
931 ZeroMemory(&primary->multi_dstblt, sizeof(MULTI_DSTBLT_ORDER));
932 ZeroMemory(&primary->multi_patblt, sizeof(MULTI_PATBLT_ORDER));
933 ZeroMemory(&primary->multi_scrblt, sizeof(MULTI_SCRBLT_ORDER));
934 ZeroMemory(&primary->multi_opaque_rect, sizeof(MULTI_OPAQUE_RECT_ORDER));
935 ZeroMemory(&primary->multi_draw_nine_grid, sizeof(MULTI_DRAW_NINE_GRID_ORDER));
936 ZeroMemory(&primary->line_to, sizeof(LINE_TO_ORDER));
937
938 free(primary->polyline.points);
939 ZeroMemory(&primary->polyline, sizeof(POLYLINE_ORDER));
940
941 ZeroMemory(&primary->memblt, sizeof(MEMBLT_ORDER));
942 ZeroMemory(&primary->mem3blt, sizeof(MEM3BLT_ORDER));
943 ZeroMemory(&primary->save_bitmap, sizeof(SAVE_BITMAP_ORDER));
944 ZeroMemory(&primary->glyph_index, sizeof(GLYPH_INDEX_ORDER));
945 ZeroMemory(&primary->fast_index, sizeof(FAST_INDEX_ORDER));
946
947 free(primary->fast_glyph.glyphData.aj);
948 ZeroMemory(&primary->fast_glyph, sizeof(FAST_GLYPH_ORDER));
949
950 free(primary->polygon_sc.points);
951 ZeroMemory(&primary->polygon_sc, sizeof(POLYGON_SC_ORDER));
952
953 free(primary->polygon_cb.points);
954 ZeroMemory(&primary->polygon_cb, sizeof(POLYGON_CB_ORDER));
955
956 ZeroMemory(&primary->ellipse_sc, sizeof(ELLIPSE_SC_ORDER));
957 ZeroMemory(&primary->ellipse_cb, sizeof(ELLIPSE_CB_ORDER));
958 primary->order_info.orderType = ORDER_TYPE_PATBLT;
959
960 if (!up->initialState)
961 {
962 rdp_altsec_update_internal* altsec = altsec_update_cast(update->altsec);
963 WINPR_ASSERT(altsec);
964
965 altsec->switch_surface.bitmapId = SCREEN_BITMAP_SURFACE;
966 IFCALL(altsec->common.SwitchSurface, update->context, &(altsec->switch_surface));
967 }
968}
969
970BOOL update_post_connect(rdpUpdate* update)
971{
972 rdp_update_internal* up = update_cast(update);
973 rdp_altsec_update_internal* altsec = altsec_update_cast(update->altsec);
974
975 WINPR_ASSERT(update->context);
976 WINPR_ASSERT(update->context->settings);
977 up->asynchronous = update->context->settings->AsyncUpdate;
978
979 if (up->asynchronous)
980 {
981#if defined(FORCE_ASYNC_UPDATE_OFF)
982 WLog_WARN(TAG, "AsyncUpdate requested, but forced deactivated");
983 WLog_WARN(TAG, "see https://github.com/FreeRDP/FreeRDP/issues/10153 for details");
984#else
985 if (!(up->proxy = update_message_proxy_new(update)))
986 return FALSE;
987#endif
988 }
989
990 altsec->switch_surface.bitmapId = SCREEN_BITMAP_SURFACE;
991 IFCALL(update->altsec->SwitchSurface, update->context, &(altsec->switch_surface));
992 up->initialState = FALSE;
993 return TRUE;
994}
995
996void update_post_disconnect(rdpUpdate* update)
997{
998 rdp_update_internal* up = update_cast(update);
999
1000 WINPR_ASSERT(update->context);
1001 WINPR_ASSERT(update->context->settings);
1002
1003 up->asynchronous = update->context->settings->AsyncUpdate;
1004
1005 if (up->asynchronous)
1006 {
1007#if !defined(FORCE_ASYNC_UPDATE_OFF)
1008 update_message_proxy_free(up->proxy);
1009#endif
1010 }
1011
1012 up->initialState = TRUE;
1013}
1014
1015static BOOL s_update_begin_paint(rdpContext* context)
1016{
1017 wStream* s = NULL;
1018 WINPR_ASSERT(context);
1019 rdp_update_internal* update = update_cast(context->update);
1020
1021 if (update->us)
1022 {
1023 if (!update_end_paint(&update->common))
1024 return FALSE;
1025 }
1026
1027 WINPR_ASSERT(context->rdp);
1028 s = fastpath_update_pdu_init_new(context->rdp->fastpath);
1029
1030 if (!s)
1031 return FALSE;
1032
1033 Stream_SealLength(s);
1034 Stream_GetLength(s, update->offsetOrders);
1035 Stream_Seek(s, 2); /* numberOrders (2 bytes) */
1036 update->combineUpdates = TRUE;
1037 update->numberOrders = 0;
1038 update->us = s;
1039 return TRUE;
1040}
1041
1042static BOOL s_update_end_paint(rdpContext* context)
1043{
1044 wStream* s = NULL;
1045 WINPR_ASSERT(context);
1046 rdp_update_internal* update = update_cast(context->update);
1047
1048 if (!update->us)
1049 return FALSE;
1050
1051 s = update->us;
1052 Stream_SealLength(s);
1053 Stream_SetPosition(s, update->offsetOrders);
1054 Stream_Write_UINT16(s, update->numberOrders); /* numberOrders (2 bytes) */
1055 Stream_SetPosition(s, Stream_Length(s));
1056
1057 if (update->numberOrders > 0)
1058 {
1059 WLog_DBG(TAG, "sending %" PRIu16 " orders", update->numberOrders);
1060 fastpath_send_update_pdu(context->rdp->fastpath, FASTPATH_UPDATETYPE_ORDERS, s, FALSE);
1061 }
1062
1063 update->combineUpdates = FALSE;
1064 update->numberOrders = 0;
1065 update->offsetOrders = 0;
1066 update->us = NULL;
1067 Stream_Free(s, TRUE);
1068 return TRUE;
1069}
1070
1071static BOOL update_flush(rdpContext* context)
1072{
1073 rdp_update_internal* update = NULL;
1074
1075 WINPR_ASSERT(context);
1076 update = update_cast(context->update);
1077
1078 if (update->numberOrders > 0)
1079 {
1080 if (!update_end_paint(&update->common))
1081 return FALSE;
1082
1083 if (!update_begin_paint(&update->common))
1084 return FALSE;
1085 }
1086 return TRUE;
1087}
1088
1089static BOOL update_force_flush(rdpContext* context)
1090{
1091 return update_flush(context);
1092}
1093
1094static BOOL update_check_flush(rdpContext* context, size_t size)
1095{
1096 WINPR_ASSERT(context);
1097 rdp_update_internal* update = update_cast(context->update);
1098
1099 wStream* s = update->us;
1100
1101 if (!s)
1102 {
1103 if (!update_begin_paint(&update->common))
1104 return FALSE;
1105 s = update->us;
1106 }
1107
1108 if (Stream_GetPosition(s) + size + 64 >= FASTPATH_MAX_PACKET_SIZE)
1109 {
1110 // Too big for the current packet. Flush first
1111 if (!update_flush(context))
1112 return FALSE;
1113 }
1114
1115 return TRUE;
1116}
1117
1118static BOOL update_set_bounds(rdpContext* context, const rdpBounds* bounds)
1119{
1120 rdp_update_internal* update = NULL;
1121
1122 WINPR_ASSERT(context);
1123
1124 update = update_cast(context->update);
1125
1126 CopyMemory(&update->previousBounds, &update->currentBounds, sizeof(rdpBounds));
1127
1128 if (!bounds)
1129 ZeroMemory(&update->currentBounds, sizeof(rdpBounds));
1130 else
1131 CopyMemory(&update->currentBounds, bounds, sizeof(rdpBounds));
1132
1133 return TRUE;
1134}
1135
1136static BOOL update_bounds_is_null(rdpBounds* bounds)
1137{
1138 WINPR_ASSERT(bounds);
1139 if ((bounds->left == 0) && (bounds->top == 0) && (bounds->right == 0) && (bounds->bottom == 0))
1140 return TRUE;
1141
1142 return FALSE;
1143}
1144
1145static BOOL update_bounds_equals(rdpBounds* bounds1, rdpBounds* bounds2)
1146{
1147 WINPR_ASSERT(bounds1);
1148 WINPR_ASSERT(bounds2);
1149
1150 if ((bounds1->left == bounds2->left) && (bounds1->top == bounds2->top) &&
1151 (bounds1->right == bounds2->right) && (bounds1->bottom == bounds2->bottom))
1152 return TRUE;
1153
1154 return FALSE;
1155}
1156
1157static size_t update_prepare_bounds(rdpContext* context, ORDER_INFO* orderInfo)
1158{
1159 size_t length = 0;
1160 rdp_update_internal* update = NULL;
1161
1162 WINPR_ASSERT(context);
1163 WINPR_ASSERT(orderInfo);
1164
1165 update = update_cast(context->update);
1166
1167 orderInfo->boundsFlags = 0;
1168
1169 if (update_bounds_is_null(&update->currentBounds))
1170 return 0;
1171
1172 orderInfo->controlFlags |= ORDER_BOUNDS;
1173
1174 if (update_bounds_equals(&update->previousBounds, &update->currentBounds))
1175 {
1176 orderInfo->controlFlags |= ORDER_ZERO_BOUNDS_DELTAS;
1177 return 0;
1178 }
1179 else
1180 {
1181 length += 1;
1182
1183 if (update->previousBounds.left != update->currentBounds.left)
1184 {
1185 orderInfo->bounds.left = update->currentBounds.left;
1186 orderInfo->boundsFlags |= BOUND_LEFT;
1187 length += 2;
1188 }
1189
1190 if (update->previousBounds.top != update->currentBounds.top)
1191 {
1192 orderInfo->bounds.top = update->currentBounds.top;
1193 orderInfo->boundsFlags |= BOUND_TOP;
1194 length += 2;
1195 }
1196
1197 if (update->previousBounds.right != update->currentBounds.right)
1198 {
1199 orderInfo->bounds.right = update->currentBounds.right;
1200 orderInfo->boundsFlags |= BOUND_RIGHT;
1201 length += 2;
1202 }
1203
1204 if (update->previousBounds.bottom != update->currentBounds.bottom)
1205 {
1206 orderInfo->bounds.bottom = update->currentBounds.bottom;
1207 orderInfo->boundsFlags |= BOUND_BOTTOM;
1208 length += 2;
1209 }
1210 }
1211
1212 return length;
1213}
1214
1215static size_t update_prepare_order_info(rdpContext* context, ORDER_INFO* orderInfo,
1216 UINT32 orderType)
1217{
1218 WINPR_ASSERT(context);
1219 WINPR_ASSERT(orderInfo);
1220
1221 orderInfo->fieldFlags = 0;
1222 orderInfo->orderType = orderType;
1223 orderInfo->controlFlags = ORDER_STANDARD;
1224 orderInfo->controlFlags |= ORDER_TYPE_CHANGE;
1225 size_t length = 2;
1226 length += get_primary_drawing_order_field_bytes(orderInfo->orderType, NULL);
1227 length += update_prepare_bounds(context, orderInfo);
1228 return length;
1229}
1230
1231static int update_write_order_info(rdpContext* context, wStream* s, const ORDER_INFO* orderInfo,
1232 size_t offset)
1233{
1234 WINPR_UNUSED(context);
1235 WINPR_ASSERT(orderInfo);
1236 WINPR_ASSERT(orderInfo->controlFlags <= UINT8_MAX);
1237
1238 const size_t position = Stream_GetPosition(s);
1239 const UINT8 controlFlags = (UINT8)orderInfo->controlFlags;
1240
1241 Stream_SetPosition(s, offset);
1242 Stream_Write_UINT8(s, controlFlags); /* controlFlags (1 byte) */
1243
1244 if (orderInfo->controlFlags & ORDER_TYPE_CHANGE)
1245 Stream_Write_UINT8(
1246 s, WINPR_ASSERTING_INT_CAST(uint8_t, orderInfo->orderType)); /* orderType (1 byte) */
1247
1248 if (!update_write_field_flags(
1249 s, orderInfo->fieldFlags, controlFlags,
1250 get_primary_drawing_order_field_bytes(orderInfo->orderType, NULL)))
1251 return -1;
1252 if (!update_write_bounds(s, orderInfo))
1253 return -1;
1254 Stream_SetPosition(s, position);
1255 return 0;
1256}
1257
1258static void update_write_refresh_rect(wStream* s, BYTE count, const RECTANGLE_16* areas)
1259{
1260 WINPR_ASSERT(s);
1261 WINPR_ASSERT(areas || (count == 0));
1262
1263 Stream_Write_UINT8(s, count); /* numberOfAreas (1 byte) */
1264 Stream_Seek(s, 3); /* pad3Octets (3 bytes) */
1265
1266 for (BYTE i = 0; i < count; i++)
1267 {
1268 Stream_Write_UINT16(s, areas[i].left); /* left (2 bytes) */
1269 Stream_Write_UINT16(s, areas[i].top); /* top (2 bytes) */
1270 Stream_Write_UINT16(s, areas[i].right); /* right (2 bytes) */
1271 Stream_Write_UINT16(s, areas[i].bottom); /* bottom (2 bytes) */
1272 }
1273}
1274
1275static BOOL update_send_refresh_rect(rdpContext* context, BYTE count, const RECTANGLE_16* areas)
1276{
1277 WINPR_ASSERT(context);
1278 rdpRdp* rdp = context->rdp;
1279
1280 WINPR_ASSERT(rdp->settings);
1281 if (rdp->settings->RefreshRect)
1282 {
1283 UINT16 sec_flags = 0;
1284 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
1285
1286 if (!s)
1287 return FALSE;
1288
1289 update_write_refresh_rect(s, count, areas);
1290 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_REFRESH_RECT, rdp->mcs->userId, sec_flags);
1291 }
1292
1293 return TRUE;
1294}
1295
1296static void update_write_suppress_output(wStream* s, BYTE allow, const RECTANGLE_16* area)
1297{
1298 WINPR_ASSERT(s);
1299
1300 Stream_Write_UINT8(s, allow); /* allowDisplayUpdates (1 byte) */
1301 /* Use zeros for padding (like mstsc) for compatibility with legacy servers */
1302 Stream_Zero(s, 3); /* pad3Octets (3 bytes) */
1303
1304 if (allow > 0)
1305 {
1306 WINPR_ASSERT(area);
1307 Stream_Write_UINT16(s, area->left); /* left (2 bytes) */
1308 Stream_Write_UINT16(s, area->top); /* top (2 bytes) */
1309 Stream_Write_UINT16(s, area->right); /* right (2 bytes) */
1310 Stream_Write_UINT16(s, area->bottom); /* bottom (2 bytes) */
1311 }
1312}
1313
1314static BOOL update_send_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
1315{
1316 WINPR_ASSERT(context);
1317 rdpRdp* rdp = context->rdp;
1318
1319 WINPR_ASSERT(rdp);
1320 WINPR_ASSERT(rdp->settings);
1321 if (rdp->settings->SuppressOutput)
1322 {
1323 UINT16 sec_flags = 0;
1324 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
1325
1326 if (!s)
1327 return FALSE;
1328
1329 update_write_suppress_output(s, allow, area);
1330 WINPR_ASSERT(rdp->mcs);
1331 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SUPPRESS_OUTPUT, rdp->mcs->userId,
1332 sec_flags);
1333 }
1334
1335 return TRUE;
1336}
1337
1338static BOOL update_send_surface_command(rdpContext* context, wStream* s)
1339{
1340 wStream* update = NULL;
1341 WINPR_ASSERT(context);
1342 rdpRdp* rdp = context->rdp;
1343 BOOL ret = 0;
1344
1345 WINPR_ASSERT(rdp);
1346 update = fastpath_update_pdu_init(rdp->fastpath);
1347
1348 if (!update)
1349 return FALSE;
1350
1351 if (!Stream_EnsureRemainingCapacity(update, Stream_GetPosition(s)))
1352 {
1353 ret = FALSE;
1354 goto out;
1355 }
1356
1357 Stream_Write(update, Stream_Buffer(s), Stream_GetPosition(s));
1358 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, update, FALSE);
1359out:
1360 Stream_Release(update);
1361 return ret;
1362}
1363
1364static BOOL update_send_surface_bits(rdpContext* context,
1365 const SURFACE_BITS_COMMAND* surfaceBitsCommand)
1366{
1367 wStream* s = NULL;
1368 WINPR_ASSERT(context);
1369 rdpRdp* rdp = context->rdp;
1370 BOOL ret = FALSE;
1371
1372 WINPR_ASSERT(surfaceBitsCommand);
1373 WINPR_ASSERT(rdp);
1374
1375 if (!update_force_flush(context))
1376 return FALSE;
1377 s = fastpath_update_pdu_init(rdp->fastpath);
1378
1379 if (!s)
1380 return FALSE;
1381
1382 if (!update_write_surfcmd_surface_bits(s, surfaceBitsCommand))
1383 goto out_fail;
1384
1385 if (!fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s,
1386 surfaceBitsCommand->skipCompression))
1387 goto out_fail;
1388
1389 ret = update_force_flush(context);
1390out_fail:
1391 Stream_Release(s);
1392 return ret;
1393}
1394
1395static BOOL update_send_surface_frame_marker(rdpContext* context,
1396 const SURFACE_FRAME_MARKER* surfaceFrameMarker)
1397{
1398 wStream* s = NULL;
1399 WINPR_ASSERT(context);
1400 rdpRdp* rdp = context->rdp;
1401 BOOL ret = FALSE;
1402 if (!update_force_flush(context))
1403 return FALSE;
1404
1405 WINPR_ASSERT(rdp);
1406 s = fastpath_update_pdu_init(rdp->fastpath);
1407
1408 if (!s)
1409 return FALSE;
1410
1411 WINPR_ASSERT(surfaceFrameMarker->frameAction <= UINT16_MAX);
1412 if (!update_write_surfcmd_frame_marker(s, (UINT16)surfaceFrameMarker->frameAction,
1413 surfaceFrameMarker->frameId) ||
1414 !fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s, FALSE))
1415 goto out_fail;
1416
1417 ret = update_force_flush(context);
1418out_fail:
1419 Stream_Release(s);
1420 return ret;
1421}
1422
1423static BOOL update_send_surface_frame_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cmd,
1424 BOOL first, BOOL last, UINT32 frameId)
1425{
1426 wStream* s = NULL;
1427
1428 WINPR_ASSERT(context);
1429 rdpRdp* rdp = context->rdp;
1430 BOOL ret = FALSE;
1431
1432 if (!update_force_flush(context))
1433 return FALSE;
1434
1435 WINPR_ASSERT(rdp);
1436 s = fastpath_update_pdu_init(rdp->fastpath);
1437
1438 if (!s)
1439 return FALSE;
1440
1441 if (first)
1442 {
1443 if (!update_write_surfcmd_frame_marker(s, SURFACECMD_FRAMEACTION_BEGIN, frameId))
1444 goto out_fail;
1445 }
1446
1447 if (!update_write_surfcmd_surface_bits(s, cmd))
1448 goto out_fail;
1449
1450 if (last)
1451 {
1452 if (!update_write_surfcmd_frame_marker(s, SURFACECMD_FRAMEACTION_END, frameId))
1453 goto out_fail;
1454 }
1455
1456 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s,
1457 cmd->skipCompression);
1458 if (!ret)
1459 goto out_fail;
1460
1461 ret = update_force_flush(context);
1462out_fail:
1463 Stream_Release(s);
1464 return ret;
1465}
1466
1467static BOOL update_send_frame_acknowledge(rdpContext* context, UINT32 frameId)
1468{
1469 WINPR_ASSERT(context);
1470 rdpRdp* rdp = context->rdp;
1471
1472 WINPR_ASSERT(rdp);
1473 WINPR_ASSERT(rdp->settings);
1474 if (rdp->settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
1475 {
1476 UINT16 sec_flags = 0;
1477 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
1478
1479 if (!s)
1480 return FALSE;
1481
1482 Stream_Write_UINT32(s, frameId);
1483 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_FRAME_ACKNOWLEDGE, rdp->mcs->userId,
1484 sec_flags);
1485 }
1486
1487 return TRUE;
1488}
1489
1490static BOOL update_send_synchronize(rdpContext* context)
1491{
1492 wStream* s = NULL;
1493 WINPR_ASSERT(context);
1494 rdpRdp* rdp = context->rdp;
1495 BOOL ret = 0;
1496
1497 WINPR_ASSERT(rdp);
1498 s = fastpath_update_pdu_init(rdp->fastpath);
1499
1500 if (!s)
1501 return FALSE;
1502
1503 Stream_Zero(s, 2); /* pad2Octets (2 bytes) */
1504 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SYNCHRONIZE, s, FALSE);
1505 Stream_Release(s);
1506 return ret;
1507}
1508
1509static BOOL update_send_desktop_resize(rdpContext* context)
1510{
1511 WINPR_ASSERT(context);
1512 return rdp_server_reactivate(context->rdp);
1513}
1514
1515static BOOL update_send_bitmap_update(rdpContext* context, const BITMAP_UPDATE* bitmapUpdate)
1516{
1517 wStream* s = NULL;
1518 WINPR_ASSERT(context);
1519 rdpRdp* rdp = context->rdp;
1520 rdpUpdate* update = context->update;
1521 BOOL ret = TRUE;
1522
1523 if (!update_force_flush(context))
1524 return FALSE;
1525
1526 WINPR_ASSERT(rdp);
1527 s = fastpath_update_pdu_init(rdp->fastpath);
1528
1529 if (!s)
1530 return FALSE;
1531
1532 if (!update_write_bitmap_update(update, s, bitmapUpdate) ||
1533 !fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_BITMAP, s,
1534 bitmapUpdate->skipCompression))
1535 {
1536 ret = FALSE;
1537 goto out_fail;
1538 }
1539
1540 ret = update_force_flush(context);
1541
1542out_fail:
1543 Stream_Release(s);
1544 return ret;
1545}
1546
1547static BOOL update_send_play_sound(rdpContext* context, const PLAY_SOUND_UPDATE* play_sound)
1548{
1549 UINT16 sec_flags = 0;
1550 wStream* s = NULL;
1551 WINPR_ASSERT(context);
1552 rdpRdp* rdp = context->rdp;
1553
1554 WINPR_ASSERT(rdp);
1555 WINPR_ASSERT(rdp->settings);
1556 WINPR_ASSERT(play_sound);
1557 if (!rdp->settings->ReceivedCapabilities[CAPSET_TYPE_SOUND])
1558 {
1559 return TRUE;
1560 }
1561
1562 s = rdp_data_pdu_init(rdp, &sec_flags);
1563
1564 if (!s)
1565 return FALSE;
1566
1567 Stream_Write_UINT32(s, play_sound->duration);
1568 Stream_Write_UINT32(s, play_sound->frequency);
1569 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_PLAY_SOUND, rdp->mcs->userId, sec_flags);
1570}
1571
1576static BOOL update_send_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt)
1577{
1578 ORDER_INFO orderInfo = { 0 };
1579
1580 WINPR_ASSERT(context);
1581 WINPR_ASSERT(dstblt);
1582
1583 rdp_update_internal* update = update_cast(context->update);
1584
1585 const size_t headerLength = update_prepare_order_info(context, &orderInfo, ORDER_TYPE_DSTBLT);
1586 const size_t inf = update_approximate_dstblt_order(&orderInfo, dstblt);
1587 if (!update_check_flush(context, headerLength + inf))
1588 return FALSE;
1589
1590 wStream* s = update->us;
1591
1592 if (!s)
1593 return FALSE;
1594
1595 const size_t offset = Stream_GetPosition(s);
1596
1597 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1598 return FALSE;
1599
1600 Stream_Seek(s, headerLength);
1601
1602 if (!update_write_dstblt_order(s, &orderInfo, dstblt))
1603 return FALSE;
1604
1605 update_write_order_info(context, s, &orderInfo, offset);
1606 update->numberOrders++;
1607 return TRUE;
1608}
1609
1610static BOOL update_send_patblt(rdpContext* context, PATBLT_ORDER* patblt)
1611{
1612 size_t offset = 0;
1613 ORDER_INFO orderInfo = { 0 };
1614
1615 WINPR_ASSERT(context);
1616 WINPR_ASSERT(patblt);
1617 rdp_update_internal* update = update_cast(context->update);
1618
1619 const size_t headerLength = update_prepare_order_info(context, &orderInfo, ORDER_TYPE_PATBLT);
1620 if (!update_check_flush(context,
1621 headerLength + update_approximate_patblt_order(&orderInfo, patblt)))
1622 return FALSE;
1623
1624 wStream* s = update->us;
1625
1626 if (!s)
1627 return FALSE;
1628
1629 offset = Stream_GetPosition(s);
1630
1631 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1632 return FALSE;
1633
1634 Stream_Seek(s, headerLength);
1635 update_write_patblt_order(s, &orderInfo, patblt);
1636 update_write_order_info(context, s, &orderInfo, offset);
1637 update->numberOrders++;
1638 return TRUE;
1639}
1640
1641static BOOL update_send_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt)
1642{
1643 ORDER_INFO orderInfo = { 0 };
1644
1645 WINPR_ASSERT(context);
1646 WINPR_ASSERT(scrblt);
1647 rdp_update_internal* update = update_cast(context->update);
1648
1649 const size_t headerLength = update_prepare_order_info(context, &orderInfo, ORDER_TYPE_SCRBLT);
1650 const size_t inf = update_approximate_scrblt_order(&orderInfo, scrblt);
1651 if (!update_check_flush(context, headerLength + inf))
1652 return FALSE;
1653
1654 wStream* s = update->us;
1655
1656 if (!s)
1657 return TRUE;
1658
1659 const size_t offset = Stream_GetPosition(s);
1660
1661 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1662 return FALSE;
1663
1664 Stream_Seek(s, headerLength);
1665 update_write_scrblt_order(s, &orderInfo, scrblt);
1666 update_write_order_info(context, s, &orderInfo, offset);
1667 update->numberOrders++;
1668 return TRUE;
1669}
1670
1671static BOOL update_send_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect)
1672{
1673 size_t offset = 0;
1674 ORDER_INFO orderInfo = { 0 };
1675
1676 WINPR_ASSERT(context);
1677 WINPR_ASSERT(opaque_rect);
1678 rdp_update_internal* update = update_cast(context->update);
1679
1680 const size_t headerLength =
1681 update_prepare_order_info(context, &orderInfo, ORDER_TYPE_OPAQUE_RECT);
1682 if (!update_check_flush(
1683 context, headerLength + update_approximate_opaque_rect_order(&orderInfo, opaque_rect)))
1684 return FALSE;
1685
1686 wStream* s = update->us;
1687
1688 if (!s)
1689 return FALSE;
1690
1691 offset = Stream_GetPosition(s);
1692
1693 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1694 return FALSE;
1695
1696 Stream_Seek(s, headerLength);
1697 update_write_opaque_rect_order(s, &orderInfo, opaque_rect);
1698 update_write_order_info(context, s, &orderInfo, offset);
1699 update->numberOrders++;
1700 return TRUE;
1701}
1702
1703static BOOL update_send_line_to(rdpContext* context, const LINE_TO_ORDER* line_to)
1704{
1705 ORDER_INFO orderInfo = { 0 };
1706
1707 WINPR_ASSERT(context);
1708 WINPR_ASSERT(line_to);
1709 rdp_update_internal* update = update_cast(context->update);
1710 const size_t headerLength = update_prepare_order_info(context, &orderInfo, ORDER_TYPE_LINE_TO);
1711 const size_t inf = update_approximate_line_to_order(&orderInfo, line_to);
1712 if (!update_check_flush(context, headerLength + inf))
1713 return FALSE;
1714
1715 wStream* s = update->us;
1716
1717 if (!s)
1718 return FALSE;
1719
1720 const size_t offset = Stream_GetPosition(s);
1721
1722 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1723 return FALSE;
1724
1725 Stream_Seek(s, headerLength);
1726 update_write_line_to_order(s, &orderInfo, line_to);
1727 update_write_order_info(context, s, &orderInfo, offset);
1728 update->numberOrders++;
1729 return TRUE;
1730}
1731
1732static BOOL update_send_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
1733{
1734 size_t offset = 0;
1735 ORDER_INFO orderInfo = { 0 };
1736
1737 WINPR_ASSERT(context);
1738 WINPR_ASSERT(memblt);
1739 rdp_update_internal* update = update_cast(context->update);
1740 const size_t headerLength = update_prepare_order_info(context, &orderInfo, ORDER_TYPE_MEMBLT);
1741 if (!update_check_flush(context,
1742 headerLength + update_approximate_memblt_order(&orderInfo, memblt)))
1743 return FALSE;
1744
1745 wStream* s = update->us;
1746
1747 if (!s)
1748 return FALSE;
1749
1750 offset = Stream_GetPosition(s);
1751
1752 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1753 return FALSE;
1754
1755 Stream_Seek(s, headerLength);
1756 update_write_memblt_order(s, &orderInfo, memblt);
1757 update_write_order_info(context, s, &orderInfo, offset);
1758 update->numberOrders++;
1759 return TRUE;
1760}
1761
1762static BOOL update_send_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyph_index)
1763{
1764 ORDER_INFO orderInfo = { 0 };
1765
1766 WINPR_ASSERT(context);
1767 WINPR_ASSERT(glyph_index);
1768 rdp_update_internal* update = update_cast(context->update);
1769
1770 const size_t headerLength =
1771 update_prepare_order_info(context, &orderInfo, ORDER_TYPE_GLYPH_INDEX);
1772 const size_t inf = update_approximate_glyph_index_order(&orderInfo, glyph_index);
1773 if (!update_check_flush(context, headerLength + inf))
1774 return FALSE;
1775
1776 wStream* s = update->us;
1777
1778 if (!s)
1779 return FALSE;
1780
1781 const size_t offset = Stream_GetPosition(s);
1782
1783 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1784 return FALSE;
1785
1786 Stream_Seek(s, headerLength);
1787 update_write_glyph_index_order(s, &orderInfo, glyph_index);
1788 update_write_order_info(context, s, &orderInfo, offset);
1789 update->numberOrders++;
1790 return TRUE;
1791}
1792
1793/*
1794 * Secondary Drawing Orders
1795 */
1796
1797static BOOL update_send_cache_bitmap(rdpContext* context, const CACHE_BITMAP_ORDER* cache_bitmap)
1798{
1799 const size_t headerLength = 6;
1800 UINT16 extraFlags = 0;
1801
1802 WINPR_ASSERT(context);
1803 WINPR_ASSERT(cache_bitmap);
1804 rdp_update_internal* update = update_cast(context->update);
1805
1806 const BYTE orderType = cache_bitmap->compressed ? ORDER_TYPE_CACHE_BITMAP_COMPRESSED
1807 : ORDER_TYPE_BITMAP_UNCOMPRESSED;
1808 const size_t inf =
1809 update_approximate_cache_bitmap_order(cache_bitmap, cache_bitmap->compressed, &extraFlags);
1810 if (!update_check_flush(context, headerLength + inf))
1811 return FALSE;
1812
1813 wStream* s = update->us;
1814
1815 if (!s)
1816 return FALSE;
1817
1818 const size_t bm = Stream_GetPosition(s);
1819
1820 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1821 return FALSE;
1822
1823 Stream_Seek(s, headerLength);
1824
1825 if (!update_write_cache_bitmap_order(s, cache_bitmap, cache_bitmap->compressed, &extraFlags))
1826 return FALSE;
1827
1828 const size_t em = Stream_GetPosition(s);
1829 WINPR_ASSERT(em >= bm + 13);
1830 const size_t orderLength = (em - bm) - 13;
1831 WINPR_ASSERT(orderLength <= UINT16_MAX);
1832
1833 Stream_SetPosition(s, bm);
1834 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
1835 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
1836 Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
1837 Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */
1838 Stream_SetPosition(s, em);
1839 update->numberOrders++;
1840 return TRUE;
1841}
1842
1843static BOOL update_send_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cache_bitmap_v2)
1844{
1845 const size_t headerLength = 6;
1846 UINT16 extraFlags = 0;
1847
1848 WINPR_ASSERT(context);
1849 WINPR_ASSERT(cache_bitmap_v2);
1850 rdp_update_internal* update = update_cast(context->update);
1851
1852 const BYTE orderType = cache_bitmap_v2->compressed ? ORDER_TYPE_BITMAP_COMPRESSED_V2
1853 : ORDER_TYPE_BITMAP_UNCOMPRESSED_V2;
1854
1855 if (context->settings->NoBitmapCompressionHeader)
1856 cache_bitmap_v2->flags |= CBR2_NO_BITMAP_COMPRESSION_HDR;
1857
1858 if (!update_check_flush(
1859 context, headerLength + update_approximate_cache_bitmap_v2_order(
1860 cache_bitmap_v2, cache_bitmap_v2->compressed, &extraFlags)))
1861 return FALSE;
1862
1863 wStream* s = update->us;
1864
1865 if (!s)
1866 return FALSE;
1867
1868 const size_t bm = Stream_GetPosition(s);
1869
1870 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1871 return FALSE;
1872
1873 Stream_Seek(s, headerLength);
1874
1875 if (!update_write_cache_bitmap_v2_order(s, cache_bitmap_v2, cache_bitmap_v2->compressed,
1876 &extraFlags))
1877 return FALSE;
1878
1879 const size_t em = Stream_GetPosition(s);
1880 WINPR_ASSERT(em >= bm + 13);
1881 const size_t orderLength = (em - bm) - 13;
1882 WINPR_ASSERT(orderLength <= UINT16_MAX);
1883
1884 Stream_SetPosition(s, bm);
1885 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
1886 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
1887 Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
1888 Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */
1889 Stream_SetPosition(s, em);
1890 update->numberOrders++;
1891 return TRUE;
1892}
1893
1894static BOOL update_send_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cache_bitmap_v3)
1895{
1896 const size_t headerLength = 6;
1897 UINT16 extraFlags = 0;
1898
1899 WINPR_ASSERT(context);
1900 WINPR_ASSERT(cache_bitmap_v3);
1901 rdp_update_internal* update = update_cast(context->update);
1902
1903 const BYTE orderType = ORDER_TYPE_BITMAP_COMPRESSED_V3;
1904 if (!update_check_flush(context, headerLength + update_approximate_cache_bitmap_v3_order(
1905 cache_bitmap_v3, &extraFlags)))
1906 return FALSE;
1907
1908 wStream* s = update->us;
1909
1910 if (!s)
1911 return FALSE;
1912
1913 const size_t bm = Stream_GetPosition(s);
1914
1915 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1916 return FALSE;
1917
1918 Stream_Seek(s, headerLength);
1919
1920 if (!update_write_cache_bitmap_v3_order(s, cache_bitmap_v3, &extraFlags))
1921 return FALSE;
1922
1923 const size_t em = Stream_GetPosition(s);
1924 WINPR_ASSERT(em >= bm + 13);
1925 const size_t orderLength = (em - bm) - 13;
1926 WINPR_ASSERT(orderLength <= UINT16_MAX);
1927
1928 Stream_SetPosition(s, bm);
1929 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
1930 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
1931 Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
1932 Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */
1933 Stream_SetPosition(s, em);
1934 update->numberOrders++;
1935 return TRUE;
1936}
1937
1938static BOOL update_send_cache_color_table(rdpContext* context,
1939 const CACHE_COLOR_TABLE_ORDER* cache_color_table)
1940{
1941 UINT16 flags = 0;
1942 size_t headerLength = 6;
1943
1944 WINPR_ASSERT(context);
1945 WINPR_ASSERT(cache_color_table);
1946 rdp_update_internal* update = update_cast(context->update);
1947
1948 const size_t inf = update_approximate_cache_color_table_order(cache_color_table, &flags);
1949 if (!update_check_flush(context, headerLength + inf))
1950 return FALSE;
1951
1952 wStream* s = update->us;
1953
1954 if (!s)
1955 return FALSE;
1956
1957 const size_t bm = Stream_GetPosition(s);
1958
1959 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1960 return FALSE;
1961
1962 Stream_Seek(s, headerLength);
1963
1964 if (!update_write_cache_color_table_order(s, cache_color_table, &flags))
1965 return FALSE;
1966
1967 const size_t em = Stream_GetPosition(s);
1968 WINPR_ASSERT(em >= bm + 13);
1969 const size_t orderLength = (em - bm) - 13;
1970 WINPR_ASSERT(orderLength <= UINT16_MAX);
1971 Stream_SetPosition(s, bm);
1972 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
1973 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
1974 Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
1975 Stream_Write_UINT8(s, ORDER_TYPE_CACHE_COLOR_TABLE); /* orderType (1 byte) */
1976 Stream_SetPosition(s, em);
1977 update->numberOrders++;
1978 return TRUE;
1979}
1980
1981static BOOL update_send_cache_glyph(rdpContext* context, const CACHE_GLYPH_ORDER* cache_glyph)
1982{
1983 UINT16 flags = 0;
1984 const size_t headerLength = 6;
1985
1986 WINPR_ASSERT(context);
1987 WINPR_ASSERT(cache_glyph);
1988 rdp_update_internal* update = update_cast(context->update);
1989
1990 const size_t inf = update_approximate_cache_glyph_order(cache_glyph, &flags);
1991 if (!update_check_flush(context, headerLength + inf))
1992 return FALSE;
1993
1994 wStream* s = update->us;
1995
1996 if (!s)
1997 return FALSE;
1998
1999 const size_t bm = Stream_GetPosition(s);
2000
2001 if (!Stream_EnsureRemainingCapacity(s, headerLength))
2002 return FALSE;
2003
2004 Stream_Seek(s, headerLength);
2005
2006 if (!update_write_cache_glyph_order(s, cache_glyph, &flags))
2007 return FALSE;
2008
2009 const size_t em = Stream_GetPosition(s);
2010 WINPR_ASSERT(em >= bm + 13);
2011 const size_t orderLength = (em - bm) - 13;
2012 WINPR_ASSERT(orderLength <= UINT16_MAX);
2013 Stream_SetPosition(s, bm);
2014 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
2015 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
2016 Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
2017 Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */
2018 Stream_SetPosition(s, em);
2019 update->numberOrders++;
2020 return TRUE;
2021}
2022
2023static BOOL update_send_cache_glyph_v2(rdpContext* context,
2024 const CACHE_GLYPH_V2_ORDER* cache_glyph_v2)
2025{
2026 UINT16 flags = 0;
2027 const size_t headerLength = 6;
2028
2029 WINPR_ASSERT(context);
2030 WINPR_ASSERT(cache_glyph_v2);
2031 rdp_update_internal* update = update_cast(context->update);
2032
2033 const size_t inf = update_approximate_cache_glyph_v2_order(cache_glyph_v2, &flags);
2034 if (!update_check_flush(context, headerLength + inf))
2035 return FALSE;
2036
2037 wStream* s = update->us;
2038
2039 if (!s)
2040 return FALSE;
2041
2042 const size_t bm = Stream_GetPosition(s);
2043
2044 if (!Stream_EnsureRemainingCapacity(s, headerLength))
2045 return FALSE;
2046
2047 Stream_Seek(s, headerLength);
2048
2049 if (!update_write_cache_glyph_v2_order(s, cache_glyph_v2, &flags))
2050 return FALSE;
2051
2052 const size_t em = Stream_GetPosition(s);
2053 WINPR_ASSERT(em >= bm + 13);
2054 const size_t orderLength = (em - bm) - 13;
2055 WINPR_ASSERT(orderLength <= UINT16_MAX);
2056 Stream_SetPosition(s, bm);
2057 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
2058 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
2059 Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
2060 Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */
2061 Stream_SetPosition(s, em);
2062 update->numberOrders++;
2063 return TRUE;
2064}
2065
2066static BOOL update_send_cache_brush(rdpContext* context, const CACHE_BRUSH_ORDER* cache_brush)
2067{
2068 UINT16 flags = 0;
2069 const size_t headerLength = 6;
2070
2071 WINPR_ASSERT(context);
2072 WINPR_ASSERT(cache_brush);
2073 rdp_update_internal* update = update_cast(context->update);
2074
2075 const size_t inf = update_approximate_cache_brush_order(cache_brush, &flags);
2076 if (!update_check_flush(context, headerLength + inf))
2077 return FALSE;
2078
2079 wStream* s = update->us;
2080
2081 if (!s)
2082 return FALSE;
2083
2084 const size_t bm = Stream_GetPosition(s);
2085
2086 if (!Stream_EnsureRemainingCapacity(s, headerLength))
2087 return FALSE;
2088
2089 Stream_Seek(s, headerLength);
2090
2091 if (!update_write_cache_brush_order(s, cache_brush, &flags))
2092 return FALSE;
2093
2094 const size_t em = Stream_GetPosition(s);
2095 if (em <= bm + 13)
2096 return FALSE;
2097
2098 const size_t orderLength = (em - bm) - 13;
2099 WINPR_ASSERT(orderLength <= UINT16_MAX);
2100 Stream_SetPosition(s, bm);
2101 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
2102 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
2103 Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
2104 Stream_Write_UINT8(s, ORDER_TYPE_CACHE_BRUSH); /* orderType (1 byte) */
2105 Stream_SetPosition(s, em);
2106 update->numberOrders++;
2107 return TRUE;
2108}
2109
2114static BOOL update_send_create_offscreen_bitmap_order(
2115 rdpContext* context, const CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
2116{
2117 WINPR_ASSERT(context);
2118 WINPR_ASSERT(create_offscreen_bitmap);
2119 rdp_update_internal* update = update_cast(context->update);
2120
2121 const size_t headerLength = 1;
2122 const size_t orderType = ORDER_TYPE_CREATE_OFFSCREEN_BITMAP;
2123 const size_t controlFlags = ORDER_SECONDARY | (orderType << 2);
2124 const size_t inf = update_approximate_create_offscreen_bitmap_order(create_offscreen_bitmap);
2125 if (!update_check_flush(context, headerLength + inf))
2126 return FALSE;
2127
2128 wStream* s = update->us;
2129
2130 if (!s)
2131 return FALSE;
2132
2133 const size_t bm = Stream_GetPosition(s);
2134
2135 if (!Stream_EnsureRemainingCapacity(s, headerLength))
2136 return FALSE;
2137
2138 Stream_Seek(s, headerLength);
2139
2140 if (!update_write_create_offscreen_bitmap_order(s, create_offscreen_bitmap))
2141 return FALSE;
2142
2143 const size_t em = Stream_GetPosition(s);
2144 Stream_SetPosition(s, bm);
2145 Stream_Write_UINT8(s,
2146 WINPR_ASSERTING_INT_CAST(uint8_t, controlFlags)); /* controlFlags (1 byte) */
2147 Stream_SetPosition(s, em);
2148 update->numberOrders++;
2149 return TRUE;
2150}
2151
2152static BOOL update_send_switch_surface_order(rdpContext* context,
2153 const SWITCH_SURFACE_ORDER* switch_surface)
2154{
2155 WINPR_ASSERT(context);
2156 WINPR_ASSERT(switch_surface);
2157 rdp_update_internal* update = update_cast(context->update);
2158
2159 const size_t headerLength = 1;
2160 const size_t orderType = ORDER_TYPE_SWITCH_SURFACE;
2161 const size_t controlFlags = ORDER_SECONDARY | (orderType << 2);
2162 const size_t inf = update_approximate_switch_surface_order(switch_surface);
2163 if (!update_check_flush(context, headerLength + inf))
2164 return FALSE;
2165
2166 wStream* s = update->us;
2167
2168 if (!s)
2169 return FALSE;
2170
2171 const size_t bm = Stream_GetPosition(s);
2172
2173 if (!Stream_EnsureRemainingCapacity(s, headerLength))
2174 return FALSE;
2175
2176 Stream_Seek(s, headerLength);
2177
2178 if (!update_write_switch_surface_order(s, switch_surface))
2179 return FALSE;
2180
2181 const size_t em = Stream_GetPosition(s);
2182 Stream_SetPosition(s, bm);
2183 Stream_Write_UINT8(s,
2184 WINPR_ASSERTING_INT_CAST(uint8_t, controlFlags)); /* controlFlags (1 byte) */
2185 Stream_SetPosition(s, em);
2186 update->numberOrders++;
2187 return TRUE;
2188}
2189
2190static BOOL update_send_pointer_system(rdpContext* context,
2191 const POINTER_SYSTEM_UPDATE* pointer_system)
2192{
2193 wStream* s = NULL;
2194 BYTE updateCode = 0;
2195
2196 WINPR_ASSERT(context);
2197 rdpRdp* rdp = context->rdp;
2198 BOOL ret = 0;
2199
2200 WINPR_ASSERT(rdp);
2201 s = fastpath_update_pdu_init(rdp->fastpath);
2202
2203 if (!s)
2204 return FALSE;
2205
2206 if (pointer_system->type == SYSPTR_NULL)
2207 updateCode = FASTPATH_UPDATETYPE_PTR_NULL;
2208 else
2209 updateCode = FASTPATH_UPDATETYPE_PTR_DEFAULT;
2210
2211 ret = fastpath_send_update_pdu(rdp->fastpath, updateCode, s, FALSE);
2212 Stream_Release(s);
2213 return ret;
2214}
2215
2216static BOOL update_send_pointer_position(rdpContext* context,
2217 const POINTER_POSITION_UPDATE* pointerPosition)
2218{
2219 wStream* s = NULL;
2220 WINPR_ASSERT(context);
2221 rdpRdp* rdp = context->rdp;
2222 BOOL ret = FALSE;
2223
2224 WINPR_ASSERT(rdp);
2225 s = fastpath_update_pdu_init(rdp->fastpath);
2226
2227 if (!s)
2228 return FALSE;
2229
2230 if (!Stream_EnsureRemainingCapacity(s, 16))
2231 goto out_fail;
2232
2233 Stream_Write_UINT16(
2234 s, WINPR_ASSERTING_INT_CAST(uint16_t, pointerPosition->xPos)); /* xPos (2 bytes) */
2235 Stream_Write_UINT16(
2236 s, WINPR_ASSERTING_INT_CAST(uint16_t, pointerPosition->yPos)); /* yPos (2 bytes) */
2237 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_PTR_POSITION, s, FALSE);
2238out_fail:
2239 Stream_Release(s);
2240 return ret;
2241}
2242
2243static BOOL update_write_pointer_color(wStream* s, const POINTER_COLOR_UPDATE* pointer_color)
2244{
2245 WINPR_ASSERT(pointer_color);
2246 if (!Stream_EnsureRemainingCapacity(s, 32 + pointer_color->lengthAndMask +
2247 pointer_color->lengthXorMask))
2248 return FALSE;
2249
2250 Stream_Write_UINT16(s, pointer_color->cacheIndex);
2251 Stream_Write_UINT16(s, pointer_color->hotSpotX);
2252 Stream_Write_UINT16(s, pointer_color->hotSpotY);
2253 Stream_Write_UINT16(s, pointer_color->width);
2254 Stream_Write_UINT16(s, pointer_color->height);
2255 Stream_Write_UINT16(s, pointer_color->lengthAndMask);
2256 Stream_Write_UINT16(s, pointer_color->lengthXorMask);
2257
2258 if (pointer_color->lengthXorMask > 0)
2259 Stream_Write(s, pointer_color->xorMaskData, pointer_color->lengthXorMask);
2260
2261 if (pointer_color->lengthAndMask > 0)
2262 Stream_Write(s, pointer_color->andMaskData, pointer_color->lengthAndMask);
2263
2264 Stream_Write_UINT8(s, 0); /* pad (1 byte) */
2265 return TRUE;
2266}
2267
2268static BOOL update_send_pointer_color(rdpContext* context,
2269 const POINTER_COLOR_UPDATE* pointer_color)
2270{
2271 wStream* s = NULL;
2272
2273 WINPR_ASSERT(context);
2274 rdpRdp* rdp = context->rdp;
2275 BOOL ret = FALSE;
2276
2277 WINPR_ASSERT(rdp);
2278 WINPR_ASSERT(pointer_color);
2279 s = fastpath_update_pdu_init(rdp->fastpath);
2280
2281 if (!s)
2282 return FALSE;
2283
2284 if (!update_write_pointer_color(s, pointer_color))
2285 goto out_fail;
2286
2287 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_COLOR, s, FALSE);
2288out_fail:
2289 Stream_Release(s);
2290 return ret;
2291}
2292
2293static BOOL update_write_pointer_large(wStream* s, const POINTER_LARGE_UPDATE* pointer)
2294{
2295 WINPR_ASSERT(pointer);
2296
2297 if (!Stream_EnsureRemainingCapacity(s, 32 + pointer->lengthAndMask + pointer->lengthXorMask))
2298 return FALSE;
2299
2300 Stream_Write_UINT16(s, pointer->xorBpp);
2301 Stream_Write_UINT16(s, pointer->cacheIndex);
2302 Stream_Write_UINT16(s, pointer->hotSpotX);
2303 Stream_Write_UINT16(s, pointer->hotSpotY);
2304 Stream_Write_UINT16(s, pointer->width);
2305 Stream_Write_UINT16(s, pointer->height);
2306 Stream_Write_UINT32(s, pointer->lengthAndMask);
2307 Stream_Write_UINT32(s, pointer->lengthXorMask);
2308 Stream_Write(s, pointer->xorMaskData, pointer->lengthXorMask);
2309 Stream_Write(s, pointer->andMaskData, pointer->lengthAndMask);
2310 Stream_Write_UINT8(s, 0); /* pad (1 byte) */
2311 return TRUE;
2312}
2313
2314static BOOL update_send_pointer_large(rdpContext* context, const POINTER_LARGE_UPDATE* pointer)
2315{
2316 wStream* s = NULL;
2317 WINPR_ASSERT(context);
2318 rdpRdp* rdp = context->rdp;
2319 BOOL ret = FALSE;
2320
2321 WINPR_ASSERT(rdp);
2322 WINPR_ASSERT(pointer);
2323 s = fastpath_update_pdu_init(rdp->fastpath);
2324
2325 if (!s)
2326 return FALSE;
2327
2328 if (!update_write_pointer_large(s, pointer))
2329 goto out_fail;
2330
2331 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_LARGE_POINTER, s, FALSE);
2332out_fail:
2333 Stream_Release(s);
2334 return ret;
2335}
2336
2337static BOOL update_send_pointer_new(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new)
2338{
2339 wStream* s = NULL;
2340
2341 WINPR_ASSERT(context);
2342 rdpRdp* rdp = context->rdp;
2343 BOOL ret = FALSE;
2344
2345 WINPR_ASSERT(rdp);
2346 WINPR_ASSERT(pointer_new);
2347 s = fastpath_update_pdu_init(rdp->fastpath);
2348
2349 if (!s)
2350 return FALSE;
2351
2352 if (!Stream_EnsureRemainingCapacity(s, 16))
2353 goto out_fail;
2354
2355 Stream_Write_UINT16(
2356 s, WINPR_ASSERTING_INT_CAST(uint16_t, pointer_new->xorBpp)); /* xorBpp (2 bytes) */
2357 update_write_pointer_color(s, &pointer_new->colorPtrAttr);
2358 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_POINTER, s, FALSE);
2359out_fail:
2360 Stream_Release(s);
2361 return ret;
2362}
2363
2364static BOOL update_send_pointer_cached(rdpContext* context,
2365 const POINTER_CACHED_UPDATE* pointer_cached)
2366{
2367 wStream* s = NULL;
2368
2369 WINPR_ASSERT(context);
2370 rdpRdp* rdp = context->rdp;
2371 BOOL ret = 0;
2372
2373 WINPR_ASSERT(rdp);
2374 WINPR_ASSERT(pointer_cached);
2375 s = fastpath_update_pdu_init(rdp->fastpath);
2376
2377 if (!s)
2378 return FALSE;
2379
2380 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(
2381 uint16_t, pointer_cached->cacheIndex)); /* cacheIndex (2 bytes) */
2382 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_CACHED, s, FALSE);
2383 Stream_Release(s);
2384 return ret;
2385}
2386
2387BOOL update_read_refresh_rect(rdpUpdate* update, wStream* s)
2388{
2389 BYTE numberOfAreas = 0;
2390 RECTANGLE_16 areas[256] = { 0 };
2391 rdp_update_internal* up = update_cast(update);
2392
2393 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
2394 return FALSE;
2395
2396 Stream_Read_UINT8(s, numberOfAreas);
2397 Stream_Seek(s, 3); /* pad3Octects */
2398
2399 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, numberOfAreas, 8ull))
2400 return FALSE;
2401
2402 for (BYTE index = 0; index < numberOfAreas; index++)
2403 {
2404 RECTANGLE_16* area = &areas[index];
2405
2406 Stream_Read_UINT16(s, area->left);
2407 Stream_Read_UINT16(s, area->top);
2408 Stream_Read_UINT16(s, area->right);
2409 Stream_Read_UINT16(s, area->bottom);
2410 }
2411
2412 WINPR_ASSERT(update->context);
2413 WINPR_ASSERT(update->context->settings);
2414 if (update->context->settings->RefreshRect)
2415 IFCALL(update->RefreshRect, update->context, numberOfAreas, areas);
2416 else
2417 WLog_Print(up->log, WLOG_WARN, "ignoring refresh rect request from client");
2418
2419 return TRUE;
2420}
2421
2422BOOL update_read_suppress_output(rdpUpdate* update, wStream* s)
2423{
2424 rdp_update_internal* up = update_cast(update);
2425 RECTANGLE_16* prect = NULL;
2426 RECTANGLE_16 rect = { 0 };
2427 BYTE allowDisplayUpdates = 0;
2428
2429 WINPR_ASSERT(up);
2430 WINPR_ASSERT(s);
2431
2432 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
2433 return FALSE;
2434
2435 Stream_Read_UINT8(s, allowDisplayUpdates);
2436 Stream_Seek(s, 3); /* pad3Octects */
2437
2438 if (allowDisplayUpdates > 0)
2439 {
2440 if (!Stream_CheckAndLogRequiredLength(TAG, s, sizeof(RECTANGLE_16)))
2441 return FALSE;
2442
2443 Stream_Read_UINT16(s, rect.left);
2444 Stream_Read_UINT16(s, rect.top);
2445 Stream_Read_UINT16(s, rect.right);
2446 Stream_Read_UINT16(s, rect.bottom);
2447
2448 prect = &rect;
2449 }
2450
2451 WINPR_ASSERT(update->context);
2452 WINPR_ASSERT(update->context->settings);
2453 if (update->context->settings->SuppressOutput)
2454 IFCALL(update->SuppressOutput, update->context, allowDisplayUpdates, prect);
2455 else
2456 WLog_Print(up->log, WLOG_WARN, "ignoring suppress output request from client");
2457
2458 return TRUE;
2459}
2460
2461static BOOL update_send_set_keyboard_indicators(rdpContext* context, UINT16 led_flags)
2462{
2463 UINT16 sec_flags = 0;
2464 wStream* s = NULL;
2465
2466 WINPR_ASSERT(context);
2467 rdpRdp* rdp = context->rdp;
2468 s = rdp_data_pdu_init(rdp, &sec_flags);
2469
2470 if (!s)
2471 return FALSE;
2472
2473 Stream_Write_UINT16(s, 0); /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.1.1 */
2474 Stream_Write_UINT16(s, led_flags); /* ledFlags (2 bytes) */
2475
2476 WINPR_ASSERT(rdp->mcs);
2477 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS, rdp->mcs->userId,
2478 sec_flags);
2479}
2480
2481static BOOL update_send_set_keyboard_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
2482 UINT32 imeConvMode)
2483{
2484 UINT16 sec_flags = 0;
2485 wStream* s = NULL;
2486
2487 WINPR_ASSERT(context);
2488 rdpRdp* rdp = context->rdp;
2489 s = rdp_data_pdu_init(rdp, &sec_flags);
2490
2491 if (!s)
2492 return FALSE;
2493
2494 /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.2.1 */
2495 Stream_Write_UINT16(s, imeId);
2496 Stream_Write_UINT32(s, imeState);
2497 Stream_Write_UINT32(s, imeConvMode);
2498
2499 WINPR_ASSERT(rdp->mcs);
2500 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_IME_STATUS, rdp->mcs->userId,
2501 sec_flags);
2502}
2503
2504static UINT16 update_calculate_new_or_existing_window(const WINDOW_ORDER_INFO* orderInfo,
2505 const WINDOW_STATE_ORDER* stateOrder)
2506{
2507 size_t orderSize = 11;
2508
2509 WINPR_ASSERT(orderInfo);
2510 WINPR_ASSERT(stateOrder);
2511
2512 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_OWNER) != 0)
2513 orderSize += 4;
2514
2515 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_STYLE) != 0)
2516 orderSize += 8;
2517
2518 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_SHOW) != 0)
2519 orderSize += 1;
2520
2521 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE) != 0)
2522 orderSize += 2 + stateOrder->titleInfo.length;
2523
2524 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) != 0)
2525 orderSize += 8;
2526
2527 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) != 0)
2528 orderSize += 8;
2529
2530 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_X) != 0)
2531 orderSize += 8;
2532
2533 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_Y) != 0)
2534 orderSize += 8;
2535
2536 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT) != 0)
2537 orderSize += 1;
2538
2539 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT) != 0)
2540 orderSize += 4;
2541
2542 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) != 0)
2543 orderSize += 8;
2544
2545 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) != 0)
2546 orderSize += 8;
2547
2548 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) != 0)
2549 orderSize += 8;
2550
2551 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) != 0)
2552 {
2553 const size_t len = 2ULL + stateOrder->numWindowRects * sizeof(RECTANGLE_16);
2554 orderSize += len;
2555 }
2556
2557 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) != 0)
2558 orderSize += 8;
2559
2560 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) != 0)
2561 {
2562
2563 const size_t len = 2ULL + stateOrder->numVisibilityRects * sizeof(RECTANGLE_16);
2564 orderSize += len;
2565 }
2566
2567 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_OVERLAY_DESCRIPTION) != 0)
2568 orderSize += 2 + stateOrder->OverlayDescription.length;
2569
2570 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TASKBAR_BUTTON) != 0)
2571 orderSize += 1;
2572
2573 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ENFORCE_SERVER_ZORDER) != 0)
2574 orderSize += 1;
2575
2576 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_APPBAR_STATE) != 0)
2577 orderSize += 1;
2578
2579 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_APPBAR_EDGE) != 0)
2580 orderSize += 1;
2581
2582 return WINPR_ASSERTING_INT_CAST(uint16_t, orderSize);
2583}
2584
2585static BOOL update_write_order_field_flags(UINT32 fieldFlags, const WINDOW_STATE_ORDER* stateOrder,
2586 wStream* s)
2587{
2588 WINPR_ASSERT(stateOrder);
2589
2590 if ((fieldFlags & WINDOW_ORDER_FIELD_OWNER) != 0)
2591 Stream_Write_UINT32(s, stateOrder->ownerWindowId);
2592
2593 if ((fieldFlags & WINDOW_ORDER_FIELD_STYLE) != 0)
2594 {
2595 Stream_Write_UINT32(s, stateOrder->style);
2596 Stream_Write_UINT32(s, stateOrder->extendedStyle);
2597 }
2598
2599 if ((fieldFlags & WINDOW_ORDER_FIELD_SHOW) != 0)
2600 {
2601 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, stateOrder->showState));
2602 }
2603
2604 if ((fieldFlags & WINDOW_ORDER_FIELD_TITLE) != 0)
2605 {
2606 Stream_Write_UINT16(s, stateOrder->titleInfo.length);
2607 Stream_Write(s, stateOrder->titleInfo.string, stateOrder->titleInfo.length);
2608 }
2609
2610 if ((fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) != 0)
2611 {
2612 Stream_Write_INT32(s, stateOrder->clientOffsetX);
2613 Stream_Write_INT32(s, stateOrder->clientOffsetY);
2614 }
2615
2616 if ((fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) != 0)
2617 {
2618 Stream_Write_UINT32(s, stateOrder->clientAreaWidth);
2619 Stream_Write_UINT32(s, stateOrder->clientAreaHeight);
2620 }
2621
2622 if ((fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_X) != 0)
2623 {
2624 Stream_Write_UINT32(s, stateOrder->resizeMarginLeft);
2625 Stream_Write_UINT32(s, stateOrder->resizeMarginRight);
2626 }
2627
2628 if ((fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_Y) != 0)
2629 {
2630 Stream_Write_UINT32(s, stateOrder->resizeMarginTop);
2631 Stream_Write_UINT32(s, stateOrder->resizeMarginBottom);
2632 }
2633
2634 if ((fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT) != 0)
2635 {
2636 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, stateOrder->RPContent));
2637 }
2638
2639 if ((fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT) != 0)
2640 {
2641 Stream_Write_UINT32(s, stateOrder->rootParentHandle);
2642 }
2643
2644 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) != 0)
2645 {
2646 Stream_Write_INT32(s, stateOrder->windowOffsetX);
2647 Stream_Write_INT32(s, stateOrder->windowOffsetY);
2648 }
2649
2650 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) != 0)
2651 {
2652 Stream_Write_INT32(s, stateOrder->windowClientDeltaX);
2653 Stream_Write_INT32(s, stateOrder->windowClientDeltaY);
2654 }
2655
2656 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) != 0)
2657 {
2658 Stream_Write_UINT32(s, stateOrder->windowWidth);
2659 Stream_Write_UINT32(s, stateOrder->windowHeight);
2660 }
2661
2662 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) != 0)
2663 {
2664 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, stateOrder->numWindowRects));
2665 Stream_Write(s, stateOrder->windowRects, stateOrder->numWindowRects * sizeof(RECTANGLE_16));
2666 }
2667
2668 if ((fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) != 0)
2669 {
2670 Stream_Write_INT32(s, stateOrder->visibleOffsetX);
2671 Stream_Write_INT32(s, stateOrder->visibleOffsetY);
2672 }
2673
2674 if ((fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) != 0)
2675 {
2676 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, stateOrder->numVisibilityRects));
2677 Stream_Write(s, stateOrder->visibilityRects,
2678 stateOrder->numVisibilityRects * sizeof(RECTANGLE_16));
2679 }
2680
2681 if ((fieldFlags & WINDOW_ORDER_FIELD_OVERLAY_DESCRIPTION) != 0)
2682 {
2683 Stream_Write_UINT16(s, stateOrder->OverlayDescription.length);
2684 Stream_Write(s, stateOrder->OverlayDescription.string,
2685 stateOrder->OverlayDescription.length);
2686 }
2687
2688 if ((fieldFlags & WINDOW_ORDER_FIELD_TASKBAR_BUTTON) != 0)
2689 {
2690 Stream_Write_UINT8(s, stateOrder->TaskbarButton);
2691 }
2692
2693 if ((fieldFlags & WINDOW_ORDER_FIELD_ENFORCE_SERVER_ZORDER) != 0)
2694 {
2695 Stream_Write_UINT8(s, stateOrder->EnforceServerZOrder);
2696 }
2697
2698 if ((fieldFlags & WINDOW_ORDER_FIELD_APPBAR_STATE) != 0)
2699 {
2700 Stream_Write_UINT8(s, stateOrder->AppBarState);
2701 }
2702
2703 if ((fieldFlags & WINDOW_ORDER_FIELD_APPBAR_EDGE) != 0)
2704 {
2705 Stream_Write_UINT8(s, stateOrder->AppBarEdge);
2706 }
2707
2708 return TRUE;
2709}
2710
2711static BOOL update_send_new_or_existing_window(rdpContext* context,
2712 const WINDOW_ORDER_INFO* orderInfo,
2713 const WINDOW_STATE_ORDER* stateOrder)
2714{
2715 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
2716 UINT16 orderSize = update_calculate_new_or_existing_window(orderInfo, stateOrder);
2717
2718 WINPR_ASSERT(context);
2719 WINPR_ASSERT(orderInfo);
2720 WINPR_ASSERT(stateOrder);
2721
2722 rdp_update_internal* update = update_cast(context->update);
2723
2724 if (!update_check_flush(context, orderSize))
2725 return FALSE;
2726
2727 wStream* s = update->us;
2728
2729 if (!s)
2730 return FALSE;
2731
2732 if (!Stream_EnsureRemainingCapacity(s, orderSize))
2733 return FALSE;
2734
2735 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
2736 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
2737 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
2738 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
2739
2740 if (!update_write_order_field_flags(orderInfo->fieldFlags, stateOrder, s))
2741 return FALSE;
2742
2743 update->numberOrders++;
2744 return TRUE;
2745}
2746
2747static BOOL update_send_window_create(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
2748 const WINDOW_STATE_ORDER* stateOrder)
2749{
2750 return update_send_new_or_existing_window(context, orderInfo, stateOrder);
2751}
2752
2753static BOOL update_send_window_update(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
2754 const WINDOW_STATE_ORDER* stateOrder)
2755{
2756 return update_send_new_or_existing_window(context, orderInfo, stateOrder);
2757}
2758
2759static UINT16
2760update_calculate_window_icon_order(WINPR_ATTR_UNUSED const WINDOW_ORDER_INFO* orderInfo,
2761 const WINDOW_ICON_ORDER* iconOrder)
2762{
2763 UINT16 orderSize = 23;
2764
2765 WINPR_ASSERT(iconOrder);
2766 ICON_INFO* iconInfo = iconOrder->iconInfo;
2767 WINPR_ASSERT(iconInfo);
2768
2769 orderSize += iconInfo->cbBitsColor + iconInfo->cbBitsMask;
2770
2771 if (iconInfo->bpp <= 8)
2772 orderSize += 2 + iconInfo->cbColorTable;
2773
2774 return orderSize;
2775}
2776
2777static BOOL update_send_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
2778 const WINDOW_ICON_ORDER* iconOrder)
2779{
2780 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
2781
2782 WINPR_ASSERT(iconOrder);
2783 ICON_INFO* iconInfo = iconOrder->iconInfo;
2784 UINT16 orderSize = update_calculate_window_icon_order(orderInfo, iconOrder);
2785
2786 WINPR_ASSERT(context);
2787 WINPR_ASSERT(orderInfo);
2788 WINPR_ASSERT(iconInfo);
2789
2790 rdp_update_internal* update = update_cast(context->update);
2791
2792 if (!update_check_flush(context, orderSize))
2793 return FALSE;
2794
2795 wStream* s = update->us;
2796
2797 if (!s || !iconInfo)
2798 return FALSE;
2799
2800 if (!Stream_EnsureRemainingCapacity(s, orderSize))
2801 return FALSE;
2802
2803 /* Write Hdr */
2804 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
2805 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
2806 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
2807 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
2808 /* Write body */
2809 Stream_Write_UINT16(
2810 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cacheEntry)); /* CacheEntry (2 bytes) */
2811 Stream_Write_UINT8(s,
2812 WINPR_ASSERTING_INT_CAST(uint8_t, iconInfo->cacheId)); /* CacheId (1 byte) */
2813 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, iconInfo->bpp)); /* Bpp (1 byte) */
2814 Stream_Write_UINT16(s,
2815 WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->width)); /* Width (2 bytes) */
2816 Stream_Write_UINT16(
2817 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->height)); /* Height (2 bytes) */
2818
2819 if (iconInfo->bpp <= 8)
2820 {
2821 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(
2822 uint16_t, iconInfo->cbColorTable)); /* CbColorTable (2 bytes) */
2823 }
2824
2825 Stream_Write_UINT16(
2826 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cbBitsMask)); /* CbBitsMask (2 bytes) */
2827 Stream_Write_UINT16(
2828 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cbBitsColor)); /* CbBitsColor (2 bytes) */
2829 Stream_Write(s, iconInfo->bitsMask, iconInfo->cbBitsMask); /* BitsMask (variable) */
2830
2831 if (iconInfo->bpp <= 8)
2832 {
2833 Stream_Write(s, iconInfo->colorTable, iconInfo->cbColorTable); /* ColorTable (variable) */
2834 }
2835
2836 Stream_Write(s, iconInfo->bitsColor, iconInfo->cbBitsColor); /* BitsColor (variable) */
2837
2838 update->numberOrders++;
2839 return TRUE;
2840}
2841
2842static BOOL update_send_window_cached_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
2843 const WINDOW_CACHED_ICON_ORDER* cachedIconOrder)
2844{
2845 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
2846 UINT16 orderSize = 14;
2847
2848 WINPR_ASSERT(cachedIconOrder);
2849 const CACHED_ICON_INFO* cachedIcon = &cachedIconOrder->cachedIcon;
2850
2851 WINPR_ASSERT(context);
2852 WINPR_ASSERT(orderInfo);
2853 WINPR_ASSERT(cachedIcon);
2854
2855 rdp_update_internal* update = update_cast(context->update);
2856
2857 if (!update_check_flush(context, orderSize))
2858 return FALSE;
2859
2860 wStream* s = update->us;
2861 if (!s)
2862 return FALSE;
2863
2864 if (!Stream_EnsureRemainingCapacity(s, orderSize))
2865 return FALSE;
2866
2867 /* Write Hdr */
2868 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
2869 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
2870 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
2871 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
2872 /* Write body */
2873 Stream_Write_UINT16(
2874 s, WINPR_ASSERTING_INT_CAST(uint16_t, cachedIcon->cacheEntry)); /* CacheEntry (2 bytes) */
2875 Stream_Write_UINT8(
2876 s, WINPR_ASSERTING_INT_CAST(uint8_t, cachedIcon->cacheId)); /* CacheId (1 byte) */
2877 update->numberOrders++;
2878 return TRUE;
2879}
2880
2881static BOOL update_send_window_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
2882{
2883 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
2884 UINT16 orderSize = 11;
2885
2886 WINPR_ASSERT(context);
2887 WINPR_ASSERT(orderInfo);
2888 rdp_update_internal* update = update_cast(context->update);
2889
2890 if (!update_check_flush(context, orderSize))
2891 return FALSE;
2892
2893 wStream* s = update->us;
2894
2895 if (!s)
2896 return FALSE;
2897
2898 if (!Stream_EnsureRemainingCapacity(s, orderSize))
2899 return FALSE;
2900
2901 /* Write Hdr */
2902 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
2903 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
2904 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
2905 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
2906 update->numberOrders++;
2907 return TRUE;
2908}
2909
2910static UINT16 update_calculate_new_or_existing_notification_icons_order(
2911 const WINDOW_ORDER_INFO* orderInfo, const NOTIFY_ICON_STATE_ORDER* iconStateOrder)
2912{
2913 UINT16 orderSize = 15;
2914
2915 WINPR_ASSERT(orderInfo);
2916 WINPR_ASSERT(iconStateOrder);
2917
2918 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION) != 0)
2919 orderSize += 4;
2920
2921 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP) != 0)
2922 {
2923 orderSize += 2 + iconStateOrder->toolTip.length;
2924 }
2925
2926 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) != 0)
2927 {
2928 NOTIFY_ICON_INFOTIP infoTip = iconStateOrder->infoTip;
2929 orderSize += 12 + infoTip.text.length + infoTip.title.length;
2930 }
2931
2932 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE) != 0)
2933 {
2934 orderSize += 4;
2935 }
2936
2937 if ((orderInfo->fieldFlags & WINDOW_ORDER_ICON) != 0)
2938 {
2939 ICON_INFO iconInfo = iconStateOrder->icon;
2940 orderSize += 12;
2941
2942 if (iconInfo.bpp <= 8)
2943 orderSize += 2 + iconInfo.cbColorTable;
2944
2945 orderSize += iconInfo.cbBitsMask + iconInfo.cbBitsColor;
2946 }
2947 else if ((orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON) != 0)
2948 {
2949 orderSize += 3;
2950 }
2951
2952 return orderSize;
2953}
2954
2955static BOOL update_send_new_or_existing_order_icon(const ICON_INFO* iconInfo, wStream* s)
2956{
2957 WINPR_ASSERT(iconInfo);
2958
2959 if (!Stream_EnsureRemainingCapacity(s, 8))
2960 return FALSE;
2961
2962 Stream_Write_UINT16(
2963 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cacheEntry)); /* CacheEntry (2 bytes) */
2964 Stream_Write_UINT8(s,
2965 WINPR_ASSERTING_INT_CAST(uint8_t, iconInfo->cacheId)); /* CacheId (1 byte) */
2966 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, iconInfo->bpp)); /* Bpp (1 byte) */
2967 Stream_Write_UINT16(s,
2968 WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->width)); /* Width (2 bytes) */
2969 Stream_Write_UINT16(
2970 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->height)); /* Height (2 bytes) */
2971
2972 if (iconInfo->bpp <= 8)
2973 {
2974 if (!Stream_EnsureRemainingCapacity(s, 2))
2975 return FALSE;
2976 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(
2977 uint16_t, iconInfo->cbColorTable)); /* CbColorTable (2 bytes) */
2978 }
2979
2980 if (!Stream_EnsureRemainingCapacity(s, 4ULL + iconInfo->cbBitsMask))
2981 return FALSE;
2982 Stream_Write_UINT16(
2983 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cbBitsMask)); /* CbBitsMask (2 bytes) */
2984 Stream_Write_UINT16(
2985 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cbBitsColor)); /* CbBitsColor (2 bytes) */
2986 Stream_Write(s, iconInfo->bitsMask, iconInfo->cbBitsMask); /* BitsMask (variable) */
2987
2988 if (iconInfo->bpp <= 8)
2989 {
2990 if (!Stream_EnsureRemainingCapacity(s, iconInfo->cbColorTable))
2991 return FALSE;
2992 Stream_Write(s, iconInfo->colorTable, iconInfo->cbColorTable); /* ColorTable (variable) */
2993 }
2994
2995 if (!Stream_EnsureRemainingCapacity(s, iconInfo->cbBitsColor))
2996 return FALSE;
2997 Stream_Write(s, iconInfo->bitsColor, iconInfo->cbBitsColor); /* BitsColor (variable) */
2998 return TRUE;
2999}
3000
3001static BOOL
3002update_send_new_or_existing_notification_icons(rdpContext* context,
3003 const WINDOW_ORDER_INFO* orderInfo,
3004 const NOTIFY_ICON_STATE_ORDER* iconStateOrder)
3005{
3006 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
3007 BOOL versionFieldPresent = FALSE;
3008 const UINT16 orderSize =
3009 update_calculate_new_or_existing_notification_icons_order(orderInfo, iconStateOrder);
3010
3011 WINPR_ASSERT(context);
3012 WINPR_ASSERT(orderInfo);
3013 WINPR_ASSERT(iconStateOrder);
3014 rdp_update_internal* update = update_cast(context->update);
3015
3016 if (!update_check_flush(context, orderSize))
3017 return FALSE;
3018
3019 wStream* s = update->us;
3020 if (!s)
3021 return FALSE;
3022
3023 if (!Stream_EnsureRemainingCapacity(s, orderSize))
3024 return FALSE;
3025
3026 /* Write Hdr */
3027 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
3028 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
3029 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
3030 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
3031 Stream_Write_UINT32(s, orderInfo->notifyIconId); /* NotifyIconId (4 bytes) */
3032
3033 /* Write body */
3034 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION) != 0)
3035 {
3036 versionFieldPresent = TRUE;
3037 Stream_Write_UINT32(s, iconStateOrder->version);
3038 }
3039
3040 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP) != 0)
3041 {
3042 Stream_Write_UINT16(s, iconStateOrder->toolTip.length);
3043 Stream_Write(s, iconStateOrder->toolTip.string, iconStateOrder->toolTip.length);
3044 }
3045
3046 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) != 0)
3047 {
3048 NOTIFY_ICON_INFOTIP infoTip = iconStateOrder->infoTip;
3049
3050 /* info tip should not be sent when version is 0 */
3051 if (versionFieldPresent && iconStateOrder->version == 0)
3052 return FALSE;
3053
3054 Stream_Write_UINT32(s, infoTip.timeout); /* Timeout (4 bytes) */
3055 Stream_Write_UINT32(s, infoTip.flags); /* InfoFlags (4 bytes) */
3056 Stream_Write_UINT16(s, infoTip.text.length); /* InfoTipText (variable) */
3057 Stream_Write(s, infoTip.text.string, infoTip.text.length);
3058 Stream_Write_UINT16(s, infoTip.title.length); /* Title (variable) */
3059 Stream_Write(s, infoTip.title.string, infoTip.title.length);
3060 }
3061
3062 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE) != 0)
3063 {
3064 /* notify state should not be sent when version is 0 */
3065 if (versionFieldPresent && iconStateOrder->version == 0)
3066 return FALSE;
3067
3068 Stream_Write_UINT32(s, iconStateOrder->state);
3069 }
3070
3071 if ((orderInfo->fieldFlags & WINDOW_ORDER_ICON) != 0)
3072 {
3073 const ICON_INFO* iconInfo = &iconStateOrder->icon;
3074
3075 if (!update_send_new_or_existing_order_icon(iconInfo, s))
3076 return FALSE;
3077 }
3078 else if ((orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON) != 0)
3079 {
3080 const CACHED_ICON_INFO cachedIcon = iconStateOrder->cachedIcon;
3081 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(
3082 uint16_t, cachedIcon.cacheEntry)); /* CacheEntry (2 bytes) */
3083 Stream_Write_UINT8(
3084 s, WINPR_ASSERTING_INT_CAST(uint8_t, cachedIcon.cacheId)); /* CacheId (1 byte) */
3085 }
3086
3087 update->numberOrders++;
3088 return TRUE;
3089}
3090
3091static BOOL update_send_notify_icon_create(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
3092 const NOTIFY_ICON_STATE_ORDER* iconStateOrder)
3093{
3094 return update_send_new_or_existing_notification_icons(context, orderInfo, iconStateOrder);
3095}
3096
3097static BOOL update_send_notify_icon_update(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
3098 const NOTIFY_ICON_STATE_ORDER* iconStateOrder)
3099{
3100 return update_send_new_or_existing_notification_icons(context, orderInfo, iconStateOrder);
3101}
3102
3103static BOOL update_send_notify_icon_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
3104{
3105 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
3106 UINT16 orderSize = 15;
3107
3108 WINPR_ASSERT(context);
3109 WINPR_ASSERT(orderInfo);
3110 rdp_update_internal* update = update_cast(context->update);
3111
3112 if (!update_check_flush(context, orderSize))
3113 return FALSE;
3114
3115 wStream* s = update->us;
3116
3117 if (!s)
3118 return FALSE;
3119
3120 /* Write Hdr */
3121 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
3122 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
3123 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
3124 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
3125 Stream_Write_UINT32(s, orderInfo->notifyIconId); /* NotifyIconId (4 bytes) */
3126 update->numberOrders++;
3127 return TRUE;
3128}
3129
3130static UINT16 update_calculate_monitored_desktop(const WINDOW_ORDER_INFO* orderInfo,
3131 const MONITORED_DESKTOP_ORDER* monitoredDesktop)
3132{
3133 UINT16 orderSize = 7;
3134
3135 WINPR_ASSERT(orderInfo);
3136 WINPR_ASSERT(monitoredDesktop);
3137
3138 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND)
3139 {
3140 orderSize += 4;
3141 }
3142
3143 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER)
3144 {
3145 orderSize += 1 + (4 * monitoredDesktop->numWindowIds);
3146 }
3147
3148 return orderSize;
3149}
3150
3151static BOOL update_send_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
3152 const MONITORED_DESKTOP_ORDER* monitoredDesktop)
3153{
3154 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
3155 UINT16 orderSize = update_calculate_monitored_desktop(orderInfo, monitoredDesktop);
3156
3157 WINPR_ASSERT(context);
3158 WINPR_ASSERT(orderInfo);
3159 WINPR_ASSERT(monitoredDesktop);
3160
3161 rdp_update_internal* update = update_cast(context->update);
3162
3163 if (!update_check_flush(context, orderSize))
3164 return FALSE;
3165
3166 wStream* s = update->us;
3167
3168 if (!s)
3169 return FALSE;
3170
3171 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
3172 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
3173 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
3174
3175 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND)
3176 {
3177 Stream_Write_UINT32(s, monitoredDesktop->activeWindowId); /* activeWindowId (4 bytes) */
3178 }
3179
3180 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER)
3181 {
3182 Stream_Write_UINT8(
3183 s, WINPR_ASSERTING_INT_CAST(
3184 uint8_t, monitoredDesktop->numWindowIds)); /* numWindowIds (1 byte) */
3185
3186 /* windowIds */
3187 for (UINT32 i = 0; i < monitoredDesktop->numWindowIds; i++)
3188 {
3189 Stream_Write_UINT32(s,
3190 WINPR_ASSERTING_INT_CAST(uint32_t, monitoredDesktop->windowIds[i]));
3191 }
3192 }
3193
3194 update->numberOrders++;
3195 return TRUE;
3196}
3197
3198static BOOL update_send_non_monitored_desktop(rdpContext* context,
3199 const WINDOW_ORDER_INFO* orderInfo)
3200{
3201 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
3202 UINT16 orderSize = 7;
3203
3204 WINPR_ASSERT(context);
3205 WINPR_ASSERT(orderInfo);
3206 rdp_update_internal* update = update_cast(context->update);
3207
3208 if (!update_check_flush(context, orderSize))
3209 return FALSE;
3210
3211 wStream* s = update->us;
3212
3213 if (!s)
3214 return FALSE;
3215
3216 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
3217 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
3218 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
3219 update->numberOrders++;
3220 return TRUE;
3221}
3222
3223void update_register_server_callbacks(rdpUpdate* update)
3224{
3225 WINPR_ASSERT(update);
3226
3227 update->BeginPaint = s_update_begin_paint;
3228 update->EndPaint = s_update_end_paint;
3229 update->SetBounds = update_set_bounds;
3230 update->Synchronize = update_send_synchronize;
3231 update->DesktopResize = update_send_desktop_resize;
3232 update->BitmapUpdate = update_send_bitmap_update;
3233 update->SurfaceBits = update_send_surface_bits;
3234 update->SurfaceFrameMarker = update_send_surface_frame_marker;
3235 update->SurfaceCommand = update_send_surface_command;
3236 update->SurfaceFrameBits = update_send_surface_frame_bits;
3237 update->PlaySound = update_send_play_sound;
3238 update->SetKeyboardIndicators = update_send_set_keyboard_indicators;
3239 update->SetKeyboardImeStatus = update_send_set_keyboard_ime_status;
3240 update->SaveSessionInfo = rdp_send_save_session_info;
3241 update->ServerStatusInfo = rdp_send_server_status_info;
3242 update->primary->DstBlt = update_send_dstblt;
3243 update->primary->PatBlt = update_send_patblt;
3244 update->primary->ScrBlt = update_send_scrblt;
3245 update->primary->OpaqueRect = update_send_opaque_rect;
3246 update->primary->LineTo = update_send_line_to;
3247 update->primary->MemBlt = update_send_memblt;
3248 update->primary->GlyphIndex = update_send_glyph_index;
3249 update->secondary->CacheBitmap = update_send_cache_bitmap;
3250 update->secondary->CacheBitmapV2 = update_send_cache_bitmap_v2;
3251 update->secondary->CacheBitmapV3 = update_send_cache_bitmap_v3;
3252 update->secondary->CacheColorTable = update_send_cache_color_table;
3253 update->secondary->CacheGlyph = update_send_cache_glyph;
3254 update->secondary->CacheGlyphV2 = update_send_cache_glyph_v2;
3255 update->secondary->CacheBrush = update_send_cache_brush;
3256 update->altsec->CreateOffscreenBitmap = update_send_create_offscreen_bitmap_order;
3257 update->altsec->SwitchSurface = update_send_switch_surface_order;
3258 update->pointer->PointerSystem = update_send_pointer_system;
3259 update->pointer->PointerPosition = update_send_pointer_position;
3260 update->pointer->PointerColor = update_send_pointer_color;
3261 update->pointer->PointerLarge = update_send_pointer_large;
3262 update->pointer->PointerNew = update_send_pointer_new;
3263 update->pointer->PointerCached = update_send_pointer_cached;
3264 update->window->WindowCreate = update_send_window_create;
3265 update->window->WindowUpdate = update_send_window_update;
3266 update->window->WindowIcon = update_send_window_icon;
3267 update->window->WindowCachedIcon = update_send_window_cached_icon;
3268 update->window->WindowDelete = update_send_window_delete;
3269 update->window->NotifyIconCreate = update_send_notify_icon_create;
3270 update->window->NotifyIconUpdate = update_send_notify_icon_update;
3271 update->window->NotifyIconDelete = update_send_notify_icon_delete;
3272 update->window->MonitoredDesktop = update_send_monitored_desktop;
3273 update->window->NonMonitoredDesktop = update_send_non_monitored_desktop;
3274}
3275
3276void update_register_client_callbacks(rdpUpdate* update)
3277{
3278 WINPR_ASSERT(update);
3279
3280 update->RefreshRect = update_send_refresh_rect;
3281 update->SuppressOutput = update_send_suppress_output;
3282 update->SurfaceFrameAcknowledge = update_send_frame_acknowledge;
3283}
3284
3285int update_process_messages(rdpUpdate* update)
3286{
3287 return update_message_queue_process_pending_messages(update);
3288}
3289
3290static void update_free_queued_message(void* obj)
3291{
3292 wMessage* msg = (wMessage*)obj;
3293 update_message_queue_free_message(msg);
3294}
3295
3296void update_free_window_state(WINDOW_STATE_ORDER* window_state)
3297{
3298 if (!window_state)
3299 return;
3300
3301 free(window_state->OverlayDescription.string);
3302 free(window_state->titleInfo.string);
3303 free(window_state->windowRects);
3304 free(window_state->visibilityRects);
3305 memset(window_state, 0, sizeof(WINDOW_STATE_ORDER));
3306}
3307
3308rdpUpdate* update_new(rdpRdp* rdp)
3309{
3310 const wObject cb = { NULL, NULL, NULL, update_free_queued_message, NULL };
3311
3312 WINPR_ASSERT(rdp);
3313 WINPR_ASSERT(rdp->context);
3314
3315 rdp_update_internal* update = (rdp_update_internal*)calloc(1, sizeof(rdp_update_internal));
3316
3317 if (!update)
3318 return NULL;
3319
3320 update->common.context = rdp->context;
3321 update->log = WLog_Get("com.freerdp.core.update");
3322 InitializeCriticalSection(&(update->mux));
3323 update->common.pointer = (rdpPointerUpdate*)calloc(1, sizeof(rdpPointerUpdate));
3324
3325 if (!update->common.pointer)
3326 goto fail;
3327
3330
3331 if (!primary)
3332 goto fail;
3333 update->common.primary = &primary->common;
3334
3337
3338 if (!secondary)
3339 goto fail;
3340 update->common.secondary = &secondary->common;
3341
3344
3345 if (!altsec)
3346 goto fail;
3347
3348 update->common.altsec = &altsec->common;
3349 update->common.window = (rdpWindowUpdate*)calloc(1, sizeof(rdpWindowUpdate));
3350
3351 if (!update->common.window)
3352 goto fail;
3353
3354 OFFSCREEN_DELETE_LIST* deleteList = &(altsec->create_offscreen_bitmap.deleteList);
3355 deleteList->sIndices = 64;
3356 deleteList->indices = calloc(deleteList->sIndices, 2);
3357
3358 if (!deleteList->indices)
3359 goto fail;
3360
3361 deleteList->cIndices = 0;
3362 update->common.SuppressOutput = update_send_suppress_output;
3363 update->initialState = TRUE;
3364 update->common.autoCalculateBitmapData = TRUE;
3365 update->queue = MessageQueue_New(&cb);
3366
3367 if (!update->queue)
3368 goto fail;
3369
3370 return &update->common;
3371fail:
3372 WINPR_PRAGMA_DIAG_PUSH
3373 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
3374 update_free(&update->common);
3375 WINPR_PRAGMA_DIAG_POP
3376 return NULL;
3377}
3378
3379void update_free(rdpUpdate* update)
3380{
3381 if (update != NULL)
3382 {
3383 rdp_update_internal* up = update_cast(update);
3384 rdp_altsec_update_internal* altsec = altsec_update_cast(update->altsec);
3385 OFFSCREEN_DELETE_LIST* deleteList = &(altsec->create_offscreen_bitmap.deleteList);
3386
3387 if (deleteList)
3388 free(deleteList->indices);
3389
3390 free(update->pointer);
3391
3392 if (update->primary)
3393 {
3394 rdp_primary_update_internal* primary = primary_update_cast(update->primary);
3395
3396 free(primary->polygon_cb.points);
3397 free(primary->polyline.points);
3398 free(primary->polygon_sc.points);
3399 free(primary->fast_glyph.glyphData.aj);
3400 free(primary);
3401 }
3402
3403 free(update->secondary);
3404 free(altsec);
3405
3406 if (update->window)
3407 free(update->window);
3408
3409 MessageQueue_Free(up->queue);
3410 DeleteCriticalSection(&up->mux);
3411
3412 if (up->us)
3413 Stream_Free(up->us, TRUE);
3414 free(update);
3415 }
3416}
3417
3418void rdp_update_lock(rdpUpdate* update)
3419{
3420 rdp_update_internal* up = update_cast(update);
3421 EnterCriticalSection(&up->mux);
3422}
3423
3424void rdp_update_unlock(rdpUpdate* update)
3425{
3426 rdp_update_internal* up = update_cast(update);
3427 LeaveCriticalSection(&up->mux);
3428}
3429
3430BOOL update_begin_paint(rdpUpdate* update)
3431{
3432 rdp_update_internal* up = update_cast(update);
3433 WINPR_ASSERT(update);
3434 rdp_update_lock(update);
3435
3436 up->withinBeginEndPaint = TRUE;
3437
3438 WINPR_ASSERT(update->context);
3439
3440 BOOL rc = IFCALLRESULT(TRUE, update->BeginPaint, update->context);
3441 if (!rc)
3442 WLog_WARN(TAG, "BeginPaint call failed");
3443
3444 /* Reset the invalid regions, we start a new frame here. */
3445 rdpGdi* gdi = update->context->gdi;
3446 if (!gdi)
3447 return rc;
3448
3449 if (gdi->hdc && gdi->primary && gdi->primary->hdc)
3450 {
3451 HGDI_WND hwnd = gdi->primary->hdc->hwnd;
3452 WINPR_ASSERT(hwnd);
3453 WINPR_ASSERT(hwnd->invalid);
3454
3455 hwnd->invalid->null = TRUE;
3456 hwnd->ninvalid = 0;
3457 }
3458
3459 return rc;
3460}
3461
3462BOOL update_end_paint(rdpUpdate* update)
3463{
3464 BOOL rc = TRUE;
3465
3466 WINPR_ASSERT(update);
3467 IFCALLRET(update->EndPaint, rc, update->context);
3468 if (!rc)
3469 WLog_WARN(TAG, "EndPaint call failed");
3470
3471 rdp_update_internal* up = update_cast(update);
3472
3473 if (!up->withinBeginEndPaint)
3474 return rc;
3475 up->withinBeginEndPaint = FALSE;
3476
3477 rdp_update_unlock(update);
3478 return rc;
3479}
Definition types.h:82
This struct contains function pointer to initialize/free objects.
Definition collections.h:57