Coverage Report

Created: 2024-09-08 06:20

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