FreeRDP
Loading...
Searching...
No Matches
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 nullptr;
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 nullptr;
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 = WINPR_C_ARRAY_INIT;
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 nullptr;
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 nullptr;
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 = nullptr;
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 nullptr;
554}
555
556static BOOL s_update_read_pointer_large(wStream* s, POINTER_LARGE_UPDATE* pointer)
557{
558 BYTE* newMask = nullptr;
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 nullptr;
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 nullptr;
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 nullptr;
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 if (altsec->common.SwitchSurface)
967 {
968 if (!altsec->common.SwitchSurface(update->context, &(altsec->switch_surface)))
969 WLog_Print(up->log, WLOG_WARN, "altsec->common.SwitchSurface failed");
970 }
971 }
972}
973
974BOOL update_post_connect(rdpUpdate* update)
975{
976 rdp_update_internal* up = update_cast(update);
977 rdp_altsec_update_internal* altsec = altsec_update_cast(update->altsec);
978
979 WINPR_ASSERT(update->context);
980 WINPR_ASSERT(update->context->settings);
981 up->asynchronous = update->context->settings->AsyncUpdate;
982
983 if (up->asynchronous)
984 {
985#if defined(FORCE_ASYNC_UPDATE_OFF)
986 WLog_WARN(TAG, "AsyncUpdate requested, but forced deactivated");
987 WLog_WARN(TAG, "see https://github.com/FreeRDP/FreeRDP/issues/10153 for details");
988#else
989 if (!(up->proxy = update_message_proxy_new(update)))
990 return FALSE;
991#endif
992 }
993
994 altsec->switch_surface.bitmapId = SCREEN_BITMAP_SURFACE;
995 const BOOL rc = IFCALLRESULT(TRUE, update->altsec->SwitchSurface, update->context,
996 &(altsec->switch_surface));
997 up->initialState = FALSE;
998 return rc;
999}
1000
1001void update_post_disconnect(rdpUpdate* update)
1002{
1003 rdp_update_internal* up = update_cast(update);
1004
1005 WINPR_ASSERT(update->context);
1006 WINPR_ASSERT(update->context->settings);
1007
1008 up->asynchronous = update->context->settings->AsyncUpdate;
1009
1010 if (up->asynchronous)
1011 {
1012#if !defined(FORCE_ASYNC_UPDATE_OFF)
1013 update_message_proxy_free(up->proxy);
1014#endif
1015 }
1016
1017 up->initialState = TRUE;
1018}
1019
1020static BOOL s_update_begin_paint(rdpContext* context)
1021{
1022 wStream* s = nullptr;
1023 WINPR_ASSERT(context);
1024 rdp_update_internal* update = update_cast(context->update);
1025
1026 if (update->us)
1027 {
1028 if (!update_end_paint(&update->common))
1029 return FALSE;
1030 }
1031
1032 WINPR_ASSERT(context->rdp);
1033 s = fastpath_update_pdu_init_new(context->rdp->fastpath);
1034
1035 if (!s)
1036 return FALSE;
1037
1038 Stream_SealLength(s);
1039 Stream_GetLength(s, update->offsetOrders);
1040 Stream_Seek(s, 2); /* numberOrders (2 bytes) */
1041 update->combineUpdates = TRUE;
1042 update->numberOrders = 0;
1043 update->us = s;
1044 return TRUE;
1045}
1046
1047static BOOL s_update_end_paint(rdpContext* context)
1048{
1049 BOOL rc = FALSE;
1050
1051 WINPR_ASSERT(context);
1052 rdp_update_internal* update = update_cast(context->update);
1053
1054 if (!update->us)
1055 return FALSE;
1056
1057 wStream* s = update->us;
1058 update->us = nullptr;
1059
1060 Stream_SealLength(s);
1061 Stream_SetPosition(s, update->offsetOrders);
1062 Stream_Write_UINT16(s, update->numberOrders); /* numberOrders (2 bytes) */
1063 Stream_SetPosition(s, Stream_Length(s));
1064
1065 if (update->numberOrders > 0)
1066 {
1067 WLog_DBG(TAG, "sending %" PRIu16 " orders", update->numberOrders);
1068 if (!fastpath_send_update_pdu(context->rdp->fastpath, FASTPATH_UPDATETYPE_ORDERS, s, FALSE))
1069 goto fail;
1070 }
1071
1072 update->combineUpdates = FALSE;
1073 update->numberOrders = 0;
1074 update->offsetOrders = 0;
1075
1076 rc = TRUE;
1077fail:
1078 Stream_Free(s, TRUE);
1079 return rc;
1080}
1081
1082static BOOL update_flush(rdpContext* context)
1083{
1084 rdp_update_internal* update = nullptr;
1085
1086 WINPR_ASSERT(context);
1087 update = update_cast(context->update);
1088
1089 if (update->numberOrders > 0)
1090 {
1091 if (!update_end_paint(&update->common))
1092 return FALSE;
1093
1094 if (!update_begin_paint(&update->common))
1095 return FALSE;
1096 }
1097 return TRUE;
1098}
1099
1100static BOOL update_force_flush(rdpContext* context)
1101{
1102 return update_flush(context);
1103}
1104
1105static BOOL update_check_flush(rdpContext* context, size_t size)
1106{
1107 WINPR_ASSERT(context);
1108 rdp_update_internal* update = update_cast(context->update);
1109
1110 wStream* s = update->us;
1111
1112 if (!s)
1113 {
1114 if (!update_begin_paint(&update->common))
1115 return FALSE;
1116 s = update->us;
1117 }
1118
1119 if (Stream_GetPosition(s) + size + 64 >= FASTPATH_MAX_PACKET_SIZE)
1120 {
1121 // Too big for the current packet. Flush first
1122 if (!update_flush(context))
1123 return FALSE;
1124 }
1125
1126 return TRUE;
1127}
1128
1129static BOOL update_set_bounds(rdpContext* context, const rdpBounds* bounds)
1130{
1131 rdp_update_internal* update = nullptr;
1132
1133 WINPR_ASSERT(context);
1134
1135 update = update_cast(context->update);
1136
1137 CopyMemory(&update->previousBounds, &update->currentBounds, sizeof(rdpBounds));
1138
1139 if (!bounds)
1140 ZeroMemory(&update->currentBounds, sizeof(rdpBounds));
1141 else
1142 CopyMemory(&update->currentBounds, bounds, sizeof(rdpBounds));
1143
1144 return TRUE;
1145}
1146
1147static BOOL update_bounds_is_null(rdpBounds* bounds)
1148{
1149 WINPR_ASSERT(bounds);
1150 return ((bounds->left == 0) && (bounds->top == 0) && (bounds->right == 0) &&
1151 (bounds->bottom == 0));
1152}
1153
1154static BOOL update_bounds_equals(rdpBounds* bounds1, rdpBounds* bounds2)
1155{
1156 WINPR_ASSERT(bounds1);
1157 WINPR_ASSERT(bounds2);
1158
1159 return ((bounds1->left == bounds2->left) && (bounds1->top == bounds2->top) &&
1160 (bounds1->right == bounds2->right) && (bounds1->bottom == bounds2->bottom));
1161}
1162
1163static size_t update_prepare_bounds(rdpContext* context, ORDER_INFO* orderInfo)
1164{
1165 size_t length = 0;
1166 rdp_update_internal* update = nullptr;
1167
1168 WINPR_ASSERT(context);
1169 WINPR_ASSERT(orderInfo);
1170
1171 update = update_cast(context->update);
1172
1173 orderInfo->boundsFlags = 0;
1174
1175 if (update_bounds_is_null(&update->currentBounds))
1176 return 0;
1177
1178 orderInfo->controlFlags |= ORDER_BOUNDS;
1179
1180 if (update_bounds_equals(&update->previousBounds, &update->currentBounds))
1181 {
1182 orderInfo->controlFlags |= ORDER_ZERO_BOUNDS_DELTAS;
1183 return 0;
1184 }
1185 else
1186 {
1187 length += 1;
1188
1189 if (update->previousBounds.left != update->currentBounds.left)
1190 {
1191 orderInfo->bounds.left = update->currentBounds.left;
1192 orderInfo->boundsFlags |= BOUND_LEFT;
1193 length += 2;
1194 }
1195
1196 if (update->previousBounds.top != update->currentBounds.top)
1197 {
1198 orderInfo->bounds.top = update->currentBounds.top;
1199 orderInfo->boundsFlags |= BOUND_TOP;
1200 length += 2;
1201 }
1202
1203 if (update->previousBounds.right != update->currentBounds.right)
1204 {
1205 orderInfo->bounds.right = update->currentBounds.right;
1206 orderInfo->boundsFlags |= BOUND_RIGHT;
1207 length += 2;
1208 }
1209
1210 if (update->previousBounds.bottom != update->currentBounds.bottom)
1211 {
1212 orderInfo->bounds.bottom = update->currentBounds.bottom;
1213 orderInfo->boundsFlags |= BOUND_BOTTOM;
1214 length += 2;
1215 }
1216 }
1217
1218 return length;
1219}
1220
1221static size_t update_prepare_order_info(rdpContext* context, ORDER_INFO* orderInfo,
1222 UINT32 orderType)
1223{
1224 WINPR_ASSERT(context);
1225 WINPR_ASSERT(orderInfo);
1226
1227 orderInfo->fieldFlags = 0;
1228 orderInfo->orderType = orderType;
1229 orderInfo->controlFlags = ORDER_STANDARD;
1230 orderInfo->controlFlags |= ORDER_TYPE_CHANGE;
1231 size_t length = 2;
1232 length += get_primary_drawing_order_field_bytes(orderInfo->orderType, nullptr);
1233 length += update_prepare_bounds(context, orderInfo);
1234 return length;
1235}
1236
1237WINPR_ATTR_NODISCARD
1238static int update_write_order_info(rdpContext* context, wStream* s, const ORDER_INFO* orderInfo,
1239 size_t offset)
1240{
1241 WINPR_UNUSED(context);
1242 WINPR_ASSERT(orderInfo);
1243 WINPR_ASSERT(orderInfo->controlFlags <= UINT8_MAX);
1244
1245 const size_t position = Stream_GetPosition(s);
1246 const UINT8 controlFlags = (UINT8)orderInfo->controlFlags;
1247
1248 Stream_SetPosition(s, offset);
1249 Stream_Write_UINT8(s, controlFlags); /* controlFlags (1 byte) */
1250
1251 if (orderInfo->controlFlags & ORDER_TYPE_CHANGE)
1252 Stream_Write_UINT8(
1253 s, WINPR_ASSERTING_INT_CAST(uint8_t, orderInfo->orderType)); /* orderType (1 byte) */
1254
1255 if (!update_write_field_flags(
1256 s, orderInfo->fieldFlags, controlFlags,
1257 get_primary_drawing_order_field_bytes(orderInfo->orderType, nullptr)))
1258 return -1;
1259 if (!update_write_bounds(s, orderInfo))
1260 return -1;
1261 Stream_SetPosition(s, position);
1262 return 0;
1263}
1264
1265static void update_write_refresh_rect(wStream* s, BYTE count, const RECTANGLE_16* areas)
1266{
1267 WINPR_ASSERT(s);
1268 WINPR_ASSERT(areas || (count == 0));
1269
1270 Stream_Write_UINT8(s, count); /* numberOfAreas (1 byte) */
1271 Stream_Seek(s, 3); /* pad3Octets (3 bytes) */
1272
1273 for (BYTE i = 0; i < count; i++)
1274 {
1275 Stream_Write_UINT16(s, areas[i].left); /* left (2 bytes) */
1276 Stream_Write_UINT16(s, areas[i].top); /* top (2 bytes) */
1277 Stream_Write_UINT16(s, areas[i].right); /* right (2 bytes) */
1278 Stream_Write_UINT16(s, areas[i].bottom); /* bottom (2 bytes) */
1279 }
1280}
1281
1282static BOOL update_send_refresh_rect(rdpContext* context, BYTE count, const RECTANGLE_16* areas)
1283{
1284 WINPR_ASSERT(context);
1285 rdpRdp* rdp = context->rdp;
1286
1287 WINPR_ASSERT(rdp->settings);
1288 if (rdp->settings->RefreshRect)
1289 {
1290 UINT16 sec_flags = 0;
1291 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
1292
1293 if (!s)
1294 return FALSE;
1295
1296 update_write_refresh_rect(s, count, areas);
1297 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_REFRESH_RECT, rdp->mcs->userId, sec_flags);
1298 }
1299
1300 return TRUE;
1301}
1302
1303static void update_write_suppress_output(wStream* s, BYTE allow, const RECTANGLE_16* area)
1304{
1305 WINPR_ASSERT(s);
1306
1307 Stream_Write_UINT8(s, allow); /* allowDisplayUpdates (1 byte) */
1308 /* Use zeros for padding (like mstsc) for compatibility with legacy servers */
1309 Stream_Zero(s, 3); /* pad3Octets (3 bytes) */
1310
1311 if (allow > 0)
1312 {
1313 WINPR_ASSERT(area);
1314 Stream_Write_UINT16(s, area->left); /* left (2 bytes) */
1315 Stream_Write_UINT16(s, area->top); /* top (2 bytes) */
1316 Stream_Write_UINT16(s, area->right); /* right (2 bytes) */
1317 Stream_Write_UINT16(s, area->bottom); /* bottom (2 bytes) */
1318 }
1319}
1320
1321static BOOL update_send_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
1322{
1323 WINPR_ASSERT(context);
1324 rdpRdp* rdp = context->rdp;
1325
1326 WINPR_ASSERT(rdp);
1327 WINPR_ASSERT(rdp->settings);
1328 if (rdp->settings->SuppressOutput)
1329 {
1330 UINT16 sec_flags = 0;
1331 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
1332
1333 if (!s)
1334 return FALSE;
1335
1336 update_write_suppress_output(s, allow, area);
1337 WINPR_ASSERT(rdp->mcs);
1338 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SUPPRESS_OUTPUT, rdp->mcs->userId,
1339 sec_flags);
1340 }
1341
1342 return TRUE;
1343}
1344
1345static BOOL update_send_surface_command(rdpContext* context, wStream* s)
1346{
1347 wStream* update = nullptr;
1348 WINPR_ASSERT(context);
1349 rdpRdp* rdp = context->rdp;
1350 BOOL ret = 0;
1351
1352 WINPR_ASSERT(rdp);
1353 update = fastpath_update_pdu_init(rdp->fastpath);
1354
1355 if (!update)
1356 return FALSE;
1357
1358 if (!Stream_EnsureRemainingCapacity(update, Stream_GetPosition(s)))
1359 {
1360 ret = FALSE;
1361 goto out;
1362 }
1363
1364 Stream_Write(update, Stream_Buffer(s), Stream_GetPosition(s));
1365 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, update, FALSE);
1366out:
1367 Stream_Release(update);
1368 return ret;
1369}
1370
1371static BOOL update_send_surface_bits(rdpContext* context,
1372 const SURFACE_BITS_COMMAND* surfaceBitsCommand)
1373{
1374 wStream* s = nullptr;
1375 WINPR_ASSERT(context);
1376 rdpRdp* rdp = context->rdp;
1377 BOOL ret = FALSE;
1378
1379 WINPR_ASSERT(surfaceBitsCommand);
1380 WINPR_ASSERT(rdp);
1381
1382 if (!update_force_flush(context))
1383 return FALSE;
1384 s = fastpath_update_pdu_init(rdp->fastpath);
1385
1386 if (!s)
1387 return FALSE;
1388
1389 if (!update_write_surfcmd_surface_bits(s, surfaceBitsCommand))
1390 goto out_fail;
1391
1392 if (!fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s,
1393 surfaceBitsCommand->skipCompression))
1394 goto out_fail;
1395
1396 ret = update_force_flush(context);
1397out_fail:
1398 Stream_Release(s);
1399 return ret;
1400}
1401
1402static BOOL update_send_surface_frame_marker(rdpContext* context,
1403 const SURFACE_FRAME_MARKER* surfaceFrameMarker)
1404{
1405 wStream* s = nullptr;
1406 WINPR_ASSERT(context);
1407 rdpRdp* rdp = context->rdp;
1408 BOOL ret = FALSE;
1409 if (!update_force_flush(context))
1410 return FALSE;
1411
1412 WINPR_ASSERT(rdp);
1413 s = fastpath_update_pdu_init(rdp->fastpath);
1414
1415 if (!s)
1416 return FALSE;
1417
1418 WINPR_ASSERT(surfaceFrameMarker->frameAction <= UINT16_MAX);
1419 if (!update_write_surfcmd_frame_marker(s, (UINT16)surfaceFrameMarker->frameAction,
1420 surfaceFrameMarker->frameId) ||
1421 !fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s, FALSE))
1422 goto out_fail;
1423
1424 ret = update_force_flush(context);
1425out_fail:
1426 Stream_Release(s);
1427 return ret;
1428}
1429
1430static BOOL update_send_surface_frame_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cmd,
1431 BOOL first, BOOL last, UINT32 frameId)
1432{
1433 wStream* s = nullptr;
1434
1435 WINPR_ASSERT(context);
1436 rdpRdp* rdp = context->rdp;
1437 BOOL ret = FALSE;
1438
1439 if (!update_force_flush(context))
1440 return FALSE;
1441
1442 WINPR_ASSERT(rdp);
1443 s = fastpath_update_pdu_init(rdp->fastpath);
1444
1445 if (!s)
1446 return FALSE;
1447
1448 if (first)
1449 {
1450 if (!update_write_surfcmd_frame_marker(s, SURFACECMD_FRAMEACTION_BEGIN, frameId))
1451 goto out_fail;
1452 }
1453
1454 if (!update_write_surfcmd_surface_bits(s, cmd))
1455 goto out_fail;
1456
1457 if (last)
1458 {
1459 if (!update_write_surfcmd_frame_marker(s, SURFACECMD_FRAMEACTION_END, frameId))
1460 goto out_fail;
1461 }
1462
1463 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SURFCMDS, s,
1464 cmd->skipCompression);
1465 if (!ret)
1466 goto out_fail;
1467
1468 ret = update_force_flush(context);
1469out_fail:
1470 Stream_Release(s);
1471 return ret;
1472}
1473
1474static BOOL update_send_frame_acknowledge(rdpContext* context, UINT32 frameId)
1475{
1476 WINPR_ASSERT(context);
1477 rdpRdp* rdp = context->rdp;
1478
1479 WINPR_ASSERT(rdp);
1480 WINPR_ASSERT(rdp->settings);
1481 WINPR_ASSERT(rdp->settings->ReceivedCapabilities);
1482 WINPR_ASSERT(rdp->settings->ReceivedCapabilitiesSize > CAPSET_TYPE_FRAME_ACKNOWLEDGE);
1483 if (rdp->settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
1484 {
1485 UINT16 sec_flags = 0;
1486 wStream* s = rdp_data_pdu_init(rdp, &sec_flags);
1487
1488 if (!s)
1489 return FALSE;
1490
1491 Stream_Write_UINT32(s, frameId);
1492 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_FRAME_ACKNOWLEDGE, rdp->mcs->userId,
1493 sec_flags);
1494 }
1495
1496 return TRUE;
1497}
1498
1499static BOOL update_send_synchronize(rdpContext* context)
1500{
1501 wStream* s = nullptr;
1502 WINPR_ASSERT(context);
1503 rdpRdp* rdp = context->rdp;
1504 BOOL ret = 0;
1505
1506 WINPR_ASSERT(rdp);
1507 s = fastpath_update_pdu_init(rdp->fastpath);
1508
1509 if (!s)
1510 return FALSE;
1511
1512 Stream_Zero(s, 2); /* pad2Octets (2 bytes) */
1513 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_SYNCHRONIZE, s, FALSE);
1514 Stream_Release(s);
1515 return ret;
1516}
1517
1518static BOOL update_send_desktop_resize(rdpContext* context)
1519{
1520 WINPR_ASSERT(context);
1521 return rdp_server_reactivate(context->rdp);
1522}
1523
1524static BOOL update_send_bitmap_update(rdpContext* context, const BITMAP_UPDATE* bitmapUpdate)
1525{
1526 wStream* s = nullptr;
1527 WINPR_ASSERT(context);
1528 rdpRdp* rdp = context->rdp;
1529 rdpUpdate* update = context->update;
1530 BOOL ret = TRUE;
1531
1532 if (!update_force_flush(context))
1533 return FALSE;
1534
1535 WINPR_ASSERT(rdp);
1536 s = fastpath_update_pdu_init(rdp->fastpath);
1537
1538 if (!s)
1539 return FALSE;
1540
1541 if (!update_write_bitmap_update(update, s, bitmapUpdate) ||
1542 !fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_BITMAP, s,
1543 bitmapUpdate->skipCompression))
1544 {
1545 ret = FALSE;
1546 goto out_fail;
1547 }
1548
1549 ret = update_force_flush(context);
1550
1551out_fail:
1552 Stream_Release(s);
1553 return ret;
1554}
1555
1556static BOOL update_send_play_sound(rdpContext* context, const PLAY_SOUND_UPDATE* play_sound)
1557{
1558 UINT16 sec_flags = 0;
1559 wStream* s = nullptr;
1560 WINPR_ASSERT(context);
1561 rdpRdp* rdp = context->rdp;
1562
1563 WINPR_ASSERT(rdp);
1564 WINPR_ASSERT(rdp->settings);
1565 WINPR_ASSERT(play_sound);
1566 WINPR_ASSERT(rdp->settings->ReceivedCapabilities);
1567 WINPR_ASSERT(rdp->settings->ReceivedCapabilitiesSize > CAPSET_TYPE_SOUND);
1568 if (!rdp->settings->ReceivedCapabilities[CAPSET_TYPE_SOUND])
1569 {
1570 return TRUE;
1571 }
1572
1573 s = rdp_data_pdu_init(rdp, &sec_flags);
1574
1575 if (!s)
1576 return FALSE;
1577
1578 Stream_Write_UINT32(s, play_sound->duration);
1579 Stream_Write_UINT32(s, play_sound->frequency);
1580 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_PLAY_SOUND, rdp->mcs->userId, sec_flags);
1581}
1582
1587static BOOL update_send_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt)
1588{
1589 ORDER_INFO orderInfo = WINPR_C_ARRAY_INIT;
1590
1591 WINPR_ASSERT(context);
1592 WINPR_ASSERT(dstblt);
1593
1594 rdp_update_internal* update = update_cast(context->update);
1595
1596 const size_t headerLength = update_prepare_order_info(context, &orderInfo, ORDER_TYPE_DSTBLT);
1597 const size_t inf = update_approximate_dstblt_order(&orderInfo, dstblt);
1598 if (!update_check_flush(context, headerLength + inf))
1599 return FALSE;
1600
1601 wStream* s = update->us;
1602
1603 if (!s)
1604 return FALSE;
1605
1606 const size_t offset = Stream_GetPosition(s);
1607
1608 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1609 return FALSE;
1610
1611 Stream_Seek(s, headerLength);
1612
1613 if (!update_write_dstblt_order(s, &orderInfo, dstblt))
1614 return FALSE;
1615
1616 if (update_write_order_info(context, s, &orderInfo, offset) < 0)
1617 return FALSE;
1618 update->numberOrders++;
1619 return TRUE;
1620}
1621
1622static BOOL update_send_patblt(rdpContext* context, PATBLT_ORDER* patblt)
1623{
1624 size_t offset = 0;
1625 ORDER_INFO orderInfo = WINPR_C_ARRAY_INIT;
1626
1627 WINPR_ASSERT(context);
1628 WINPR_ASSERT(patblt);
1629 rdp_update_internal* update = update_cast(context->update);
1630
1631 const size_t headerLength = update_prepare_order_info(context, &orderInfo, ORDER_TYPE_PATBLT);
1632 if (!update_check_flush(context,
1633 headerLength + update_approximate_patblt_order(&orderInfo, patblt)))
1634 return FALSE;
1635
1636 wStream* s = update->us;
1637
1638 if (!s)
1639 return FALSE;
1640
1641 offset = Stream_GetPosition(s);
1642
1643 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1644 return FALSE;
1645
1646 Stream_Seek(s, headerLength);
1647 if (!update_write_patblt_order(s, &orderInfo, patblt))
1648 return FALSE;
1649 if (update_write_order_info(context, s, &orderInfo, offset) < 0)
1650 return FALSE;
1651 update->numberOrders++;
1652 return TRUE;
1653}
1654
1655static BOOL update_send_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt)
1656{
1657 ORDER_INFO orderInfo = WINPR_C_ARRAY_INIT;
1658
1659 WINPR_ASSERT(context);
1660 WINPR_ASSERT(scrblt);
1661 rdp_update_internal* update = update_cast(context->update);
1662
1663 const size_t headerLength = update_prepare_order_info(context, &orderInfo, ORDER_TYPE_SCRBLT);
1664 const size_t inf = update_approximate_scrblt_order(&orderInfo, scrblt);
1665 if (!update_check_flush(context, headerLength + inf))
1666 return FALSE;
1667
1668 wStream* s = update->us;
1669
1670 if (!s)
1671 return TRUE;
1672
1673 const size_t offset = Stream_GetPosition(s);
1674
1675 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1676 return FALSE;
1677
1678 Stream_Seek(s, headerLength);
1679 if (!update_write_scrblt_order(s, &orderInfo, scrblt))
1680 return FALSE;
1681 if (update_write_order_info(context, s, &orderInfo, offset) < 0)
1682 return FALSE;
1683 update->numberOrders++;
1684 return TRUE;
1685}
1686
1687static BOOL update_send_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect)
1688{
1689 size_t offset = 0;
1690 ORDER_INFO orderInfo = WINPR_C_ARRAY_INIT;
1691
1692 WINPR_ASSERT(context);
1693 WINPR_ASSERT(opaque_rect);
1694 rdp_update_internal* update = update_cast(context->update);
1695
1696 const size_t headerLength =
1697 update_prepare_order_info(context, &orderInfo, ORDER_TYPE_OPAQUE_RECT);
1698 if (!update_check_flush(
1699 context, headerLength + update_approximate_opaque_rect_order(&orderInfo, opaque_rect)))
1700 return FALSE;
1701
1702 wStream* s = update->us;
1703
1704 if (!s)
1705 return FALSE;
1706
1707 offset = Stream_GetPosition(s);
1708
1709 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1710 return FALSE;
1711
1712 Stream_Seek(s, headerLength);
1713 if (!update_write_opaque_rect_order(s, &orderInfo, opaque_rect))
1714 return FALSE;
1715 if (update_write_order_info(context, s, &orderInfo, offset) < 0)
1716 return FALSE;
1717 update->numberOrders++;
1718 return TRUE;
1719}
1720
1721static BOOL update_send_line_to(rdpContext* context, const LINE_TO_ORDER* line_to)
1722{
1723 ORDER_INFO orderInfo = WINPR_C_ARRAY_INIT;
1724
1725 WINPR_ASSERT(context);
1726 WINPR_ASSERT(line_to);
1727 rdp_update_internal* update = update_cast(context->update);
1728 const size_t headerLength = update_prepare_order_info(context, &orderInfo, ORDER_TYPE_LINE_TO);
1729 const size_t inf = update_approximate_line_to_order(&orderInfo, line_to);
1730 if (!update_check_flush(context, headerLength + inf))
1731 return FALSE;
1732
1733 wStream* s = update->us;
1734
1735 if (!s)
1736 return FALSE;
1737
1738 const size_t offset = Stream_GetPosition(s);
1739
1740 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1741 return FALSE;
1742
1743 Stream_Seek(s, headerLength);
1744 if (!update_write_line_to_order(s, &orderInfo, line_to))
1745 return FALSE;
1746 if (update_write_order_info(context, s, &orderInfo, offset) < 0)
1747 return FALSE;
1748 update->numberOrders++;
1749 return TRUE;
1750}
1751
1752static BOOL update_send_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
1753{
1754 size_t offset = 0;
1755 ORDER_INFO orderInfo = WINPR_C_ARRAY_INIT;
1756
1757 WINPR_ASSERT(context);
1758 WINPR_ASSERT(memblt);
1759 rdp_update_internal* update = update_cast(context->update);
1760 const size_t headerLength = update_prepare_order_info(context, &orderInfo, ORDER_TYPE_MEMBLT);
1761 if (!update_check_flush(context,
1762 headerLength + update_approximate_memblt_order(&orderInfo, memblt)))
1763 return FALSE;
1764
1765 wStream* s = update->us;
1766
1767 if (!s)
1768 return FALSE;
1769
1770 offset = Stream_GetPosition(s);
1771
1772 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1773 return FALSE;
1774
1775 Stream_Seek(s, headerLength);
1776 if (!update_write_memblt_order(s, &orderInfo, memblt))
1777 return FALSE;
1778 if (update_write_order_info(context, s, &orderInfo, offset) < 0)
1779 return FALSE;
1780 update->numberOrders++;
1781 return TRUE;
1782}
1783
1784static BOOL update_send_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyph_index)
1785{
1786 ORDER_INFO orderInfo = WINPR_C_ARRAY_INIT;
1787
1788 WINPR_ASSERT(context);
1789 WINPR_ASSERT(glyph_index);
1790 rdp_update_internal* update = update_cast(context->update);
1791
1792 const size_t headerLength =
1793 update_prepare_order_info(context, &orderInfo, ORDER_TYPE_GLYPH_INDEX);
1794 const size_t inf = update_approximate_glyph_index_order(&orderInfo, glyph_index);
1795 if (!update_check_flush(context, headerLength + inf))
1796 return FALSE;
1797
1798 wStream* s = update->us;
1799
1800 if (!s)
1801 return FALSE;
1802
1803 const size_t offset = Stream_GetPosition(s);
1804
1805 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1806 return FALSE;
1807
1808 Stream_Seek(s, headerLength);
1809 if (!update_write_glyph_index_order(s, &orderInfo, glyph_index))
1810 return FALSE;
1811 if (update_write_order_info(context, s, &orderInfo, offset) < 0)
1812 return FALSE;
1813 update->numberOrders++;
1814 return TRUE;
1815}
1816
1817/*
1818 * Secondary Drawing Orders
1819 */
1820
1821static BOOL update_send_cache_bitmap(rdpContext* context, const CACHE_BITMAP_ORDER* cache_bitmap)
1822{
1823 const size_t headerLength = 6;
1824 UINT16 extraFlags = 0;
1825
1826 WINPR_ASSERT(context);
1827 WINPR_ASSERT(cache_bitmap);
1828 rdp_update_internal* update = update_cast(context->update);
1829
1830 const BYTE orderType = cache_bitmap->compressed ? ORDER_TYPE_CACHE_BITMAP_COMPRESSED
1831 : ORDER_TYPE_BITMAP_UNCOMPRESSED;
1832 const size_t inf =
1833 update_approximate_cache_bitmap_order(cache_bitmap, cache_bitmap->compressed, &extraFlags);
1834 if (!update_check_flush(context, headerLength + inf))
1835 return FALSE;
1836
1837 wStream* s = update->us;
1838
1839 if (!s)
1840 return FALSE;
1841
1842 const size_t bm = Stream_GetPosition(s);
1843
1844 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1845 return FALSE;
1846
1847 Stream_Seek(s, headerLength);
1848
1849 if (!update_write_cache_bitmap_order(s, cache_bitmap, cache_bitmap->compressed, &extraFlags))
1850 return FALSE;
1851
1852 const size_t em = Stream_GetPosition(s);
1853 WINPR_ASSERT(em >= bm + 13);
1854 const size_t orderLength = (em - bm) - 13;
1855 WINPR_ASSERT(orderLength <= UINT16_MAX);
1856
1857 Stream_SetPosition(s, bm);
1858 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
1859 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
1860 Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
1861 Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */
1862 Stream_SetPosition(s, em);
1863 update->numberOrders++;
1864 return TRUE;
1865}
1866
1867static BOOL update_send_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cache_bitmap_v2)
1868{
1869 const size_t headerLength = 6;
1870 UINT16 extraFlags = 0;
1871
1872 WINPR_ASSERT(context);
1873 WINPR_ASSERT(cache_bitmap_v2);
1874 rdp_update_internal* update = update_cast(context->update);
1875
1876 const BYTE orderType = cache_bitmap_v2->compressed ? ORDER_TYPE_BITMAP_COMPRESSED_V2
1877 : ORDER_TYPE_BITMAP_UNCOMPRESSED_V2;
1878
1879 if (context->settings->NoBitmapCompressionHeader)
1880 cache_bitmap_v2->flags |= CBR2_NO_BITMAP_COMPRESSION_HDR;
1881
1882 if (!update_check_flush(
1883 context, headerLength + update_approximate_cache_bitmap_v2_order(
1884 cache_bitmap_v2, cache_bitmap_v2->compressed, &extraFlags)))
1885 return FALSE;
1886
1887 wStream* s = update->us;
1888
1889 if (!s)
1890 return FALSE;
1891
1892 const size_t bm = Stream_GetPosition(s);
1893
1894 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1895 return FALSE;
1896
1897 Stream_Seek(s, headerLength);
1898
1899 if (!update_write_cache_bitmap_v2_order(s, cache_bitmap_v2, cache_bitmap_v2->compressed,
1900 &extraFlags))
1901 return FALSE;
1902
1903 const size_t em = Stream_GetPosition(s);
1904 WINPR_ASSERT(em >= bm + 13);
1905 const size_t orderLength = (em - bm) - 13;
1906 WINPR_ASSERT(orderLength <= UINT16_MAX);
1907
1908 Stream_SetPosition(s, bm);
1909 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
1910 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
1911 Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
1912 Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */
1913 Stream_SetPosition(s, em);
1914 update->numberOrders++;
1915 return TRUE;
1916}
1917
1918static BOOL update_send_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cache_bitmap_v3)
1919{
1920 const size_t headerLength = 6;
1921 UINT16 extraFlags = 0;
1922
1923 WINPR_ASSERT(context);
1924 WINPR_ASSERT(cache_bitmap_v3);
1925 rdp_update_internal* update = update_cast(context->update);
1926
1927 const BYTE orderType = ORDER_TYPE_BITMAP_COMPRESSED_V3;
1928 if (!update_check_flush(context, headerLength + update_approximate_cache_bitmap_v3_order(
1929 cache_bitmap_v3, &extraFlags)))
1930 return FALSE;
1931
1932 wStream* s = update->us;
1933
1934 if (!s)
1935 return FALSE;
1936
1937 const size_t bm = Stream_GetPosition(s);
1938
1939 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1940 return FALSE;
1941
1942 Stream_Seek(s, headerLength);
1943
1944 if (!update_write_cache_bitmap_v3_order(s, cache_bitmap_v3, &extraFlags))
1945 return FALSE;
1946
1947 const size_t em = Stream_GetPosition(s);
1948 WINPR_ASSERT(em >= bm + 13);
1949 const size_t orderLength = (em - bm) - 13;
1950 WINPR_ASSERT(orderLength <= UINT16_MAX);
1951
1952 Stream_SetPosition(s, bm);
1953 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
1954 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
1955 Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
1956 Stream_Write_UINT8(s, orderType); /* orderType (1 byte) */
1957 Stream_SetPosition(s, em);
1958 update->numberOrders++;
1959 return TRUE;
1960}
1961
1962static BOOL update_send_cache_color_table(rdpContext* context,
1963 const CACHE_COLOR_TABLE_ORDER* cache_color_table)
1964{
1965 UINT16 flags = 0;
1966 size_t headerLength = 6;
1967
1968 WINPR_ASSERT(context);
1969 WINPR_ASSERT(cache_color_table);
1970 rdp_update_internal* update = update_cast(context->update);
1971
1972 const size_t inf = update_approximate_cache_color_table_order(cache_color_table, &flags);
1973 if (!update_check_flush(context, headerLength + inf))
1974 return FALSE;
1975
1976 wStream* s = update->us;
1977
1978 if (!s)
1979 return FALSE;
1980
1981 const size_t bm = Stream_GetPosition(s);
1982
1983 if (!Stream_EnsureRemainingCapacity(s, headerLength))
1984 return FALSE;
1985
1986 Stream_Seek(s, headerLength);
1987
1988 if (!update_write_cache_color_table_order(s, cache_color_table, &flags))
1989 return FALSE;
1990
1991 const size_t em = Stream_GetPosition(s);
1992 WINPR_ASSERT(em >= bm + 13);
1993 const size_t orderLength = (em - bm) - 13;
1994 WINPR_ASSERT(orderLength <= UINT16_MAX);
1995 Stream_SetPosition(s, bm);
1996 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
1997 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
1998 Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
1999 Stream_Write_UINT8(s, ORDER_TYPE_CACHE_COLOR_TABLE); /* orderType (1 byte) */
2000 Stream_SetPosition(s, em);
2001 update->numberOrders++;
2002 return TRUE;
2003}
2004
2005static BOOL update_send_cache_glyph(rdpContext* context, const CACHE_GLYPH_ORDER* cache_glyph)
2006{
2007 UINT16 flags = 0;
2008 const size_t headerLength = 6;
2009
2010 WINPR_ASSERT(context);
2011 WINPR_ASSERT(cache_glyph);
2012 rdp_update_internal* update = update_cast(context->update);
2013
2014 const size_t inf = update_approximate_cache_glyph_order(cache_glyph, &flags);
2015 if (!update_check_flush(context, headerLength + inf))
2016 return FALSE;
2017
2018 wStream* s = update->us;
2019
2020 if (!s)
2021 return FALSE;
2022
2023 const size_t bm = Stream_GetPosition(s);
2024
2025 if (!Stream_EnsureRemainingCapacity(s, headerLength))
2026 return FALSE;
2027
2028 Stream_Seek(s, headerLength);
2029
2030 if (!update_write_cache_glyph_order(s, cache_glyph, &flags))
2031 return FALSE;
2032
2033 const size_t em = Stream_GetPosition(s);
2034 WINPR_ASSERT(em >= bm + 13);
2035 const size_t orderLength = (em - bm) - 13;
2036 WINPR_ASSERT(orderLength <= UINT16_MAX);
2037 Stream_SetPosition(s, bm);
2038 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
2039 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
2040 Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
2041 Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */
2042 Stream_SetPosition(s, em);
2043 update->numberOrders++;
2044 return TRUE;
2045}
2046
2047static BOOL update_send_cache_glyph_v2(rdpContext* context,
2048 const CACHE_GLYPH_V2_ORDER* cache_glyph_v2)
2049{
2050 UINT16 flags = 0;
2051 const size_t headerLength = 6;
2052
2053 WINPR_ASSERT(context);
2054 WINPR_ASSERT(cache_glyph_v2);
2055 rdp_update_internal* update = update_cast(context->update);
2056
2057 const size_t inf = update_approximate_cache_glyph_v2_order(cache_glyph_v2, &flags);
2058 if (!update_check_flush(context, headerLength + inf))
2059 return FALSE;
2060
2061 wStream* s = update->us;
2062
2063 if (!s)
2064 return FALSE;
2065
2066 const size_t bm = Stream_GetPosition(s);
2067
2068 if (!Stream_EnsureRemainingCapacity(s, headerLength))
2069 return FALSE;
2070
2071 Stream_Seek(s, headerLength);
2072
2073 if (!update_write_cache_glyph_v2_order(s, cache_glyph_v2, &flags))
2074 return FALSE;
2075
2076 const size_t em = Stream_GetPosition(s);
2077 WINPR_ASSERT(em >= bm + 13);
2078 const size_t orderLength = (em - bm) - 13;
2079 WINPR_ASSERT(orderLength <= UINT16_MAX);
2080 Stream_SetPosition(s, bm);
2081 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
2082 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
2083 Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
2084 Stream_Write_UINT8(s, ORDER_TYPE_CACHE_GLYPH); /* orderType (1 byte) */
2085 Stream_SetPosition(s, em);
2086 update->numberOrders++;
2087 return TRUE;
2088}
2089
2090static BOOL update_send_cache_brush(rdpContext* context, const CACHE_BRUSH_ORDER* cache_brush)
2091{
2092 UINT16 flags = 0;
2093 const size_t headerLength = 6;
2094
2095 WINPR_ASSERT(context);
2096 WINPR_ASSERT(cache_brush);
2097 rdp_update_internal* update = update_cast(context->update);
2098
2099 const size_t inf = update_approximate_cache_brush_order(cache_brush, &flags);
2100 if (!update_check_flush(context, headerLength + inf))
2101 return FALSE;
2102
2103 wStream* s = update->us;
2104
2105 if (!s)
2106 return FALSE;
2107
2108 const size_t bm = Stream_GetPosition(s);
2109
2110 if (!Stream_EnsureRemainingCapacity(s, headerLength))
2111 return FALSE;
2112
2113 Stream_Seek(s, headerLength);
2114
2115 if (!update_write_cache_brush_order(s, cache_brush, &flags))
2116 return FALSE;
2117
2118 const size_t em = Stream_GetPosition(s);
2119 if (em <= bm + 13)
2120 return FALSE;
2121
2122 const size_t orderLength = (em - bm) - 13;
2123 WINPR_ASSERT(orderLength <= UINT16_MAX);
2124 Stream_SetPosition(s, bm);
2125 Stream_Write_UINT8(s, ORDER_STANDARD | ORDER_SECONDARY); /* controlFlags (1 byte) */
2126 Stream_Write_UINT16(s, (UINT16)orderLength); /* orderLength (2 bytes) */
2127 Stream_Write_UINT16(s, flags); /* extraFlags (2 bytes) */
2128 Stream_Write_UINT8(s, ORDER_TYPE_CACHE_BRUSH); /* orderType (1 byte) */
2129 Stream_SetPosition(s, em);
2130 update->numberOrders++;
2131 return TRUE;
2132}
2133
2138static BOOL update_send_create_offscreen_bitmap_order(
2139 rdpContext* context, const CREATE_OFFSCREEN_BITMAP_ORDER* create_offscreen_bitmap)
2140{
2141 WINPR_ASSERT(context);
2142 WINPR_ASSERT(create_offscreen_bitmap);
2143 rdp_update_internal* update = update_cast(context->update);
2144
2145 const size_t headerLength = 1;
2146 const size_t orderType = ORDER_TYPE_CREATE_OFFSCREEN_BITMAP;
2147 const size_t controlFlags = ORDER_SECONDARY | (orderType << 2);
2148 const size_t inf = update_approximate_create_offscreen_bitmap_order(create_offscreen_bitmap);
2149 if (!update_check_flush(context, headerLength + inf))
2150 return FALSE;
2151
2152 wStream* s = update->us;
2153
2154 if (!s)
2155 return FALSE;
2156
2157 const size_t bm = Stream_GetPosition(s);
2158
2159 if (!Stream_EnsureRemainingCapacity(s, headerLength))
2160 return FALSE;
2161
2162 Stream_Seek(s, headerLength);
2163
2164 if (!update_write_create_offscreen_bitmap_order(s, create_offscreen_bitmap))
2165 return FALSE;
2166
2167 const size_t em = Stream_GetPosition(s);
2168 Stream_SetPosition(s, bm);
2169 Stream_Write_UINT8(s,
2170 WINPR_ASSERTING_INT_CAST(uint8_t, controlFlags)); /* controlFlags (1 byte) */
2171 Stream_SetPosition(s, em);
2172 update->numberOrders++;
2173 return TRUE;
2174}
2175
2176static BOOL update_send_switch_surface_order(rdpContext* context,
2177 const SWITCH_SURFACE_ORDER* switch_surface)
2178{
2179 WINPR_ASSERT(context);
2180 WINPR_ASSERT(switch_surface);
2181 rdp_update_internal* update = update_cast(context->update);
2182
2183 const size_t headerLength = 1;
2184 const size_t orderType = ORDER_TYPE_SWITCH_SURFACE;
2185 const size_t controlFlags = ORDER_SECONDARY | (orderType << 2);
2186 const size_t inf = update_approximate_switch_surface_order(switch_surface);
2187 if (!update_check_flush(context, headerLength + inf))
2188 return FALSE;
2189
2190 wStream* s = update->us;
2191
2192 if (!s)
2193 return FALSE;
2194
2195 const size_t bm = Stream_GetPosition(s);
2196
2197 if (!Stream_EnsureRemainingCapacity(s, headerLength))
2198 return FALSE;
2199
2200 Stream_Seek(s, headerLength);
2201
2202 if (!update_write_switch_surface_order(s, switch_surface))
2203 return FALSE;
2204
2205 const size_t em = Stream_GetPosition(s);
2206 Stream_SetPosition(s, bm);
2207 Stream_Write_UINT8(s,
2208 WINPR_ASSERTING_INT_CAST(uint8_t, controlFlags)); /* controlFlags (1 byte) */
2209 Stream_SetPosition(s, em);
2210 update->numberOrders++;
2211 return TRUE;
2212}
2213
2214static BOOL update_send_pointer_system(rdpContext* context,
2215 const POINTER_SYSTEM_UPDATE* pointer_system)
2216{
2217 wStream* s = nullptr;
2218 BYTE updateCode = 0;
2219
2220 WINPR_ASSERT(context);
2221 rdpRdp* rdp = context->rdp;
2222 BOOL ret = 0;
2223
2224 WINPR_ASSERT(rdp);
2225 s = fastpath_update_pdu_init(rdp->fastpath);
2226
2227 if (!s)
2228 return FALSE;
2229
2230 if (pointer_system->type == SYSPTR_NULL)
2231 updateCode = FASTPATH_UPDATETYPE_PTR_NULL;
2232 else
2233 updateCode = FASTPATH_UPDATETYPE_PTR_DEFAULT;
2234
2235 ret = fastpath_send_update_pdu(rdp->fastpath, updateCode, s, FALSE);
2236 Stream_Release(s);
2237 return ret;
2238}
2239
2240static BOOL update_send_pointer_position(rdpContext* context,
2241 const POINTER_POSITION_UPDATE* pointerPosition)
2242{
2243 wStream* s = nullptr;
2244 WINPR_ASSERT(context);
2245 rdpRdp* rdp = context->rdp;
2246 BOOL ret = FALSE;
2247
2248 WINPR_ASSERT(rdp);
2249 s = fastpath_update_pdu_init(rdp->fastpath);
2250
2251 if (!s)
2252 return FALSE;
2253
2254 if (!Stream_EnsureRemainingCapacity(s, 16))
2255 goto out_fail;
2256
2257 Stream_Write_UINT16(
2258 s, WINPR_ASSERTING_INT_CAST(uint16_t, pointerPosition->xPos)); /* xPos (2 bytes) */
2259 Stream_Write_UINT16(
2260 s, WINPR_ASSERTING_INT_CAST(uint16_t, pointerPosition->yPos)); /* yPos (2 bytes) */
2261 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_PTR_POSITION, s, FALSE);
2262out_fail:
2263 Stream_Release(s);
2264 return ret;
2265}
2266
2267static BOOL update_write_pointer_color(wStream* s, const POINTER_COLOR_UPDATE* pointer_color)
2268{
2269 WINPR_ASSERT(pointer_color);
2270 if (!Stream_EnsureRemainingCapacity(s, 32 + pointer_color->lengthAndMask +
2271 pointer_color->lengthXorMask))
2272 return FALSE;
2273
2274 Stream_Write_UINT16(s, pointer_color->cacheIndex);
2275 Stream_Write_UINT16(s, pointer_color->hotSpotX);
2276 Stream_Write_UINT16(s, pointer_color->hotSpotY);
2277 Stream_Write_UINT16(s, pointer_color->width);
2278 Stream_Write_UINT16(s, pointer_color->height);
2279 Stream_Write_UINT16(s, pointer_color->lengthAndMask);
2280 Stream_Write_UINT16(s, pointer_color->lengthXorMask);
2281
2282 if (pointer_color->lengthXorMask > 0)
2283 Stream_Write(s, pointer_color->xorMaskData, pointer_color->lengthXorMask);
2284
2285 if (pointer_color->lengthAndMask > 0)
2286 Stream_Write(s, pointer_color->andMaskData, pointer_color->lengthAndMask);
2287
2288 Stream_Write_UINT8(s, 0); /* pad (1 byte) */
2289 return TRUE;
2290}
2291
2292static BOOL update_send_pointer_color(rdpContext* context,
2293 const POINTER_COLOR_UPDATE* pointer_color)
2294{
2295 wStream* s = nullptr;
2296
2297 WINPR_ASSERT(context);
2298 rdpRdp* rdp = context->rdp;
2299 BOOL ret = FALSE;
2300
2301 WINPR_ASSERT(rdp);
2302 WINPR_ASSERT(pointer_color);
2303 s = fastpath_update_pdu_init(rdp->fastpath);
2304
2305 if (!s)
2306 return FALSE;
2307
2308 if (!update_write_pointer_color(s, pointer_color))
2309 goto out_fail;
2310
2311 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_COLOR, s, FALSE);
2312out_fail:
2313 Stream_Release(s);
2314 return ret;
2315}
2316
2317static BOOL update_write_pointer_large(wStream* s, const POINTER_LARGE_UPDATE* pointer)
2318{
2319 WINPR_ASSERT(pointer);
2320
2321 if (!Stream_EnsureRemainingCapacity(s, 32 + pointer->lengthAndMask + pointer->lengthXorMask))
2322 return FALSE;
2323
2324 Stream_Write_UINT16(s, pointer->xorBpp);
2325 Stream_Write_UINT16(s, pointer->cacheIndex);
2326 Stream_Write_UINT16(s, pointer->hotSpotX);
2327 Stream_Write_UINT16(s, pointer->hotSpotY);
2328 Stream_Write_UINT16(s, pointer->width);
2329 Stream_Write_UINT16(s, pointer->height);
2330 Stream_Write_UINT32(s, pointer->lengthAndMask);
2331 Stream_Write_UINT32(s, pointer->lengthXorMask);
2332 Stream_Write(s, pointer->xorMaskData, pointer->lengthXorMask);
2333 Stream_Write(s, pointer->andMaskData, pointer->lengthAndMask);
2334 Stream_Write_UINT8(s, 0); /* pad (1 byte) */
2335 return TRUE;
2336}
2337
2338static BOOL update_send_pointer_large(rdpContext* context, const POINTER_LARGE_UPDATE* pointer)
2339{
2340 wStream* s = nullptr;
2341 WINPR_ASSERT(context);
2342 rdpRdp* rdp = context->rdp;
2343 BOOL ret = FALSE;
2344
2345 WINPR_ASSERT(rdp);
2346 WINPR_ASSERT(pointer);
2347 s = fastpath_update_pdu_init(rdp->fastpath);
2348
2349 if (!s)
2350 return FALSE;
2351
2352 if (!update_write_pointer_large(s, pointer))
2353 goto out_fail;
2354
2355 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_LARGE_POINTER, s, FALSE);
2356out_fail:
2357 Stream_Release(s);
2358 return ret;
2359}
2360
2361static BOOL update_send_pointer_new(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new)
2362{
2363 wStream* s = nullptr;
2364
2365 WINPR_ASSERT(context);
2366 rdpRdp* rdp = context->rdp;
2367 BOOL ret = FALSE;
2368
2369 WINPR_ASSERT(rdp);
2370 WINPR_ASSERT(pointer_new);
2371 s = fastpath_update_pdu_init(rdp->fastpath);
2372
2373 if (!s)
2374 return FALSE;
2375
2376 if (!Stream_EnsureRemainingCapacity(s, 16))
2377 goto out_fail;
2378
2379 Stream_Write_UINT16(
2380 s, WINPR_ASSERTING_INT_CAST(uint16_t, pointer_new->xorBpp)); /* xorBpp (2 bytes) */
2381 update_write_pointer_color(s, &pointer_new->colorPtrAttr);
2382 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_POINTER, s, FALSE);
2383out_fail:
2384 Stream_Release(s);
2385 return ret;
2386}
2387
2388static BOOL update_send_pointer_cached(rdpContext* context,
2389 const POINTER_CACHED_UPDATE* pointer_cached)
2390{
2391 wStream* s = nullptr;
2392
2393 WINPR_ASSERT(context);
2394 rdpRdp* rdp = context->rdp;
2395 BOOL ret = 0;
2396
2397 WINPR_ASSERT(rdp);
2398 WINPR_ASSERT(pointer_cached);
2399 s = fastpath_update_pdu_init(rdp->fastpath);
2400
2401 if (!s)
2402 return FALSE;
2403
2404 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(
2405 uint16_t, pointer_cached->cacheIndex)); /* cacheIndex (2 bytes) */
2406 ret = fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_CACHED, s, FALSE);
2407 Stream_Release(s);
2408 return ret;
2409}
2410
2411BOOL update_read_refresh_rect(rdpUpdate* update, wStream* s)
2412{
2413 BYTE numberOfAreas = 0;
2414 RECTANGLE_16 areas[256] = WINPR_C_ARRAY_INIT;
2415 rdp_update_internal* up = update_cast(update);
2416
2417 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
2418 return FALSE;
2419
2420 Stream_Read_UINT8(s, numberOfAreas);
2421 Stream_Seek(s, 3); /* pad3Octects */
2422
2423 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, numberOfAreas, 8ull))
2424 return FALSE;
2425
2426 for (BYTE index = 0; index < numberOfAreas; index++)
2427 {
2428 RECTANGLE_16* area = &areas[index];
2429
2430 Stream_Read_UINT16(s, area->left);
2431 Stream_Read_UINT16(s, area->top);
2432 Stream_Read_UINT16(s, area->right);
2433 Stream_Read_UINT16(s, area->bottom);
2434 }
2435
2436 WINPR_ASSERT(update->context);
2437 WINPR_ASSERT(update->context->settings);
2438 if (update->context->settings->RefreshRect)
2439 IFCALL(update->RefreshRect, update->context, numberOfAreas, areas);
2440 else
2441 WLog_Print(up->log, WLOG_WARN, "ignoring refresh rect request from client");
2442
2443 return TRUE;
2444}
2445
2446BOOL update_read_suppress_output(rdpUpdate* update, wStream* s)
2447{
2448 rdp_update_internal* up = update_cast(update);
2449 RECTANGLE_16* prect = nullptr;
2450 RECTANGLE_16 rect = WINPR_C_ARRAY_INIT;
2451 BYTE allowDisplayUpdates = 0;
2452
2453 WINPR_ASSERT(up);
2454 WINPR_ASSERT(s);
2455
2456 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
2457 return FALSE;
2458
2459 Stream_Read_UINT8(s, allowDisplayUpdates);
2460 Stream_Seek(s, 3); /* pad3Octects */
2461
2462 if (allowDisplayUpdates > 0)
2463 {
2464 if (!Stream_CheckAndLogRequiredLength(TAG, s, sizeof(RECTANGLE_16)))
2465 return FALSE;
2466
2467 Stream_Read_UINT16(s, rect.left);
2468 Stream_Read_UINT16(s, rect.top);
2469 Stream_Read_UINT16(s, rect.right);
2470 Stream_Read_UINT16(s, rect.bottom);
2471
2472 prect = &rect;
2473 }
2474
2475 WINPR_ASSERT(update->context);
2476 WINPR_ASSERT(update->context->settings);
2477 if (update->context->settings->SuppressOutput)
2478 IFCALL(update->SuppressOutput, update->context, allowDisplayUpdates, prect);
2479 else
2480 WLog_Print(up->log, WLOG_WARN, "ignoring suppress output request from client");
2481
2482 return TRUE;
2483}
2484
2485static BOOL update_send_set_keyboard_indicators(rdpContext* context, UINT16 led_flags)
2486{
2487 UINT16 sec_flags = 0;
2488 wStream* s = nullptr;
2489
2490 WINPR_ASSERT(context);
2491 rdpRdp* rdp = context->rdp;
2492 s = rdp_data_pdu_init(rdp, &sec_flags);
2493
2494 if (!s)
2495 return FALSE;
2496
2497 Stream_Write_UINT16(s, 0); /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.1.1 */
2498 Stream_Write_UINT16(s, led_flags); /* ledFlags (2 bytes) */
2499
2500 WINPR_ASSERT(rdp->mcs);
2501 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS, rdp->mcs->userId,
2502 sec_flags);
2503}
2504
2505static BOOL update_send_set_keyboard_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
2506 UINT32 imeConvMode)
2507{
2508 UINT16 sec_flags = 0;
2509 wStream* s = nullptr;
2510
2511 WINPR_ASSERT(context);
2512 rdpRdp* rdp = context->rdp;
2513 s = rdp_data_pdu_init(rdp, &sec_flags);
2514
2515 if (!s)
2516 return FALSE;
2517
2518 /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.2.1 */
2519 Stream_Write_UINT16(s, imeId);
2520 Stream_Write_UINT32(s, imeState);
2521 Stream_Write_UINT32(s, imeConvMode);
2522
2523 WINPR_ASSERT(rdp->mcs);
2524 return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_IME_STATUS, rdp->mcs->userId,
2525 sec_flags);
2526}
2527
2528static UINT16 update_calculate_new_or_existing_window(const WINDOW_ORDER_INFO* orderInfo,
2529 const WINDOW_STATE_ORDER* stateOrder)
2530{
2531 size_t orderSize = 11;
2532
2533 WINPR_ASSERT(orderInfo);
2534 WINPR_ASSERT(stateOrder);
2535
2536 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_OWNER) != 0)
2537 orderSize += 4;
2538
2539 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_STYLE) != 0)
2540 orderSize += 8;
2541
2542 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_SHOW) != 0)
2543 orderSize += 1;
2544
2545 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE) != 0)
2546 orderSize += 2 + stateOrder->titleInfo.length;
2547
2548 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) != 0)
2549 orderSize += 8;
2550
2551 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) != 0)
2552 orderSize += 8;
2553
2554 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_X) != 0)
2555 orderSize += 8;
2556
2557 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_Y) != 0)
2558 orderSize += 8;
2559
2560 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT) != 0)
2561 orderSize += 1;
2562
2563 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT) != 0)
2564 orderSize += 4;
2565
2566 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) != 0)
2567 orderSize += 8;
2568
2569 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) != 0)
2570 orderSize += 8;
2571
2572 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) != 0)
2573 orderSize += 8;
2574
2575 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) != 0)
2576 {
2577 const size_t len = 2ULL + stateOrder->numWindowRects * sizeof(RECTANGLE_16);
2578 orderSize += len;
2579 }
2580
2581 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) != 0)
2582 orderSize += 8;
2583
2584 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) != 0)
2585 {
2586
2587 const size_t len = 2ULL + stateOrder->numVisibilityRects * sizeof(RECTANGLE_16);
2588 orderSize += len;
2589 }
2590
2591 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_OVERLAY_DESCRIPTION) != 0)
2592 orderSize += 2 + stateOrder->OverlayDescription.length;
2593
2594 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TASKBAR_BUTTON) != 0)
2595 orderSize += 1;
2596
2597 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ENFORCE_SERVER_ZORDER) != 0)
2598 orderSize += 1;
2599
2600 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_APPBAR_STATE) != 0)
2601 orderSize += 1;
2602
2603 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_APPBAR_EDGE) != 0)
2604 orderSize += 1;
2605
2606 return WINPR_ASSERTING_INT_CAST(uint16_t, orderSize);
2607}
2608
2609static BOOL update_write_order_field_flags(UINT32 fieldFlags, const WINDOW_STATE_ORDER* stateOrder,
2610 wStream* s)
2611{
2612 WINPR_ASSERT(stateOrder);
2613
2614 if ((fieldFlags & WINDOW_ORDER_FIELD_OWNER) != 0)
2615 Stream_Write_UINT32(s, stateOrder->ownerWindowId);
2616
2617 if ((fieldFlags & WINDOW_ORDER_FIELD_STYLE) != 0)
2618 {
2619 Stream_Write_UINT32(s, stateOrder->style);
2620 Stream_Write_UINT32(s, stateOrder->extendedStyle);
2621 }
2622
2623 if ((fieldFlags & WINDOW_ORDER_FIELD_SHOW) != 0)
2624 {
2625 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, stateOrder->showState));
2626 }
2627
2628 if ((fieldFlags & WINDOW_ORDER_FIELD_TITLE) != 0)
2629 {
2630 Stream_Write_UINT16(s, stateOrder->titleInfo.length);
2631 Stream_Write(s, stateOrder->titleInfo.string, stateOrder->titleInfo.length);
2632 }
2633
2634 if ((fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET) != 0)
2635 {
2636 Stream_Write_INT32(s, stateOrder->clientOffsetX);
2637 Stream_Write_INT32(s, stateOrder->clientOffsetY);
2638 }
2639
2640 if ((fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE) != 0)
2641 {
2642 Stream_Write_UINT32(s, stateOrder->clientAreaWidth);
2643 Stream_Write_UINT32(s, stateOrder->clientAreaHeight);
2644 }
2645
2646 if ((fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_X) != 0)
2647 {
2648 Stream_Write_UINT32(s, stateOrder->resizeMarginLeft);
2649 Stream_Write_UINT32(s, stateOrder->resizeMarginRight);
2650 }
2651
2652 if ((fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_Y) != 0)
2653 {
2654 Stream_Write_UINT32(s, stateOrder->resizeMarginTop);
2655 Stream_Write_UINT32(s, stateOrder->resizeMarginBottom);
2656 }
2657
2658 if ((fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT) != 0)
2659 {
2660 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, stateOrder->RPContent));
2661 }
2662
2663 if ((fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT) != 0)
2664 {
2665 Stream_Write_UINT32(s, stateOrder->rootParentHandle);
2666 }
2667
2668 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) != 0)
2669 {
2670 Stream_Write_INT32(s, stateOrder->windowOffsetX);
2671 Stream_Write_INT32(s, stateOrder->windowOffsetY);
2672 }
2673
2674 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA) != 0)
2675 {
2676 Stream_Write_INT32(s, stateOrder->windowClientDeltaX);
2677 Stream_Write_INT32(s, stateOrder->windowClientDeltaY);
2678 }
2679
2680 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE) != 0)
2681 {
2682 Stream_Write_UINT32(s, stateOrder->windowWidth);
2683 Stream_Write_UINT32(s, stateOrder->windowHeight);
2684 }
2685
2686 if ((fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS) != 0)
2687 {
2688 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, stateOrder->numWindowRects));
2689 Stream_Write(s, stateOrder->windowRects, stateOrder->numWindowRects * sizeof(RECTANGLE_16));
2690 }
2691
2692 if ((fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET) != 0)
2693 {
2694 Stream_Write_INT32(s, stateOrder->visibleOffsetX);
2695 Stream_Write_INT32(s, stateOrder->visibleOffsetY);
2696 }
2697
2698 if ((fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY) != 0)
2699 {
2700 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, stateOrder->numVisibilityRects));
2701 Stream_Write(s, stateOrder->visibilityRects,
2702 stateOrder->numVisibilityRects * sizeof(RECTANGLE_16));
2703 }
2704
2705 if ((fieldFlags & WINDOW_ORDER_FIELD_OVERLAY_DESCRIPTION) != 0)
2706 {
2707 Stream_Write_UINT16(s, stateOrder->OverlayDescription.length);
2708 Stream_Write(s, stateOrder->OverlayDescription.string,
2709 stateOrder->OverlayDescription.length);
2710 }
2711
2712 if ((fieldFlags & WINDOW_ORDER_FIELD_TASKBAR_BUTTON) != 0)
2713 {
2714 Stream_Write_UINT8(s, stateOrder->TaskbarButton);
2715 }
2716
2717 if ((fieldFlags & WINDOW_ORDER_FIELD_ENFORCE_SERVER_ZORDER) != 0)
2718 {
2719 Stream_Write_UINT8(s, stateOrder->EnforceServerZOrder);
2720 }
2721
2722 if ((fieldFlags & WINDOW_ORDER_FIELD_APPBAR_STATE) != 0)
2723 {
2724 Stream_Write_UINT8(s, stateOrder->AppBarState);
2725 }
2726
2727 if ((fieldFlags & WINDOW_ORDER_FIELD_APPBAR_EDGE) != 0)
2728 {
2729 Stream_Write_UINT8(s, stateOrder->AppBarEdge);
2730 }
2731
2732 return TRUE;
2733}
2734
2735static BOOL update_send_new_or_existing_window(rdpContext* context,
2736 const WINDOW_ORDER_INFO* orderInfo,
2737 const WINDOW_STATE_ORDER* stateOrder)
2738{
2739 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
2740 UINT16 orderSize = update_calculate_new_or_existing_window(orderInfo, stateOrder);
2741
2742 WINPR_ASSERT(context);
2743 WINPR_ASSERT(orderInfo);
2744 WINPR_ASSERT(stateOrder);
2745
2746 rdp_update_internal* update = update_cast(context->update);
2747
2748 if (!update_check_flush(context, orderSize))
2749 return FALSE;
2750
2751 wStream* s = update->us;
2752
2753 if (!s)
2754 return FALSE;
2755
2756 if (!Stream_EnsureRemainingCapacity(s, orderSize))
2757 return FALSE;
2758
2759 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
2760 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
2761 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
2762 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
2763
2764 if (!update_write_order_field_flags(orderInfo->fieldFlags, stateOrder, s))
2765 return FALSE;
2766
2767 update->numberOrders++;
2768 return TRUE;
2769}
2770
2771static BOOL update_send_window_create(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
2772 const WINDOW_STATE_ORDER* stateOrder)
2773{
2774 return update_send_new_or_existing_window(context, orderInfo, stateOrder);
2775}
2776
2777static BOOL update_send_window_update(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
2778 const WINDOW_STATE_ORDER* stateOrder)
2779{
2780 return update_send_new_or_existing_window(context, orderInfo, stateOrder);
2781}
2782
2783static UINT16
2784update_calculate_window_icon_order(WINPR_ATTR_UNUSED const WINDOW_ORDER_INFO* orderInfo,
2785 const WINDOW_ICON_ORDER* iconOrder)
2786{
2787 UINT16 orderSize = 23;
2788
2789 WINPR_ASSERT(iconOrder);
2790 ICON_INFO* iconInfo = iconOrder->iconInfo;
2791 WINPR_ASSERT(iconInfo);
2792
2793 orderSize += iconInfo->cbBitsColor + iconInfo->cbBitsMask;
2794
2795 if (iconInfo->bpp <= 8)
2796 orderSize += 2 + iconInfo->cbColorTable;
2797
2798 return orderSize;
2799}
2800
2801static BOOL update_send_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
2802 const WINDOW_ICON_ORDER* iconOrder)
2803{
2804 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
2805
2806 WINPR_ASSERT(iconOrder);
2807 ICON_INFO* iconInfo = iconOrder->iconInfo;
2808 UINT16 orderSize = update_calculate_window_icon_order(orderInfo, iconOrder);
2809
2810 WINPR_ASSERT(context);
2811 WINPR_ASSERT(orderInfo);
2812 WINPR_ASSERT(iconInfo);
2813
2814 rdp_update_internal* update = update_cast(context->update);
2815
2816 if (!update_check_flush(context, orderSize))
2817 return FALSE;
2818
2819 wStream* s = update->us;
2820
2821 if (!s || !iconInfo)
2822 return FALSE;
2823
2824 if (!Stream_EnsureRemainingCapacity(s, orderSize))
2825 return FALSE;
2826
2827 /* Write Hdr */
2828 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
2829 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
2830 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
2831 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
2832 /* Write body */
2833 Stream_Write_UINT16(
2834 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cacheEntry)); /* CacheEntry (2 bytes) */
2835 Stream_Write_UINT8(s,
2836 WINPR_ASSERTING_INT_CAST(uint8_t, iconInfo->cacheId)); /* CacheId (1 byte) */
2837 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, iconInfo->bpp)); /* Bpp (1 byte) */
2838 Stream_Write_UINT16(s,
2839 WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->width)); /* Width (2 bytes) */
2840 Stream_Write_UINT16(
2841 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->height)); /* Height (2 bytes) */
2842
2843 if (iconInfo->bpp <= 8)
2844 {
2845 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(
2846 uint16_t, iconInfo->cbColorTable)); /* CbColorTable (2 bytes) */
2847 }
2848
2849 Stream_Write_UINT16(
2850 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cbBitsMask)); /* CbBitsMask (2 bytes) */
2851 Stream_Write_UINT16(
2852 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cbBitsColor)); /* CbBitsColor (2 bytes) */
2853 Stream_Write(s, iconInfo->bitsMask, iconInfo->cbBitsMask); /* BitsMask (variable) */
2854
2855 if (iconInfo->bpp <= 8)
2856 {
2857 Stream_Write(s, iconInfo->colorTable, iconInfo->cbColorTable); /* ColorTable (variable) */
2858 }
2859
2860 Stream_Write(s, iconInfo->bitsColor, iconInfo->cbBitsColor); /* BitsColor (variable) */
2861
2862 update->numberOrders++;
2863 return TRUE;
2864}
2865
2866static BOOL update_send_window_cached_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
2867 const WINDOW_CACHED_ICON_ORDER* cachedIconOrder)
2868{
2869 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
2870 UINT16 orderSize = 14;
2871
2872 WINPR_ASSERT(cachedIconOrder);
2873 const CACHED_ICON_INFO* cachedIcon = &cachedIconOrder->cachedIcon;
2874
2875 WINPR_ASSERT(context);
2876 WINPR_ASSERT(orderInfo);
2877 WINPR_ASSERT(cachedIcon);
2878
2879 rdp_update_internal* update = update_cast(context->update);
2880
2881 if (!update_check_flush(context, orderSize))
2882 return FALSE;
2883
2884 wStream* s = update->us;
2885 if (!s)
2886 return FALSE;
2887
2888 if (!Stream_EnsureRemainingCapacity(s, orderSize))
2889 return FALSE;
2890
2891 /* Write Hdr */
2892 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
2893 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
2894 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
2895 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
2896 /* Write body */
2897 Stream_Write_UINT16(
2898 s, WINPR_ASSERTING_INT_CAST(uint16_t, cachedIcon->cacheEntry)); /* CacheEntry (2 bytes) */
2899 Stream_Write_UINT8(
2900 s, WINPR_ASSERTING_INT_CAST(uint8_t, cachedIcon->cacheId)); /* CacheId (1 byte) */
2901 update->numberOrders++;
2902 return TRUE;
2903}
2904
2905static BOOL update_send_window_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
2906{
2907 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
2908 UINT16 orderSize = 11;
2909
2910 WINPR_ASSERT(context);
2911 WINPR_ASSERT(orderInfo);
2912 rdp_update_internal* update = update_cast(context->update);
2913
2914 if (!update_check_flush(context, orderSize))
2915 return FALSE;
2916
2917 wStream* s = update->us;
2918
2919 if (!s)
2920 return FALSE;
2921
2922 if (!Stream_EnsureRemainingCapacity(s, orderSize))
2923 return FALSE;
2924
2925 /* Write Hdr */
2926 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
2927 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
2928 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
2929 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
2930 update->numberOrders++;
2931 return TRUE;
2932}
2933
2934static UINT16 update_calculate_new_or_existing_notification_icons_order(
2935 const WINDOW_ORDER_INFO* orderInfo, const NOTIFY_ICON_STATE_ORDER* iconStateOrder)
2936{
2937 UINT16 orderSize = 15;
2938
2939 WINPR_ASSERT(orderInfo);
2940 WINPR_ASSERT(iconStateOrder);
2941
2942 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION) != 0)
2943 orderSize += 4;
2944
2945 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP) != 0)
2946 {
2947 orderSize += 2 + iconStateOrder->toolTip.length;
2948 }
2949
2950 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) != 0)
2951 {
2952 NOTIFY_ICON_INFOTIP infoTip = iconStateOrder->infoTip;
2953 orderSize += 12 + infoTip.text.length + infoTip.title.length;
2954 }
2955
2956 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE) != 0)
2957 {
2958 orderSize += 4;
2959 }
2960
2961 if ((orderInfo->fieldFlags & WINDOW_ORDER_ICON) != 0)
2962 {
2963 ICON_INFO iconInfo = iconStateOrder->icon;
2964 orderSize += 12;
2965
2966 if (iconInfo.bpp <= 8)
2967 orderSize += 2 + iconInfo.cbColorTable;
2968
2969 orderSize += iconInfo.cbBitsMask + iconInfo.cbBitsColor;
2970 }
2971 else if ((orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON) != 0)
2972 {
2973 orderSize += 3;
2974 }
2975
2976 return orderSize;
2977}
2978
2979static BOOL update_send_new_or_existing_order_icon(const ICON_INFO* iconInfo, wStream* s)
2980{
2981 WINPR_ASSERT(iconInfo);
2982
2983 if (!Stream_EnsureRemainingCapacity(s, 8))
2984 return FALSE;
2985
2986 Stream_Write_UINT16(
2987 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cacheEntry)); /* CacheEntry (2 bytes) */
2988 Stream_Write_UINT8(s,
2989 WINPR_ASSERTING_INT_CAST(uint8_t, iconInfo->cacheId)); /* CacheId (1 byte) */
2990 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, iconInfo->bpp)); /* Bpp (1 byte) */
2991 Stream_Write_UINT16(s,
2992 WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->width)); /* Width (2 bytes) */
2993 Stream_Write_UINT16(
2994 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->height)); /* Height (2 bytes) */
2995
2996 if (iconInfo->bpp <= 8)
2997 {
2998 if (!Stream_EnsureRemainingCapacity(s, 2))
2999 return FALSE;
3000 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(
3001 uint16_t, iconInfo->cbColorTable)); /* CbColorTable (2 bytes) */
3002 }
3003
3004 if (!Stream_EnsureRemainingCapacity(s, 4ULL + iconInfo->cbBitsMask))
3005 return FALSE;
3006 Stream_Write_UINT16(
3007 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cbBitsMask)); /* CbBitsMask (2 bytes) */
3008 Stream_Write_UINT16(
3009 s, WINPR_ASSERTING_INT_CAST(uint16_t, iconInfo->cbBitsColor)); /* CbBitsColor (2 bytes) */
3010 Stream_Write(s, iconInfo->bitsMask, iconInfo->cbBitsMask); /* BitsMask (variable) */
3011
3012 if (iconInfo->bpp <= 8)
3013 {
3014 if (!Stream_EnsureRemainingCapacity(s, iconInfo->cbColorTable))
3015 return FALSE;
3016 Stream_Write(s, iconInfo->colorTable, iconInfo->cbColorTable); /* ColorTable (variable) */
3017 }
3018
3019 if (!Stream_EnsureRemainingCapacity(s, iconInfo->cbBitsColor))
3020 return FALSE;
3021 Stream_Write(s, iconInfo->bitsColor, iconInfo->cbBitsColor); /* BitsColor (variable) */
3022 return TRUE;
3023}
3024
3025static BOOL
3026update_send_new_or_existing_notification_icons(rdpContext* context,
3027 const WINDOW_ORDER_INFO* orderInfo,
3028 const NOTIFY_ICON_STATE_ORDER* iconStateOrder)
3029{
3030 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
3031 BOOL versionFieldPresent = FALSE;
3032 const UINT16 orderSize =
3033 update_calculate_new_or_existing_notification_icons_order(orderInfo, iconStateOrder);
3034
3035 WINPR_ASSERT(context);
3036 WINPR_ASSERT(orderInfo);
3037 WINPR_ASSERT(iconStateOrder);
3038 rdp_update_internal* update = update_cast(context->update);
3039
3040 if (!update_check_flush(context, orderSize))
3041 return FALSE;
3042
3043 wStream* s = update->us;
3044 if (!s)
3045 return FALSE;
3046
3047 if (!Stream_EnsureRemainingCapacity(s, orderSize))
3048 return FALSE;
3049
3050 /* Write Hdr */
3051 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
3052 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
3053 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
3054 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
3055 Stream_Write_UINT32(s, orderInfo->notifyIconId); /* NotifyIconId (4 bytes) */
3056
3057 /* Write body */
3058 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION) != 0)
3059 {
3060 versionFieldPresent = TRUE;
3061 Stream_Write_UINT32(s, iconStateOrder->version);
3062 }
3063
3064 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP) != 0)
3065 {
3066 Stream_Write_UINT16(s, iconStateOrder->toolTip.length);
3067 Stream_Write(s, iconStateOrder->toolTip.string, iconStateOrder->toolTip.length);
3068 }
3069
3070 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP) != 0)
3071 {
3072 NOTIFY_ICON_INFOTIP infoTip = iconStateOrder->infoTip;
3073
3074 /* info tip should not be sent when version is 0 */
3075 if (versionFieldPresent && iconStateOrder->version == 0)
3076 return FALSE;
3077
3078 Stream_Write_UINT32(s, infoTip.timeout); /* Timeout (4 bytes) */
3079 Stream_Write_UINT32(s, infoTip.flags); /* InfoFlags (4 bytes) */
3080 Stream_Write_UINT16(s, infoTip.text.length); /* InfoTipText (variable) */
3081 Stream_Write(s, infoTip.text.string, infoTip.text.length);
3082 Stream_Write_UINT16(s, infoTip.title.length); /* Title (variable) */
3083 Stream_Write(s, infoTip.title.string, infoTip.title.length);
3084 }
3085
3086 if ((orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE) != 0)
3087 {
3088 /* notify state should not be sent when version is 0 */
3089 if (versionFieldPresent && iconStateOrder->version == 0)
3090 return FALSE;
3091
3092 Stream_Write_UINT32(s, iconStateOrder->state);
3093 }
3094
3095 if ((orderInfo->fieldFlags & WINDOW_ORDER_ICON) != 0)
3096 {
3097 const ICON_INFO* iconInfo = &iconStateOrder->icon;
3098
3099 if (!update_send_new_or_existing_order_icon(iconInfo, s))
3100 return FALSE;
3101 }
3102 else if ((orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON) != 0)
3103 {
3104 const CACHED_ICON_INFO cachedIcon = iconStateOrder->cachedIcon;
3105 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(
3106 uint16_t, cachedIcon.cacheEntry)); /* CacheEntry (2 bytes) */
3107 Stream_Write_UINT8(
3108 s, WINPR_ASSERTING_INT_CAST(uint8_t, cachedIcon.cacheId)); /* CacheId (1 byte) */
3109 }
3110
3111 update->numberOrders++;
3112 return TRUE;
3113}
3114
3115static BOOL update_send_notify_icon_create(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
3116 const NOTIFY_ICON_STATE_ORDER* iconStateOrder)
3117{
3118 return update_send_new_or_existing_notification_icons(context, orderInfo, iconStateOrder);
3119}
3120
3121static BOOL update_send_notify_icon_update(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
3122 const NOTIFY_ICON_STATE_ORDER* iconStateOrder)
3123{
3124 return update_send_new_or_existing_notification_icons(context, orderInfo, iconStateOrder);
3125}
3126
3127static BOOL update_send_notify_icon_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
3128{
3129 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
3130 UINT16 orderSize = 15;
3131
3132 WINPR_ASSERT(context);
3133 WINPR_ASSERT(orderInfo);
3134 rdp_update_internal* update = update_cast(context->update);
3135
3136 if (!update_check_flush(context, orderSize))
3137 return FALSE;
3138
3139 wStream* s = update->us;
3140
3141 if (!s)
3142 return FALSE;
3143
3144 /* Write Hdr */
3145 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
3146 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
3147 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
3148 Stream_Write_UINT32(s, orderInfo->windowId); /* WindowID (4 bytes) */
3149 Stream_Write_UINT32(s, orderInfo->notifyIconId); /* NotifyIconId (4 bytes) */
3150 update->numberOrders++;
3151 return TRUE;
3152}
3153
3154static UINT16 update_calculate_monitored_desktop(const WINDOW_ORDER_INFO* orderInfo,
3155 const MONITORED_DESKTOP_ORDER* monitoredDesktop)
3156{
3157 UINT16 orderSize = 7;
3158
3159 WINPR_ASSERT(orderInfo);
3160 WINPR_ASSERT(monitoredDesktop);
3161
3162 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND)
3163 {
3164 orderSize += 4;
3165 }
3166
3167 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER)
3168 {
3169 orderSize += 1 + (4 * monitoredDesktop->numWindowIds);
3170 }
3171
3172 return orderSize;
3173}
3174
3175static BOOL update_send_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
3176 const MONITORED_DESKTOP_ORDER* monitoredDesktop)
3177{
3178 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
3179 UINT16 orderSize = update_calculate_monitored_desktop(orderInfo, monitoredDesktop);
3180
3181 WINPR_ASSERT(context);
3182 WINPR_ASSERT(orderInfo);
3183 WINPR_ASSERT(monitoredDesktop);
3184
3185 rdp_update_internal* update = update_cast(context->update);
3186
3187 if (!update_check_flush(context, orderSize))
3188 return FALSE;
3189
3190 wStream* s = update->us;
3191
3192 if (!s)
3193 return FALSE;
3194
3195 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
3196 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
3197 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
3198
3199 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND)
3200 {
3201 Stream_Write_UINT32(s, monitoredDesktop->activeWindowId); /* activeWindowId (4 bytes) */
3202 }
3203
3204 if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER)
3205 {
3206 Stream_Write_UINT8(
3207 s, WINPR_ASSERTING_INT_CAST(
3208 uint8_t, monitoredDesktop->numWindowIds)); /* numWindowIds (1 byte) */
3209
3210 /* windowIds */
3211 for (UINT32 i = 0; i < monitoredDesktop->numWindowIds; i++)
3212 {
3213 Stream_Write_UINT32(s,
3214 WINPR_ASSERTING_INT_CAST(uint32_t, monitoredDesktop->windowIds[i]));
3215 }
3216 }
3217
3218 update->numberOrders++;
3219 return TRUE;
3220}
3221
3222static BOOL update_send_non_monitored_desktop(rdpContext* context,
3223 const WINDOW_ORDER_INFO* orderInfo)
3224{
3225 BYTE controlFlags = ORDER_SECONDARY | (ORDER_TYPE_WINDOW << 2);
3226 UINT16 orderSize = 7;
3227
3228 WINPR_ASSERT(context);
3229 WINPR_ASSERT(orderInfo);
3230 rdp_update_internal* update = update_cast(context->update);
3231
3232 if (!update_check_flush(context, orderSize))
3233 return FALSE;
3234
3235 wStream* s = update->us;
3236
3237 if (!s)
3238 return FALSE;
3239
3240 Stream_Write_UINT8(s, controlFlags); /* Header (1 byte) */
3241 Stream_Write_UINT16(s, orderSize); /* OrderSize (2 bytes) */
3242 Stream_Write_UINT32(s, orderInfo->fieldFlags); /* FieldsPresentFlags (4 bytes) */
3243 update->numberOrders++;
3244 return TRUE;
3245}
3246
3247void update_register_server_callbacks(rdpUpdate* update)
3248{
3249 WINPR_ASSERT(update);
3250
3251 update->BeginPaint = s_update_begin_paint;
3252 update->EndPaint = s_update_end_paint;
3253 update->SetBounds = update_set_bounds;
3254 update->Synchronize = update_send_synchronize;
3255 update->DesktopResize = update_send_desktop_resize;
3256 update->BitmapUpdate = update_send_bitmap_update;
3257 update->SurfaceBits = update_send_surface_bits;
3258 update->SurfaceFrameMarker = update_send_surface_frame_marker;
3259 update->SurfaceCommand = update_send_surface_command;
3260 update->SurfaceFrameBits = update_send_surface_frame_bits;
3261 update->PlaySound = update_send_play_sound;
3262 update->SetKeyboardIndicators = update_send_set_keyboard_indicators;
3263 update->SetKeyboardImeStatus = update_send_set_keyboard_ime_status;
3264 update->SaveSessionInfo = rdp_send_save_session_info;
3265 update->ServerStatusInfo = rdp_send_server_status_info;
3266 update->primary->DstBlt = update_send_dstblt;
3267 update->primary->PatBlt = update_send_patblt;
3268 update->primary->ScrBlt = update_send_scrblt;
3269 update->primary->OpaqueRect = update_send_opaque_rect;
3270 update->primary->LineTo = update_send_line_to;
3271 update->primary->MemBlt = update_send_memblt;
3272 update->primary->GlyphIndex = update_send_glyph_index;
3273 update->secondary->CacheBitmap = update_send_cache_bitmap;
3274 update->secondary->CacheBitmapV2 = update_send_cache_bitmap_v2;
3275 update->secondary->CacheBitmapV3 = update_send_cache_bitmap_v3;
3276 update->secondary->CacheColorTable = update_send_cache_color_table;
3277 update->secondary->CacheGlyph = update_send_cache_glyph;
3278 update->secondary->CacheGlyphV2 = update_send_cache_glyph_v2;
3279 update->secondary->CacheBrush = update_send_cache_brush;
3280 update->altsec->CreateOffscreenBitmap = update_send_create_offscreen_bitmap_order;
3281 update->altsec->SwitchSurface = update_send_switch_surface_order;
3282 update->pointer->PointerSystem = update_send_pointer_system;
3283 update->pointer->PointerPosition = update_send_pointer_position;
3284 update->pointer->PointerColor = update_send_pointer_color;
3285 update->pointer->PointerLarge = update_send_pointer_large;
3286 update->pointer->PointerNew = update_send_pointer_new;
3287 update->pointer->PointerCached = update_send_pointer_cached;
3288 update->window->WindowCreate = update_send_window_create;
3289 update->window->WindowUpdate = update_send_window_update;
3290 update->window->WindowIcon = update_send_window_icon;
3291 update->window->WindowCachedIcon = update_send_window_cached_icon;
3292 update->window->WindowDelete = update_send_window_delete;
3293 update->window->NotifyIconCreate = update_send_notify_icon_create;
3294 update->window->NotifyIconUpdate = update_send_notify_icon_update;
3295 update->window->NotifyIconDelete = update_send_notify_icon_delete;
3296 update->window->MonitoredDesktop = update_send_monitored_desktop;
3297 update->window->NonMonitoredDesktop = update_send_non_monitored_desktop;
3298}
3299
3300void update_register_client_callbacks(rdpUpdate* update)
3301{
3302 WINPR_ASSERT(update);
3303
3304 update->RefreshRect = update_send_refresh_rect;
3305 update->SuppressOutput = update_send_suppress_output;
3306 update->SurfaceFrameAcknowledge = update_send_frame_acknowledge;
3307}
3308
3309int update_process_messages(rdpUpdate* update)
3310{
3311 return update_message_queue_process_pending_messages(update);
3312}
3313
3314static void update_free_queued_message(void* obj)
3315{
3316 wMessage* msg = (wMessage*)obj;
3317 update_message_queue_free_message(msg);
3318}
3319
3320void update_free_window_state(WINDOW_STATE_ORDER* window_state)
3321{
3322 if (!window_state)
3323 return;
3324
3325 free(window_state->OverlayDescription.string);
3326 free(window_state->titleInfo.string);
3327 free(window_state->windowRects);
3328 free(window_state->visibilityRects);
3329 memset(window_state, 0, sizeof(WINDOW_STATE_ORDER));
3330}
3331
3332rdpUpdate* update_new(rdpRdp* rdp)
3333{
3334 const wObject cb = { nullptr, nullptr, nullptr, update_free_queued_message, nullptr };
3335
3336 WINPR_ASSERT(rdp);
3337 WINPR_ASSERT(rdp->context);
3338
3339 rdp_update_internal* update = (rdp_update_internal*)calloc(1, sizeof(rdp_update_internal));
3340
3341 if (!update)
3342 return nullptr;
3343
3344 update->common.context = rdp->context;
3345 update->log = WLog_Get("com.freerdp.core.update");
3346 InitializeCriticalSection(&(update->mux));
3347 update->common.pointer = (rdpPointerUpdate*)calloc(1, sizeof(rdpPointerUpdate));
3348
3349 if (!update->common.pointer)
3350 goto fail;
3351
3352 {
3355
3356 if (!primary)
3357 goto fail;
3358 update->common.primary = &primary->common;
3359 }
3360
3361 {
3364
3365 if (!secondary)
3366 goto fail;
3367 update->common.secondary = &secondary->common;
3368 }
3369
3370 {
3373
3374 if (!altsec)
3375 goto fail;
3376
3377 update->common.altsec = &altsec->common;
3378
3379 update->common.window = (rdpWindowUpdate*)calloc(1, sizeof(rdpWindowUpdate));
3380
3381 if (!update->common.window)
3382 goto fail;
3383
3384 {
3385 OFFSCREEN_DELETE_LIST* deleteList = &(altsec->create_offscreen_bitmap.deleteList);
3386 deleteList->sIndices = 64;
3387 deleteList->indices = calloc(deleteList->sIndices, 2);
3388
3389 if (!deleteList->indices)
3390 goto fail;
3391
3392 deleteList->cIndices = 0;
3393 }
3394 }
3395
3396 update->common.SuppressOutput = update_send_suppress_output;
3397 update->initialState = TRUE;
3398 update->common.autoCalculateBitmapData = TRUE;
3399 update->queue = MessageQueue_New(&cb);
3400
3401 if (!update->queue)
3402 goto fail;
3403
3404 return &update->common;
3405fail:
3406 WINPR_PRAGMA_DIAG_PUSH
3407 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
3408 update_free(&update->common);
3409 WINPR_PRAGMA_DIAG_POP
3410 return nullptr;
3411}
3412
3413void update_free(rdpUpdate* update)
3414{
3415 if (update != nullptr)
3416 {
3417 rdp_update_internal* up = update_cast(update);
3418 rdp_altsec_update_internal* altsec = altsec_update_cast(update->altsec);
3419 OFFSCREEN_DELETE_LIST* deleteList = &(altsec->create_offscreen_bitmap.deleteList);
3420
3421 if (deleteList)
3422 free(deleteList->indices);
3423
3424 free(update->pointer);
3425
3426 if (update->primary)
3427 {
3428 rdp_primary_update_internal* primary = primary_update_cast(update->primary);
3429
3430 free(primary->polygon_cb.points);
3431 free(primary->polyline.points);
3432 free(primary->polygon_sc.points);
3433 free(primary->fast_glyph.glyphData.aj);
3434 free(primary);
3435 }
3436
3437 free(update->secondary);
3438 free(altsec);
3439
3440 if (update->window)
3441 free(update->window);
3442
3443 MessageQueue_Free(up->queue);
3444 DeleteCriticalSection(&up->mux);
3445
3446 if (up->us)
3447 Stream_Free(up->us, TRUE);
3448 free(update);
3449 }
3450}
3451
3452void rdp_update_lock(rdpUpdate* update)
3453{
3454 rdp_update_internal* up = update_cast(update);
3455 EnterCriticalSection(&up->mux);
3456}
3457
3458void rdp_update_unlock(rdpUpdate* update)
3459{
3460 rdp_update_internal* up = update_cast(update);
3461 LeaveCriticalSection(&up->mux);
3462}
3463
3464BOOL update_begin_paint(rdpUpdate* update)
3465{
3466 rdp_update_internal* up = update_cast(update);
3467 WINPR_ASSERT(update);
3468 rdp_update_lock(update);
3469
3470 up->withinBeginEndPaint = TRUE;
3471
3472 WINPR_ASSERT(update->context);
3473
3474 BOOL rc = IFCALLRESULT(TRUE, update->BeginPaint, update->context);
3475 if (!rc)
3476 WLog_WARN(TAG, "BeginPaint call failed");
3477
3478 /* Reset the invalid regions, we start a new frame here. */
3479 rdpGdi* gdi = update->context->gdi;
3480 if (!gdi)
3481 return rc;
3482
3483 if (gdi->hdc && gdi->primary && gdi->primary->hdc)
3484 {
3485 HGDI_WND hwnd = gdi->primary->hdc->hwnd;
3486 WINPR_ASSERT(hwnd);
3487 WINPR_ASSERT(hwnd->invalid);
3488
3489 hwnd->invalid->null = TRUE;
3490 hwnd->ninvalid = 0;
3491 }
3492
3493 return rc;
3494}
3495
3496BOOL update_end_paint(rdpUpdate* update)
3497{
3498 BOOL rc = TRUE;
3499
3500 WINPR_ASSERT(update);
3501 IFCALLRET(update->EndPaint, rc, update->context);
3502 if (!rc)
3503 WLog_WARN(TAG, "EndPaint call failed");
3504
3505 rdp_update_internal* up = update_cast(update);
3506
3507 if (!up->withinBeginEndPaint)
3508 return rc;
3509 up->withinBeginEndPaint = FALSE;
3510
3511 rdp_update_unlock(update);
3512 return rc;
3513}
Definition types.h:82
This struct contains function pointer to initialize/free objects.
Definition collections.h:52