Coverage Report

Created: 2026-01-10 06:35

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