Coverage Report

Created: 2024-05-20 06:11

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