Coverage Report

Created: 2026-08-31 06:29

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