Coverage Report

Created: 2026-09-14 06:32

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