Coverage Report

Created: 2026-02-26 06:54

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