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