Coverage Report

Created: 2025-07-01 06:46

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