Coverage Report

Created: 2026-05-11 07:01

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