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