Coverage Report

Created: 2026-06-15 06:57

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