Coverage Report

Created: 2026-10-15 06:31

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