Coverage Report

Created: 2026-09-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/core/capabilities.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * RDP Capability Sets
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *   http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/wtsapi.h>
21
#include <winpr/assert.h>
22
#include <winpr/cast.h>
23
#include <freerdp/config.h>
24
25
#include "settings.h"
26
#include "capabilities.h"
27
#include "fastpath.h"
28
29
#include <winpr/crt.h>
30
#include <winpr/rpc.h>
31
32
#include <freerdp/log.h>
33
34
static const char* const CAPSET_TYPE_STRINGS[] = { "Unknown",
35
                                                 "General",
36
                                                 "Bitmap",
37
                                                 "Order",
38
                                                 "Bitmap Cache",
39
                                                 "Control",
40
                                                 "Unknown",
41
                                                 "Window Activation",
42
                                                 "Pointer",
43
                                                 "Share",
44
                                                 "Color Cache",
45
                                                 "Unknown",
46
                                                 "Sound",
47
                                                 "Input",
48
                                                 "Font",
49
                                                 "Brush",
50
                                                 "Glyph Cache",
51
                                                 "Offscreen Bitmap Cache",
52
                                                 "Bitmap Cache Host Support",
53
                                                 "Bitmap Cache v2",
54
                                                 "Virtual Channel",
55
                                                 "DrawNineGrid Cache",
56
                                                 "Draw GDI+ Cache",
57
                                                 "Remote Programs",
58
                                                 "Window List",
59
                                                 "Desktop Composition",
60
                                                 "Multifragment Update",
61
                                                 "Large Pointer",
62
                                                 "Surface Commands",
63
                                                 "Bitmap Codecs",
64
                                                 "Frame Acknowledge" };
65
66
static const char* get_capability_name(UINT16 type)
67
0
{
68
0
  if (type > CAPSET_TYPE_FRAME_ACKNOWLEDGE)
69
0
    return "<unknown>";
70
71
0
  return CAPSET_TYPE_STRINGS[type];
72
0
}
73
74
#ifdef WITH_DEBUG_CAPABILITIES
75
static BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving);
76
#endif
77
78
/* CODEC_GUID_REMOTEFX: 0x76772F12BD724463AFB3B73C9C6F7886 */
79
80
static const GUID CODEC_GUID_REMOTEFX = {
81
  0x76772F12, 0xBD72, 0x4463, { 0xAF, 0xB3, 0xB7, 0x3C, 0x9C, 0x6F, 0x78, 0x86 }
82
};
83
84
/* CODEC_GUID_NSCODEC 0xCA8D1BB9000F154F589FAE2D1A87E2D6 */
85
86
static const GUID CODEC_GUID_NSCODEC = {
87
  0xCA8D1BB9, 0x000F, 0x154F, { 0x58, 0x9F, 0xAE, 0x2D, 0x1A, 0x87, 0xE2, 0xD6 }
88
};
89
90
/* CODEC_GUID_IGNORE 0x9C4351A6353542AE910CCDFCE5760B58 */
91
92
static const GUID CODEC_GUID_IGNORE = {
93
  0x9C4351A6, 0x3535, 0x42AE, { 0x91, 0x0C, 0xCD, 0xFC, 0xE5, 0x76, 0x0B, 0x58 }
94
};
95
96
/* CODEC_GUID_IMAGE_REMOTEFX 0x2744CCD49D8A4E74803C0ECBEEA19C54 */
97
98
static const GUID CODEC_GUID_IMAGE_REMOTEFX = {
99
  0x2744CCD4, 0x9D8A, 0x4E74, { 0x80, 0x3C, 0x0E, 0xCB, 0xEE, 0xA1, 0x9C, 0x54 }
100
};
101
102
#if defined(WITH_JPEG)
103
/* CODEC_GUID_JPEG 0x430C9EED1BAF4CE6869ACB8B37B66237 */
104
105
static const GUID CODEC_GUID_JPEG = {
106
  0x430C9EED, 0x1BAF, 0x4CE6, { 0x86, 0x9A, 0xCB, 0x8B, 0x37, 0xB6, 0x62, 0x37 }
107
};
108
#endif
109
110
static BOOL rdp_read_capability_set_header(wLog* log, wStream* s, UINT16* length, UINT16* type)
111
0
{
112
0
  WINPR_ASSERT(s);
113
0
  WINPR_ASSERT(length);
114
0
  WINPR_ASSERT(type);
115
116
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
117
0
    return FALSE;
118
0
  Stream_Read_UINT16(s, *type);   /* capabilitySetType */
119
0
  Stream_Read_UINT16(s, *length); /* lengthCapability */
120
0
  return (*length >= 4);
121
0
}
122
123
static void rdp_write_capability_set_header(wStream* s, UINT16 length, UINT16 type)
124
0
{
125
0
  WINPR_ASSERT(s);
126
0
  WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 4);
127
0
  Stream_Write_UINT16(s, type);   /* capabilitySetType */
128
0
  Stream_Write_UINT16(s, length); /* lengthCapability */
129
0
}
130
131
static size_t rdp_capability_set_start(wLog* log, wStream* s)
132
0
{
133
0
  size_t header = Stream_GetPosition(s);
134
0
  if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), CAPSET_HEADER_LENGTH))
135
0
    return SIZE_MAX;
136
0
  Stream_Zero(s, CAPSET_HEADER_LENGTH);
137
0
  return header;
138
0
}
139
140
static BOOL rdp_capability_set_finish(wStream* s, size_t header, UINT16 type)
141
0
{
142
0
  const size_t footer = Stream_GetPosition(s);
143
0
  if (header > footer)
144
0
    return FALSE;
145
0
  if (header > UINT16_MAX)
146
0
    return FALSE;
147
0
  const size_t length = footer - header;
148
0
  if ((Stream_Capacity(s) < header + 4ULL) || (length > UINT16_MAX))
149
0
    return FALSE;
150
0
  if (!Stream_SetPosition(s, header))
151
0
    return FALSE;
152
0
  rdp_write_capability_set_header(s, (UINT16)length, type);
153
0
  return Stream_SetPosition(s, footer);
154
0
}
155
156
static BOOL rdp_apply_general_capability_set(rdpSettings* settings, const rdpSettings* src)
157
0
{
158
0
  WINPR_ASSERT(settings);
159
0
  WINPR_ASSERT(src);
160
161
0
  if (settings->ServerMode)
162
0
  {
163
0
    settings->OsMajorType = src->OsMajorType;
164
0
    settings->OsMinorType = src->OsMinorType;
165
0
  }
166
167
0
  settings->CapsProtocolVersion = src->CapsProtocolVersion;
168
0
  settings->NoBitmapCompressionHeader = src->NoBitmapCompressionHeader;
169
0
  settings->LongCredentialsSupported = src->LongCredentialsSupported;
170
0
  settings->AutoReconnectionPacketSupported = src->AutoReconnectionPacketSupported;
171
0
  if (!src->FastPathOutput)
172
0
    settings->FastPathOutput = FALSE;
173
174
0
  if (!src->SaltedChecksum)
175
0
    settings->SaltedChecksum = FALSE;
176
177
0
  if (!settings->ServerMode)
178
0
  {
179
    /*
180
     * Note: refreshRectSupport and suppressOutputSupport are
181
     * server-only flags indicating to the client weather the
182
     * respective PDUs are supported. See MS-RDPBCGR 2.2.7.1.1
183
     */
184
0
    if (!src->RefreshRect)
185
0
      settings->RefreshRect = FALSE;
186
187
0
    if (!src->SuppressOutput)
188
0
      settings->SuppressOutput = FALSE;
189
0
  }
190
0
  return TRUE;
191
0
}
192
193
/*
194
 * Read general capability set.
195
 * msdn{cc240549}
196
 */
197
198
static BOOL rdp_read_general_capability_set(wLog* log, wStream* s, rdpSettings* settings)
199
0
{
200
0
  UINT16 extraFlags = 0;
201
0
  BYTE refreshRectSupport = 0;
202
0
  BYTE suppressOutputSupport = 0;
203
204
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
205
0
    return FALSE;
206
207
0
  WINPR_ASSERT(settings);
208
0
  Stream_Read_UINT16(s, settings->OsMajorType); /* osMajorType (2 bytes) */
209
0
  Stream_Read_UINT16(s, settings->OsMinorType); /* osMinorType (2 bytes) */
210
211
0
  Stream_Read_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
212
0
  if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
213
0
  {
214
0
    WLog_Print(log, WLOG_ERROR,
215
0
               "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
216
0
               ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
217
0
               settings->CapsProtocolVersion,
218
0
               WINPR_CXX_COMPAT_CAST(UINT32, TS_CAPS_PROTOCOLVERSION));
219
0
    if (settings->CapsProtocolVersion == 0x0000)
220
0
    {
221
0
      WLog_Print(log, WLOG_WARN,
222
0
                 "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
223
0
                 " assuming old FreeRDP, ignoring protocol violation, correcting value.",
224
0
                 settings->CapsProtocolVersion);
225
0
      settings->CapsProtocolVersion = TS_CAPS_PROTOCOLVERSION;
226
0
    }
227
0
    else
228
0
      return FALSE;
229
0
  }
230
0
  Stream_Seek_UINT16(s);                                /* pad2OctetsA (2 bytes) */
231
0
  Stream_Read_UINT16(
232
0
      s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
233
0
  Stream_Read_UINT16(s, extraFlags);             /* extraFlags (2 bytes) */
234
0
  Stream_Read_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
235
0
  Stream_Read_UINT16(s, settings->CapsRemoteUnshareFlag);    /* remoteUnshareFlag (2 bytes) */
236
0
  Stream_Read_UINT16(
237
0
      s, settings->CapsGeneralCompressionLevel); /* generalCompressionLevel (2 bytes) */
238
0
  Stream_Read_UINT8(s, refreshRectSupport);      /* refreshRectSupport (1 byte) */
239
0
  Stream_Read_UINT8(s, suppressOutputSupport);   /* suppressOutputSupport (1 byte) */
240
0
  settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) != 0;
241
0
  settings->LongCredentialsSupported = (extraFlags & LONG_CREDENTIALS_SUPPORTED) != 0;
242
243
0
  settings->AutoReconnectionPacketSupported = (extraFlags & AUTORECONNECT_SUPPORTED) != 0;
244
0
  settings->FastPathOutput = (extraFlags & FASTPATH_OUTPUT_SUPPORTED) != 0;
245
0
  settings->SaltedChecksum = (extraFlags & ENC_SALTED_CHECKSUM) != 0;
246
0
  settings->RefreshRect = refreshRectSupport;
247
0
  settings->SuppressOutput = suppressOutputSupport;
248
249
0
  return TRUE;
250
0
}
251
252
/*
253
 * Write general capability set.
254
 * msdn{cc240549}
255
 */
256
257
static BOOL rdp_write_general_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
258
0
{
259
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
260
0
    return FALSE;
261
262
0
  const size_t header = rdp_capability_set_start(log, s);
263
0
  UINT16 extraFlags = 0;
264
265
0
  WINPR_ASSERT(settings);
266
0
  if (settings->LongCredentialsSupported)
267
0
    extraFlags |= LONG_CREDENTIALS_SUPPORTED;
268
269
0
  if (settings->NoBitmapCompressionHeader)
270
0
    extraFlags |= NO_BITMAP_COMPRESSION_HDR;
271
272
0
  if (settings->AutoReconnectionPacketSupported)
273
0
    extraFlags |= AUTORECONNECT_SUPPORTED;
274
275
0
  if (settings->FastPathOutput)
276
0
    extraFlags |= FASTPATH_OUTPUT_SUPPORTED;
277
278
0
  if (settings->SaltedChecksum)
279
0
    extraFlags |= ENC_SALTED_CHECKSUM;
280
281
0
  if ((settings->OsMajorType > UINT16_MAX) || (settings->OsMinorType > UINT16_MAX))
282
0
  {
283
0
    WLog_Print(log, WLOG_ERROR,
284
0
               "OsMajorType=%08" PRIx32 ", OsMinorType=%08" PRIx32
285
0
               " they need to be smaller %04" PRIx32,
286
0
               settings->OsMajorType, settings->OsMinorType,
287
0
               WINPR_CXX_COMPAT_CAST(UINT32, UINT16_MAX));
288
0
    return FALSE;
289
0
  }
290
0
  if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
291
0
  {
292
0
    WLog_Print(log, WLOG_ERROR,
293
0
               "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
294
0
               ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
295
0
               settings->CapsProtocolVersion,
296
0
               WINPR_CXX_COMPAT_CAST(UINT32, TS_CAPS_PROTOCOLVERSION));
297
0
    return FALSE;
298
0
  }
299
0
  Stream_Write_UINT16(s, (UINT16)settings->OsMajorType); /* osMajorType (2 bytes) */
300
0
  Stream_Write_UINT16(s, (UINT16)settings->OsMinorType); /* osMinorType (2 bytes) */
301
0
  Stream_Write_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
302
0
  Stream_Write_UINT16(s, 0);                             /* pad2OctetsA (2 bytes) */
303
0
  Stream_Write_UINT16(
304
0
      s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
305
0
  Stream_Write_UINT16(s, extraFlags);            /* extraFlags (2 bytes) */
306
0
  Stream_Write_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
307
0
  Stream_Write_UINT16(s, settings->CapsRemoteUnshareFlag);    /* remoteUnshareFlag (2 bytes) */
308
0
  Stream_Write_UINT16(
309
0
      s, settings->CapsGeneralCompressionLevel);           /* generalCompressionLevel (2 bytes) */
310
0
  Stream_Write_UINT8(s, settings->RefreshRect ? 1 : 0);    /* refreshRectSupport (1 byte) */
311
0
  Stream_Write_UINT8(s, settings->SuppressOutput ? 1 : 0); /* suppressOutputSupport (1 byte) */
312
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_GENERAL);
313
0
}
314
315
#ifdef WITH_DEBUG_CAPABILITIES
316
static BOOL rdp_print_general_capability_set(wLog* log, wStream* s)
317
{
318
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
319
    return FALSE;
320
321
  WLog_Print(log, WLOG_TRACE,
322
             "GeneralCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
323
  const uint16_t osMinorType = Stream_Get_UINT16(s);     /* osMajorType (2 bytes) */
324
  const uint16_t osMajorType = Stream_Get_UINT16(s);     /* osMinorType (2 bytes) */
325
  const uint16_t protocolVersion = Stream_Get_UINT16(s); /* protocolVersion (2 bytes) */
326
  const uint16_t pad2OctetsA = Stream_Get_UINT16(s);     /* pad2OctetsA (2 bytes) */
327
  const uint16_t generalCompressionTypes =
328
      Stream_Get_UINT16(s);                         /* generalCompressionTypes (2 bytes) */
329
  const uint16_t extraFlags = Stream_Get_UINT16(s); /* extraFlags (2 bytes) */
330
  const uint16_t updateCapabilityFlag = Stream_Get_UINT16(s); /* updateCapabilityFlag (2 bytes) */
331
  const uint16_t remoteUnshareFlag = Stream_Get_UINT16(s);    /* remoteUnshareFlag (2 bytes) */
332
  const uint16_t generalCompressionLevel =
333
      Stream_Get_UINT16(s);                               /* generalCompressionLevel (2 bytes) */
334
  const uint8_t refreshRectSupport = Stream_Get_UINT8(s); /* refreshRectSupport (1 byte) */
335
  const uint8_t suppressOutputSupport = Stream_Get_UINT8(s); /* suppressOutputSupport (1 byte) */
336
  WLog_Print(log, WLOG_TRACE, "\tosMajorType: 0x%04" PRIX16 "", osMajorType);
337
  WLog_Print(log, WLOG_TRACE, "\tosMinorType: 0x%04" PRIX16 "", osMinorType);
338
  WLog_Print(log, WLOG_TRACE, "\tprotocolVersion: 0x%04" PRIX16 "", protocolVersion);
339
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
340
  WLog_Print(log, WLOG_TRACE, "\tgeneralCompressionTypes: 0x%04" PRIX16 "",
341
             generalCompressionTypes);
342
  WLog_Print(log, WLOG_TRACE, "\textraFlags: 0x%04" PRIX16 "", extraFlags);
343
  WLog_Print(log, WLOG_TRACE, "\tupdateCapabilityFlag: 0x%04" PRIX16 "", updateCapabilityFlag);
344
  WLog_Print(log, WLOG_TRACE, "\tremoteUnshareFlag: 0x%04" PRIX16 "", remoteUnshareFlag);
345
  WLog_Print(log, WLOG_TRACE, "\tgeneralCompressionLevel: 0x%04" PRIX16 "",
346
             generalCompressionLevel);
347
  WLog_Print(log, WLOG_TRACE, "\trefreshRectSupport: 0x%02" PRIX8 "", refreshRectSupport);
348
  WLog_Print(log, WLOG_TRACE, "\tsuppressOutputSupport: 0x%02" PRIX8 "", suppressOutputSupport);
349
  return TRUE;
350
}
351
#endif
352
static BOOL rdp_apply_bitmap_capability_set(rdpSettings* settings, const rdpSettings* src)
353
0
{
354
0
  WINPR_ASSERT(settings);
355
0
  WINPR_ASSERT(src);
356
357
0
  if (!settings->ServerMode)
358
0
  {
359
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
360
0
                                     freerdp_settings_get_uint32(src, FreeRDP_ColorDepth)))
361
0
      return FALSE;
362
0
  }
363
364
0
  if (!src->DesktopResize)
365
0
    settings->DesktopResize = FALSE;
366
367
0
  if (!settings->ServerMode && settings->DesktopResize)
368
0
  {
369
    /* The server may request a different desktop size during Deactivation-Reactivation sequence
370
     */
371
0
    settings->DesktopWidth = src->DesktopWidth;
372
0
    settings->DesktopHeight = src->DesktopHeight;
373
0
  }
374
375
0
  if (settings->DrawAllowSkipAlpha)
376
0
    settings->DrawAllowSkipAlpha = src->DrawAllowSkipAlpha;
377
378
0
  if (settings->DrawAllowDynamicColorFidelity)
379
0
    settings->DrawAllowDynamicColorFidelity = src->DrawAllowDynamicColorFidelity;
380
381
0
  if (settings->DrawAllowColorSubsampling)
382
0
    settings->DrawAllowColorSubsampling = src->DrawAllowColorSubsampling;
383
384
0
  return TRUE;
385
0
}
386
387
/*
388
 * Read bitmap capability set.
389
 * msdn{cc240554}
390
 */
391
392
static BOOL rdp_read_bitmap_capability_set(wLog* log, wStream* s, rdpSettings* settings)
393
0
{
394
0
  BYTE drawingFlags = 0;
395
0
  UINT16 desktopWidth = 0;
396
0
  UINT16 desktopHeight = 0;
397
0
  UINT16 desktopResizeFlag = 0;
398
0
  UINT16 preferredBitsPerPixel = 0;
399
400
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 24))
401
0
    return FALSE;
402
403
0
  Stream_Read_UINT16(s, preferredBitsPerPixel); /* preferredBitsPerPixel (2 bytes) */
404
0
  Stream_Seek_UINT16(s);                        /* receive1BitPerPixel (2 bytes) */
405
0
  Stream_Seek_UINT16(s);                        /* receive4BitsPerPixel (2 bytes) */
406
0
  Stream_Seek_UINT16(s);                        /* receive8BitsPerPixel (2 bytes) */
407
0
  Stream_Read_UINT16(s, desktopWidth);          /* desktopWidth (2 bytes) */
408
0
  Stream_Read_UINT16(s, desktopHeight);         /* desktopHeight (2 bytes) */
409
0
  Stream_Seek_UINT16(s);                        /* pad2Octets (2 bytes) */
410
0
  Stream_Read_UINT16(s, desktopResizeFlag);     /* desktopResizeFlag (2 bytes) */
411
0
  Stream_Seek_UINT16(s);                        /* bitmapCompressionFlag (2 bytes) */
412
0
  Stream_Seek_UINT8(s);                         /* highColorFlags (1 byte) */
413
0
  Stream_Read_UINT8(s, drawingFlags);           /* drawingFlags (1 byte) */
414
0
  Stream_Seek_UINT16(s);                        /* multipleRectangleSupport (2 bytes) */
415
0
  Stream_Seek_UINT16(s);                        /* pad2OctetsB (2 bytes) */
416
417
0
  if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, preferredBitsPerPixel))
418
0
    return FALSE;
419
0
  settings->DesktopResize = desktopResizeFlag;
420
0
  settings->DesktopWidth = desktopWidth;
421
0
  settings->DesktopHeight = desktopHeight;
422
0
  settings->DrawAllowSkipAlpha = (drawingFlags & DRAW_ALLOW_SKIP_ALPHA) != 0;
423
0
  settings->DrawAllowDynamicColorFidelity =
424
0
      (drawingFlags & DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY) != 0;
425
0
  settings->DrawAllowColorSubsampling = (drawingFlags & DRAW_ALLOW_COLOR_SUBSAMPLING) != 0;
426
427
0
  return TRUE;
428
0
}
429
430
/*
431
 * Write bitmap capability set.
432
 * msdn{cc240554}
433
 */
434
435
static BOOL rdp_write_bitmap_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
436
0
{
437
0
  BYTE drawingFlags = 0;
438
0
  UINT16 preferredBitsPerPixel = 0;
439
440
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
441
0
    return FALSE;
442
443
0
  const size_t header = rdp_capability_set_start(log, s);
444
445
0
  WINPR_ASSERT(settings);
446
0
  if (settings->DrawAllowSkipAlpha)
447
0
    drawingFlags |= DRAW_ALLOW_SKIP_ALPHA;
448
449
0
  if (settings->DrawAllowDynamicColorFidelity)
450
0
    drawingFlags |= DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY;
451
452
0
  if (settings->DrawAllowColorSubsampling)
453
0
    drawingFlags |= DRAW_ALLOW_COLOR_SUBSAMPLING; /* currently unimplemented */
454
455
  /* While bitmap_decode.c now implements YCoCg, in turning it
456
   * on we have found Microsoft is inconsistent on whether to invert R & B.
457
   * And it's not only from one server to another; on Win7/2008R2, it appears
458
   * to send the main content with a different inversion than the Windows
459
   * button!  So... don't advertise that we support YCoCg and the server
460
   * will not send it.  YCoCg is still needed for EGFX, but it at least
461
   * appears consistent in its use.
462
   */
463
464
0
  if ((freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) > UINT16_MAX) ||
465
0
      (settings->DesktopWidth > UINT16_MAX) || (settings->DesktopHeight > UINT16_MAX))
466
0
    return FALSE;
467
468
0
  if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
469
0
    preferredBitsPerPixel = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
470
0
  else
471
0
    preferredBitsPerPixel = 8;
472
473
0
  Stream_Write_UINT16(s, preferredBitsPerPixel);           /* preferredBitsPerPixel (2 bytes) */
474
0
  Stream_Write_UINT16(s, 1);                               /* receive1BitPerPixel (2 bytes) */
475
0
  Stream_Write_UINT16(s, 1);                               /* receive4BitsPerPixel (2 bytes) */
476
0
  Stream_Write_UINT16(s, 1);                               /* receive8BitsPerPixel (2 bytes) */
477
0
  Stream_Write_UINT16(s, (UINT16)settings->DesktopWidth);  /* desktopWidth (2 bytes) */
478
0
  Stream_Write_UINT16(s, (UINT16)settings->DesktopHeight); /* desktopHeight (2 bytes) */
479
0
  Stream_Write_UINT16(s, 0);                               /* pad2Octets (2 bytes) */
480
0
  Stream_Write_UINT16(s, (UINT16)settings->DesktopResize); /* desktopResizeFlag (2 bytes) */
481
0
  Stream_Write_UINT16(s, 1);                               /* bitmapCompressionFlag (2 bytes) */
482
0
  Stream_Write_UINT8(s, 0);                                /* highColorFlags (1 byte) */
483
0
  Stream_Write_UINT8(s, drawingFlags);                     /* drawingFlags (1 byte) */
484
0
  Stream_Write_UINT16(s, 1); /* multipleRectangleSupport (2 bytes) */
485
0
  Stream_Write_UINT16(s, 0); /* pad2OctetsB (2 bytes) */
486
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP);
487
0
}
488
489
#ifdef WITH_DEBUG_CAPABILITIES
490
static BOOL rdp_print_bitmap_capability_set(wLog* log, wStream* s)
491
{
492
  UINT16 preferredBitsPerPixel = 0;
493
  UINT16 receive1BitPerPixel = 0;
494
  UINT16 receive4BitsPerPixel = 0;
495
  UINT16 receive8BitsPerPixel = 0;
496
  UINT16 desktopWidth = 0;
497
  UINT16 desktopHeight = 0;
498
  UINT16 pad2Octets = 0;
499
  UINT16 desktopResizeFlag = 0;
500
  UINT16 bitmapCompressionFlag = 0;
501
  BYTE highColorFlags = 0;
502
  BYTE drawingFlags = 0;
503
  UINT16 multipleRectangleSupport = 0;
504
  UINT16 pad2OctetsB = 0;
505
  WLog_Print(log, WLOG_TRACE,
506
             "BitmapCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
507
508
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 24))
509
    return FALSE;
510
511
  Stream_Read_UINT16(s, preferredBitsPerPixel);    /* preferredBitsPerPixel (2 bytes) */
512
  Stream_Read_UINT16(s, receive1BitPerPixel);      /* receive1BitPerPixel (2 bytes) */
513
  Stream_Read_UINT16(s, receive4BitsPerPixel);     /* receive4BitsPerPixel (2 bytes) */
514
  Stream_Read_UINT16(s, receive8BitsPerPixel);     /* receive8BitsPerPixel (2 bytes) */
515
  Stream_Read_UINT16(s, desktopWidth);             /* desktopWidth (2 bytes) */
516
  Stream_Read_UINT16(s, desktopHeight);            /* desktopHeight (2 bytes) */
517
  Stream_Read_UINT16(s, pad2Octets);               /* pad2Octets (2 bytes) */
518
  Stream_Read_UINT16(s, desktopResizeFlag);        /* desktopResizeFlag (2 bytes) */
519
  Stream_Read_UINT16(s, bitmapCompressionFlag);    /* bitmapCompressionFlag (2 bytes) */
520
  Stream_Read_UINT8(s, highColorFlags);            /* highColorFlags (1 byte) */
521
  Stream_Read_UINT8(s, drawingFlags);              /* drawingFlags (1 byte) */
522
  Stream_Read_UINT16(s, multipleRectangleSupport); /* multipleRectangleSupport (2 bytes) */
523
  Stream_Read_UINT16(s, pad2OctetsB);              /* pad2OctetsB (2 bytes) */
524
  WLog_Print(log, WLOG_TRACE, "\tpreferredBitsPerPixel: 0x%04" PRIX16 "", preferredBitsPerPixel);
525
  WLog_Print(log, WLOG_TRACE, "\treceive1BitPerPixel: 0x%04" PRIX16 "", receive1BitPerPixel);
526
  WLog_Print(log, WLOG_TRACE, "\treceive4BitsPerPixel: 0x%04" PRIX16 "", receive4BitsPerPixel);
527
  WLog_Print(log, WLOG_TRACE, "\treceive8BitsPerPixel: 0x%04" PRIX16 "", receive8BitsPerPixel);
528
  WLog_Print(log, WLOG_TRACE, "\tdesktopWidth: 0x%04" PRIX16 "", desktopWidth);
529
  WLog_Print(log, WLOG_TRACE, "\tdesktopHeight: 0x%04" PRIX16 "", desktopHeight);
530
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
531
  WLog_Print(log, WLOG_TRACE, "\tdesktopResizeFlag: 0x%04" PRIX16 "", desktopResizeFlag);
532
  WLog_Print(log, WLOG_TRACE, "\tbitmapCompressionFlag: 0x%04" PRIX16 "", bitmapCompressionFlag);
533
  WLog_Print(log, WLOG_TRACE, "\thighColorFlags: 0x%02" PRIX8 "", highColorFlags);
534
  WLog_Print(log, WLOG_TRACE, "\tdrawingFlags: 0x%02" PRIX8 "", drawingFlags);
535
  WLog_Print(log, WLOG_TRACE, "\tmultipleRectangleSupport: 0x%04" PRIX16 "",
536
             multipleRectangleSupport);
537
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsB: 0x%04" PRIX16 "", pad2OctetsB);
538
  return TRUE;
539
}
540
#endif
541
static BOOL rdp_apply_order_capability_set(rdpSettings* settings, const rdpSettings* src)
542
0
{
543
0
  WINPR_ASSERT(settings);
544
0
  WINPR_ASSERT(src);
545
546
0
  BOOL BitmapCacheV3Enabled = FALSE;
547
0
  BOOL FrameMarkerCommandEnabled = FALSE;
548
549
0
  for (size_t i = 0; i < 32; i++)
550
0
  {
551
0
    if (!src->OrderSupport[i])
552
0
      settings->OrderSupport[i] = FALSE;
553
0
  }
554
555
0
  if (src->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
556
0
  {
557
0
    if (src->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT)
558
0
      BitmapCacheV3Enabled = TRUE;
559
560
0
    if (src->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT)
561
0
      FrameMarkerCommandEnabled = TRUE;
562
0
  }
563
564
0
  if (BitmapCacheV3Enabled && settings->BitmapCacheV3Enabled)
565
0
  {
566
0
    settings->BitmapCacheV3Enabled = src->BitmapCacheV3Enabled;
567
0
    settings->BitmapCacheVersion = src->BitmapCacheVersion;
568
0
  }
569
0
  else
570
0
    settings->BitmapCacheV3Enabled = FALSE;
571
572
0
  settings->FrameMarkerCommandEnabled =
573
0
      (FrameMarkerCommandEnabled && src->FrameMarkerCommandEnabled);
574
575
0
  return TRUE;
576
0
}
577
578
/*
579
 * Read order capability set.
580
 * msdn{cc240556}
581
 */
582
583
static BOOL rdp_read_order_capability_set(wLog* log, wStream* s, rdpSettings* settings)
584
0
{
585
0
  char terminalDescriptor[17] = WINPR_C_ARRAY_INIT;
586
0
  BYTE orderSupport[32] = WINPR_C_ARRAY_INIT;
587
0
  BOOL BitmapCacheV3Enabled = FALSE;
588
0
  BOOL FrameMarkerCommandEnabled = FALSE;
589
590
0
  WINPR_ASSERT(settings);
591
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
592
0
    return FALSE;
593
594
0
  Stream_Read(s, terminalDescriptor, 16);               /* terminalDescriptor (16 bytes) */
595
0
  Stream_Seek_UINT32(s);                                /* pad4OctetsA (4 bytes) */
596
0
  Stream_Seek_UINT16(s);                                /* desktopSaveXGranularity (2 bytes) */
597
0
  Stream_Seek_UINT16(s);                                /* desktopSaveYGranularity (2 bytes) */
598
0
  Stream_Seek_UINT16(s);                                /* pad2OctetsA (2 bytes) */
599
0
  Stream_Seek_UINT16(s);                                /* maximumOrderLevel (2 bytes) */
600
0
  Stream_Seek_UINT16(s);                                /* numberFonts (2 bytes) */
601
0
  Stream_Read_UINT16(s, settings->OrderSupportFlags);   /* orderFlags (2 bytes) */
602
0
  Stream_Read(s, orderSupport, 32);                     /* orderSupport (32 bytes) */
603
0
  Stream_Seek_UINT16(s);                                /* textFlags (2 bytes) */
604
0
  Stream_Read_UINT16(s, settings->OrderSupportFlagsEx); /* orderSupportExFlags (2 bytes) */
605
0
  Stream_Seek_UINT32(s);                                /* pad4OctetsB (4 bytes) */
606
0
  Stream_Seek_UINT32(s);                                /* desktopSaveSize (4 bytes) */
607
0
  Stream_Seek_UINT16(s);                                /* pad2OctetsC (2 bytes) */
608
0
  Stream_Seek_UINT16(s);                                /* pad2OctetsD (2 bytes) */
609
0
  Stream_Read_UINT16(s, settings->TextANSICodePage);    /* textANSICodePage (2 bytes) */
610
0
  Stream_Seek_UINT16(s);                                /* pad2OctetsE (2 bytes) */
611
612
0
  if (!freerdp_settings_set_string(settings, FreeRDP_TerminalDescriptor, terminalDescriptor))
613
0
    return FALSE;
614
615
0
  for (size_t i = 0; i < ARRAYSIZE(orderSupport); i++)
616
0
    settings->OrderSupport[i] = orderSupport[i];
617
618
0
  if (settings->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
619
0
  {
620
0
    BitmapCacheV3Enabled = (settings->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT) != 0;
621
0
    FrameMarkerCommandEnabled =
622
0
        (settings->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT) != 0;
623
0
  }
624
625
0
  settings->BitmapCacheV3Enabled = BitmapCacheV3Enabled;
626
0
  if (BitmapCacheV3Enabled)
627
0
    settings->BitmapCacheVersion = 3;
628
629
0
  settings->FrameMarkerCommandEnabled = FrameMarkerCommandEnabled;
630
631
0
  return TRUE;
632
0
}
633
634
/*
635
 * Write order capability set.
636
 * msdn{cc240556}
637
 */
638
639
static BOOL rdp_write_order_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
640
0
{
641
0
  char terminalDescriptor[16] = WINPR_C_ARRAY_INIT;
642
643
0
  WINPR_ASSERT(settings);
644
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
645
0
    return FALSE;
646
647
0
  const size_t header = rdp_capability_set_start(log, s);
648
649
0
  UINT16 orderSupportExFlags = settings->OrderSupportFlagsEx;
650
0
  UINT16 orderFlags = settings->OrderSupportFlags;
651
652
0
  if (settings->BitmapCacheV3Enabled)
653
0
  {
654
0
    if ((orderSupportExFlags & CACHE_BITMAP_V3_SUPPORT) == 0)
655
0
    {
656
0
      WLog_Print(log, WLOG_WARN,
657
0
                 "rdpSettings::BitmapCacheV3Enabled=TRUE, but CACHE_BITMAP_V3_SUPPORT not "
658
0
                 "set in rdpSettings::OrderSupportEx, aborting.");
659
0
    }
660
0
    if ((orderFlags & ORDER_FLAGS_EXTRA_SUPPORT) == 0)
661
0
    {
662
0
      WLog_Print(log, WLOG_WARN,
663
0
                 "rdpSettings::BitmapCacheV3Enabled=TRUE, but ORDER_FLAGS_EXTRA_SUPPORT not "
664
0
                 "set in rdpSettings::OrderSupport, aborting.");
665
0
    }
666
0
  }
667
668
0
  if (settings->FrameMarkerCommandEnabled)
669
0
  {
670
0
    if ((orderSupportExFlags & ALTSEC_FRAME_MARKER_SUPPORT) == 0)
671
0
    {
672
0
      WLog_Print(
673
0
          log, WLOG_WARN,
674
0
          "rdpSettings::FrameMarkerCommandEnabled=TRUE, but "
675
0
          "ALTSEC_FRAME_MARKER_SUPPORT not set in rdpSettings::OrderSupportEx, aborting.");
676
0
    }
677
0
    if ((orderFlags & ORDER_FLAGS_EXTRA_SUPPORT) == 0)
678
0
    {
679
0
      WLog_Print(log, WLOG_WARN,
680
0
                 "rdpSettings::FrameMarkerCommandEnabled=TRUE, but ORDER_FLAGS_EXTRA_SUPPORT "
681
0
                 "not set in rdpSettings::OrderSupport, aborting.");
682
0
    }
683
0
  }
684
685
0
  const char* dsc = freerdp_settings_get_string(settings, FreeRDP_TerminalDescriptor);
686
0
  if (dsc)
687
0
  {
688
0
    const size_t len = strnlen(dsc, ARRAYSIZE(terminalDescriptor));
689
0
    strncpy(terminalDescriptor, dsc, len);
690
0
  }
691
0
  Stream_Write(s, terminalDescriptor,
692
0
               sizeof(terminalDescriptor));           /* terminalDescriptor (16 bytes) */
693
0
  Stream_Write_UINT32(s, 0);                          /* pad4OctetsA (4 bytes) */
694
0
  Stream_Write_UINT16(s, 1);                          /* desktopSaveXGranularity (2 bytes) */
695
0
  Stream_Write_UINT16(s, 20);                         /* desktopSaveYGranularity (2 bytes) */
696
0
  Stream_Write_UINT16(s, 0);                          /* pad2OctetsA (2 bytes) */
697
0
  Stream_Write_UINT16(s, 1);                          /* maximumOrderLevel (2 bytes) */
698
0
  Stream_Write_UINT16(s, 0);                          /* numberFonts (2 bytes) */
699
0
  Stream_Write_UINT16(s, orderFlags);                 /* orderFlags (2 bytes) */
700
0
  Stream_Write(s, settings->OrderSupport, 32);        /* orderSupport (32 bytes) */
701
0
  Stream_Write_UINT16(s, 0);                          /* textFlags (2 bytes) */
702
0
  Stream_Write_UINT16(s, orderSupportExFlags);        /* orderSupportExFlags (2 bytes) */
703
0
  Stream_Write_UINT32(s, 0);                          /* pad4OctetsB (4 bytes) */
704
0
  Stream_Write_UINT32(s, 230400);                     /* desktopSaveSize (4 bytes) */
705
0
  Stream_Write_UINT16(s, 0);                          /* pad2OctetsC (2 bytes) */
706
0
  Stream_Write_UINT16(s, 0);                          /* pad2OctetsD (2 bytes) */
707
0
  Stream_Write_UINT16(s, settings->TextANSICodePage); /* textANSICodePage (2 bytes) */
708
0
  Stream_Write_UINT16(s, 0);                          /* pad2OctetsE (2 bytes) */
709
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_ORDER);
710
0
}
711
712
#ifdef WITH_DEBUG_CAPABILITIES
713
static BOOL rdp_print_order_capability_set(wLog* log, wStream* s)
714
{
715
  BYTE terminalDescriptor[16];
716
  UINT32 pad4OctetsA = 0;
717
  UINT16 desktopSaveXGranularity = 0;
718
  UINT16 desktopSaveYGranularity = 0;
719
  UINT16 pad2OctetsA = 0;
720
  UINT16 maximumOrderLevel = 0;
721
  UINT16 numberFonts = 0;
722
  UINT16 orderFlags = 0;
723
  BYTE orderSupport[32];
724
  UINT16 textFlags = 0;
725
  UINT16 orderSupportExFlags = 0;
726
  UINT32 pad4OctetsB = 0;
727
  UINT32 desktopSaveSize = 0;
728
  UINT16 pad2OctetsC = 0;
729
  UINT16 pad2OctetsD = 0;
730
  UINT16 textANSICodePage = 0;
731
  UINT16 pad2OctetsE = 0;
732
  WLog_Print(log, WLOG_TRACE,
733
             "OrderCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
734
735
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
736
    return FALSE;
737
738
  Stream_Read(s, terminalDescriptor, 16);         /* terminalDescriptor (16 bytes) */
739
  Stream_Read_UINT32(s, pad4OctetsA);             /* pad4OctetsA (4 bytes) */
740
  Stream_Read_UINT16(s, desktopSaveXGranularity); /* desktopSaveXGranularity (2 bytes) */
741
  Stream_Read_UINT16(s, desktopSaveYGranularity); /* desktopSaveYGranularity (2 bytes) */
742
  Stream_Read_UINT16(s, pad2OctetsA);             /* pad2OctetsA (2 bytes) */
743
  Stream_Read_UINT16(s, maximumOrderLevel);       /* maximumOrderLevel (2 bytes) */
744
  Stream_Read_UINT16(s, numberFonts);             /* numberFonts (2 bytes) */
745
  Stream_Read_UINT16(s, orderFlags);              /* orderFlags (2 bytes) */
746
  Stream_Read(s, orderSupport, 32);               /* orderSupport (32 bytes) */
747
  Stream_Read_UINT16(s, textFlags);               /* textFlags (2 bytes) */
748
  Stream_Read_UINT16(s, orderSupportExFlags);     /* orderSupportExFlags (2 bytes) */
749
  Stream_Read_UINT32(s, pad4OctetsB);             /* pad4OctetsB (4 bytes) */
750
  Stream_Read_UINT32(s, desktopSaveSize);         /* desktopSaveSize (4 bytes) */
751
  Stream_Read_UINT16(s, pad2OctetsC);             /* pad2OctetsC (2 bytes) */
752
  Stream_Read_UINT16(s, pad2OctetsD);             /* pad2OctetsD (2 bytes) */
753
  Stream_Read_UINT16(s, textANSICodePage);        /* textANSICodePage (2 bytes) */
754
  Stream_Read_UINT16(s, pad2OctetsE);             /* pad2OctetsE (2 bytes) */
755
  WLog_Print(log, WLOG_TRACE, "\tpad4OctetsA: 0x%08" PRIX32 "", pad4OctetsA);
756
  WLog_Print(log, WLOG_TRACE, "\tdesktopSaveXGranularity: 0x%04" PRIX16 "",
757
             desktopSaveXGranularity);
758
  WLog_Print(log, WLOG_TRACE, "\tdesktopSaveYGranularity: 0x%04" PRIX16 "",
759
             desktopSaveYGranularity);
760
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
761
  WLog_Print(log, WLOG_TRACE, "\tmaximumOrderLevel: 0x%04" PRIX16 "", maximumOrderLevel);
762
  WLog_Print(log, WLOG_TRACE, "\tnumberFonts: 0x%04" PRIX16 "", numberFonts);
763
  WLog_Print(log, WLOG_TRACE, "\torderFlags: 0x%04" PRIX16 "", orderFlags);
764
  WLog_Print(log, WLOG_TRACE, "\torderSupport:");
765
  WLog_Print(log, WLOG_TRACE, "\t\tDSTBLT: %" PRIu8 "", orderSupport[NEG_DSTBLT_INDEX]);
766
  WLog_Print(log, WLOG_TRACE, "\t\tPATBLT: %" PRIu8 "", orderSupport[NEG_PATBLT_INDEX]);
767
  WLog_Print(log, WLOG_TRACE, "\t\tSCRBLT: %" PRIu8 "", orderSupport[NEG_SCRBLT_INDEX]);
768
  WLog_Print(log, WLOG_TRACE, "\t\tMEMBLT: %" PRIu8 "", orderSupport[NEG_MEMBLT_INDEX]);
769
  WLog_Print(log, WLOG_TRACE, "\t\tMEM3BLT: %" PRIu8 "", orderSupport[NEG_MEM3BLT_INDEX]);
770
  WLog_Print(log, WLOG_TRACE, "\t\tATEXTOUT: %" PRIu8 "", orderSupport[NEG_ATEXTOUT_INDEX]);
771
  WLog_Print(log, WLOG_TRACE, "\t\tAEXTTEXTOUT: %" PRIu8 "", orderSupport[NEG_AEXTTEXTOUT_INDEX]);
772
  WLog_Print(log, WLOG_TRACE, "\t\tDRAWNINEGRID: %" PRIu8 "",
773
             orderSupport[NEG_DRAWNINEGRID_INDEX]);
774
  WLog_Print(log, WLOG_TRACE, "\t\tLINETO: %" PRIu8 "", orderSupport[NEG_LINETO_INDEX]);
775
  WLog_Print(log, WLOG_TRACE, "\t\tMULTI_DRAWNINEGRID: %" PRIu8 "",
776
             orderSupport[NEG_MULTI_DRAWNINEGRID_INDEX]);
777
  WLog_Print(log, WLOG_TRACE, "\t\tOPAQUE_RECT: %" PRIu8 "", orderSupport[NEG_OPAQUE_RECT_INDEX]);
778
  WLog_Print(log, WLOG_TRACE, "\t\tSAVEBITMAP: %" PRIu8 "", orderSupport[NEG_SAVEBITMAP_INDEX]);
779
  WLog_Print(log, WLOG_TRACE, "\t\tWTEXTOUT: %" PRIu8 "", orderSupport[NEG_WTEXTOUT_INDEX]);
780
  WLog_Print(log, WLOG_TRACE, "\t\tMEMBLT_V2: %" PRIu8 "", orderSupport[NEG_MEMBLT_V2_INDEX]);
781
  WLog_Print(log, WLOG_TRACE, "\t\tMEM3BLT_V2: %" PRIu8 "", orderSupport[NEG_MEM3BLT_V2_INDEX]);
782
  WLog_Print(log, WLOG_TRACE, "\t\tMULTIDSTBLT: %" PRIu8 "", orderSupport[NEG_MULTIDSTBLT_INDEX]);
783
  WLog_Print(log, WLOG_TRACE, "\t\tMULTIPATBLT: %" PRIu8 "", orderSupport[NEG_MULTIPATBLT_INDEX]);
784
  WLog_Print(log, WLOG_TRACE, "\t\tMULTISCRBLT: %" PRIu8 "", orderSupport[NEG_MULTISCRBLT_INDEX]);
785
  WLog_Print(log, WLOG_TRACE, "\t\tMULTIOPAQUERECT: %" PRIu8 "",
786
             orderSupport[NEG_MULTIOPAQUERECT_INDEX]);
787
  WLog_Print(log, WLOG_TRACE, "\t\tFAST_INDEX: %" PRIu8 "", orderSupport[NEG_FAST_INDEX_INDEX]);
788
  WLog_Print(log, WLOG_TRACE, "\t\tPOLYGON_SC: %" PRIu8 "", orderSupport[NEG_POLYGON_SC_INDEX]);
789
  WLog_Print(log, WLOG_TRACE, "\t\tPOLYGON_CB: %" PRIu8 "", orderSupport[NEG_POLYGON_CB_INDEX]);
790
  WLog_Print(log, WLOG_TRACE, "\t\tPOLYLINE: %" PRIu8 "", orderSupport[NEG_POLYLINE_INDEX]);
791
  WLog_Print(log, WLOG_TRACE, "\t\tUNUSED23: %" PRIu8 "", orderSupport[NEG_UNUSED23_INDEX]);
792
  WLog_Print(log, WLOG_TRACE, "\t\tFAST_GLYPH: %" PRIu8 "", orderSupport[NEG_FAST_GLYPH_INDEX]);
793
  WLog_Print(log, WLOG_TRACE, "\t\tELLIPSE_SC: %" PRIu8 "", orderSupport[NEG_ELLIPSE_SC_INDEX]);
794
  WLog_Print(log, WLOG_TRACE, "\t\tELLIPSE_CB: %" PRIu8 "", orderSupport[NEG_ELLIPSE_CB_INDEX]);
795
  WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_INDEX: %" PRIu8 "", orderSupport[NEG_GLYPH_INDEX_INDEX]);
796
  WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_WEXTTEXTOUT: %" PRIu8 "",
797
             orderSupport[NEG_GLYPH_WEXTTEXTOUT_INDEX]);
798
  WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_WLONGTEXTOUT: %" PRIu8 "",
799
             orderSupport[NEG_GLYPH_WLONGTEXTOUT_INDEX]);
800
  WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_WLONGEXTTEXTOUT: %" PRIu8 "",
801
             orderSupport[NEG_GLYPH_WLONGEXTTEXTOUT_INDEX]);
802
  WLog_Print(log, WLOG_TRACE, "\t\tUNUSED31: %" PRIu8 "", orderSupport[NEG_UNUSED31_INDEX]);
803
  WLog_Print(log, WLOG_TRACE, "\ttextFlags: 0x%04" PRIX16 "", textFlags);
804
  WLog_Print(log, WLOG_TRACE, "\torderSupportExFlags: 0x%04" PRIX16 "", orderSupportExFlags);
805
  WLog_Print(log, WLOG_TRACE, "\tpad4OctetsB: 0x%08" PRIX32 "", pad4OctetsB);
806
  WLog_Print(log, WLOG_TRACE, "\tdesktopSaveSize: 0x%08" PRIX32 "", desktopSaveSize);
807
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsC: 0x%04" PRIX16 "", pad2OctetsC);
808
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsD: 0x%04" PRIX16 "", pad2OctetsD);
809
  WLog_Print(log, WLOG_TRACE, "\ttextANSICodePage: 0x%04" PRIX16 "", textANSICodePage);
810
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsE: 0x%04" PRIX16 "", pad2OctetsE);
811
  return TRUE;
812
}
813
#endif
814
815
static BOOL rdp_apply_bitmap_cache_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
816
                                                  WINPR_ATTR_UNUSED const rdpSettings* src)
817
0
{
818
0
  WINPR_ASSERT(settings);
819
0
  WINPR_ASSERT(src);
820
0
  return TRUE;
821
0
}
822
823
/*
824
 * Read bitmap cache capability set.
825
 * msdn{cc240559}
826
 */
827
828
static BOOL rdp_read_bitmap_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
829
0
{
830
0
  WINPR_UNUSED(settings);
831
0
  WINPR_ASSERT(settings);
832
833
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
834
0
    return FALSE;
835
836
0
  Stream_Seek_UINT32(s); /* pad1 (4 bytes) */
837
0
  Stream_Seek_UINT32(s); /* pad2 (4 bytes) */
838
0
  Stream_Seek_UINT32(s); /* pad3 (4 bytes) */
839
0
  Stream_Seek_UINT32(s); /* pad4 (4 bytes) */
840
0
  Stream_Seek_UINT32(s); /* pad5 (4 bytes) */
841
0
  Stream_Seek_UINT32(s); /* pad6 (4 bytes) */
842
0
  Stream_Seek_UINT16(s); /* Cache0Entries (2 bytes) */
843
0
  Stream_Seek_UINT16(s); /* Cache0MaximumCellSize (2 bytes) */
844
0
  Stream_Seek_UINT16(s); /* Cache1Entries (2 bytes) */
845
0
  Stream_Seek_UINT16(s); /* Cache1MaximumCellSize (2 bytes) */
846
0
  Stream_Seek_UINT16(s); /* Cache2Entries (2 bytes) */
847
0
  Stream_Seek_UINT16(s); /* Cache2MaximumCellSize (2 bytes) */
848
0
  return TRUE;
849
0
}
850
851
/*
852
 * Write bitmap cache capability set.
853
 * msdn{cc240559}
854
 */
855
856
static BOOL rdp_write_bitmap_cache_capability_set(wLog* log, wStream* s,
857
                                                  const rdpSettings* settings)
858
0
{
859
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
860
0
    return FALSE;
861
862
0
  const size_t header = rdp_capability_set_start(log, s);
863
0
  const UINT32 bpp = (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) + 7) / 8;
864
0
  if (bpp > UINT16_MAX)
865
0
    return FALSE;
866
0
  Stream_Write_UINT32(s, 0); /* pad1 (4 bytes) */
867
0
  Stream_Write_UINT32(s, 0); /* pad2 (4 bytes) */
868
0
  Stream_Write_UINT32(s, 0); /* pad3 (4 bytes) */
869
0
  Stream_Write_UINT32(s, 0); /* pad4 (4 bytes) */
870
0
  Stream_Write_UINT32(s, 0); /* pad5 (4 bytes) */
871
0
  Stream_Write_UINT32(s, 0); /* pad6 (4 bytes) */
872
0
  UINT32 size = bpp * 256;
873
0
  if (size > UINT16_MAX)
874
0
    return FALSE;
875
0
  Stream_Write_UINT16(s, 200);          /* Cache0Entries (2 bytes) */
876
0
  Stream_Write_UINT16(s, (UINT16)size); /* Cache0MaximumCellSize (2 bytes) */
877
0
  size = bpp * 1024;
878
0
  if (size > UINT16_MAX)
879
0
    return FALSE;
880
0
  Stream_Write_UINT16(s, 600);          /* Cache1Entries (2 bytes) */
881
0
  Stream_Write_UINT16(s, (UINT16)size); /* Cache1MaximumCellSize (2 bytes) */
882
0
  size = bpp * 4096;
883
0
  if (size > UINT16_MAX)
884
0
    return FALSE;
885
0
  Stream_Write_UINT16(s, 1000);         /* Cache2Entries (2 bytes) */
886
0
  Stream_Write_UINT16(s, (UINT16)size); /* Cache2MaximumCellSize (2 bytes) */
887
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE);
888
0
}
889
890
#ifdef WITH_DEBUG_CAPABILITIES
891
static BOOL rdp_print_bitmap_cache_capability_set(wLog* log, wStream* s)
892
{
893
  UINT32 pad1 = 0;
894
  UINT32 pad2 = 0;
895
  UINT32 pad3 = 0;
896
  UINT32 pad4 = 0;
897
  UINT32 pad5 = 0;
898
  UINT32 pad6 = 0;
899
  UINT16 Cache0Entries = 0;
900
  UINT16 Cache0MaximumCellSize = 0;
901
  UINT16 Cache1Entries = 0;
902
  UINT16 Cache1MaximumCellSize = 0;
903
  UINT16 Cache2Entries = 0;
904
  UINT16 Cache2MaximumCellSize = 0;
905
  WLog_Print(log, WLOG_TRACE,
906
             "BitmapCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
907
908
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
909
    return FALSE;
910
911
  Stream_Read_UINT32(s, pad1);                  /* pad1 (4 bytes) */
912
  Stream_Read_UINT32(s, pad2);                  /* pad2 (4 bytes) */
913
  Stream_Read_UINT32(s, pad3);                  /* pad3 (4 bytes) */
914
  Stream_Read_UINT32(s, pad4);                  /* pad4 (4 bytes) */
915
  Stream_Read_UINT32(s, pad5);                  /* pad5 (4 bytes) */
916
  Stream_Read_UINT32(s, pad6);                  /* pad6 (4 bytes) */
917
  Stream_Read_UINT16(s, Cache0Entries);         /* Cache0Entries (2 bytes) */
918
  Stream_Read_UINT16(s, Cache0MaximumCellSize); /* Cache0MaximumCellSize (2 bytes) */
919
  Stream_Read_UINT16(s, Cache1Entries);         /* Cache1Entries (2 bytes) */
920
  Stream_Read_UINT16(s, Cache1MaximumCellSize); /* Cache1MaximumCellSize (2 bytes) */
921
  Stream_Read_UINT16(s, Cache2Entries);         /* Cache2Entries (2 bytes) */
922
  Stream_Read_UINT16(s, Cache2MaximumCellSize); /* Cache2MaximumCellSize (2 bytes) */
923
  WLog_Print(log, WLOG_TRACE, "\tpad1: 0x%08" PRIX32 "", pad1);
924
  WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%08" PRIX32 "", pad2);
925
  WLog_Print(log, WLOG_TRACE, "\tpad3: 0x%08" PRIX32 "", pad3);
926
  WLog_Print(log, WLOG_TRACE, "\tpad4: 0x%08" PRIX32 "", pad4);
927
  WLog_Print(log, WLOG_TRACE, "\tpad5: 0x%08" PRIX32 "", pad5);
928
  WLog_Print(log, WLOG_TRACE, "\tpad6: 0x%08" PRIX32 "", pad6);
929
  WLog_Print(log, WLOG_TRACE, "\tCache0Entries: 0x%04" PRIX16 "", Cache0Entries);
930
  WLog_Print(log, WLOG_TRACE, "\tCache0MaximumCellSize: 0x%04" PRIX16 "", Cache0MaximumCellSize);
931
  WLog_Print(log, WLOG_TRACE, "\tCache1Entries: 0x%04" PRIX16 "", Cache1Entries);
932
  WLog_Print(log, WLOG_TRACE, "\tCache1MaximumCellSize: 0x%04" PRIX16 "", Cache1MaximumCellSize);
933
  WLog_Print(log, WLOG_TRACE, "\tCache2Entries: 0x%04" PRIX16 "", Cache2Entries);
934
  WLog_Print(log, WLOG_TRACE, "\tCache2MaximumCellSize: 0x%04" PRIX16 "", Cache2MaximumCellSize);
935
  return TRUE;
936
}
937
#endif
938
939
static BOOL rdp_apply_control_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
940
                                             WINPR_ATTR_UNUSED const rdpSettings* src)
941
0
{
942
0
  WINPR_ASSERT(settings);
943
0
  WINPR_ASSERT(src);
944
945
0
  return TRUE;
946
0
}
947
948
/*
949
 * Read control capability set.
950
 * msdn{cc240568}
951
 */
952
953
static BOOL rdp_read_control_capability_set(wLog* log, wStream* s, rdpSettings* settings)
954
0
{
955
0
  WINPR_UNUSED(settings);
956
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
957
0
    return FALSE;
958
959
0
  Stream_Seek_UINT16(s); /* controlFlags (2 bytes) */
960
0
  Stream_Seek_UINT16(s); /* remoteDetachFlag (2 bytes) */
961
0
  Stream_Seek_UINT16(s); /* controlInterest (2 bytes) */
962
0
  Stream_Seek_UINT16(s); /* detachInterest (2 bytes) */
963
0
  return TRUE;
964
0
}
965
966
/*
967
 * Write control capability set.
968
 * msdn{cc240568}
969
 */
970
971
static BOOL rdp_write_control_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
972
0
{
973
0
  WINPR_UNUSED(settings);
974
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
975
0
    return FALSE;
976
977
0
  const size_t header = rdp_capability_set_start(log, s);
978
0
  Stream_Write_UINT16(s, 0); /* controlFlags (2 bytes) */
979
0
  Stream_Write_UINT16(s, 0); /* remoteDetachFlag (2 bytes) */
980
0
  Stream_Write_UINT16(s, 2); /* controlInterest (2 bytes) */
981
0
  Stream_Write_UINT16(s, 2); /* detachInterest (2 bytes) */
982
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_CONTROL);
983
0
}
984
985
#ifdef WITH_DEBUG_CAPABILITIES
986
static BOOL rdp_print_control_capability_set(wLog* log, wStream* s)
987
{
988
  UINT16 controlFlags = 0;
989
  UINT16 remoteDetachFlag = 0;
990
  UINT16 controlInterest = 0;
991
  UINT16 detachInterest = 0;
992
  WLog_Print(log, WLOG_TRACE,
993
             "ControlCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
994
995
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
996
    return FALSE;
997
998
  Stream_Read_UINT16(s, controlFlags);     /* controlFlags (2 bytes) */
999
  Stream_Read_UINT16(s, remoteDetachFlag); /* remoteDetachFlag (2 bytes) */
1000
  Stream_Read_UINT16(s, controlInterest);  /* controlInterest (2 bytes) */
1001
  Stream_Read_UINT16(s, detachInterest);   /* detachInterest (2 bytes) */
1002
  WLog_Print(log, WLOG_TRACE, "\tcontrolFlags: 0x%04" PRIX16 "", controlFlags);
1003
  WLog_Print(log, WLOG_TRACE, "\tremoteDetachFlag: 0x%04" PRIX16 "", remoteDetachFlag);
1004
  WLog_Print(log, WLOG_TRACE, "\tcontrolInterest: 0x%04" PRIX16 "", controlInterest);
1005
  WLog_Print(log, WLOG_TRACE, "\tdetachInterest: 0x%04" PRIX16 "", detachInterest);
1006
  return TRUE;
1007
}
1008
#endif
1009
1010
static BOOL rdp_apply_window_activation_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1011
                                                       WINPR_ATTR_UNUSED const rdpSettings* src)
1012
0
{
1013
0
  WINPR_ASSERT(settings);
1014
0
  WINPR_ASSERT(src);
1015
1016
0
  return TRUE;
1017
0
}
1018
1019
/*
1020
 * Read window activation capability set.
1021
 * msdn{cc240569}
1022
 */
1023
1024
static BOOL rdp_read_window_activation_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1025
0
{
1026
0
  WINPR_UNUSED(settings);
1027
0
  WINPR_ASSERT(settings);
1028
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1029
0
    return FALSE;
1030
1031
0
  Stream_Seek_UINT16(s); /* helpKeyFlag (2 bytes) */
1032
0
  Stream_Seek_UINT16(s); /* helpKeyIndexFlag (2 bytes) */
1033
0
  Stream_Seek_UINT16(s); /* helpExtendedKeyFlag (2 bytes) */
1034
0
  Stream_Seek_UINT16(s); /* windowManagerKeyFlag (2 bytes) */
1035
0
  return TRUE;
1036
0
}
1037
1038
/*
1039
 * Write window activation capability set.
1040
 * msdn{cc240569}
1041
 */
1042
1043
static BOOL rdp_write_window_activation_capability_set(wLog* log, wStream* s,
1044
                                                       const rdpSettings* settings)
1045
0
{
1046
0
  WINPR_UNUSED(settings);
1047
0
  WINPR_ASSERT(settings);
1048
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1049
0
    return FALSE;
1050
1051
0
  const size_t header = rdp_capability_set_start(log, s);
1052
0
  Stream_Write_UINT16(s, 0); /* helpKeyFlag (2 bytes) */
1053
0
  Stream_Write_UINT16(s, 0); /* helpKeyIndexFlag (2 bytes) */
1054
0
  Stream_Write_UINT16(s, 0); /* helpExtendedKeyFlag (2 bytes) */
1055
0
  Stream_Write_UINT16(s, 0); /* windowManagerKeyFlag (2 bytes) */
1056
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_ACTIVATION);
1057
0
}
1058
1059
#ifdef WITH_DEBUG_CAPABILITIES
1060
static BOOL rdp_print_window_activation_capability_set(wLog* log, wStream* s)
1061
{
1062
  UINT16 helpKeyFlag = 0;
1063
  UINT16 helpKeyIndexFlag = 0;
1064
  UINT16 helpExtendedKeyFlag = 0;
1065
  UINT16 windowManagerKeyFlag = 0;
1066
  WLog_Print(log, WLOG_TRACE,
1067
             "WindowActivationCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1068
1069
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1070
    return FALSE;
1071
1072
  Stream_Read_UINT16(s, helpKeyFlag);          /* helpKeyFlag (2 bytes) */
1073
  Stream_Read_UINT16(s, helpKeyIndexFlag);     /* helpKeyIndexFlag (2 bytes) */
1074
  Stream_Read_UINT16(s, helpExtendedKeyFlag);  /* helpExtendedKeyFlag (2 bytes) */
1075
  Stream_Read_UINT16(s, windowManagerKeyFlag); /* windowManagerKeyFlag (2 bytes) */
1076
  WLog_Print(log, WLOG_TRACE, "\thelpKeyFlag: 0x%04" PRIX16 "", helpKeyFlag);
1077
  WLog_Print(log, WLOG_TRACE, "\thelpKeyIndexFlag: 0x%04" PRIX16 "", helpKeyIndexFlag);
1078
  WLog_Print(log, WLOG_TRACE, "\thelpExtendedKeyFlag: 0x%04" PRIX16 "", helpExtendedKeyFlag);
1079
  WLog_Print(log, WLOG_TRACE, "\twindowManagerKeyFlag: 0x%04" PRIX16 "", windowManagerKeyFlag);
1080
  return TRUE;
1081
}
1082
#endif
1083
1084
static BOOL rdp_apply_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
1085
0
{
1086
0
  WINPR_ASSERT(settings);
1087
0
  WINPR_ASSERT(src);
1088
1089
0
  const UINT32 pointerCacheSize = freerdp_settings_get_uint32(src, FreeRDP_PointerCacheSize);
1090
0
  const UINT32 colorPointerCacheSize =
1091
0
      freerdp_settings_get_uint32(src, FreeRDP_ColorPointerCacheSize);
1092
0
  const UINT32 dstPointerCacheSize =
1093
0
      freerdp_settings_get_uint32(settings, FreeRDP_PointerCacheSize);
1094
0
  const UINT32 dstColorPointerCacheSize =
1095
0
      freerdp_settings_get_uint32(settings, FreeRDP_ColorPointerCacheSize);
1096
1097
  /* We want the minimum of our setting and the remote announced value. */
1098
0
  const UINT32 actualPointerCacheSize = MIN(pointerCacheSize, dstPointerCacheSize);
1099
0
  const UINT32 actualColorPointerCacheSize = MIN(colorPointerCacheSize, dstColorPointerCacheSize);
1100
1101
0
  return !(
1102
0
      !freerdp_settings_set_uint32(settings, FreeRDP_PointerCacheSize, actualPointerCacheSize) ||
1103
0
      !freerdp_settings_set_uint32(settings, FreeRDP_ColorPointerCacheSize,
1104
0
                                   actualColorPointerCacheSize));
1105
0
}
1106
1107
/*
1108
 * Read pointer capability set.
1109
 * msdn{cc240562}
1110
 */
1111
1112
static BOOL rdp_read_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1113
0
{
1114
0
  UINT16 colorPointerFlag = 0;
1115
0
  UINT16 colorPointerCacheSize = 0;
1116
0
  UINT16 pointerCacheSize = 0;
1117
1118
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1119
0
    return FALSE;
1120
1121
0
  Stream_Read_UINT16(s, colorPointerFlag);      /* colorPointerFlag (2 bytes) */
1122
0
  Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1123
1124
0
  if (colorPointerFlag == 0)
1125
0
  {
1126
0
    WLog_Print(log, WLOG_WARN,
1127
0
               "[MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set "
1128
0
               "(TS_POINTER_CAPABILITYSET)::colorPointerFlag received is %" PRIu16
1129
0
               ". Value is ignored and always assumed to be TRUE",
1130
0
               colorPointerFlag);
1131
0
  }
1132
1133
  /* pointerCacheSize is optional */
1134
0
  if (Stream_GetRemainingLength(s) >= 2)
1135
0
    Stream_Read_UINT16(s, pointerCacheSize); /* pointerCacheSize (2 bytes) */
1136
1137
0
  WINPR_ASSERT(settings);
1138
0
  settings->PointerCacheSize = pointerCacheSize;
1139
0
  settings->ColorPointerCacheSize = colorPointerCacheSize;
1140
1141
0
  return TRUE;
1142
0
}
1143
1144
/*
1145
 * Write pointer capability set.
1146
 * msdn{cc240562}
1147
 */
1148
1149
static BOOL rdp_write_pointer_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1150
0
{
1151
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1152
0
    return FALSE;
1153
1154
0
  const size_t header = rdp_capability_set_start(log, s);
1155
0
  if (settings->PointerCacheSize > UINT16_MAX)
1156
0
    return FALSE;
1157
0
  if (settings->ColorPointerCacheSize > UINT16_MAX)
1158
0
    return FALSE;
1159
1160
0
  WINPR_ASSERT(settings);
1161
0
  const UINT32 colorPointerFlag =
1162
0
      1; /* [MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set (TS_POINTER_CAPABILITYSET)
1163
          * colorPointerFlag is ignored and always assumed to be TRUE */
1164
0
  Stream_Write_UINT16(s, colorPointerFlag); /* colorPointerFlag (2 bytes) */
1165
0
  Stream_Write_UINT16(
1166
0
      s, (UINT16)settings->ColorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1167
0
  Stream_Write_UINT16(s, (UINT16)settings->PointerCacheSize); /* pointerCacheSize (2 bytes) */
1168
1169
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_POINTER);
1170
0
}
1171
1172
#ifdef WITH_DEBUG_CAPABILITIES
1173
static BOOL rdp_print_pointer_capability_set(wLog* log, wStream* s)
1174
{
1175
  UINT16 colorPointerFlag = 0;
1176
  UINT16 colorPointerCacheSize = 0;
1177
  UINT16 pointerCacheSize = 0;
1178
1179
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
1180
    return FALSE;
1181
1182
  WLog_Print(log, WLOG_TRACE,
1183
             "PointerCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1184
  Stream_Read_UINT16(s, colorPointerFlag);      /* colorPointerFlag (2 bytes) */
1185
  Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1186
  Stream_Read_UINT16(s, pointerCacheSize);      /* pointerCacheSize (2 bytes) */
1187
  WLog_Print(log, WLOG_TRACE, "\tcolorPointerFlag: 0x%04" PRIX16 "", colorPointerFlag);
1188
  WLog_Print(log, WLOG_TRACE, "\tcolorPointerCacheSize: 0x%04" PRIX16 "", colorPointerCacheSize);
1189
  WLog_Print(log, WLOG_TRACE, "\tpointerCacheSize: 0x%04" PRIX16 "", pointerCacheSize);
1190
  return TRUE;
1191
}
1192
#endif
1193
1194
static BOOL rdp_apply_share_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1195
                                           WINPR_ATTR_UNUSED const rdpSettings* src)
1196
0
{
1197
0
  WINPR_ASSERT(settings);
1198
0
  WINPR_ASSERT(src);
1199
1200
0
  return TRUE;
1201
0
}
1202
1203
/*
1204
 * Read share capability set.
1205
 * msdn{cc240570}
1206
 */
1207
1208
static BOOL rdp_read_share_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1209
0
{
1210
0
  WINPR_UNUSED(settings);
1211
0
  WINPR_ASSERT(settings);
1212
1213
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1214
0
    return FALSE;
1215
1216
0
  Stream_Seek_UINT16(s); /* nodeId (2 bytes) */
1217
0
  Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1218
0
  return TRUE;
1219
0
}
1220
1221
/*
1222
 * Write share capability set.
1223
 * msdn{cc240570}
1224
 */
1225
1226
static BOOL rdp_write_share_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1227
0
{
1228
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1229
0
    return FALSE;
1230
1231
0
  const size_t header = rdp_capability_set_start(log, s);
1232
1233
0
  WINPR_ASSERT(settings);
1234
0
  const UINT16 nodeId = (settings->ServerMode) ? 0x03EA : 0;
1235
0
  Stream_Write_UINT16(s, nodeId); /* nodeId (2 bytes) */
1236
0
  Stream_Write_UINT16(s, 0);      /* pad2Octets (2 bytes) */
1237
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_SHARE);
1238
0
}
1239
1240
#ifdef WITH_DEBUG_CAPABILITIES
1241
static BOOL rdp_print_share_capability_set(wLog* log, wStream* s)
1242
{
1243
  UINT16 nodeId = 0;
1244
  UINT16 pad2Octets = 0;
1245
  WLog_Print(log, WLOG_TRACE,
1246
             "ShareCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1247
1248
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1249
    return FALSE;
1250
1251
  Stream_Read_UINT16(s, nodeId);     /* nodeId (2 bytes) */
1252
  Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
1253
  WLog_Print(log, WLOG_TRACE, "\tnodeId: 0x%04" PRIX16 "", nodeId);
1254
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1255
  return TRUE;
1256
}
1257
#endif
1258
1259
static BOOL rdp_apply_color_cache_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1260
                                                 WINPR_ATTR_UNUSED const rdpSettings* src)
1261
0
{
1262
0
  WINPR_ASSERT(settings);
1263
0
  WINPR_ASSERT(src);
1264
0
  return TRUE;
1265
0
}
1266
1267
/*
1268
 * Read color cache capability set.
1269
 * msdn{cc241564}
1270
 */
1271
1272
static BOOL rdp_read_color_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1273
0
{
1274
0
  WINPR_UNUSED(settings);
1275
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1276
0
    return FALSE;
1277
1278
0
  Stream_Seek_UINT16(s); /* colorTableCacheSize (2 bytes) */
1279
0
  Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1280
0
  return TRUE;
1281
0
}
1282
1283
/*
1284
 * Write color cache capability set.
1285
 * msdn{cc241564}
1286
 */
1287
1288
static BOOL rdp_write_color_cache_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1289
0
{
1290
0
  WINPR_UNUSED(settings);
1291
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1292
0
    return FALSE;
1293
1294
0
  const size_t header = rdp_capability_set_start(log, s);
1295
0
  Stream_Write_UINT16(s, 6); /* colorTableCacheSize (2 bytes) */
1296
0
  Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1297
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_COLOR_CACHE);
1298
0
}
1299
1300
#ifdef WITH_DEBUG_CAPABILITIES
1301
static BOOL rdp_print_color_cache_capability_set(wLog* log, wStream* s)
1302
{
1303
  UINT16 colorTableCacheSize = 0;
1304
  UINT16 pad2Octets = 0;
1305
  WLog_Print(log, WLOG_TRACE,
1306
             "ColorCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1307
1308
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1309
    return FALSE;
1310
1311
  Stream_Read_UINT16(s, colorTableCacheSize); /* colorTableCacheSize (2 bytes) */
1312
  Stream_Read_UINT16(s, pad2Octets);          /* pad2Octets (2 bytes) */
1313
  WLog_Print(log, WLOG_TRACE, "\tcolorTableCacheSize: 0x%04" PRIX16 "", colorTableCacheSize);
1314
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1315
  return TRUE;
1316
}
1317
#endif
1318
1319
static BOOL rdp_apply_sound_capability_set(rdpSettings* settings, const rdpSettings* src)
1320
0
{
1321
0
  WINPR_ASSERT(settings);
1322
0
  WINPR_ASSERT(src);
1323
1324
0
  settings->SoundBeepsEnabled = src->SoundBeepsEnabled;
1325
1326
0
  return TRUE;
1327
0
}
1328
1329
/*
1330
 * Read sound capability set.
1331
 * msdn{cc240552}
1332
 */
1333
1334
static BOOL rdp_read_sound_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1335
0
{
1336
0
  UINT16 soundFlags = 0;
1337
1338
0
  WINPR_ASSERT(settings);
1339
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1340
0
    return FALSE;
1341
1342
0
  Stream_Read_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1343
0
  Stream_Seek_UINT16(s);             /* pad2OctetsA (2 bytes) */
1344
0
  settings->SoundBeepsEnabled = (soundFlags & SOUND_BEEPS_FLAG) != 0;
1345
0
  return TRUE;
1346
0
}
1347
1348
/*
1349
 * Write sound capability set.
1350
 * msdn{cc240552}
1351
 */
1352
1353
static BOOL rdp_write_sound_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1354
0
{
1355
0
  WINPR_ASSERT(settings);
1356
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1357
0
    return FALSE;
1358
1359
0
  const size_t header = rdp_capability_set_start(log, s);
1360
0
  const UINT16 soundFlags = (settings->SoundBeepsEnabled) ? SOUND_BEEPS_FLAG : 0;
1361
0
  Stream_Write_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1362
0
  Stream_Write_UINT16(s, 0);          /* pad2OctetsA (2 bytes) */
1363
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_SOUND);
1364
0
}
1365
1366
#ifdef WITH_DEBUG_CAPABILITIES
1367
static BOOL rdp_print_sound_capability_set(wLog* log, wStream* s)
1368
{
1369
  UINT16 soundFlags = 0;
1370
  UINT16 pad2OctetsA = 0;
1371
  WLog_Print(log, WLOG_TRACE,
1372
             "SoundCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1373
1374
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1375
    return FALSE;
1376
1377
  Stream_Read_UINT16(s, soundFlags);  /* soundFlags (2 bytes) */
1378
  Stream_Read_UINT16(s, pad2OctetsA); /* pad2OctetsA (2 bytes) */
1379
  WLog_Print(log, WLOG_TRACE, "\tsoundFlags: 0x%04" PRIX16 "", soundFlags);
1380
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
1381
  return TRUE;
1382
}
1383
#endif
1384
1385
static BOOL rdp_apply_input_capability_set(rdpSettings* settings, const rdpSettings* src)
1386
0
{
1387
0
  WINPR_ASSERT(settings);
1388
0
  WINPR_ASSERT(src);
1389
1390
0
  if (settings->ServerMode)
1391
0
  {
1392
0
    settings->KeyboardLayout = src->KeyboardLayout;
1393
0
    settings->KeyboardType = src->KeyboardType;
1394
0
    settings->KeyboardSubType = src->KeyboardSubType;
1395
0
    settings->KeyboardFunctionKey = src->KeyboardFunctionKey;
1396
0
  }
1397
1398
0
  if (!freerdp_settings_set_string(settings, FreeRDP_ImeFileName, src->ImeFileName))
1399
0
    return FALSE;
1400
1401
0
  if (!settings->ServerMode)
1402
0
  {
1403
0
    settings->FastPathInput = src->FastPathInput;
1404
1405
    /* Note: These settings have split functionality:
1406
     * 1. If disabled in client pre_connect, it can disable announcing the feature
1407
     * 2. If enabled in client pre_connect, override it with the server announced support flag.
1408
     */
1409
0
    if (settings->HasHorizontalWheel)
1410
0
      settings->HasHorizontalWheel = src->HasHorizontalWheel;
1411
0
    const BOOL UnicodeInput = freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput);
1412
0
    if (UnicodeInput)
1413
0
    {
1414
0
      const BOOL srcVal = freerdp_settings_get_bool(src, FreeRDP_UnicodeInput);
1415
0
      if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, srcVal))
1416
0
        return FALSE;
1417
0
    }
1418
0
    if (settings->HasExtendedMouseEvent)
1419
0
      settings->HasExtendedMouseEvent = src->HasExtendedMouseEvent;
1420
0
    if (settings->HasRelativeMouseEvent)
1421
0
      settings->HasRelativeMouseEvent = src->HasRelativeMouseEvent;
1422
0
    if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1423
0
      settings->HasQoeEvent = freerdp_settings_get_bool(src, FreeRDP_HasQoeEvent);
1424
0
  }
1425
0
  return TRUE;
1426
0
}
1427
1428
/*
1429
 * Read input capability set.
1430
 * msdn{cc240563}
1431
 */
1432
1433
static BOOL rdp_read_input_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1434
0
{
1435
0
  UINT16 inputFlags = 0;
1436
1437
0
  WINPR_ASSERT(settings);
1438
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1439
0
    return FALSE;
1440
1441
0
  Stream_Read_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1442
0
  Stream_Seek_UINT16(s);             /* pad2OctetsA (2 bytes) */
1443
1444
0
  Stream_Read_UINT32(s, settings->KeyboardLayout);      /* keyboardLayout (4 bytes) */
1445
0
  Stream_Read_UINT32(s, settings->KeyboardType);        /* keyboardType (4 bytes) */
1446
0
  Stream_Read_UINT32(s, settings->KeyboardSubType);     /* keyboardSubType (4 bytes) */
1447
0
  Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1448
1449
0
  {
1450
0
    WCHAR wstr[32] = WINPR_C_ARRAY_INIT;
1451
0
    char str[65] = WINPR_C_ARRAY_INIT;
1452
1453
    /* Older windows versions report invalid UTF16
1454
     * [MS-RDPBCGR] <29> Section 2.2.7.1.6: Microsoft RDP 4.0, 5.0, 5.1, and 5.2 servers do not
1455
     * explicitly fill the imeFileName field with zeros.
1456
     */
1457
0
    if (!Stream_Read_UTF16_String(s, wstr, ARRAYSIZE(wstr)))
1458
0
      return FALSE;
1459
1460
0
    if (ConvertWCharNToUtf8(wstr, ARRAYSIZE(wstr), str, ARRAYSIZE(str)) < 0)
1461
0
      memset(str, 0, sizeof(str));
1462
1463
0
    if (!freerdp_settings_set_string_len(settings, FreeRDP_ImeFileName, str, ARRAYSIZE(str)))
1464
0
      return FALSE;
1465
0
  }
1466
1467
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathInput,
1468
0
                                 inputFlags &
1469
0
                                     (INPUT_FLAG_FASTPATH_INPUT | INPUT_FLAG_FASTPATH_INPUT2)))
1470
0
    return FALSE;
1471
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel,
1472
0
                                 (inputFlags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0))
1473
0
    return FALSE;
1474
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput,
1475
0
                                 (inputFlags & INPUT_FLAG_UNICODE) != 0))
1476
0
    return FALSE;
1477
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent,
1478
0
                                 (inputFlags & INPUT_FLAG_MOUSE_RELATIVE) != 0))
1479
0
    return FALSE;
1480
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent,
1481
0
                                 (inputFlags & INPUT_FLAG_MOUSEX) != 0))
1482
0
    return FALSE;
1483
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasQoeEvent,
1484
0
                                 (inputFlags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0))
1485
0
    return FALSE;
1486
1487
0
  return TRUE;
1488
0
}
1489
1490
/*
1491
 * Write input capability set.
1492
 * msdn{cc240563}
1493
 */
1494
1495
static BOOL rdp_write_input_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1496
0
{
1497
0
  WINPR_ASSERT(settings);
1498
0
  if (!Stream_EnsureRemainingCapacity(s, 128))
1499
0
    return FALSE;
1500
1501
0
  const size_t header = rdp_capability_set_start(log, s);
1502
0
  UINT16 inputFlags = INPUT_FLAG_SCANCODES;
1503
1504
0
  if (settings->FastPathInput)
1505
0
  {
1506
0
    inputFlags |= INPUT_FLAG_FASTPATH_INPUT;
1507
0
    inputFlags |= INPUT_FLAG_FASTPATH_INPUT2;
1508
0
  }
1509
1510
0
  if (freerdp_settings_get_bool(settings, FreeRDP_HasRelativeMouseEvent))
1511
0
    inputFlags |= INPUT_FLAG_MOUSE_RELATIVE;
1512
1513
0
  if (freerdp_settings_get_bool(settings, FreeRDP_HasHorizontalWheel))
1514
0
    inputFlags |= TS_INPUT_FLAG_MOUSE_HWHEEL;
1515
1516
0
  if (freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput))
1517
0
    inputFlags |= INPUT_FLAG_UNICODE;
1518
1519
0
  if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1520
0
    inputFlags |= TS_INPUT_FLAG_QOE_TIMESTAMPS;
1521
1522
0
  if (settings->HasExtendedMouseEvent)
1523
0
    inputFlags |= INPUT_FLAG_MOUSEX;
1524
1525
0
  Stream_Write_UINT16(s, inputFlags);                    /* inputFlags (2 bytes) */
1526
0
  Stream_Write_UINT16(s, 0);                             /* pad2OctetsA (2 bytes) */
1527
0
  Stream_Write_UINT32(s, settings->KeyboardLayout);      /* keyboardLayout (4 bytes) */
1528
0
  Stream_Write_UINT32(s, settings->KeyboardType);        /* keyboardType (4 bytes) */
1529
0
  Stream_Write_UINT32(s, settings->KeyboardSubType);     /* keyboardSubType (4 bytes) */
1530
0
  Stream_Write_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1531
0
  Stream_Zero(s, 64);                                    /* imeFileName (64 bytes) */
1532
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_INPUT);
1533
0
}
1534
1535
#ifdef WITH_DEBUG_CAPABILITIES
1536
static BOOL rdp_print_input_capability_set(wLog* log, wStream* s)
1537
{
1538
  UINT16 inputFlags = 0;
1539
  UINT16 pad2OctetsA = 0;
1540
  UINT32 keyboardLayout = 0;
1541
  UINT32 keyboardType = 0;
1542
  UINT32 keyboardSubType = 0;
1543
  UINT32 keyboardFunctionKey = 0;
1544
  WLog_Print(log, WLOG_TRACE, "InputCapabilitySet (length %" PRIuz ")",
1545
             Stream_GetRemainingLength(s));
1546
1547
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1548
    return FALSE;
1549
1550
  Stream_Read_UINT16(s, inputFlags);          /* inputFlags (2 bytes) */
1551
  Stream_Read_UINT16(s, pad2OctetsA);         /* pad2OctetsA (2 bytes) */
1552
  Stream_Read_UINT32(s, keyboardLayout);      /* keyboardLayout (4 bytes) */
1553
  Stream_Read_UINT32(s, keyboardType);        /* keyboardType (4 bytes) */
1554
  Stream_Read_UINT32(s, keyboardSubType);     /* keyboardSubType (4 bytes) */
1555
  Stream_Read_UINT32(s, keyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1556
  Stream_Seek(s, 64);                         /* imeFileName (64 bytes) */
1557
  WLog_Print(log, WLOG_TRACE, "\tinputFlags: 0x%04" PRIX16 "", inputFlags);
1558
  WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
1559
  WLog_Print(log, WLOG_TRACE, "\tkeyboardLayout: 0x%08" PRIX32 "", keyboardLayout);
1560
  WLog_Print(log, WLOG_TRACE, "\tkeyboardType: 0x%08" PRIX32 "", keyboardType);
1561
  WLog_Print(log, WLOG_TRACE, "\tkeyboardSubType: 0x%08" PRIX32 "", keyboardSubType);
1562
  WLog_Print(log, WLOG_TRACE, "\tkeyboardFunctionKey: 0x%08" PRIX32 "", keyboardFunctionKey);
1563
  return TRUE;
1564
}
1565
#endif
1566
1567
static BOOL rdp_apply_font_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1568
                                          WINPR_ATTR_UNUSED const rdpSettings* src)
1569
0
{
1570
0
  WINPR_ASSERT(settings);
1571
0
  WINPR_ASSERT(src);
1572
0
  return TRUE;
1573
0
}
1574
1575
/*
1576
 * Read font capability set.
1577
 * msdn{cc240571}
1578
 */
1579
1580
static BOOL rdp_read_font_capability_set(WINPR_ATTR_UNUSED wLog* log, wStream* s,
1581
                                         rdpSettings* settings)
1582
0
{
1583
0
  WINPR_UNUSED(settings);
1584
0
  if (Stream_GetRemainingLength(s) >= 2)
1585
0
    Stream_Seek_UINT16(s); /* fontSupportFlags (2 bytes) */
1586
1587
0
  if (Stream_GetRemainingLength(s) >= 2)
1588
0
    Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1589
1590
0
  return TRUE;
1591
0
}
1592
1593
/*
1594
 * Write font capability set.
1595
 * msdn{cc240571}
1596
 */
1597
1598
static BOOL rdp_write_font_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1599
0
{
1600
0
  WINPR_UNUSED(settings);
1601
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1602
0
    return FALSE;
1603
1604
0
  const size_t header = rdp_capability_set_start(log, s);
1605
0
  Stream_Write_UINT16(s, FONTSUPPORT_FONTLIST); /* fontSupportFlags (2 bytes) */
1606
0
  Stream_Write_UINT16(s, 0);                    /* pad2Octets (2 bytes) */
1607
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_FONT);
1608
0
}
1609
1610
#ifdef WITH_DEBUG_CAPABILITIES
1611
static BOOL rdp_print_font_capability_set(wLog* log, wStream* s)
1612
{
1613
  UINT16 fontSupportFlags = 0;
1614
  UINT16 pad2Octets = 0;
1615
  WLog_Print(log, WLOG_TRACE,
1616
             "FontCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1617
1618
  if (Stream_GetRemainingLength(s) >= 2)
1619
    Stream_Read_UINT16(s, fontSupportFlags); /* fontSupportFlags (2 bytes) */
1620
1621
  if (Stream_GetRemainingLength(s) >= 2)
1622
    Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
1623
1624
  WLog_Print(log, WLOG_TRACE, "\tfontSupportFlags: 0x%04" PRIX16 "", fontSupportFlags);
1625
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1626
  return TRUE;
1627
}
1628
#endif
1629
1630
static BOOL rdp_apply_brush_capability_set(rdpSettings* settings, const rdpSettings* src)
1631
0
{
1632
0
  WINPR_ASSERT(settings);
1633
0
  WINPR_ASSERT(src);
1634
1635
  // TODO: Minimum of what?
1636
0
  settings->BrushSupportLevel = src->BrushSupportLevel;
1637
0
  return TRUE;
1638
0
}
1639
1640
/*
1641
 * Read brush capability set.
1642
 * msdn{cc240564}
1643
 */
1644
1645
static BOOL rdp_read_brush_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1646
0
{
1647
0
  WINPR_UNUSED(settings);
1648
0
  WINPR_ASSERT(settings);
1649
1650
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1651
0
    return FALSE;
1652
0
  Stream_Read_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1653
0
  return TRUE;
1654
0
}
1655
1656
/*
1657
 * Write brush capability set.
1658
 * msdn{cc240564}
1659
 */
1660
1661
static BOOL rdp_write_brush_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1662
0
{
1663
0
  WINPR_ASSERT(settings);
1664
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1665
0
    return FALSE;
1666
1667
0
  const size_t header = rdp_capability_set_start(log, s);
1668
0
  Stream_Write_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1669
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BRUSH);
1670
0
}
1671
1672
#ifdef WITH_DEBUG_CAPABILITIES
1673
static BOOL rdp_print_brush_capability_set(wLog* log, wStream* s)
1674
{
1675
  UINT32 brushSupportLevel = 0;
1676
  WLog_Print(log, WLOG_TRACE,
1677
             "BrushCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1678
1679
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1680
    return FALSE;
1681
1682
  Stream_Read_UINT32(s, brushSupportLevel); /* brushSupportLevel (4 bytes) */
1683
  WLog_Print(log, WLOG_TRACE, "\tbrushSupportLevel: 0x%08" PRIX32 "", brushSupportLevel);
1684
  return TRUE;
1685
}
1686
#endif
1687
1688
/*
1689
 * Read cache definition (glyph).
1690
 * msdn{cc240566}
1691
 */
1692
static void rdp_read_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_definition)
1693
0
{
1694
0
  WINPR_ASSERT(cache_definition);
1695
0
  Stream_Read_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1696
0
  Stream_Read_UINT16(s,
1697
0
                     cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1698
0
}
1699
1700
/*
1701
 * Write cache definition (glyph).
1702
 * msdn{cc240566}
1703
 */
1704
static void rdp_write_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_definition)
1705
0
{
1706
0
  WINPR_ASSERT(cache_definition);
1707
0
  Stream_Write_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1708
0
  Stream_Write_UINT16(
1709
0
      s, cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1710
0
}
1711
1712
static BOOL rdp_apply_glyph_cache_capability_set(rdpSettings* settings, const rdpSettings* src)
1713
0
{
1714
0
  WINPR_ASSERT(settings);
1715
0
  WINPR_ASSERT(src);
1716
1717
0
  WINPR_ASSERT(src->GlyphCache);
1718
0
  WINPR_ASSERT(settings->GlyphCache);
1719
0
  for (size_t x = 0; x < 10; x++)
1720
0
    settings->GlyphCache[x] = src->GlyphCache[x];
1721
1722
0
  WINPR_ASSERT(src->FragCache);
1723
0
  WINPR_ASSERT(settings->FragCache);
1724
0
  settings->FragCache[0] = src->FragCache[0];
1725
0
  settings->GlyphSupportLevel = src->GlyphSupportLevel;
1726
1727
0
  return TRUE;
1728
0
}
1729
1730
/*
1731
 * Read glyph cache capability set.
1732
 * msdn{cc240565}
1733
 */
1734
1735
static BOOL rdp_read_glyph_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1736
0
{
1737
0
  WINPR_ASSERT(settings);
1738
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1739
0
    return FALSE;
1740
1741
  /* glyphCache (40 bytes) */
1742
0
  for (size_t x = 0; x < 10; x++)
1743
0
    rdp_read_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1744
0
  rdp_read_cache_definition(s, settings->FragCache);            /* fragCache (4 bytes) */
1745
0
  Stream_Read_UINT16(s, settings->GlyphSupportLevel);           /* glyphSupportLevel (2 bytes) */
1746
0
  Stream_Seek_UINT16(s);                                        /* pad2Octets (2 bytes) */
1747
0
  return TRUE;
1748
0
}
1749
1750
/*
1751
 * Write glyph cache capability set.
1752
 * msdn{cc240565}
1753
 */
1754
1755
static BOOL rdp_write_glyph_cache_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1756
0
{
1757
0
  WINPR_ASSERT(settings);
1758
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
1759
0
    return FALSE;
1760
1761
0
  const size_t header = rdp_capability_set_start(log, s);
1762
0
  if (settings->GlyphSupportLevel > UINT16_MAX)
1763
0
    return FALSE;
1764
  /* glyphCache (40 bytes) */
1765
0
  for (size_t x = 0; x < 10; x++)
1766
0
    rdp_write_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1767
0
  rdp_write_cache_definition(s, settings->FragCache);            /* fragCache (4 bytes) */
1768
0
  Stream_Write_UINT16(s, (UINT16)settings->GlyphSupportLevel);   /* glyphSupportLevel (2 bytes) */
1769
0
  Stream_Write_UINT16(s, 0);                                     /* pad2Octets (2 bytes) */
1770
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_GLYPH_CACHE);
1771
0
}
1772
1773
#ifdef WITH_DEBUG_CAPABILITIES
1774
static BOOL rdp_print_glyph_cache_capability_set(wLog* log, wStream* s)
1775
{
1776
  GLYPH_CACHE_DEFINITION glyphCache[10] = WINPR_C_ARRAY_INIT;
1777
  GLYPH_CACHE_DEFINITION fragCache = WINPR_C_ARRAY_INIT;
1778
  UINT16 glyphSupportLevel = 0;
1779
  UINT16 pad2Octets = 0;
1780
  WLog_Print(log, WLOG_TRACE,
1781
             "GlyphCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1782
1783
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1784
    return FALSE;
1785
1786
  /* glyphCache (40 bytes) */
1787
  rdp_read_cache_definition(s, &glyphCache[0]); /* glyphCache0 (4 bytes) */
1788
  rdp_read_cache_definition(s, &glyphCache[1]); /* glyphCache1 (4 bytes) */
1789
  rdp_read_cache_definition(s, &glyphCache[2]); /* glyphCache2 (4 bytes) */
1790
  rdp_read_cache_definition(s, &glyphCache[3]); /* glyphCache3 (4 bytes) */
1791
  rdp_read_cache_definition(s, &glyphCache[4]); /* glyphCache4 (4 bytes) */
1792
  rdp_read_cache_definition(s, &glyphCache[5]); /* glyphCache5 (4 bytes) */
1793
  rdp_read_cache_definition(s, &glyphCache[6]); /* glyphCache6 (4 bytes) */
1794
  rdp_read_cache_definition(s, &glyphCache[7]); /* glyphCache7 (4 bytes) */
1795
  rdp_read_cache_definition(s, &glyphCache[8]); /* glyphCache8 (4 bytes) */
1796
  rdp_read_cache_definition(s, &glyphCache[9]); /* glyphCache9 (4 bytes) */
1797
  rdp_read_cache_definition(s, &fragCache);     /* fragCache (4 bytes) */
1798
  Stream_Read_UINT16(s, glyphSupportLevel);     /* glyphSupportLevel (2 bytes) */
1799
  Stream_Read_UINT16(s, pad2Octets);            /* pad2Octets (2 bytes) */
1800
  WLog_Print(log, WLOG_TRACE, "\tglyphCache0: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1801
             glyphCache[0].cacheEntries, glyphCache[0].cacheMaximumCellSize);
1802
  WLog_Print(log, WLOG_TRACE, "\tglyphCache1: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1803
             glyphCache[1].cacheEntries, glyphCache[1].cacheMaximumCellSize);
1804
  WLog_Print(log, WLOG_TRACE, "\tglyphCache2: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1805
             glyphCache[2].cacheEntries, glyphCache[2].cacheMaximumCellSize);
1806
  WLog_Print(log, WLOG_TRACE, "\tglyphCache3: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1807
             glyphCache[3].cacheEntries, glyphCache[3].cacheMaximumCellSize);
1808
  WLog_Print(log, WLOG_TRACE, "\tglyphCache4: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1809
             glyphCache[4].cacheEntries, glyphCache[4].cacheMaximumCellSize);
1810
  WLog_Print(log, WLOG_TRACE, "\tglyphCache5: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1811
             glyphCache[5].cacheEntries, glyphCache[5].cacheMaximumCellSize);
1812
  WLog_Print(log, WLOG_TRACE, "\tglyphCache6: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1813
             glyphCache[6].cacheEntries, glyphCache[6].cacheMaximumCellSize);
1814
  WLog_Print(log, WLOG_TRACE, "\tglyphCache7: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1815
             glyphCache[7].cacheEntries, glyphCache[7].cacheMaximumCellSize);
1816
  WLog_Print(log, WLOG_TRACE, "\tglyphCache8: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1817
             glyphCache[8].cacheEntries, glyphCache[8].cacheMaximumCellSize);
1818
  WLog_Print(log, WLOG_TRACE, "\tglyphCache9: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1819
             glyphCache[9].cacheEntries, glyphCache[9].cacheMaximumCellSize);
1820
  WLog_Print(log, WLOG_TRACE, "\tfragCache: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1821
             fragCache.cacheEntries, fragCache.cacheMaximumCellSize);
1822
  WLog_Print(log, WLOG_TRACE, "\tglyphSupportLevel: 0x%04" PRIX16 "", glyphSupportLevel);
1823
  WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1824
  return TRUE;
1825
}
1826
#endif
1827
1828
static BOOL rdp_apply_offscreen_bitmap_cache_capability_set(rdpSettings* settings,
1829
                                                            const rdpSettings* src)
1830
0
{
1831
0
  WINPR_ASSERT(settings);
1832
0
  WINPR_ASSERT(src);
1833
1834
0
  settings->OffscreenCacheSize = src->OffscreenCacheSize;
1835
0
  settings->OffscreenCacheEntries = src->OffscreenCacheEntries;
1836
0
  settings->OffscreenSupportLevel = src->OffscreenSupportLevel;
1837
1838
0
  return TRUE;
1839
0
}
1840
1841
/*
1842
 * Read offscreen bitmap cache capability set.
1843
 * msdn{cc240550}
1844
 */
1845
1846
static BOOL rdp_read_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s,
1847
                                                           rdpSettings* settings)
1848
0
{
1849
0
  UINT32 offscreenSupportLevel = 0;
1850
1851
0
  WINPR_ASSERT(settings);
1852
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1853
0
    return FALSE;
1854
1855
0
  Stream_Read_UINT32(s, offscreenSupportLevel);           /* offscreenSupportLevel (4 bytes) */
1856
0
  Stream_Read_UINT16(s, settings->OffscreenCacheSize);    /* offscreenCacheSize (2 bytes) */
1857
0
  Stream_Read_UINT16(s, settings->OffscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1858
1859
0
  settings->OffscreenSupportLevel = offscreenSupportLevel & 0x01;
1860
1861
0
  return TRUE;
1862
0
}
1863
1864
/*
1865
 * Write offscreen bitmap cache capability set.
1866
 * msdn{cc240550}
1867
 */
1868
1869
static BOOL rdp_write_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s,
1870
                                                            const rdpSettings* settings)
1871
0
{
1872
0
  UINT32 offscreenSupportLevel = 0x00;
1873
1874
0
  WINPR_ASSERT(settings);
1875
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1876
0
    return FALSE;
1877
1878
0
  const size_t header = rdp_capability_set_start(log, s);
1879
0
  if (settings->OffscreenSupportLevel)
1880
0
  {
1881
0
    offscreenSupportLevel = 0x01;
1882
0
    Stream_Write_UINT32(s, offscreenSupportLevel);        /* offscreenSupportLevel (4 bytes) */
1883
0
    Stream_Write_UINT16(
1884
0
        s, WINPR_ASSERTING_INT_CAST(
1885
0
               uint16_t, settings->OffscreenCacheSize)); /* offscreenCacheSize (2 bytes) */
1886
0
    Stream_Write_UINT16(
1887
0
        s,
1888
0
        WINPR_ASSERTING_INT_CAST(
1889
0
            uint16_t, settings->OffscreenCacheEntries)); /* offscreenCacheEntries (2 bytes) */
1890
0
  }
1891
0
  else
1892
0
    Stream_Zero(s, 8);
1893
1894
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_OFFSCREEN_CACHE);
1895
0
}
1896
1897
#ifdef WITH_DEBUG_CAPABILITIES
1898
static BOOL rdp_print_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s)
1899
{
1900
  UINT32 offscreenSupportLevel = 0;
1901
  UINT16 offscreenCacheSize = 0;
1902
  UINT16 offscreenCacheEntries = 0;
1903
  WLog_Print(log, WLOG_TRACE, "OffscreenBitmapCacheCapabilitySet (length %" PRIuz "):",
1904
             Stream_GetRemainingLength(s));
1905
1906
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1907
    return FALSE;
1908
1909
  Stream_Read_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */
1910
  Stream_Read_UINT16(s, offscreenCacheSize);    /* offscreenCacheSize (2 bytes) */
1911
  Stream_Read_UINT16(s, offscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1912
  WLog_Print(log, WLOG_TRACE, "\toffscreenSupportLevel: 0x%08" PRIX32 "", offscreenSupportLevel);
1913
  WLog_Print(log, WLOG_TRACE, "\toffscreenCacheSize: 0x%04" PRIX16 "", offscreenCacheSize);
1914
  WLog_Print(log, WLOG_TRACE, "\toffscreenCacheEntries: 0x%04" PRIX16 "", offscreenCacheEntries);
1915
  return TRUE;
1916
}
1917
#endif
1918
1919
static BOOL rdp_apply_bitmap_cache_host_support_capability_set(rdpSettings* settings,
1920
                                                               const rdpSettings* src)
1921
0
{
1922
0
  const BOOL val = (freerdp_settings_get_bool(src, FreeRDP_BitmapCachePersistEnabled) &&
1923
0
                    freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled));
1924
0
  return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, val);
1925
0
}
1926
1927
/*
1928
 * Read bitmap cache host support capability set.
1929
 * msdn{cc240557}
1930
 */
1931
1932
static BOOL rdp_read_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
1933
                                                              rdpSettings* settings)
1934
0
{
1935
0
  BYTE cacheVersion = 0;
1936
1937
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1938
0
    return FALSE;
1939
1940
0
  Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1941
0
  Stream_Seek_UINT8(s);               /* pad1 (1 byte) */
1942
0
  Stream_Seek_UINT16(s);              /* pad2 (2 bytes) */
1943
1944
0
  return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
1945
0
                                   cacheVersion & BITMAP_CACHE_V2);
1946
0
}
1947
1948
/*
1949
 * Write bitmap cache host support capability set.
1950
 * msdn{cc240557}
1951
 */
1952
1953
static BOOL rdp_write_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
1954
                                                               const rdpSettings* settings)
1955
0
{
1956
0
  UINT8 cacheVersion = 0;
1957
1958
0
  if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled))
1959
0
    cacheVersion |= BITMAP_CACHE_V2;
1960
1961
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
1962
0
    return FALSE;
1963
1964
0
  const size_t header = rdp_capability_set_start(log, s);
1965
0
  Stream_Write_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1966
0
  Stream_Write_UINT8(s, 0);            /* pad1 (1 byte) */
1967
0
  Stream_Write_UINT16(s, 0);           /* pad2 (2 bytes) */
1968
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT);
1969
0
}
1970
1971
#ifdef WITH_DEBUG_CAPABILITIES
1972
static BOOL rdp_print_bitmap_cache_host_support_capability_set(wLog* log, wStream* s)
1973
{
1974
  BYTE cacheVersion = 0;
1975
  BYTE pad1 = 0;
1976
  UINT16 pad2 = 0;
1977
  WLog_Print(log, WLOG_TRACE, "BitmapCacheHostSupportCapabilitySet (length %" PRIuz "):",
1978
             Stream_GetRemainingLength(s));
1979
1980
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1981
    return FALSE;
1982
1983
  Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1984
  Stream_Read_UINT8(s, pad1);         /* pad1 (1 byte) */
1985
  Stream_Read_UINT16(s, pad2);        /* pad2 (2 bytes) */
1986
  WLog_Print(log, WLOG_TRACE, "\tcacheVersion: 0x%02" PRIX8 "", cacheVersion);
1987
  WLog_Print(log, WLOG_TRACE, "\tpad1: 0x%02" PRIX8 "", pad1);
1988
  WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%04" PRIX16 "", pad2);
1989
  return TRUE;
1990
}
1991
#endif
1992
1993
static BOOL rdp_read_bitmap_cache_cell_info(wLog* log, wStream* s,
1994
                                            BITMAP_CACHE_V2_CELL_INFO* cellInfo)
1995
0
{
1996
0
  UINT32 info = 0;
1997
1998
0
  WINPR_ASSERT(cellInfo);
1999
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2000
0
    return FALSE;
2001
2002
  /*
2003
   * numEntries is in the first 31 bits, while the last bit (k)
2004
   * is used to indicate a persistent bitmap cache.
2005
   */
2006
0
  Stream_Read_UINT32(s, info);
2007
0
  cellInfo->numEntries = (info & 0x7FFFFFFF);
2008
0
  cellInfo->persistent = (info & 0x80000000) ? 1 : 0;
2009
0
  return TRUE;
2010
0
}
2011
2012
static void rdp_write_bitmap_cache_cell_info(wStream* s, BITMAP_CACHE_V2_CELL_INFO* cellInfo)
2013
0
{
2014
0
  UINT32 info = 0;
2015
  /*
2016
   * numEntries is in the first 31 bits, while the last bit (k)
2017
   * is used to indicate a persistent bitmap cache.
2018
   */
2019
0
  WINPR_ASSERT(cellInfo);
2020
0
  info = (cellInfo->numEntries | (((UINT32)cellInfo->persistent << 31) & 0xFF000000));
2021
0
  Stream_Write_UINT32(s, info);
2022
0
}
2023
2024
static BOOL rdp_apply_bitmap_cache_v2_capability_set(rdpSettings* settings, const rdpSettings* src)
2025
0
{
2026
0
  const FreeRDP_Settings_Keys_Bool keys[] = { FreeRDP_BitmapCacheEnabled,
2027
0
                                            FreeRDP_BitmapCachePersistEnabled };
2028
2029
0
  for (size_t x = 0; x < ARRAYSIZE(keys); x++)
2030
0
  {
2031
0
    const FreeRDP_Settings_Keys_Bool id = keys[x];
2032
0
    const BOOL val = freerdp_settings_get_bool(src, id);
2033
0
    if (!freerdp_settings_set_bool(settings, id, val))
2034
0
      return FALSE;
2035
0
  }
2036
2037
0
  {
2038
0
    const UINT32 BitmapCacheV2NumCells =
2039
0
        freerdp_settings_get_uint32(src, FreeRDP_BitmapCacheV2NumCells);
2040
0
    if (!freerdp_settings_set_pointer_len(settings, FreeRDP_BitmapCacheV2CellInfo, nullptr,
2041
0
                                          BitmapCacheV2NumCells))
2042
0
      return FALSE;
2043
2044
0
    for (size_t x = 0; x < BitmapCacheV2NumCells; x++)
2045
0
    {
2046
0
      const BITMAP_CACHE_V2_CELL_INFO* cdata =
2047
0
          freerdp_settings_get_pointer_array(src, FreeRDP_BitmapCacheV2CellInfo, x);
2048
0
      if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, x,
2049
0
                                              cdata))
2050
0
        return FALSE;
2051
0
    }
2052
0
  }
2053
2054
0
  return TRUE;
2055
0
}
2056
2057
/*
2058
 * Read bitmap cache v2 capability set.
2059
 * msdn{cc240560}
2060
 */
2061
2062
static BOOL rdp_read_bitmap_cache_v2_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2063
0
{
2064
0
  UINT16 cacheFlags = 0;
2065
0
  WINPR_UNUSED(settings);
2066
0
  WINPR_ASSERT(settings);
2067
2068
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2069
0
    return FALSE;
2070
2071
0
  Stream_Read_UINT16(s, cacheFlags); /* cacheFlags (2 bytes) */
2072
2073
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE))
2074
0
    return FALSE;
2075
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
2076
0
                                 cacheFlags & PERSISTENT_KEYS_EXPECTED_FLAG))
2077
0
    return FALSE;
2078
2079
0
  Stream_Seek_UINT8(s);                                  /* pad2 (1 byte) */
2080
0
  Stream_Read_UINT8(s, settings->BitmapCacheV2NumCells); /* numCellCaches (1 byte) */
2081
0
  if (settings->BitmapCacheV2NumCells > 5)
2082
0
  {
2083
0
    WLog_Print(log, WLOG_ERROR,
2084
0
               "Invalid TS_BITMAPCACHE_CAPABILITYSET_REV2::numCellCaches %" PRIu32 " > 5",
2085
0
               settings->BitmapCacheV2NumCells);
2086
0
    return FALSE;
2087
0
  }
2088
2089
0
  for (size_t x = 0; x < settings->BitmapCacheV2NumCells; x++)
2090
0
  {
2091
0
    BITMAP_CACHE_V2_CELL_INFO* info =
2092
0
        freerdp_settings_get_pointer_array_writable(settings, FreeRDP_BitmapCacheV2CellInfo, x);
2093
0
    if (!rdp_read_bitmap_cache_cell_info(log, s, info))
2094
0
      return FALSE;
2095
0
  }
2096
2097
  /* Input must always have 5 BitmapCacheV2CellInfo values */
2098
0
  for (size_t x = settings->BitmapCacheV2NumCells; x < 5; x++)
2099
0
  {
2100
0
    if (!Stream_SafeSeek(s, 4))
2101
0
      return FALSE;
2102
0
  }
2103
0
  Stream_Seek(s, 12); /* pad3 (12 bytes) */
2104
0
  return TRUE;
2105
0
}
2106
2107
/*
2108
 * Write bitmap cache v2 capability set.
2109
 * msdn{cc240560}
2110
 */
2111
2112
static BOOL rdp_write_bitmap_cache_v2_capability_set(wLog* log, wStream* s,
2113
                                                     const rdpSettings* settings)
2114
0
{
2115
0
  WINPR_ASSERT(settings);
2116
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
2117
0
    return FALSE;
2118
2119
0
  const size_t header = rdp_capability_set_start(log, s);
2120
0
  UINT16 cacheFlags = ALLOW_CACHE_WAITING_LIST_FLAG;
2121
2122
0
  if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
2123
0
  {
2124
0
    cacheFlags |= PERSISTENT_KEYS_EXPECTED_FLAG;
2125
0
    settings->BitmapCacheV2CellInfo[0].persistent = 1;
2126
0
    settings->BitmapCacheV2CellInfo[1].persistent = 1;
2127
0
    settings->BitmapCacheV2CellInfo[2].persistent = 1;
2128
0
    settings->BitmapCacheV2CellInfo[3].persistent = 1;
2129
0
    settings->BitmapCacheV2CellInfo[4].persistent = 1;
2130
0
  }
2131
2132
0
  Stream_Write_UINT16(s, cacheFlags);                     /* cacheFlags (2 bytes) */
2133
0
  Stream_Write_UINT8(s, 0);                               /* pad2 (1 byte) */
2134
0
  Stream_Write_UINT8(
2135
0
      s, WINPR_ASSERTING_INT_CAST(uint8_t,
2136
0
                                  settings->BitmapCacheV2NumCells)); /* numCellCaches (1 byte) */
2137
0
  rdp_write_bitmap_cache_cell_info(
2138
0
      s, &settings->BitmapCacheV2CellInfo[0]); /* bitmapCache0CellInfo (4 bytes) */
2139
0
  rdp_write_bitmap_cache_cell_info(
2140
0
      s, &settings->BitmapCacheV2CellInfo[1]); /* bitmapCache1CellInfo (4 bytes) */
2141
0
  rdp_write_bitmap_cache_cell_info(
2142
0
      s, &settings->BitmapCacheV2CellInfo[2]); /* bitmapCache2CellInfo (4 bytes) */
2143
0
  rdp_write_bitmap_cache_cell_info(
2144
0
      s, &settings->BitmapCacheV2CellInfo[3]); /* bitmapCache3CellInfo (4 bytes) */
2145
0
  rdp_write_bitmap_cache_cell_info(
2146
0
      s, &settings->BitmapCacheV2CellInfo[4]); /* bitmapCache4CellInfo (4 bytes) */
2147
0
  Stream_Zero(s, 12);                          /* pad3 (12 bytes) */
2148
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V2);
2149
0
}
2150
2151
#ifdef WITH_DEBUG_CAPABILITIES
2152
static BOOL rdp_print_bitmap_cache_v2_capability_set(wLog* log, wStream* s)
2153
{
2154
  BITMAP_CACHE_V2_CELL_INFO bitmapCacheV2CellInfo[5] = WINPR_C_ARRAY_INIT;
2155
  WLog_Print(log, WLOG_TRACE,
2156
             "BitmapCacheV2CapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2157
2158
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2159
    return FALSE;
2160
2161
  const UINT16 cacheFlags = Stream_Get_UINT16(s);  /* cacheFlags (2 bytes) */
2162
  const UINT8 pad2 = Stream_Get_UINT8(s);          /* pad2 (1 byte) */
2163
  const UINT8 numCellCaches = Stream_Get_UINT8(s); /* numCellCaches (1 byte) */
2164
2165
  for (size_t x = 0; x < ARRAYSIZE(bitmapCacheV2CellInfo); x++)
2166
  {
2167
    if (!rdp_read_bitmap_cache_cell_info(
2168
            log, s, &bitmapCacheV2CellInfo[x])) /* bitmapCache0CellInfo (4 bytes) */
2169
      return FALSE;
2170
  }
2171
2172
  if (!Stream_SafeSeek(s, 12)) /* pad3 (12 bytes) */
2173
    return FALSE;
2174
2175
  WLog_Print(log, WLOG_TRACE, "\tcacheFlags: 0x%04" PRIX16 "", cacheFlags);
2176
  WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%02" PRIX8 "", pad2);
2177
  WLog_Print(log, WLOG_TRACE, "\tnumCellCaches: 0x%02" PRIX8 "", numCellCaches);
2178
  for (size_t x = 0; x < ARRAYSIZE(bitmapCacheV2CellInfo); x++)
2179
  {
2180
    const BITMAP_CACHE_V2_CELL_INFO* info = &bitmapCacheV2CellInfo[x];
2181
    WLog_Print(log, WLOG_TRACE,
2182
               "\tbitmapCache%" PRIuz "CellInfo: numEntries: %" PRIu32 " persistent: %" PRId32
2183
               "",
2184
               x, info->numEntries, info->persistent);
2185
  }
2186
  return TRUE;
2187
}
2188
#endif
2189
2190
static BOOL rdp_apply_virtual_channel_capability_set(rdpSettings* settings, const rdpSettings* src)
2191
0
{
2192
0
  WINPR_ASSERT(settings);
2193
0
  WINPR_ASSERT(src);
2194
2195
  /* MS servers and clients disregard in advertising what is relevant for their own side */
2196
0
  if (settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_SC) &&
2197
0
      (src->VCFlags & VCCAPS_COMPR_SC))
2198
0
    settings->VCFlags |= VCCAPS_COMPR_SC;
2199
0
  else
2200
0
    settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_SC;
2201
2202
0
  if (!settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_CS_8K) &&
2203
0
      (src->VCFlags & VCCAPS_COMPR_CS_8K))
2204
0
    settings->VCFlags |= VCCAPS_COMPR_CS_8K;
2205
0
  else
2206
0
    settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_CS_8K;
2207
2208
  /*
2209
   * When one peer does not write the VCChunkSize, the VCChunkSize must not be
2210
   * larger than CHANNEL_CHUNK_LENGTH (1600) bytes.
2211
   * Also prevent an invalid 0 size.
2212
   */
2213
0
  if (!settings->ServerMode)
2214
0
  {
2215
0
    if ((src->VCChunkSize > CHANNEL_CHUNK_MAX_LENGTH) || (src->VCChunkSize == 0))
2216
0
      settings->VCChunkSize = CHANNEL_CHUNK_LENGTH;
2217
0
    else
2218
0
    {
2219
0
      settings->VCChunkSize = src->VCChunkSize;
2220
0
    }
2221
0
  }
2222
2223
0
  return TRUE;
2224
0
}
2225
2226
/*
2227
 * Read virtual channel capability set.
2228
 * msdn{cc240551}
2229
 */
2230
2231
static BOOL rdp_read_virtual_channel_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2232
0
{
2233
0
  UINT32 flags = 0;
2234
0
  UINT32 VCChunkSize = 0;
2235
2236
0
  WINPR_ASSERT(settings);
2237
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2238
0
    return FALSE;
2239
2240
0
  Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2241
2242
0
  if (Stream_GetRemainingLength(s) >= 4)
2243
0
    Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2244
0
  else
2245
0
    VCChunkSize = UINT32_MAX; /* Use an invalid value to determine that value is not present */
2246
2247
0
  settings->VCFlags = flags;
2248
0
  settings->VCChunkSize = VCChunkSize;
2249
2250
0
  return TRUE;
2251
0
}
2252
2253
/*
2254
 * Write virtual channel capability set.
2255
 * msdn{cc240551}
2256
 */
2257
2258
static BOOL rdp_write_virtual_channel_capability_set(wLog* log, wStream* s,
2259
                                                     const rdpSettings* settings)
2260
0
{
2261
0
  WINPR_ASSERT(settings);
2262
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2263
0
    return FALSE;
2264
2265
0
  const size_t header = rdp_capability_set_start(log, s);
2266
0
  Stream_Write_UINT32(s, settings->VCFlags);     /* flags (4 bytes) */
2267
0
  Stream_Write_UINT32(s, settings->VCChunkSize); /* VCChunkSize (4 bytes) */
2268
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_VIRTUAL_CHANNEL);
2269
0
}
2270
2271
#ifdef WITH_DEBUG_CAPABILITIES
2272
static BOOL rdp_print_virtual_channel_capability_set(wLog* log, wStream* s)
2273
{
2274
  UINT32 flags = 0;
2275
  UINT32 VCChunkSize = 0;
2276
  WLog_Print(log, WLOG_TRACE,
2277
             "VirtualChannelCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2278
2279
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2280
    return FALSE;
2281
2282
  Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2283
2284
  if (Stream_GetRemainingLength(s) >= 4)
2285
    Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2286
  else
2287
    VCChunkSize = 1600;
2288
2289
  WLog_Print(log, WLOG_TRACE, "\tflags: 0x%08" PRIX32 "", flags);
2290
  WLog_Print(log, WLOG_TRACE, "\tVCChunkSize: 0x%08" PRIX32 "", VCChunkSize);
2291
  return TRUE;
2292
}
2293
#endif
2294
2295
static BOOL rdp_apply_draw_nine_grid_cache_capability_set(rdpSettings* settings,
2296
                                                          const rdpSettings* src)
2297
0
{
2298
0
  WINPR_ASSERT(settings);
2299
0
  WINPR_ASSERT(src);
2300
2301
0
  settings->DrawNineGridCacheSize = src->DrawNineGridCacheSize;
2302
0
  settings->DrawNineGridCacheEntries = src->DrawNineGridCacheEntries;
2303
0
  settings->DrawNineGridEnabled = src->DrawNineGridEnabled;
2304
2305
0
  return TRUE;
2306
0
}
2307
2308
/*
2309
 * Read drawn nine grid cache capability set.
2310
 * msdn{cc241565}
2311
 */
2312
2313
static BOOL rdp_read_draw_nine_grid_cache_capability_set(wLog* log, wStream* s,
2314
                                                         rdpSettings* settings)
2315
0
{
2316
0
  UINT32 drawNineGridSupportLevel = 0;
2317
2318
0
  WINPR_ASSERT(settings);
2319
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2320
0
    return FALSE;
2321
2322
0
  Stream_Read_UINT32(s, drawNineGridSupportLevel);        /* drawNineGridSupportLevel (4 bytes) */
2323
0
  Stream_Read_UINT16(s, settings->DrawNineGridCacheSize); /* drawNineGridCacheSize (2 bytes) */
2324
0
  Stream_Read_UINT16(s,
2325
0
                     settings->DrawNineGridCacheEntries); /* drawNineGridCacheEntries (2 bytes) */
2326
2327
0
  settings->DrawNineGridEnabled =
2328
0
      (drawNineGridSupportLevel & (DRAW_NINEGRID_SUPPORTED | DRAW_NINEGRID_SUPPORTED_V2)) != 0;
2329
2330
0
  return TRUE;
2331
0
}
2332
2333
/*
2334
 * Write drawn nine grid cache capability set.
2335
 * msdn{cc241565}
2336
 */
2337
2338
static BOOL rdp_write_draw_nine_grid_cache_capability_set(wLog* log, wStream* s,
2339
                                                          const rdpSettings* settings)
2340
0
{
2341
0
  WINPR_ASSERT(settings);
2342
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2343
0
    return FALSE;
2344
2345
0
  const size_t header = rdp_capability_set_start(log, s);
2346
0
  const UINT32 drawNineGridSupportLevel =
2347
0
      (settings->DrawNineGridEnabled) ? DRAW_NINEGRID_SUPPORTED_V2 : DRAW_NINEGRID_NO_SUPPORT;
2348
0
  Stream_Write_UINT32(s, drawNineGridSupportLevel); /* drawNineGridSupportLevel (4 bytes) */
2349
0
  Stream_Write_UINT16(
2350
0
      s, WINPR_ASSERTING_INT_CAST(
2351
0
             uint16_t, settings->DrawNineGridCacheSize)); /* drawNineGridCacheSize (2 bytes) */
2352
0
  Stream_Write_UINT16(
2353
0
      s,
2354
0
      WINPR_ASSERTING_INT_CAST(
2355
0
          uint16_t, settings->DrawNineGridCacheEntries)); /* drawNineGridCacheEntries (2 bytes) */
2356
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_DRAW_NINE_GRID_CACHE);
2357
0
}
2358
2359
#ifdef WITH_DEBUG_CAPABILITIES
2360
static BOOL rdp_print_draw_nine_grid_cache_capability_set(wLog* log, wStream* s)
2361
{
2362
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2363
    return FALSE;
2364
2365
  const uint32_t drawNineGridSupportLevel =
2366
      Stream_Get_UINT32(s); /* drawNineGridSupportLevel (4 bytes) */
2367
  const uint32_t DrawNineGridCacheSize =
2368
      Stream_Get_UINT16(s); /* drawNineGridCacheSize (2 bytes) */
2369
  const uint32_t DrawNineGridCacheEntries =
2370
      Stream_Get_UINT16(s); /* drawNineGridCacheEntries (2 bytes) */
2371
2372
  WLog_Print(log, WLOG_TRACE,
2373
             "DrawNineGridCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2374
  WLog_Print(log, WLOG_TRACE, "drawNineGridSupportLevel=0x%08" PRIx32, drawNineGridSupportLevel);
2375
  WLog_Print(log, WLOG_TRACE, "DrawNineGridCacheSize=0x%08" PRIx32, DrawNineGridCacheSize);
2376
  WLog_Print(log, WLOG_TRACE, "DrawNineGridCacheEntries=0x%08" PRIx32, DrawNineGridCacheEntries);
2377
  return TRUE;
2378
}
2379
#endif
2380
2381
static BOOL rdp_apply_draw_gdiplus_cache_capability_set(rdpSettings* settings,
2382
                                                        const rdpSettings* src)
2383
0
{
2384
0
  WINPR_ASSERT(settings);
2385
0
  WINPR_ASSERT(src);
2386
2387
0
  if (src->DrawGdiPlusEnabled)
2388
0
    settings->DrawGdiPlusEnabled = TRUE;
2389
2390
0
  if (src->DrawGdiPlusCacheEnabled)
2391
0
    settings->DrawGdiPlusCacheEnabled = TRUE;
2392
2393
0
  return TRUE;
2394
0
}
2395
2396
/*
2397
 * Read GDI+ cache capability set.
2398
 * msdn{cc241566}
2399
 */
2400
2401
static BOOL rdp_read_draw_gdiplus_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2402
0
{
2403
0
  UINT32 drawGDIPlusSupportLevel = 0;
2404
0
  UINT32 drawGdiplusCacheLevel = 0;
2405
2406
0
  WINPR_ASSERT(settings);
2407
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2408
0
    return FALSE;
2409
2410
0
  Stream_Read_UINT32(s, drawGDIPlusSupportLevel); /* drawGDIPlusSupportLevel (4 bytes) */
2411
0
  Stream_Seek_UINT32(s);                          /* GdipVersion (4 bytes) */
2412
0
  Stream_Read_UINT32(s, drawGdiplusCacheLevel);   /* drawGdiplusCacheLevel (4 bytes) */
2413
0
  Stream_Seek(s, 10);                             /* GdipCacheEntries (10 bytes) */
2414
0
  Stream_Seek(s, 8);                              /* GdipCacheChunkSize (8 bytes) */
2415
0
  Stream_Seek(s, 6);                              /* GdipImageCacheProperties (6 bytes) */
2416
2417
0
  settings->DrawGdiPlusEnabled = (drawGDIPlusSupportLevel & DRAW_GDIPLUS_SUPPORTED) != 0;
2418
0
  settings->DrawGdiPlusCacheEnabled = (drawGdiplusCacheLevel & DRAW_GDIPLUS_CACHE_LEVEL_ONE) != 0;
2419
2420
0
  return TRUE;
2421
0
}
2422
2423
#ifdef WITH_DEBUG_CAPABILITIES
2424
static BOOL rdp_print_draw_gdiplus_cache_capability_set(wLog* log, wStream* s)
2425
{
2426
  WLog_Print(log, WLOG_TRACE,
2427
             "DrawGdiPlusCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2428
2429
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2430
    return FALSE;
2431
2432
  const uint32_t drawGdiPlusSupportLevel =
2433
      Stream_Get_UINT32(s);                          /* drawGdiPlusSupportLevel (4 bytes) */
2434
  const uint32_t GdipVersion = Stream_Get_UINT32(s); /* GdipVersion (4 bytes) */
2435
  const uint32_t drawGdiplusCacheLevel =
2436
      Stream_Get_UINT32(s); /* drawGdiPlusCacheLevel (4 bytes) */
2437
  WLog_Print(log, WLOG_TRACE,
2438
             "drawGdiPlusSupportLevel=0x%08" PRIx32 ", GdipVersion=0x%08" PRIx32
2439
             ", drawGdiplusdrawGdiplusCacheLevelCacheLevel=0x%08" PRIx32,
2440
             drawGdiPlusSupportLevel, GdipVersion, drawGdiplusCacheLevel);
2441
  /* GdipCacheEntries (10 bytes) */
2442
  const uint16_t GdipGraphicsCacheEntries = Stream_Get_UINT16(s);
2443
  const uint16_t GdipBrushCacheEntries = Stream_Get_UINT16(s);
2444
  const uint16_t GdipPenCacheEntries = Stream_Get_UINT16(s);
2445
  const uint16_t GdipImageCacheEntries = Stream_Get_UINT16(s);
2446
  const uint16_t GdipImageAttributesCacheEntries = Stream_Get_UINT16(s);
2447
  WLog_Print(log, WLOG_TRACE,
2448
             "GdipGraphicsCacheEntries=0x%04" PRIx16 ", GdipBrushCacheEntries=0x%04" PRIx16
2449
             ", GdipPenCacheEntries=0x%04" PRIx16 ", GdipImageCacheEntries=0x%04" PRIx16
2450
             ", GdipImageAttributesCacheEntries=0x%04" PRIx16,
2451
             GdipGraphicsCacheEntries, GdipBrushCacheEntries, GdipPenCacheEntries,
2452
             GdipImageCacheEntries, GdipImageAttributesCacheEntries);
2453
  /* GdipCacheChunkSize (8 bytes) */
2454
  const uint16_t GdipGraphicsCacheChunkSize = Stream_Get_UINT16(s);
2455
  const uint16_t GdipObjectBrushCacheChunkSize = Stream_Get_UINT16(s);
2456
  const uint16_t GdipObjectPenCacheChunkSize = Stream_Get_UINT16(s);
2457
  const uint16_t GdipObjectImageAttributesCacheChunkSize = Stream_Get_UINT16(s);
2458
  WLog_Print(log, WLOG_TRACE,
2459
             "GdipGraphicsCacheChunkSize=0x%04" PRIx16
2460
             ", GdipObjectBrushCacheChunkSize=0x%04" PRIx16
2461
             ", GdipObjectPenCacheChunkSize=0x%04" PRIx16
2462
             ",GdipObjectImageAttributesCacheChunkSize=0x%04" PRIx16,
2463
             GdipGraphicsCacheChunkSize, GdipObjectBrushCacheChunkSize,
2464
             GdipObjectPenCacheChunkSize, GdipObjectImageAttributesCacheChunkSize);
2465
  /* GdipImageCacheProperties (6 bytes) */
2466
  const uint16_t GdipObjectImageCacheChunkSize = Stream_Get_UINT16(s);
2467
  const uint16_t GdipObjectImageCacheTotalSize = Stream_Get_UINT16(s);
2468
  const uint16_t GdipObjectImageCacheMaxSize = Stream_Get_UINT16(s);
2469
  WLog_Print(
2470
      log, WLOG_TRACE,
2471
      "GdipObjectImageCacheChunkSize=0x%04" PRIx16 ", GdipObjectImageCacheTotalSize=0x%04" PRIx16
2472
      ", GdipObjectImageCacheMaxSize=0x%04" PRIx16,
2473
      GdipObjectImageCacheChunkSize, GdipObjectImageCacheTotalSize, GdipObjectImageCacheMaxSize);
2474
  return TRUE;
2475
}
2476
#endif
2477
2478
static BOOL rdp_apply_remote_programs_capability_set(rdpSettings* settings, const rdpSettings* src)
2479
0
{
2480
0
  WINPR_ASSERT(settings);
2481
0
  WINPR_ASSERT(src);
2482
2483
0
  if (settings->RemoteApplicationMode)
2484
0
    settings->RemoteApplicationMode = src->RemoteApplicationMode;
2485
2486
  /* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX)
2487
   * the handshake ex pdu is supported when both, client and server announce
2488
   * it OR if we are ready to begin enhanced remoteAPP mode. */
2489
0
  UINT32 supportLevel = src->RemoteApplicationSupportLevel;
2490
0
  if (settings->RemoteApplicationMode)
2491
0
    supportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2492
2493
0
  settings->RemoteApplicationSupportLevel = supportLevel & settings->RemoteApplicationSupportMask;
2494
2495
0
  return TRUE;
2496
0
}
2497
2498
/*
2499
 * Read remote programs capability set.
2500
 * msdn{cc242518}
2501
 */
2502
2503
static BOOL rdp_read_remote_programs_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2504
0
{
2505
0
  UINT32 railSupportLevel = 0;
2506
2507
0
  WINPR_ASSERT(settings);
2508
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2509
0
    return FALSE;
2510
2511
0
  Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2512
2513
0
  settings->RemoteApplicationMode = (railSupportLevel & RAIL_LEVEL_SUPPORTED) != 0;
2514
0
  settings->RemoteApplicationSupportLevel = railSupportLevel;
2515
0
  return TRUE;
2516
0
}
2517
2518
/*
2519
 * Write remote programs capability set.
2520
 * msdn{cc242518}
2521
 */
2522
2523
static BOOL rdp_write_remote_programs_capability_set(wLog* log, wStream* s,
2524
                                                     const rdpSettings* settings)
2525
0
{
2526
0
  WINPR_ASSERT(settings);
2527
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
2528
0
    return FALSE;
2529
2530
0
  const size_t header = rdp_capability_set_start(log, s);
2531
0
  UINT32 railSupportLevel = RAIL_LEVEL_SUPPORTED;
2532
2533
0
  if (settings->RemoteApplicationSupportLevel & RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED)
2534
0
  {
2535
0
    if (settings->RemoteAppLanguageBarSupported)
2536
0
      railSupportLevel |= RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED;
2537
0
  }
2538
2539
0
  railSupportLevel |= RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED;
2540
0
  railSupportLevel |= RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED;
2541
0
  railSupportLevel |= RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED;
2542
0
  railSupportLevel |= RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED;
2543
0
  railSupportLevel |= RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED;
2544
0
  railSupportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2545
  /* Mask out everything the server does not support. */
2546
0
  railSupportLevel &= settings->RemoteApplicationSupportLevel;
2547
0
  Stream_Write_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2548
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_RAIL);
2549
0
}
2550
2551
#ifdef WITH_DEBUG_CAPABILITIES
2552
static BOOL rdp_print_remote_programs_capability_set(wLog* log, wStream* s)
2553
{
2554
  UINT32 railSupportLevel = 0;
2555
  WLog_Print(log, WLOG_TRACE,
2556
             "RemoteProgramsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2557
2558
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2559
    return FALSE;
2560
2561
  Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2562
  WLog_Print(log, WLOG_TRACE, "\trailSupportLevel: 0x%08" PRIX32 "", railSupportLevel);
2563
  return TRUE;
2564
}
2565
#endif
2566
2567
static BOOL rdp_apply_window_list_capability_set(rdpSettings* settings, const rdpSettings* src)
2568
0
{
2569
0
  WINPR_ASSERT(settings);
2570
0
  WINPR_ASSERT(src);
2571
2572
0
  settings->RemoteWndSupportLevel = src->RemoteWndSupportLevel;
2573
0
  settings->RemoteAppNumIconCaches = src->RemoteAppNumIconCaches;
2574
0
  settings->RemoteAppNumIconCacheEntries = src->RemoteAppNumIconCacheEntries;
2575
2576
0
  return TRUE;
2577
0
}
2578
2579
/*
2580
 * Read window list capability set.
2581
 * msdn{cc242564}
2582
 */
2583
2584
static BOOL rdp_read_window_list_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2585
0
{
2586
0
  WINPR_ASSERT(settings);
2587
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2588
0
    return FALSE;
2589
2590
0
  Stream_Read_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2591
0
  Stream_Read_UINT8(s, settings->RemoteAppNumIconCaches); /* numIconCaches (1 byte) */
2592
0
  Stream_Read_UINT16(s,
2593
0
                     settings->RemoteAppNumIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2594
0
  return TRUE;
2595
0
}
2596
2597
/*
2598
 * Write window list capability set.
2599
 * msdn{cc242564}
2600
 */
2601
2602
static BOOL rdp_write_window_list_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
2603
0
{
2604
0
  WINPR_ASSERT(settings);
2605
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2606
0
    return FALSE;
2607
2608
0
  const size_t header = rdp_capability_set_start(log, s);
2609
0
  Stream_Write_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2610
0
  Stream_Write_UINT8(
2611
0
      s, WINPR_ASSERTING_INT_CAST(uint8_t,
2612
0
                                  settings->RemoteAppNumIconCaches)); /* numIconCaches (1 byte) */
2613
0
  Stream_Write_UINT16(
2614
0
      s,
2615
0
      WINPR_ASSERTING_INT_CAST(
2616
0
          uint16_t, settings->RemoteAppNumIconCacheEntries)); /* numIconCacheEntries (2 bytes) */
2617
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_WINDOW);
2618
0
}
2619
2620
#ifdef WITH_DEBUG_CAPABILITIES
2621
static BOOL rdp_print_window_list_capability_set(wLog* log, wStream* s)
2622
{
2623
  UINT32 wndSupportLevel = 0;
2624
  BYTE numIconCaches = 0;
2625
  UINT16 numIconCacheEntries = 0;
2626
  WLog_Print(log, WLOG_TRACE,
2627
             "WindowListCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2628
2629
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2630
    return FALSE;
2631
2632
  Stream_Read_UINT32(s, wndSupportLevel);     /* wndSupportLevel (4 bytes) */
2633
  Stream_Read_UINT8(s, numIconCaches);        /* numIconCaches (1 byte) */
2634
  Stream_Read_UINT16(s, numIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2635
  WLog_Print(log, WLOG_TRACE, "\twndSupportLevel: 0x%08" PRIX32 "", wndSupportLevel);
2636
  WLog_Print(log, WLOG_TRACE, "\tnumIconCaches: 0x%02" PRIX8 "", numIconCaches);
2637
  WLog_Print(log, WLOG_TRACE, "\tnumIconCacheEntries: 0x%04" PRIX16 "", numIconCacheEntries);
2638
  return TRUE;
2639
}
2640
#endif
2641
2642
static BOOL rdp_apply_desktop_composition_capability_set(rdpSettings* settings,
2643
                                                         const rdpSettings* src)
2644
0
{
2645
0
  WINPR_ASSERT(settings);
2646
0
  WINPR_ASSERT(src);
2647
2648
0
  settings->CompDeskSupportLevel = src->CompDeskSupportLevel;
2649
0
  return TRUE;
2650
0
}
2651
2652
/*
2653
 * Read desktop composition capability set.
2654
 * msdn{cc240855}
2655
 */
2656
2657
static BOOL rdp_read_desktop_composition_capability_set(wLog* log, wStream* s,
2658
                                                        rdpSettings* settings)
2659
0
{
2660
0
  WINPR_UNUSED(settings);
2661
0
  WINPR_ASSERT(settings);
2662
2663
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2664
0
    return FALSE;
2665
2666
0
  Stream_Read_UINT16(s, settings->CompDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2667
0
  return TRUE;
2668
0
}
2669
2670
/*
2671
 * Write desktop composition capability set.
2672
 * msdn{cc240855}
2673
 */
2674
2675
static BOOL rdp_write_desktop_composition_capability_set(wLog* log, wStream* s,
2676
                                                         const rdpSettings* settings)
2677
0
{
2678
0
  WINPR_ASSERT(settings);
2679
2680
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2681
0
    return FALSE;
2682
2683
0
  const size_t header = rdp_capability_set_start(log, s);
2684
0
  const UINT16 compDeskSupportLevel =
2685
0
      (settings->AllowDesktopComposition) ? COMPDESK_SUPPORTED : COMPDESK_NOT_SUPPORTED;
2686
0
  Stream_Write_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2687
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_COMP_DESK);
2688
0
}
2689
2690
#ifdef WITH_DEBUG_CAPABILITIES
2691
static BOOL rdp_print_desktop_composition_capability_set(wLog* log, wStream* s)
2692
{
2693
  UINT16 compDeskSupportLevel = 0;
2694
  WLog_Print(log, WLOG_TRACE, "DesktopCompositionCapabilitySet (length %" PRIuz "):",
2695
             Stream_GetRemainingLength(s));
2696
2697
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2698
    return FALSE;
2699
2700
  Stream_Read_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2701
  WLog_Print(log, WLOG_TRACE, "\tcompDeskSupportLevel: 0x%04" PRIX16 "", compDeskSupportLevel);
2702
  return TRUE;
2703
}
2704
#endif
2705
2706
static BOOL rdp_apply_multifragment_update_capability_set(rdpSettings* settings,
2707
                                                          const rdpSettings* src)
2708
0
{
2709
0
  WINPR_ASSERT(settings);
2710
0
  WINPR_ASSERT(src);
2711
2712
0
  UINT32 multifragMaxRequestSize =
2713
0
      freerdp_settings_get_uint32(src, FreeRDP_MultifragMaxRequestSize);
2714
2715
0
  if (settings->ServerMode)
2716
0
  {
2717
    /*
2718
     * Special case: The client announces multifragment update support but sets the maximum
2719
     * request size to something smaller than maximum size for *one* fast-path PDU. In this case
2720
     * behave like no multifragment updates were supported and make sure no fragmentation
2721
     * happens by setting FASTPATH_FRAGMENT_SAFE_SIZE.
2722
     *
2723
     * This behaviour was observed with some windows ce rdp clients.
2724
     */
2725
0
    if (multifragMaxRequestSize < FASTPATH_MAX_PACKET_SIZE)
2726
0
      multifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE;
2727
2728
0
    if (settings->RemoteFxCodec)
2729
0
    {
2730
      /*
2731
       * If we are using RemoteFX the client MUST use a value greater
2732
       * than or equal to the value we've previously sent in the server to
2733
       * client multi-fragment update capability set (MS-RDPRFX 1.5)
2734
       */
2735
0
      if (multifragMaxRequestSize <
2736
0
          freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize))
2737
0
      {
2738
        /*
2739
         * If it happens to be smaller we honor the client's value but
2740
         * have to disable RemoteFX
2741
         */
2742
0
        settings->RemoteFxCodec = FALSE;
2743
0
        if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2744
0
                                         multifragMaxRequestSize))
2745
0
          return FALSE;
2746
0
      }
2747
0
      else
2748
0
      {
2749
        /* no need to increase server's max request size setting here */
2750
0
      }
2751
0
    }
2752
0
    else
2753
0
    {
2754
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2755
0
                                       multifragMaxRequestSize))
2756
0
        return FALSE;
2757
0
    }
2758
0
  }
2759
0
  else
2760
0
  {
2761
    /*
2762
     * In client mode we keep up with the server's capabilities.
2763
     * In RemoteFX mode we MUST do this but it might also be useful to
2764
     * receive larger related bitmap updates.
2765
     */
2766
0
    if (multifragMaxRequestSize >
2767
0
        freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize))
2768
0
    {
2769
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2770
0
                                       multifragMaxRequestSize))
2771
0
        return FALSE;
2772
0
    }
2773
0
  }
2774
0
  return TRUE;
2775
0
}
2776
2777
/*
2778
 * Read multifragment update capability set.
2779
 * msdn{cc240649}
2780
 */
2781
2782
static BOOL rdp_read_multifragment_update_capability_set(wLog* log, wStream* s,
2783
                                                         rdpSettings* settings)
2784
0
{
2785
0
  WINPR_ASSERT(settings);
2786
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2787
0
    return FALSE;
2788
2789
0
  const UINT32 multifragMaxRequestSize = Stream_Get_UINT32(s); /* MaxRequestSize (4 bytes) */
2790
0
  return freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2791
0
                                     multifragMaxRequestSize);
2792
0
}
2793
2794
/*
2795
 * Write multifragment update capability set.
2796
 * msdn{cc240649}
2797
 */
2798
2799
static BOOL rdp_write_multifragment_update_capability_set(wLog* log, wStream* s,
2800
                                                          rdpSettings* settings)
2801
0
{
2802
0
  WINPR_ASSERT(settings);
2803
0
  if (settings->ServerMode &&
2804
0
      (freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize) == 0))
2805
0
  {
2806
    /*
2807
     * In server mode we prefer to use the highest useful request size that
2808
     * will allow us to pack a complete screen update into a single fast
2809
     * path PDU using any of the supported codecs.
2810
     * However, the client is completely free to accept our proposed
2811
     * max request size or send a different value in the client-to-server
2812
     * multi-fragment update capability set and we have to accept that,
2813
     * unless we are using RemoteFX where the client MUST announce a value
2814
     * greater than or equal to the value we're sending here.
2815
     * See [MS-RDPRFX 1.5 capability #2]
2816
     */
2817
0
    const UINT32 tileNumX = (settings->DesktopWidth + 63) / 64;
2818
0
    const UINT32 tileNumY = (settings->DesktopHeight + 63) / 64;
2819
0
    const UINT32 limit = UINT32_MAX / 16384u;
2820
2821
0
    if (tileNumX >= limit / tileNumY)
2822
0
    {
2823
0
      WLog_Print(log, WLOG_ERROR,
2824
0
                 "(DesktopWidth * DesktopHeigth) / 64 exceed limit of %" PRIu32, limit);
2825
0
      return FALSE;
2826
0
    }
2827
0
    if (tileNumY >= limit / tileNumX)
2828
0
    {
2829
0
      WLog_Print(log, WLOG_ERROR,
2830
0
                 "(DesktopWidth * DesktopHeigth) / 64 exceed limit of %" PRIu32, limit);
2831
0
      return FALSE;
2832
0
    }
2833
2834
    /* and add room for headers, regions, frame markers, etc. */
2835
0
    const UINT32 MultifragMaxRequestSize = (tileNumX * tileNumY + 1u) * 16384u;
2836
2837
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2838
0
                                     MultifragMaxRequestSize))
2839
0
      return FALSE;
2840
0
  }
2841
2842
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2843
0
    return FALSE;
2844
0
  const size_t header = rdp_capability_set_start(log, s);
2845
0
  Stream_Write_UINT32(s, settings->MultifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
2846
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_MULTI_FRAGMENT_UPDATE);
2847
0
}
2848
2849
#ifdef WITH_DEBUG_CAPABILITIES
2850
static BOOL rdp_print_multifragment_update_capability_set(wLog* log, wStream* s)
2851
{
2852
  UINT32 maxRequestSize = 0;
2853
  WLog_Print(log, WLOG_TRACE, "MultifragmentUpdateCapabilitySet (length %" PRIuz "):",
2854
             Stream_GetRemainingLength(s));
2855
2856
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2857
    return FALSE;
2858
2859
  Stream_Read_UINT32(s, maxRequestSize); /* maxRequestSize (4 bytes) */
2860
  WLog_Print(log, WLOG_TRACE, "\tmaxRequestSize: 0x%08" PRIX32 "", maxRequestSize);
2861
  return TRUE;
2862
}
2863
#endif
2864
2865
static BOOL rdp_apply_large_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
2866
0
{
2867
0
  WINPR_ASSERT(settings);
2868
0
  WINPR_ASSERT(src);
2869
2870
0
  settings->LargePointerFlag = src->LargePointerFlag;
2871
0
  return TRUE;
2872
0
}
2873
2874
/*
2875
 * Read large pointer capability set.
2876
 * msdn{cc240650}
2877
 */
2878
2879
static BOOL rdp_read_large_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2880
0
{
2881
0
  UINT16 largePointerSupportFlags = 0;
2882
2883
0
  WINPR_ASSERT(settings);
2884
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2885
0
    return FALSE;
2886
2887
0
  Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2888
0
  settings->LargePointerFlag &= largePointerSupportFlags;
2889
0
  if ((largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) != 0)
2890
0
  {
2891
0
    WLog_Print(
2892
0
        log, WLOG_WARN,
2893
0
        "TS_LARGE_POINTER_CAPABILITYSET with unsupported flags %04X (all flags %04X) received",
2894
0
        WINPR_CXX_COMPAT_CAST(UINT32, largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 |
2895
0
                                                                   LARGE_POINTER_FLAG_384x384)),
2896
0
        largePointerSupportFlags);
2897
0
  }
2898
0
  return TRUE;
2899
0
}
2900
2901
/*
2902
 * Write large pointer capability set.
2903
 * msdn{cc240650}
2904
 */
2905
2906
static BOOL rdp_write_large_pointer_capability_set(wLog* log, wStream* s,
2907
                                                   const rdpSettings* settings)
2908
0
{
2909
0
  WINPR_ASSERT(settings);
2910
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2911
0
    return FALSE;
2912
2913
0
  const size_t header = rdp_capability_set_start(log, s);
2914
0
  const UINT16 largePointerSupportFlags =
2915
0
      settings->LargePointerFlag & (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
2916
0
  Stream_Write_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2917
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_LARGE_POINTER);
2918
0
}
2919
2920
#ifdef WITH_DEBUG_CAPABILITIES
2921
static BOOL rdp_print_large_pointer_capability_set(wLog* log, wStream* s)
2922
{
2923
  UINT16 largePointerSupportFlags = 0;
2924
  WLog_Print(log, WLOG_TRACE,
2925
             "LargePointerCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2926
2927
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2928
    return FALSE;
2929
2930
  Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2931
  WLog_Print(log, WLOG_TRACE, "\tlargePointerSupportFlags: 0x%04" PRIX16 "",
2932
             largePointerSupportFlags);
2933
  return TRUE;
2934
}
2935
#endif
2936
2937
static BOOL rdp_apply_surface_commands_capability_set(rdpSettings* settings, const rdpSettings* src)
2938
0
{
2939
0
  WINPR_ASSERT(settings);
2940
0
  WINPR_ASSERT(src);
2941
2942
  /* [MS-RDPBCGR] 2.2.7.2.9 Surface Commands Capability Set (TS_SURFCMDS_CAPABILITYSET)
2943
   *
2944
   * disable surface commands if the remote does not support fastpath
2945
   */
2946
0
  if (src->FastPathOutput)
2947
0
  {
2948
0
    settings->SurfaceCommandsSupported &= src->SurfaceCommandsSupported;
2949
0
    settings->SurfaceCommandsEnabled = src->SurfaceCommandsEnabled;
2950
0
    settings->SurfaceFrameMarkerEnabled = src->SurfaceFrameMarkerEnabled;
2951
0
  }
2952
0
  else
2953
0
  {
2954
0
    settings->SurfaceCommandsSupported = 0;
2955
0
    settings->SurfaceCommandsEnabled = FALSE;
2956
0
    settings->SurfaceFrameMarkerEnabled = FALSE;
2957
0
  }
2958
2959
0
  return TRUE;
2960
0
}
2961
2962
/*
2963
 * Read surface commands capability set.
2964
 * msdn{dd871563}
2965
 */
2966
2967
static BOOL rdp_read_surface_commands_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2968
0
{
2969
0
  UINT32 cmdFlags = 0;
2970
2971
0
  WINPR_ASSERT(settings);
2972
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2973
0
    return FALSE;
2974
2975
0
  Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
2976
0
  Stream_Seek_UINT32(s);           /* reserved (4 bytes) */
2977
0
  settings->SurfaceCommandsSupported = cmdFlags;
2978
0
  settings->SurfaceCommandsEnabled =
2979
0
      (cmdFlags & (SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS)) != 0;
2980
0
  settings->SurfaceFrameMarkerEnabled = (cmdFlags & SURFCMDS_FRAME_MARKER) != 0;
2981
0
  return TRUE;
2982
0
}
2983
2984
/*
2985
 * Write surface commands capability set.
2986
 * msdn{dd871563}
2987
 */
2988
2989
static BOOL rdp_write_surface_commands_capability_set(wLog* log, wStream* s,
2990
                                                      const rdpSettings* settings)
2991
0
{
2992
0
  WINPR_ASSERT(settings);
2993
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2994
0
    return FALSE;
2995
2996
0
  const size_t header = rdp_capability_set_start(log, s);
2997
  // TODO: Make these configurable too
2998
0
  UINT32 cmdFlags = freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
2999
3000
0
  if (settings->SurfaceFrameMarkerEnabled)
3001
0
    cmdFlags |= SURFCMDS_FRAME_MARKER;
3002
3003
0
  Stream_Write_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3004
0
  Stream_Write_UINT32(s, 0);        /* reserved (4 bytes) */
3005
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_SURFACE_COMMANDS);
3006
0
}
3007
3008
static bool sUuidEqual(const UUID* Uuid1, const UUID* Uuid2)
3009
0
{
3010
0
  if (!Uuid1 && !Uuid2)
3011
0
    return false;
3012
3013
0
  if (Uuid1 && !Uuid2)
3014
0
    return false;
3015
3016
0
  if (!Uuid1 && Uuid2)
3017
0
    return false;
3018
3019
0
  if (Uuid1->Data1 != Uuid2->Data1)
3020
0
    return false;
3021
3022
0
  if (Uuid1->Data2 != Uuid2->Data2)
3023
0
    return false;
3024
3025
0
  if (Uuid1->Data3 != Uuid2->Data3)
3026
0
    return false;
3027
3028
0
  for (int index = 0; index < 8; index++)
3029
0
  {
3030
0
    if (Uuid1->Data4[index] != Uuid2->Data4[index])
3031
0
      return false;
3032
0
  }
3033
3034
0
  return true;
3035
0
}
3036
3037
#ifdef WITH_DEBUG_CAPABILITIES
3038
static BOOL rdp_print_surface_commands_capability_set(wLog* log, wStream* s)
3039
{
3040
  UINT32 cmdFlags = 0;
3041
  UINT32 reserved = 0;
3042
3043
  WLog_Print(log, WLOG_TRACE,
3044
             "SurfaceCommandsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3045
3046
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
3047
    return FALSE;
3048
3049
  Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3050
  Stream_Read_UINT32(s, reserved); /* reserved (4 bytes) */
3051
  WLog_Print(log, WLOG_TRACE, "\tcmdFlags: 0x%08" PRIX32 "", cmdFlags);
3052
  WLog_Print(log, WLOG_TRACE, "\treserved: 0x%08" PRIX32 "", reserved);
3053
  return TRUE;
3054
}
3055
3056
static void rdp_print_bitmap_codec_guid(wLog* log, const GUID* guid)
3057
{
3058
  WINPR_ASSERT(guid);
3059
  WLog_Print(log, WLOG_TRACE,
3060
             "%08" PRIX32 "%04" PRIX16 "%04" PRIX16 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8
3061
             "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "",
3062
             guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
3063
             guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6],
3064
             guid->Data4[7]);
3065
}
3066
3067
static char* rdp_get_bitmap_codec_guid_name(const GUID* guid)
3068
{
3069
  WINPR_ASSERT(guid);
3070
  if (sUuidEqual(guid, &CODEC_GUID_REMOTEFX))
3071
    return "CODEC_GUID_REMOTEFX";
3072
  else if (sUuidEqual(guid, &CODEC_GUID_NSCODEC))
3073
    return "CODEC_GUID_NSCODEC";
3074
  else if (sUuidEqual(guid, &CODEC_GUID_IGNORE))
3075
    return "CODEC_GUID_IGNORE";
3076
  else if (sUuidEqual(guid, &CODEC_GUID_IMAGE_REMOTEFX))
3077
    return "CODEC_GUID_IMAGE_REMOTEFX";
3078
3079
#if defined(WITH_JPEG)
3080
  else if (sUuidEqual(guid, &CODEC_GUID_JPEG))
3081
    return "CODEC_GUID_JPEG";
3082
3083
#endif
3084
  return "CODEC_GUID_UNKNOWN";
3085
}
3086
#endif
3087
3088
static BOOL rdp_read_bitmap_codec_guid(wLog* log, wStream* s, GUID* guid)
3089
0
{
3090
0
  BYTE g[16] = WINPR_C_ARRAY_INIT;
3091
3092
0
  WINPR_ASSERT(guid);
3093
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16))
3094
0
    return FALSE;
3095
0
  Stream_Read(s, g, 16);
3096
0
  guid->Data1 = ((UINT32)g[3] << 24U) | ((UINT32)g[2] << 16U) | (UINT32)(g[1] << 8U) | g[0];
3097
0
  guid->Data2 = ((g[5] << 8U) | g[4]) & 0xFFFF;
3098
0
  guid->Data3 = ((g[7] << 8U) | g[6]) & 0xFFFF;
3099
0
  guid->Data4[0] = g[8];
3100
0
  guid->Data4[1] = g[9];
3101
0
  guid->Data4[2] = g[10];
3102
0
  guid->Data4[3] = g[11];
3103
0
  guid->Data4[4] = g[12];
3104
0
  guid->Data4[5] = g[13];
3105
0
  guid->Data4[6] = g[14];
3106
0
  guid->Data4[7] = g[15];
3107
0
  return TRUE;
3108
0
}
3109
3110
static void rdp_write_bitmap_codec_guid(wStream* s, const GUID* guid)
3111
0
{
3112
0
  BYTE g[16] = WINPR_C_ARRAY_INIT;
3113
0
  WINPR_ASSERT(guid);
3114
0
  g[0] = guid->Data1 & 0xFF;
3115
0
  g[1] = (guid->Data1 >> 8) & 0xFF;
3116
0
  g[2] = (guid->Data1 >> 16) & 0xFF;
3117
0
  g[3] = (guid->Data1 >> 24) & 0xFF;
3118
0
  g[4] = (guid->Data2) & 0xFF;
3119
0
  g[5] = (guid->Data2 >> 8) & 0xFF;
3120
0
  g[6] = (guid->Data3) & 0xFF;
3121
0
  g[7] = (guid->Data3 >> 8) & 0xFF;
3122
0
  g[8] = guid->Data4[0];
3123
0
  g[9] = guid->Data4[1];
3124
0
  g[10] = guid->Data4[2];
3125
0
  g[11] = guid->Data4[3];
3126
0
  g[12] = guid->Data4[4];
3127
0
  g[13] = guid->Data4[5];
3128
0
  g[14] = guid->Data4[6];
3129
0
  g[15] = guid->Data4[7];
3130
0
  Stream_Write(s, g, 16);
3131
0
}
3132
3133
static BOOL rdp_apply_bitmap_codecs_capability_set(rdpSettings* settings, const rdpSettings* src)
3134
0
{
3135
0
  WINPR_ASSERT(settings);
3136
0
  WINPR_ASSERT(src);
3137
3138
0
  if (settings->ServerMode)
3139
0
  {
3140
3141
0
    settings->RemoteFxCodecId = src->RemoteFxCodecId;
3142
0
    settings->RemoteFxCaptureFlags = src->RemoteFxCaptureFlags;
3143
0
    settings->RemoteFxOnly = src->RemoteFxOnly;
3144
0
    settings->RemoteFxRlgrMode = src->RemoteFxRlgrMode;
3145
0
    settings->RemoteFxCodecMode = src->RemoteFxCodecMode;
3146
0
    settings->NSCodecId = src->NSCodecId;
3147
0
    settings->NSCodecAllowDynamicColorFidelity = src->NSCodecAllowDynamicColorFidelity;
3148
0
    settings->NSCodecAllowSubsampling = src->NSCodecAllowSubsampling;
3149
0
    settings->NSCodecColorLossLevel = src->NSCodecColorLossLevel;
3150
3151
    /* only enable a codec if we've announced/enabled it before */
3152
0
    settings->RemoteFxCodec = settings->RemoteFxCodec && src->RemoteFxCodecId;
3153
0
    settings->RemoteFxImageCodec = settings->RemoteFxImageCodec && src->RemoteFxImageCodec;
3154
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec,
3155
0
                                   settings->NSCodec && src->NSCodec))
3156
0
      return FALSE;
3157
0
    settings->JpegCodec = src->JpegCodec;
3158
0
  }
3159
0
  return TRUE;
3160
0
}
3161
3162
static BOOL rdp_read_codec_ts_rfx_icap(wLog* log, wStream* sub, rdpSettings* settings,
3163
                                       UINT16 icapLen)
3164
0
{
3165
0
  UINT16 version = 0;
3166
0
  UINT16 tileSize = 0;
3167
0
  BYTE codecFlags = 0;
3168
0
  BYTE colConvBits = 0;
3169
0
  BYTE transformBits = 0;
3170
0
  BYTE entropyBits = 0;
3171
  /* TS_RFX_ICAP */
3172
0
  if (icapLen != 8)
3173
0
  {
3174
0
    WLog_Print(log, WLOG_ERROR,
3175
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP size %" PRIu16
3176
0
               " unsupported, expecting size %" PRIu16 " not supported",
3177
0
               icapLen, 8u);
3178
0
    return FALSE;
3179
0
  }
3180
3181
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3182
0
    return FALSE;
3183
3184
0
  Stream_Read_UINT16(sub, version);      /* version (2 bytes) */
3185
0
  Stream_Read_UINT16(sub, tileSize);     /* tileSize (2 bytes) */
3186
0
  Stream_Read_UINT8(sub, codecFlags);    /* flags (1 byte) */
3187
0
  Stream_Read_UINT8(sub, colConvBits);   /* colConvBits (1 byte) */
3188
0
  Stream_Read_UINT8(sub, transformBits); /* transformBits (1 byte) */
3189
0
  Stream_Read_UINT8(sub, entropyBits);   /* entropyBits (1 byte) */
3190
3191
0
  if (version == 0x0009)
3192
0
  {
3193
    /* Version 0.9 */
3194
0
    if (tileSize != 0x0080)
3195
0
    {
3196
0
      WLog_Print(log, WLOG_ERROR,
3197
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3198
0
                 " tile size %" PRIu16 " not supported",
3199
0
                 version, tileSize);
3200
0
      return FALSE;
3201
0
    }
3202
0
  }
3203
0
  else if (version == 0x0100)
3204
0
  {
3205
    /* Version 1.0 */
3206
0
    if (tileSize != 0x0040)
3207
0
    {
3208
0
      WLog_Print(log, WLOG_ERROR,
3209
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3210
0
                 " tile size %" PRIu16 " not supported",
3211
0
                 version, tileSize);
3212
0
      return FALSE;
3213
0
    }
3214
0
  }
3215
0
  else
3216
0
  {
3217
0
    WLog_Print(log, WLOG_ERROR,
3218
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16 " not supported",
3219
0
               version);
3220
0
    return FALSE;
3221
0
  }
3222
3223
  /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_COL_CONV_ICT (0x1) */
3224
0
  if (colConvBits != 1)
3225
0
  {
3226
0
    WLog_Print(log, WLOG_ERROR,
3227
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::colConvBits %" PRIu8
3228
0
               " not supported, must be CLW_COL_CONV_ICT (0x1)",
3229
0
               colConvBits);
3230
0
    return FALSE;
3231
0
  }
3232
3233
  /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_XFORM_DWT_53_A (0x1) */
3234
0
  if (transformBits != 1)
3235
0
  {
3236
0
    WLog_Print(log, WLOG_ERROR,
3237
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::transformBits %" PRIu8
3238
0
               " not supported, must be CLW_XFORM_DWT_53_A (0x1)",
3239
0
               colConvBits);
3240
0
    return FALSE;
3241
0
  }
3242
3243
0
  const UINT8 CODEC_MODE = 0x02; /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP */
3244
0
  if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x00))
3245
0
    return FALSE;
3246
3247
0
  if ((codecFlags & CODEC_MODE) != 0)
3248
0
  {
3249
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x02))
3250
0
      return FALSE;
3251
0
  }
3252
0
  else if ((codecFlags & ~CODEC_MODE) != 0)
3253
0
    WLog_Print(log, WLOG_WARN,
3254
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::flags unknown value "
3255
0
               "0x%02" PRIx32,
3256
0
               WINPR_CXX_COMPAT_CAST(UINT32, (codecFlags & ~CODEC_MODE)));
3257
3258
0
  switch (entropyBits)
3259
0
  {
3260
0
    case CLW_ENTROPY_RLGR1:
3261
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR1))
3262
0
        return FALSE;
3263
0
      break;
3264
0
    case CLW_ENTROPY_RLGR3:
3265
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3))
3266
0
        return FALSE;
3267
0
      break;
3268
0
    default:
3269
0
      WLog_Print(log, WLOG_ERROR,
3270
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::entropyBits "
3271
0
                 "unsupported value 0x%02" PRIx8
3272
0
                 ", must be CLW_ENTROPY_RLGR1 (0x01) or CLW_ENTROPY_RLGR3 "
3273
0
                 "(0x04)",
3274
0
                 entropyBits);
3275
0
      return FALSE;
3276
0
  }
3277
0
  return TRUE;
3278
0
}
3279
3280
static BOOL rdp_read_codec_ts_rfx_capset(wLog* log, wStream* s, rdpSettings* settings)
3281
0
{
3282
0
  UINT16 blockType = 0;
3283
0
  UINT32 blockLen = 0;
3284
0
  BYTE rfxCodecId = 0;
3285
0
  UINT16 capsetType = 0;
3286
0
  UINT16 numIcaps = 0;
3287
0
  UINT16 icapLen = 0;
3288
3289
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
3290
0
    return FALSE;
3291
3292
  /* TS_RFX_CAPSET */
3293
0
  Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
3294
0
  Stream_Read_UINT32(s, blockLen);  /* blockLen (4 bytes) */
3295
0
  if (blockType != 0xCBC1)
3296
0
  {
3297
0
    WLog_Print(log, WLOG_ERROR,
3298
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockType[0x%04" PRIx16
3299
0
               "] != CBY_CAPSET (0xCBC1)",
3300
0
               blockType);
3301
0
    return FALSE;
3302
0
  }
3303
0
  if (blockLen < 6ull)
3304
0
  {
3305
0
    WLog_Print(log, WLOG_ERROR,
3306
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockLen[%" PRIu32 "] < 6", blockLen);
3307
0
    return FALSE;
3308
0
  }
3309
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, blockLen - 6ull))
3310
0
    return FALSE;
3311
3312
0
  wStream sbuffer = WINPR_C_ARRAY_INIT;
3313
0
  wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), blockLen - 6ull);
3314
0
  WINPR_ASSERT(sub);
3315
3316
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 7))
3317
0
    return FALSE;
3318
3319
0
  Stream_Read_UINT8(sub, rfxCodecId);  /* codecId (1 byte) */
3320
0
  Stream_Read_UINT16(sub, capsetType); /* capsetType (2 bytes) */
3321
0
  Stream_Read_UINT16(sub, numIcaps);   /* numIcaps (2 bytes) */
3322
0
  Stream_Read_UINT16(sub, icapLen);    /* icapLen (2 bytes) */
3323
3324
0
  if (rfxCodecId != 1)
3325
0
  {
3326
0
    WLog_Print(log, WLOG_ERROR,
3327
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::codecId[%" PRIu16 "] != 1", rfxCodecId);
3328
0
    return FALSE;
3329
0
  }
3330
3331
0
  if (capsetType != 0xCFC0)
3332
0
  {
3333
0
    WLog_Print(log, WLOG_ERROR,
3334
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::capsetType[0x%04" PRIx16
3335
0
               "] != CLY_CAPSET (0xCFC0)",
3336
0
               capsetType);
3337
0
    return FALSE;
3338
0
  }
3339
3340
0
  while (numIcaps--)
3341
0
  {
3342
0
    if (!rdp_read_codec_ts_rfx_icap(log, sub, settings, icapLen))
3343
0
      return FALSE;
3344
0
  }
3345
0
  return TRUE;
3346
0
}
3347
3348
static BOOL rdp_read_codec_ts_rfx_caps(wLog* log, wStream* sub, rdpSettings* settings)
3349
0
{
3350
0
  if (Stream_GetRemainingLength(sub) == 0)
3351
0
    return TRUE;
3352
3353
0
  UINT16 blockType = 0;
3354
0
  UINT32 blockLen = 0;
3355
0
  UINT16 numCapsets = 0;
3356
3357
  /* TS_RFX_CAPS */
3358
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3359
0
    return FALSE;
3360
0
  Stream_Read_UINT16(sub, blockType);  /* blockType (2 bytes) */
3361
0
  Stream_Read_UINT32(sub, blockLen);   /* blockLen (4 bytes) */
3362
0
  Stream_Read_UINT16(sub, numCapsets); /* numCapsets (2 bytes) */
3363
3364
0
  if (blockType != 0xCBC0)
3365
0
  {
3366
0
    WLog_Print(log, WLOG_ERROR,
3367
0
               "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockType[0x%04" PRIx16
3368
0
               "] != CBY_CAPS (0xCBC0)",
3369
0
               blockType);
3370
0
    return FALSE;
3371
0
  }
3372
3373
0
  if (blockLen != 8)
3374
0
  {
3375
0
    WLog_Print(log, WLOG_ERROR, "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockLen[%" PRIu16 "] != 8",
3376
0
               blockLen);
3377
0
    return FALSE;
3378
0
  }
3379
3380
0
  if (numCapsets != 1)
3381
0
  {
3382
0
    WLog_Print(log, WLOG_ERROR,
3383
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::numIcaps[%" PRIu16 "] != 1", numCapsets);
3384
0
    return FALSE;
3385
0
  }
3386
3387
0
  for (UINT16 x = 0; x < numCapsets; x++)
3388
0
  {
3389
0
    if (!rdp_read_codec_ts_rfx_capset(log, sub, settings))
3390
0
      return FALSE;
3391
0
  }
3392
3393
0
  return TRUE;
3394
0
}
3395
3396
static BOOL rdp_read_codec_ts_rfx_clnt_caps_container(wLog* log, wStream* s, rdpSettings* settings)
3397
0
{
3398
0
  UINT32 rfxCapsLength = 0;
3399
0
  UINT32 rfxPropsLength = 0;
3400
0
  UINT32 captureFlags = 0;
3401
3402
  /* [MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER */
3403
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3404
0
    return FALSE;
3405
0
  Stream_Read_UINT32(s, rfxPropsLength); /* length (4 bytes) */
3406
0
  if (rfxPropsLength < 4)
3407
0
  {
3408
0
    WLog_Print(log, WLOG_ERROR,
3409
0
               "[MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER::length %" PRIu32
3410
0
               " too short, require at least 4 bytes",
3411
0
               rfxPropsLength);
3412
0
    return FALSE;
3413
0
  }
3414
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, rfxPropsLength - 4ull))
3415
0
    return FALSE;
3416
3417
0
  wStream sbuffer = WINPR_C_ARRAY_INIT;
3418
0
  wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), rfxPropsLength - 4ull);
3419
0
  WINPR_ASSERT(sub);
3420
3421
0
  Stream_Seek(s, rfxPropsLength - 4ull);
3422
3423
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3424
0
    return FALSE;
3425
3426
0
  Stream_Read_UINT32(sub, captureFlags);  /* captureFlags (4 bytes) */
3427
0
  Stream_Read_UINT32(sub, rfxCapsLength); /* capsLength (4 bytes) */
3428
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, rfxCapsLength))
3429
0
    return FALSE;
3430
3431
0
  settings->RemoteFxCaptureFlags = captureFlags;
3432
0
  settings->RemoteFxOnly = !(captureFlags & CARDP_CAPS_CAPTURE_NON_CAC);
3433
3434
  /* [MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS */
3435
0
  wStream tsbuffer = WINPR_C_ARRAY_INIT;
3436
0
  wStream* ts_sub = Stream_StaticConstInit(&tsbuffer, Stream_Pointer(sub), rfxCapsLength);
3437
0
  WINPR_ASSERT(ts_sub);
3438
0
  return rdp_read_codec_ts_rfx_caps(log, ts_sub, settings);
3439
0
}
3440
3441
/*
3442
 * Read bitmap codecs capability set.
3443
 * msdn{dd891377}
3444
 */
3445
3446
static BOOL rdp_read_bitmap_codecs_capability_set(wLog* log, wStream* s, rdpSettings* settings,
3447
                                                  BOOL isServer)
3448
0
{
3449
0
  BYTE codecId = 0;
3450
0
  GUID codecGuid = WINPR_C_ARRAY_INIT;
3451
0
  BYTE bitmapCodecCount = 0;
3452
0
  UINT16 codecPropertiesLength = 0;
3453
3454
0
  BOOL guidNSCodec = FALSE;
3455
0
  BOOL guidRemoteFx = FALSE;
3456
0
  BOOL guidRemoteFxImage = FALSE;
3457
3458
0
  WINPR_ASSERT(settings);
3459
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3460
0
    return FALSE;
3461
3462
0
  Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3463
3464
0
  while (bitmapCodecCount > 0)
3465
0
  {
3466
0
    wStream subbuffer = WINPR_C_ARRAY_INIT;
3467
3468
0
    if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3469
0
      return FALSE;
3470
0
    if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3471
0
      return FALSE;
3472
0
    Stream_Read_UINT8(s, codecId);                /* codecId (1 byte) */
3473
0
    Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3474
3475
0
    wStream* sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), codecPropertiesLength);
3476
0
    if (!Stream_SafeSeek(s, codecPropertiesLength))
3477
0
      return FALSE;
3478
3479
0
    if (isServer)
3480
0
    {
3481
0
      if (sUuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX))
3482
0
      {
3483
0
        guidRemoteFx = TRUE;
3484
0
        settings->RemoteFxCodecId = codecId;
3485
0
        if (!rdp_read_codec_ts_rfx_clnt_caps_container(log, sub, settings))
3486
0
          return FALSE;
3487
0
      }
3488
0
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_IMAGE_REMOTEFX))
3489
0
      {
3490
        /* Microsoft RDP servers ignore CODEC_GUID_IMAGE_REMOTEFX codec properties */
3491
0
        guidRemoteFxImage = TRUE;
3492
0
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3493
0
          return FALSE;
3494
0
      }
3495
0
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_NSCODEC))
3496
0
      {
3497
0
        BYTE colorLossLevel = 0;
3498
0
        BYTE fAllowSubsampling = 0;
3499
0
        BYTE fAllowDynamicFidelity = 0;
3500
0
        guidNSCodec = TRUE;
3501
0
        settings->NSCodecId = codecId;
3502
0
        if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 3))
3503
0
          return FALSE;
3504
0
        Stream_Read_UINT8(sub, fAllowDynamicFidelity); /* fAllowDynamicFidelity (1 byte) */
3505
0
        Stream_Read_UINT8(sub, fAllowSubsampling);     /* fAllowSubsampling (1 byte) */
3506
0
        Stream_Read_UINT8(sub, colorLossLevel);        /* colorLossLevel (1 byte) */
3507
3508
0
        if (colorLossLevel < 1)
3509
0
          colorLossLevel = 1;
3510
3511
0
        if (colorLossLevel > 7)
3512
0
          colorLossLevel = 7;
3513
3514
0
        settings->NSCodecAllowDynamicColorFidelity = fAllowDynamicFidelity;
3515
0
        settings->NSCodecAllowSubsampling = fAllowSubsampling;
3516
0
        settings->NSCodecColorLossLevel = colorLossLevel;
3517
0
      }
3518
0
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_IGNORE))
3519
0
      {
3520
0
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3521
0
          return FALSE;
3522
0
      }
3523
0
      else
3524
0
      {
3525
0
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3526
0
          return FALSE;
3527
0
      }
3528
0
    }
3529
0
    else
3530
0
    {
3531
0
      if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3532
0
        return FALSE;
3533
0
    }
3534
3535
0
    const size_t rest = Stream_GetRemainingLength(sub);
3536
0
    if (rest > 0)
3537
0
    {
3538
0
      WLog_Print(log, WLOG_ERROR,
3539
0
                 "error while reading codec properties: actual size: %" PRIuz
3540
0
                 " expected size: %" PRIu32 "",
3541
0
                 rest + codecPropertiesLength, codecPropertiesLength);
3542
0
    }
3543
0
    bitmapCodecCount--;
3544
3545
    /* only enable a codec if we've announced/enabled it before */
3546
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, guidRemoteFx))
3547
0
      return FALSE;
3548
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, guidRemoteFxImage))
3549
0
      return FALSE;
3550
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, guidNSCodec))
3551
0
      return FALSE;
3552
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
3553
0
      return FALSE;
3554
0
  }
3555
3556
0
  return TRUE;
3557
0
}
3558
3559
/*
3560
 * Write RemoteFX Client Capability Container.
3561
 */
3562
static BOOL rdp_write_rfx_client_capability_container(wStream* s, const rdpSettings* settings)
3563
0
{
3564
0
  WINPR_ASSERT(settings);
3565
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
3566
0
    return FALSE;
3567
3568
0
  const UINT32 captureFlags = settings->RemoteFxOnly ? 0 : CARDP_CAPS_CAPTURE_NON_CAC;
3569
3570
0
  WINPR_ASSERT(settings->RemoteFxCodecMode <= UINT8_MAX);
3571
0
  const UINT8 codecMode = (UINT8)settings->RemoteFxCodecMode;
3572
0
  Stream_Write_UINT16(s, 49); /* codecPropertiesLength */
3573
  /* TS_RFX_CLNT_CAPS_CONTAINER */
3574
0
  Stream_Write_UINT32(s, 49);           /* length */
3575
0
  Stream_Write_UINT32(s, captureFlags); /* captureFlags */
3576
0
  Stream_Write_UINT32(s, 37);           /* capsLength */
3577
  /* TS_RFX_CAPS */
3578
0
  Stream_Write_UINT16(s, CBY_CAPS); /* blockType */
3579
0
  Stream_Write_UINT32(s, 8);        /* blockLen */
3580
0
  Stream_Write_UINT16(s, 1);        /* numCapsets */
3581
  /* TS_RFX_CAPSET */
3582
0
  Stream_Write_UINT16(s, CBY_CAPSET); /* blockType */
3583
0
  Stream_Write_UINT32(s, 29);         /* blockLen */
3584
0
  Stream_Write_UINT8(s, 0x01);        /* codecId (MUST be set to 0x01) */
3585
0
  Stream_Write_UINT16(s, CLY_CAPSET); /* capsetType */
3586
0
  Stream_Write_UINT16(s, 2);          /* numIcaps */
3587
0
  Stream_Write_UINT16(s, 8);          /* icapLen */
3588
  /* TS_RFX_ICAP (RLGR1) */
3589
0
  Stream_Write_UINT16(s, CLW_VERSION_1_0);   /* version */
3590
0
  Stream_Write_UINT16(s, CT_TILE_64x64);     /* tileSize */
3591
0
  Stream_Write_UINT8(s, codecMode);          /* flags */
3592
0
  Stream_Write_UINT8(s, CLW_COL_CONV_ICT);   /* colConvBits */
3593
0
  Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3594
0
  Stream_Write_UINT8(s, CLW_ENTROPY_RLGR1);  /* entropyBits */
3595
  /* TS_RFX_ICAP (RLGR3) */
3596
0
  Stream_Write_UINT16(s, CLW_VERSION_1_0);   /* version */
3597
0
  Stream_Write_UINT16(s, CT_TILE_64x64);     /* tileSize */
3598
0
  Stream_Write_UINT8(s, codecMode);          /* flags */
3599
0
  Stream_Write_UINT8(s, CLW_COL_CONV_ICT);   /* colConvBits */
3600
0
  Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3601
0
  Stream_Write_UINT8(s, CLW_ENTROPY_RLGR3);  /* entropyBits */
3602
0
  return TRUE;
3603
0
}
3604
3605
/*
3606
 * Write NSCODEC Client Capability Container.
3607
 */
3608
static BOOL rdp_write_nsc_client_capability_container(wStream* s, const rdpSettings* settings)
3609
0
{
3610
0
  WINPR_ASSERT(settings);
3611
3612
0
  const BOOL fAllowDynamicFidelity = settings->NSCodecAllowDynamicColorFidelity;
3613
0
  const BOOL fAllowSubsampling = settings->NSCodecAllowSubsampling;
3614
0
  UINT32 colorLossLevel = settings->NSCodecColorLossLevel;
3615
3616
0
  if (colorLossLevel < 1)
3617
0
    colorLossLevel = 1;
3618
3619
0
  if (colorLossLevel > 7)
3620
0
    colorLossLevel = 7;
3621
3622
0
  if (!Stream_EnsureRemainingCapacity(s, 8))
3623
0
    return FALSE;
3624
3625
0
  Stream_Write_UINT16(s, 3); /* codecPropertiesLength */
3626
  /* TS_NSCODEC_CAPABILITYSET */
3627
0
  Stream_Write_UINT8(s, fAllowDynamicFidelity != 0);        /* fAllowDynamicFidelity (1 byte) */
3628
0
  Stream_Write_UINT8(s, fAllowSubsampling != 0);            /* fAllowSubsampling (1 byte) */
3629
0
  Stream_Write_UINT8(s, (UINT8)colorLossLevel);             /* colorLossLevel (1 byte) */
3630
0
  return TRUE;
3631
0
}
3632
3633
#if defined(WITH_JPEG)
3634
static BOOL rdp_write_jpeg_client_capability_container(wStream* s, const rdpSettings* settings)
3635
{
3636
  WINPR_ASSERT(settings);
3637
  if (!Stream_EnsureRemainingCapacity(s, 8))
3638
    return FALSE;
3639
3640
  Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3641
3642
  const UINT32 q = freerdp_settings_get_uint32(settings, FreeRDP_JpegQuality);
3643
  Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, q));
3644
  return TRUE;
3645
}
3646
#endif
3647
3648
/*
3649
 * Write RemoteFX Server Capability Container.
3650
 */
3651
static BOOL rdp_write_rfx_server_capability_container(wStream* s, const rdpSettings* settings)
3652
0
{
3653
0
  WINPR_UNUSED(settings);
3654
0
  WINPR_ASSERT(settings);
3655
3656
0
  if (!Stream_EnsureRemainingCapacity(s, 8))
3657
0
    return FALSE;
3658
3659
0
  Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3660
0
  Stream_Write_UINT32(s, 0); /* reserved */
3661
0
  return TRUE;
3662
0
}
3663
3664
#if defined(WITH_JPEG)
3665
static BOOL rdp_write_jpeg_server_capability_container(wStream* s, const rdpSettings* settings)
3666
{
3667
  WINPR_UNUSED(settings);
3668
  WINPR_ASSERT(settings);
3669
3670
  if (!Stream_EnsureRemainingCapacity(s, 8))
3671
    return FALSE;
3672
3673
  Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3674
  Stream_Write_UINT8(s, 75);
3675
  return TRUE;
3676
}
3677
#endif
3678
3679
/*
3680
 * Write NSCODEC Server Capability Container.
3681
 */
3682
static BOOL rdp_write_nsc_server_capability_container(wStream* s, const rdpSettings* settings)
3683
0
{
3684
0
  WINPR_UNUSED(settings);
3685
0
  WINPR_ASSERT(settings);
3686
3687
0
  if (!Stream_EnsureRemainingCapacity(s, 8))
3688
0
    return FALSE;
3689
3690
0
  Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3691
0
  Stream_Write_UINT32(s, 0); /* reserved */
3692
0
  return TRUE;
3693
0
}
3694
3695
/*
3696
 * Write bitmap codecs capability set.
3697
 * msdn{dd891377}
3698
 */
3699
3700
static BOOL rdp_write_bitmap_codecs_capability_set(wLog* log, wStream* s,
3701
                                                   const rdpSettings* settings)
3702
0
{
3703
0
  WINPR_ASSERT(settings);
3704
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
3705
0
    return FALSE;
3706
3707
0
  const size_t header = rdp_capability_set_start(log, s);
3708
0
  BYTE bitmapCodecCount = 0;
3709
3710
0
  if (settings->RemoteFxCodec)
3711
0
    bitmapCodecCount++;
3712
3713
0
  if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3714
0
    bitmapCodecCount++;
3715
3716
#if defined(WITH_JPEG)
3717
3718
  if (settings->JpegCodec)
3719
    bitmapCodecCount++;
3720
3721
#endif
3722
3723
0
  if (settings->RemoteFxImageCodec)
3724
0
    bitmapCodecCount++;
3725
3726
0
  Stream_Write_UINT8(s, bitmapCodecCount);
3727
3728
0
  if (settings->RemoteFxCodec)
3729
0
  {
3730
0
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_REMOTEFX); /* codecGUID */
3731
3732
0
    if (settings->ServerMode)
3733
0
    {
3734
0
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3735
3736
0
      if (!rdp_write_rfx_server_capability_container(s, settings))
3737
0
        return FALSE;
3738
0
    }
3739
0
    else
3740
0
    {
3741
0
      Stream_Write_UINT8(s, RDP_CODEC_ID_REMOTEFX); /* codecID */
3742
3743
0
      if (!rdp_write_rfx_client_capability_container(s, settings))
3744
0
        return FALSE;
3745
0
    }
3746
0
  }
3747
3748
0
  if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3749
0
  {
3750
0
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_NSCODEC); /* codecGUID */
3751
3752
0
    if (settings->ServerMode)
3753
0
    {
3754
0
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3755
3756
0
      if (!rdp_write_nsc_server_capability_container(s, settings))
3757
0
        return FALSE;
3758
0
    }
3759
0
    else
3760
0
    {
3761
0
      Stream_Write_UINT8(s, RDP_CODEC_ID_NSCODEC); /* codecID */
3762
3763
0
      if (!rdp_write_nsc_client_capability_container(s, settings))
3764
0
        return FALSE;
3765
0
    }
3766
0
  }
3767
3768
#if defined(WITH_JPEG)
3769
3770
  if (settings->JpegCodec)
3771
  {
3772
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_JPEG); /* codecGUID */
3773
3774
    if (settings->ServerMode)
3775
    {
3776
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3777
3778
      if (!rdp_write_jpeg_server_capability_container(s, settings))
3779
        return FALSE;
3780
    }
3781
    else
3782
    {
3783
      Stream_Write_UINT8(s, RDP_CODEC_ID_JPEG); /* codecID */
3784
3785
      if (!rdp_write_jpeg_client_capability_container(s, settings))
3786
        return FALSE;
3787
    }
3788
  }
3789
3790
#endif
3791
3792
0
  if (settings->RemoteFxImageCodec)
3793
0
  {
3794
0
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_IMAGE_REMOTEFX); /* codecGUID */
3795
3796
0
    if (settings->ServerMode)
3797
0
    {
3798
0
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3799
3800
0
      if (!rdp_write_rfx_server_capability_container(s, settings))
3801
0
        return FALSE;
3802
0
    }
3803
0
    else
3804
0
    {
3805
0
      Stream_Write_UINT8(s, RDP_CODEC_ID_IMAGE_REMOTEFX); /* codecID */
3806
3807
0
      if (!rdp_write_rfx_client_capability_container(s, settings))
3808
0
        return FALSE;
3809
0
    }
3810
0
  }
3811
3812
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CODECS);
3813
0
}
3814
3815
#ifdef WITH_DEBUG_CAPABILITIES
3816
static BOOL rdp_print_bitmap_codecs_capability_set(wLog* log, wStream* s)
3817
{
3818
  GUID codecGuid = WINPR_C_ARRAY_INIT;
3819
  BYTE bitmapCodecCount = 0;
3820
  BYTE codecId = 0;
3821
  UINT16 codecPropertiesLength = 0;
3822
3823
  WLog_Print(log, WLOG_TRACE,
3824
             "BitmapCodecsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3825
3826
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3827
    return FALSE;
3828
3829
  Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3830
  WLog_Print(log, WLOG_TRACE, "\tbitmapCodecCount: %" PRIu8 "", bitmapCodecCount);
3831
3832
  while (bitmapCodecCount > 0)
3833
  {
3834
    if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3835
      return FALSE;
3836
    if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3837
      return FALSE;
3838
    Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3839
    WLog_Print(log, WLOG_TRACE, "\tcodecGuid: 0x");
3840
    rdp_print_bitmap_codec_guid(log, &codecGuid);
3841
    WLog_Print(log, WLOG_TRACE, " (%s)", rdp_get_bitmap_codec_guid_name(&codecGuid));
3842
    WLog_Print(log, WLOG_TRACE, "\tcodecId: %" PRIu8 "", codecId);
3843
    Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3844
    WLog_Print(log, WLOG_TRACE, "\tcodecPropertiesLength: %" PRIu16 "", codecPropertiesLength);
3845
3846
    if (!Stream_SafeSeek(s, codecPropertiesLength)) /* codecProperties */
3847
      return FALSE;
3848
    bitmapCodecCount--;
3849
  }
3850
3851
  return TRUE;
3852
}
3853
#endif
3854
3855
static BOOL rdp_apply_frame_acknowledge_capability_set(rdpSettings* settings,
3856
                                                       const rdpSettings* src)
3857
0
{
3858
0
  WINPR_ASSERT(settings);
3859
0
  WINPR_ASSERT(src);
3860
3861
0
  if (settings->ServerMode)
3862
0
    settings->FrameAcknowledge = src->FrameAcknowledge;
3863
3864
0
  return TRUE;
3865
0
}
3866
3867
/*
3868
 * Read frame acknowledge capability set.
3869
 */
3870
3871
static BOOL rdp_read_frame_acknowledge_capability_set(wLog* log, wStream* s, rdpSettings* settings)
3872
0
{
3873
0
  WINPR_ASSERT(settings);
3874
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3875
0
    return FALSE;
3876
3877
0
  Stream_Read_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3878
3879
0
  return TRUE;
3880
0
}
3881
3882
/*
3883
 * Write frame acknowledge capability set.
3884
 */
3885
3886
static BOOL rdp_write_frame_acknowledge_capability_set(wLog* log, wStream* s,
3887
                                                       const rdpSettings* settings)
3888
0
{
3889
0
  WINPR_ASSERT(settings);
3890
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
3891
0
    return FALSE;
3892
3893
0
  const size_t header = rdp_capability_set_start(log, s);
3894
0
  Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3895
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE);
3896
0
}
3897
3898
#ifdef WITH_DEBUG_CAPABILITIES
3899
static BOOL rdp_print_frame_acknowledge_capability_set(wLog* log, wStream* s)
3900
{
3901
  UINT32 frameAcknowledge = 0;
3902
  WLog_Print(log, WLOG_TRACE,
3903
             "FrameAcknowledgeCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3904
3905
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3906
    return FALSE;
3907
3908
  Stream_Read_UINT32(s, frameAcknowledge); /* frameAcknowledge (4 bytes) */
3909
  WLog_Print(log, WLOG_TRACE, "\tframeAcknowledge: 0x%08" PRIX32 "", frameAcknowledge);
3910
  return TRUE;
3911
}
3912
#endif
3913
3914
static BOOL rdp_apply_bitmap_cache_v3_codec_id_capability_set(rdpSettings* settings,
3915
                                                              const rdpSettings* src)
3916
0
{
3917
0
  WINPR_ASSERT(settings);
3918
0
  WINPR_ASSERT(src);
3919
3920
0
  settings->BitmapCacheV3CodecId = src->BitmapCacheV3CodecId;
3921
0
  return TRUE;
3922
0
}
3923
3924
static BOOL rdp_read_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3925
                                                             rdpSettings* settings)
3926
0
{
3927
0
  BYTE bitmapCacheV3CodecId = 0;
3928
3929
0
  WINPR_ASSERT(settings);
3930
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3931
0
    return FALSE;
3932
3933
0
  Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3934
0
  settings->BitmapCacheV3CodecId = bitmapCacheV3CodecId;
3935
0
  return TRUE;
3936
0
}
3937
3938
static BOOL rdp_write_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3939
                                                              const rdpSettings* settings)
3940
0
{
3941
0
  WINPR_ASSERT(settings);
3942
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
3943
0
    return FALSE;
3944
3945
0
  const size_t header = rdp_capability_set_start(log, s);
3946
0
  if (settings->BitmapCacheV3CodecId > UINT8_MAX)
3947
0
    return FALSE;
3948
0
  Stream_Write_UINT8(s, (UINT8)settings->BitmapCacheV3CodecId);
3949
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID);
3950
0
}
3951
3952
#ifdef WITH_DEBUG_CAPABILITIES
3953
static BOOL rdp_print_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s)
3954
{
3955
  BYTE bitmapCacheV3CodecId = 0;
3956
  WLog_Print(log, WLOG_TRACE, "BitmapCacheV3CodecIdCapabilitySet (length %" PRIuz "):",
3957
             Stream_GetRemainingLength(s));
3958
3959
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3960
    return FALSE;
3961
3962
  Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3963
  WLog_Print(log, WLOG_TRACE, "\tbitmapCacheV3CodecId: 0x%02" PRIX8 "", bitmapCacheV3CodecId);
3964
  return TRUE;
3965
}
3966
3967
BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving)
3968
{
3969
  BOOL rc = FALSE;
3970
  UINT16 type = 0;
3971
  UINT16 length = 0;
3972
  UINT16 numberCapabilities = 0;
3973
3974
  size_t pos = Stream_GetPosition(s);
3975
3976
  if (!Stream_SetPosition(s, start))
3977
    goto fail;
3978
3979
  if (receiving)
3980
  {
3981
    if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3982
      goto fail;
3983
  }
3984
  else
3985
  {
3986
    if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), 4))
3987
      goto fail;
3988
  }
3989
3990
  Stream_Read_UINT16(s, numberCapabilities);
3991
  Stream_Seek(s, 2);
3992
3993
  while (numberCapabilities > 0)
3994
  {
3995
    size_t rest = 0;
3996
    wStream subBuffer;
3997
    wStream* sub = nullptr;
3998
3999
    if (!rdp_read_capability_set_header(log, s, &length, &type))
4000
      goto fail;
4001
4002
    WLog_Print(log, WLOG_TRACE, "%s ", receiving ? "Receiving" : "Sending");
4003
    sub = Stream_StaticInit(&subBuffer, Stream_Pointer(s), length - 4);
4004
    if (!Stream_SafeSeek(s, length - 4))
4005
      goto fail;
4006
4007
    switch (type)
4008
    {
4009
      case CAPSET_TYPE_GENERAL:
4010
        if (!rdp_print_general_capability_set(log, sub))
4011
          goto fail;
4012
4013
        break;
4014
4015
      case CAPSET_TYPE_BITMAP:
4016
        if (!rdp_print_bitmap_capability_set(log, sub))
4017
          goto fail;
4018
4019
        break;
4020
4021
      case CAPSET_TYPE_ORDER:
4022
        if (!rdp_print_order_capability_set(log, sub))
4023
          goto fail;
4024
4025
        break;
4026
4027
      case CAPSET_TYPE_BITMAP_CACHE:
4028
        if (!rdp_print_bitmap_cache_capability_set(log, sub))
4029
          goto fail;
4030
4031
        break;
4032
4033
      case CAPSET_TYPE_CONTROL:
4034
        if (!rdp_print_control_capability_set(log, sub))
4035
          goto fail;
4036
4037
        break;
4038
4039
      case CAPSET_TYPE_ACTIVATION:
4040
        if (!rdp_print_window_activation_capability_set(log, sub))
4041
          goto fail;
4042
4043
        break;
4044
4045
      case CAPSET_TYPE_POINTER:
4046
        if (!rdp_print_pointer_capability_set(log, sub))
4047
          goto fail;
4048
4049
        break;
4050
4051
      case CAPSET_TYPE_SHARE:
4052
        if (!rdp_print_share_capability_set(log, sub))
4053
          goto fail;
4054
4055
        break;
4056
4057
      case CAPSET_TYPE_COLOR_CACHE:
4058
        if (!rdp_print_color_cache_capability_set(log, sub))
4059
          goto fail;
4060
4061
        break;
4062
4063
      case CAPSET_TYPE_SOUND:
4064
        if (!rdp_print_sound_capability_set(log, sub))
4065
          goto fail;
4066
4067
        break;
4068
4069
      case CAPSET_TYPE_INPUT:
4070
        if (!rdp_print_input_capability_set(log, sub))
4071
          goto fail;
4072
4073
        break;
4074
4075
      case CAPSET_TYPE_FONT:
4076
        if (!rdp_print_font_capability_set(log, sub))
4077
          goto fail;
4078
4079
        break;
4080
4081
      case CAPSET_TYPE_BRUSH:
4082
        if (!rdp_print_brush_capability_set(log, sub))
4083
          goto fail;
4084
4085
        break;
4086
4087
      case CAPSET_TYPE_GLYPH_CACHE:
4088
        if (!rdp_print_glyph_cache_capability_set(log, sub))
4089
          goto fail;
4090
4091
        break;
4092
4093
      case CAPSET_TYPE_OFFSCREEN_CACHE:
4094
        if (!rdp_print_offscreen_bitmap_cache_capability_set(log, sub))
4095
          goto fail;
4096
4097
        break;
4098
4099
      case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4100
        if (!rdp_print_bitmap_cache_host_support_capability_set(log, sub))
4101
          goto fail;
4102
4103
        break;
4104
4105
      case CAPSET_TYPE_BITMAP_CACHE_V2:
4106
        if (!rdp_print_bitmap_cache_v2_capability_set(log, sub))
4107
          goto fail;
4108
4109
        break;
4110
4111
      case CAPSET_TYPE_VIRTUAL_CHANNEL:
4112
        if (!rdp_print_virtual_channel_capability_set(log, sub))
4113
          goto fail;
4114
4115
        break;
4116
4117
      case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4118
        if (!rdp_print_draw_nine_grid_cache_capability_set(log, sub))
4119
          goto fail;
4120
4121
        break;
4122
4123
      case CAPSET_TYPE_DRAW_GDI_PLUS:
4124
        if (!rdp_print_draw_gdiplus_cache_capability_set(log, sub))
4125
          goto fail;
4126
4127
        break;
4128
4129
      case CAPSET_TYPE_RAIL:
4130
        if (!rdp_print_remote_programs_capability_set(log, sub))
4131
          goto fail;
4132
4133
        break;
4134
4135
      case CAPSET_TYPE_WINDOW:
4136
        if (!rdp_print_window_list_capability_set(log, sub))
4137
          goto fail;
4138
4139
        break;
4140
4141
      case CAPSET_TYPE_COMP_DESK:
4142
        if (!rdp_print_desktop_composition_capability_set(log, sub))
4143
          goto fail;
4144
4145
        break;
4146
4147
      case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4148
        if (!rdp_print_multifragment_update_capability_set(log, sub))
4149
          goto fail;
4150
4151
        break;
4152
4153
      case CAPSET_TYPE_LARGE_POINTER:
4154
        if (!rdp_print_large_pointer_capability_set(log, sub))
4155
          goto fail;
4156
4157
        break;
4158
4159
      case CAPSET_TYPE_SURFACE_COMMANDS:
4160
        if (!rdp_print_surface_commands_capability_set(log, sub))
4161
          goto fail;
4162
4163
        break;
4164
4165
      case CAPSET_TYPE_BITMAP_CODECS:
4166
        if (!rdp_print_bitmap_codecs_capability_set(log, sub))
4167
          goto fail;
4168
4169
        break;
4170
4171
      case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4172
        if (!rdp_print_frame_acknowledge_capability_set(log, sub))
4173
          goto fail;
4174
4175
        break;
4176
4177
      case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4178
        if (!rdp_print_bitmap_cache_v3_codec_id_capability_set(log, sub))
4179
          goto fail;
4180
4181
        break;
4182
4183
      default:
4184
        WLog_Print(log, WLOG_ERROR, "unknown capability type %" PRIu16 "", type);
4185
        break;
4186
    }
4187
4188
    rest = Stream_GetRemainingLength(sub);
4189
    if (rest > 0)
4190
    {
4191
      WLog_Print(log, WLOG_WARN,
4192
                 "incorrect capability offset, type:0x%04" PRIX16 " %" PRIu16
4193
                 " bytes expected, %" PRIuz "bytes remaining",
4194
                 type, length, rest);
4195
    }
4196
4197
    numberCapabilities--;
4198
  }
4199
4200
  rc = TRUE;
4201
fail:
4202
  if (!Stream_SetPosition(s, pos))
4203
    return FALSE;
4204
4205
  return rc;
4206
}
4207
#endif
4208
4209
static BOOL rdp_apply_from_received(UINT16 type, rdpSettings* dst, const rdpSettings* src)
4210
0
{
4211
0
  switch (type)
4212
0
  {
4213
0
    case CAPSET_TYPE_GENERAL:
4214
0
      return rdp_apply_general_capability_set(dst, src);
4215
0
    case CAPSET_TYPE_BITMAP:
4216
0
      return rdp_apply_bitmap_capability_set(dst, src);
4217
0
    case CAPSET_TYPE_ORDER:
4218
0
      return rdp_apply_order_capability_set(dst, src);
4219
0
    case CAPSET_TYPE_POINTER:
4220
0
      return rdp_apply_pointer_capability_set(dst, src);
4221
0
    case CAPSET_TYPE_INPUT:
4222
0
      return rdp_apply_input_capability_set(dst, src);
4223
0
    case CAPSET_TYPE_VIRTUAL_CHANNEL:
4224
0
      return rdp_apply_virtual_channel_capability_set(dst, src);
4225
0
    case CAPSET_TYPE_SHARE:
4226
0
      return rdp_apply_share_capability_set(dst, src);
4227
0
    case CAPSET_TYPE_COLOR_CACHE:
4228
0
      return rdp_apply_color_cache_capability_set(dst, src);
4229
0
    case CAPSET_TYPE_FONT:
4230
0
      return rdp_apply_font_capability_set(dst, src);
4231
0
    case CAPSET_TYPE_DRAW_GDI_PLUS:
4232
0
      return rdp_apply_draw_gdiplus_cache_capability_set(dst, src);
4233
0
    case CAPSET_TYPE_RAIL:
4234
0
      return rdp_apply_remote_programs_capability_set(dst, src);
4235
0
    case CAPSET_TYPE_WINDOW:
4236
0
      return rdp_apply_window_list_capability_set(dst, src);
4237
0
    case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4238
0
      return rdp_apply_multifragment_update_capability_set(dst, src);
4239
0
    case CAPSET_TYPE_LARGE_POINTER:
4240
0
      return rdp_apply_large_pointer_capability_set(dst, src);
4241
0
    case CAPSET_TYPE_COMP_DESK:
4242
0
      return rdp_apply_desktop_composition_capability_set(dst, src);
4243
0
    case CAPSET_TYPE_SURFACE_COMMANDS:
4244
0
      return rdp_apply_surface_commands_capability_set(dst, src);
4245
0
    case CAPSET_TYPE_BITMAP_CODECS:
4246
0
      return rdp_apply_bitmap_codecs_capability_set(dst, src);
4247
0
    case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4248
0
      return rdp_apply_frame_acknowledge_capability_set(dst, src);
4249
0
    case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4250
0
      return rdp_apply_bitmap_cache_v3_codec_id_capability_set(dst, src);
4251
0
    case CAPSET_TYPE_BITMAP_CACHE:
4252
0
      return rdp_apply_bitmap_cache_capability_set(dst, src);
4253
0
    case CAPSET_TYPE_BITMAP_CACHE_V2:
4254
0
      return rdp_apply_bitmap_cache_v2_capability_set(dst, src);
4255
0
    case CAPSET_TYPE_BRUSH:
4256
0
      return rdp_apply_brush_capability_set(dst, src);
4257
0
    case CAPSET_TYPE_GLYPH_CACHE:
4258
0
      return rdp_apply_glyph_cache_capability_set(dst, src);
4259
0
    case CAPSET_TYPE_OFFSCREEN_CACHE:
4260
0
      return rdp_apply_offscreen_bitmap_cache_capability_set(dst, src);
4261
0
    case CAPSET_TYPE_SOUND:
4262
0
      return rdp_apply_sound_capability_set(dst, src);
4263
0
    case CAPSET_TYPE_CONTROL:
4264
0
      return rdp_apply_control_capability_set(dst, src);
4265
0
    case CAPSET_TYPE_ACTIVATION:
4266
0
      return rdp_apply_window_activation_capability_set(dst, src);
4267
0
    case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4268
0
      return rdp_apply_draw_nine_grid_cache_capability_set(dst, src);
4269
0
    case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4270
0
      return rdp_apply_bitmap_cache_host_support_capability_set(dst, src);
4271
0
    default:
4272
0
      return TRUE;
4273
0
  }
4274
0
}
4275
4276
BOOL rdp_read_capability_set(wLog* log, wStream* sub, UINT16 type, rdpSettings* settings,
4277
                             BOOL isServer)
4278
0
{
4279
0
  WINPR_ASSERT(settings);
4280
4281
0
  if (type <= CAPSET_TYPE_FRAME_ACKNOWLEDGE)
4282
0
  {
4283
0
    const size_t size = Stream_Length(sub);
4284
0
    if (size > UINT32_MAX)
4285
0
      return FALSE;
4286
4287
0
    WINPR_ASSERT(settings->ReceivedCapabilities);
4288
0
    settings->ReceivedCapabilities[type] = TRUE;
4289
4290
0
    WINPR_ASSERT(settings->ReceivedCapabilityDataSizes);
4291
0
    settings->ReceivedCapabilityDataSizes[type] = (UINT32)size;
4292
4293
0
    WINPR_ASSERT(settings->ReceivedCapabilityData);
4294
0
    void* tmp = realloc(settings->ReceivedCapabilityData[type], size);
4295
0
    if (!tmp && (size > 0))
4296
0
      return FALSE;
4297
0
    if (tmp)
4298
0
      memcpy(tmp, Stream_Buffer(sub), size);
4299
0
    settings->ReceivedCapabilityData[type] = tmp;
4300
0
  }
4301
0
  else
4302
0
    WLog_Print(log, WLOG_WARN, "not handling capability type %" PRIu16 " yet", type);
4303
4304
0
  BOOL treated = TRUE;
4305
4306
0
  switch (type)
4307
0
  {
4308
0
    case CAPSET_TYPE_GENERAL:
4309
0
      if (!rdp_read_general_capability_set(log, sub, settings))
4310
0
        return FALSE;
4311
4312
0
      break;
4313
4314
0
    case CAPSET_TYPE_BITMAP:
4315
0
      if (!rdp_read_bitmap_capability_set(log, sub, settings))
4316
0
        return FALSE;
4317
4318
0
      break;
4319
4320
0
    case CAPSET_TYPE_ORDER:
4321
0
      if (!rdp_read_order_capability_set(log, sub, settings))
4322
0
        return FALSE;
4323
4324
0
      break;
4325
4326
0
    case CAPSET_TYPE_POINTER:
4327
0
      if (!rdp_read_pointer_capability_set(log, sub, settings))
4328
0
        return FALSE;
4329
4330
0
      break;
4331
4332
0
    case CAPSET_TYPE_INPUT:
4333
0
      if (!rdp_read_input_capability_set(log, sub, settings))
4334
0
        return FALSE;
4335
4336
0
      break;
4337
4338
0
    case CAPSET_TYPE_VIRTUAL_CHANNEL:
4339
0
      if (!rdp_read_virtual_channel_capability_set(log, sub, settings))
4340
0
        return FALSE;
4341
4342
0
      break;
4343
4344
0
    case CAPSET_TYPE_SHARE:
4345
0
      if (!rdp_read_share_capability_set(log, sub, settings))
4346
0
        return FALSE;
4347
4348
0
      break;
4349
4350
0
    case CAPSET_TYPE_COLOR_CACHE:
4351
0
      if (!rdp_read_color_cache_capability_set(log, sub, settings))
4352
0
        return FALSE;
4353
4354
0
      break;
4355
4356
0
    case CAPSET_TYPE_FONT:
4357
0
      if (!rdp_read_font_capability_set(log, sub, settings))
4358
0
        return FALSE;
4359
4360
0
      break;
4361
4362
0
    case CAPSET_TYPE_DRAW_GDI_PLUS:
4363
0
      if (!rdp_read_draw_gdiplus_cache_capability_set(log, sub, settings))
4364
0
        return FALSE;
4365
4366
0
      break;
4367
4368
0
    case CAPSET_TYPE_RAIL:
4369
0
      if (!rdp_read_remote_programs_capability_set(log, sub, settings))
4370
0
        return FALSE;
4371
4372
0
      break;
4373
4374
0
    case CAPSET_TYPE_WINDOW:
4375
0
      if (!rdp_read_window_list_capability_set(log, sub, settings))
4376
0
        return FALSE;
4377
4378
0
      break;
4379
4380
0
    case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4381
0
      if (!rdp_read_multifragment_update_capability_set(log, sub, settings))
4382
0
        return FALSE;
4383
4384
0
      break;
4385
4386
0
    case CAPSET_TYPE_LARGE_POINTER:
4387
0
      if (!rdp_read_large_pointer_capability_set(log, sub, settings))
4388
0
        return FALSE;
4389
4390
0
      break;
4391
4392
0
    case CAPSET_TYPE_COMP_DESK:
4393
0
      if (!rdp_read_desktop_composition_capability_set(log, sub, settings))
4394
0
        return FALSE;
4395
4396
0
      break;
4397
4398
0
    case CAPSET_TYPE_SURFACE_COMMANDS:
4399
0
      if (!rdp_read_surface_commands_capability_set(log, sub, settings))
4400
0
        return FALSE;
4401
4402
0
      break;
4403
4404
0
    case CAPSET_TYPE_BITMAP_CODECS:
4405
0
      if (!rdp_read_bitmap_codecs_capability_set(log, sub, settings, isServer))
4406
0
        return FALSE;
4407
4408
0
      break;
4409
4410
0
    case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4411
0
      if (!rdp_read_frame_acknowledge_capability_set(log, sub, settings))
4412
0
        return FALSE;
4413
4414
0
      break;
4415
4416
0
    case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4417
0
      if (!rdp_read_bitmap_cache_v3_codec_id_capability_set(log, sub, settings))
4418
0
        return FALSE;
4419
4420
0
      break;
4421
4422
0
    default:
4423
0
      treated = FALSE;
4424
0
      break;
4425
0
  }
4426
4427
0
  if (!treated)
4428
0
  {
4429
0
    if (isServer)
4430
0
    {
4431
      /* treating capabilities that are supposed to be send only from the client */
4432
0
      switch (type)
4433
0
      {
4434
0
        case CAPSET_TYPE_BITMAP_CACHE:
4435
0
          if (!rdp_read_bitmap_cache_capability_set(log, sub, settings))
4436
0
            return FALSE;
4437
4438
0
          break;
4439
4440
0
        case CAPSET_TYPE_BITMAP_CACHE_V2:
4441
0
          if (!rdp_read_bitmap_cache_v2_capability_set(log, sub, settings))
4442
0
            return FALSE;
4443
4444
0
          break;
4445
4446
0
        case CAPSET_TYPE_BRUSH:
4447
0
          if (!rdp_read_brush_capability_set(log, sub, settings))
4448
0
            return FALSE;
4449
4450
0
          break;
4451
4452
0
        case CAPSET_TYPE_GLYPH_CACHE:
4453
0
          if (!rdp_read_glyph_cache_capability_set(log, sub, settings))
4454
0
            return FALSE;
4455
4456
0
          break;
4457
4458
0
        case CAPSET_TYPE_OFFSCREEN_CACHE:
4459
0
          if (!rdp_read_offscreen_bitmap_cache_capability_set(log, sub, settings))
4460
0
            return FALSE;
4461
4462
0
          break;
4463
4464
0
        case CAPSET_TYPE_SOUND:
4465
0
          if (!rdp_read_sound_capability_set(log, sub, settings))
4466
0
            return FALSE;
4467
4468
0
          break;
4469
4470
0
        case CAPSET_TYPE_CONTROL:
4471
0
          if (!rdp_read_control_capability_set(log, sub, settings))
4472
0
            return FALSE;
4473
4474
0
          break;
4475
4476
0
        case CAPSET_TYPE_ACTIVATION:
4477
0
          if (!rdp_read_window_activation_capability_set(log, sub, settings))
4478
0
            return FALSE;
4479
4480
0
          break;
4481
4482
0
        case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4483
0
          if (!rdp_read_draw_nine_grid_cache_capability_set(log, sub, settings))
4484
0
            return FALSE;
4485
4486
0
          break;
4487
4488
0
        default:
4489
0
          WLog_Print(log, WLOG_ERROR,
4490
0
                     "capability %s(%" PRIu16 ") not expected from client",
4491
0
                     get_capability_name(type), type);
4492
0
          return FALSE;
4493
0
      }
4494
0
    }
4495
0
    else
4496
0
    {
4497
      /* treating capabilities that are supposed to be send only from the server */
4498
0
      switch (type)
4499
0
      {
4500
0
        case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4501
0
          if (!rdp_read_bitmap_cache_host_support_capability_set(log, sub, settings))
4502
0
            return FALSE;
4503
4504
0
          break;
4505
4506
0
        default:
4507
0
          WLog_Print(log, WLOG_ERROR,
4508
0
                     "capability %s(%" PRIu16 ") not expected from server",
4509
0
                     get_capability_name(type), type);
4510
0
          return FALSE;
4511
0
      }
4512
0
    }
4513
0
  }
4514
4515
0
  const size_t rest = Stream_GetRemainingLength(sub);
4516
0
  if (rest > 0)
4517
0
  {
4518
0
    const size_t length = Stream_Capacity(sub);
4519
0
    WLog_Print(log, WLOG_ERROR,
4520
0
               "incorrect offset, type:0x%04" PRIx16 " actual:%" PRIuz " expected:%" PRIuz "",
4521
0
               type, length - rest, length);
4522
0
  }
4523
0
  return TRUE;
4524
0
}
4525
4526
static BOOL rdp_read_capability_sets(wLog* log, wStream* s, rdpSettings* settings,
4527
                                     rdpSettings* rcvSettings, UINT16 totalLength)
4528
0
{
4529
0
  BOOL rc = FALSE;
4530
0
  size_t start = 0;
4531
0
  size_t end = 0;
4532
0
  size_t len = 0;
4533
0
  UINT16 numberCapabilities = 0;
4534
0
  UINT16 count = 0;
4535
4536
#ifdef WITH_DEBUG_CAPABILITIES
4537
  const size_t capstart = Stream_GetPosition(s);
4538
#endif
4539
4540
0
  WINPR_ASSERT(s);
4541
0
  WINPR_ASSERT(settings);
4542
4543
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4544
0
    return FALSE;
4545
4546
0
  Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4547
0
  Stream_Seek(s, 2);                         /* pad2Octets (2 bytes) */
4548
0
  count = numberCapabilities;
4549
4550
0
  start = Stream_GetPosition(s);
4551
0
  while (numberCapabilities > 0 && Stream_GetRemainingLength(s) >= 4)
4552
0
  {
4553
0
    UINT16 type = 0;
4554
0
    UINT16 length = 0;
4555
0
    wStream subbuffer;
4556
0
    wStream* sub = nullptr;
4557
4558
0
    if (!rdp_read_capability_set_header(log, s, &length, &type))
4559
0
      goto fail;
4560
0
    sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), length - 4);
4561
0
    if (!Stream_SafeSeek(s, length - 4))
4562
0
      goto fail;
4563
4564
0
    if (!rdp_read_capability_set(log, sub, type, rcvSettings, settings->ServerMode))
4565
0
      goto fail;
4566
4567
0
    if (!rdp_apply_from_received(type, settings, rcvSettings))
4568
0
      goto fail;
4569
0
    numberCapabilities--;
4570
0
  }
4571
4572
0
  end = Stream_GetPosition(s);
4573
0
  len = end - start;
4574
4575
0
  if (numberCapabilities)
4576
0
  {
4577
0
    WLog_Print(log, WLOG_ERROR,
4578
0
               "strange we haven't read the number of announced capacity sets, read=%d "
4579
0
               "expected=%" PRIu16 "",
4580
0
               count - numberCapabilities, count);
4581
0
  }
4582
4583
#ifdef WITH_DEBUG_CAPABILITIES
4584
  rdp_print_capability_sets(log, s, capstart, TRUE);
4585
#endif
4586
4587
0
  if (len > totalLength)
4588
0
  {
4589
0
    WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIuz,
4590
0
               totalLength, len);
4591
0
    goto fail;
4592
0
  }
4593
0
  rc = freerdp_capability_buffer_copy(settings, rcvSettings);
4594
0
fail:
4595
0
  return rc;
4596
0
}
4597
4598
BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId, UINT16* length)
4599
0
{
4600
0
  WINPR_ASSERT(rdp);
4601
0
  WINPR_ASSERT(rdp->context);
4602
4603
0
  if (!rdp_read_header(rdp, s, length, pChannelId))
4604
0
    return FALSE;
4605
4606
0
  if (freerdp_shall_disconnect_context(rdp->context))
4607
0
    return TRUE;
4608
4609
0
  if (*pChannelId != MCS_GLOBAL_CHANNEL_ID)
4610
0
  {
4611
0
    UINT16 mcsMessageChannelId = rdp->mcs->messageChannelId;
4612
4613
0
    if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId))
4614
0
    {
4615
0
      WLog_Print(rdp->log, WLOG_ERROR, "unexpected MCS channel id %04" PRIx16 " received",
4616
0
                 *pChannelId);
4617
0
      return FALSE;
4618
0
    }
4619
0
  }
4620
4621
0
  return TRUE;
4622
0
}
4623
4624
BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s, UINT16 pduSource, UINT16 length)
4625
0
{
4626
0
  UINT16 lengthSourceDescriptor = 0;
4627
0
  UINT16 lengthCombinedCapabilities = 0;
4628
4629
0
  WINPR_ASSERT(rdp);
4630
0
  WINPR_ASSERT(rdp->settings);
4631
0
  WINPR_ASSERT(rdp->context);
4632
0
  WINPR_ASSERT(s);
4633
4634
0
  rdp->settings->PduSource = pduSource;
4635
4636
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 8))
4637
0
    return FALSE;
4638
4639
0
  Stream_Read_UINT32(s, rdp->settings->ShareId);     /* shareId (4 bytes) */
4640
0
  Stream_Read_UINT16(s, lengthSourceDescriptor);     /* lengthSourceDescriptor (2 bytes) */
4641
0
  Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4642
4643
0
  if (!Stream_SafeSeek(s, lengthSourceDescriptor) ||
4644
0
      !Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4)) /* sourceDescriptor */
4645
0
    return FALSE;
4646
4647
  /* capabilitySets */
4648
0
  if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4649
0
                                lengthCombinedCapabilities))
4650
0
  {
4651
0
    WLog_Print(rdp->log, WLOG_ERROR, "rdp_read_capability_sets failed");
4652
0
    return FALSE;
4653
0
  }
4654
4655
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4))
4656
0
    return FALSE;
4657
4658
  /* [MS-RDPBCGR] 2.2.1.13.1.1 Demand Active PDU Data (TS_DEMAND_ACTIVE_PDU)::sessionId
4659
   * is ignored by client */
4660
0
  Stream_Seek_UINT32(s); /* SessionId */
4661
4662
0
  {
4663
0
    rdp_secondary_update_internal* secondary = secondary_update_cast(rdp->update->secondary);
4664
0
    secondary->glyph_v2 = (rdp->settings->GlyphSupportLevel > GLYPH_SUPPORT_FULL);
4665
0
  }
4666
4667
0
  return tpkt_ensure_stream_consumed(rdp->log, s, length);
4668
0
}
4669
4670
static BOOL rdp_write_demand_active(wLog* log, wStream* s, rdpSettings* settings)
4671
0
{
4672
0
  size_t bm = 0;
4673
0
  size_t em = 0;
4674
0
  size_t lm = 0;
4675
0
  UINT16 numberCapabilities = 0;
4676
0
  size_t lengthCombinedCapabilities = 0;
4677
4678
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
4679
0
    return FALSE;
4680
4681
0
  Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4682
0
  Stream_Write_UINT16(s, 4);                 /* lengthSourceDescriptor (2 bytes) */
4683
0
  lm = Stream_GetPosition(s);
4684
0
  Stream_Seek_UINT16(s);     /* lengthCombinedCapabilities (2 bytes) */
4685
0
  Stream_Write(s, "RDP", 4); /* sourceDescriptor */
4686
0
  bm = Stream_GetPosition(s);
4687
0
  Stream_Seek_UINT16(s);     /* numberCapabilities (2 bytes) */
4688
0
  Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4689
0
  numberCapabilities = 14;
4690
4691
0
  if (!rdp_write_general_capability_set(log, s, settings) ||
4692
0
      !rdp_write_bitmap_capability_set(log, s, settings) ||
4693
0
      !rdp_write_order_capability_set(log, s, settings) ||
4694
0
      !rdp_write_pointer_capability_set(log, s, settings) ||
4695
0
      !rdp_write_input_capability_set(log, s, settings) ||
4696
0
      !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4697
0
      !rdp_write_share_capability_set(log, s, settings) ||
4698
0
      !rdp_write_font_capability_set(log, s, settings) ||
4699
0
      !rdp_write_multifragment_update_capability_set(log, s, settings) ||
4700
0
      !rdp_write_large_pointer_capability_set(log, s, settings) ||
4701
0
      !rdp_write_desktop_composition_capability_set(log, s, settings) ||
4702
0
      !rdp_write_surface_commands_capability_set(log, s, settings) ||
4703
0
      !rdp_write_bitmap_codecs_capability_set(log, s, settings) ||
4704
0
      !rdp_write_frame_acknowledge_capability_set(log, s, settings))
4705
0
  {
4706
0
    return FALSE;
4707
0
  }
4708
4709
0
  if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
4710
0
  {
4711
0
    numberCapabilities++;
4712
4713
0
    if (!rdp_write_bitmap_cache_host_support_capability_set(log, s, settings))
4714
0
      return FALSE;
4715
0
  }
4716
4717
0
  if (settings->RemoteApplicationMode)
4718
0
  {
4719
0
    numberCapabilities += 2;
4720
4721
0
    if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4722
0
        !rdp_write_window_list_capability_set(log, s, settings))
4723
0
      return FALSE;
4724
0
  }
4725
4726
0
  em = Stream_GetPosition(s);
4727
0
  if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4728
0
    return FALSE;
4729
0
  lengthCombinedCapabilities = (em - bm);
4730
0
  if (lengthCombinedCapabilities > UINT16_MAX)
4731
0
    return FALSE;
4732
0
  Stream_Write_UINT16(
4733
0
      s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4734
0
  if (!Stream_SetPosition(s, bm))             /* go back to numberCapabilities */
4735
0
    return FALSE;
4736
0
  Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4737
#ifdef WITH_DEBUG_CAPABILITIES
4738
  rdp_print_capability_sets(log, s, bm, FALSE);
4739
#endif
4740
0
  if (!Stream_SetPosition(s, em))
4741
0
    return FALSE;
4742
0
  Stream_Write_UINT32(s, 0); /* sessionId */
4743
0
  return TRUE;
4744
0
}
4745
4746
BOOL rdp_send_demand_active(rdpRdp* rdp)
4747
0
{
4748
0
  UINT16 sec_flags = 0;
4749
0
  wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4750
0
  BOOL status = 0;
4751
4752
0
  if (!s)
4753
0
    return FALSE;
4754
4755
0
  rdp->settings->ShareId = 0x10000 + rdp->mcs->userId;
4756
0
  status = rdp_write_demand_active(rdp->log, s, rdp->settings) &&
4757
0
           rdp_send_pdu(rdp, s, PDU_TYPE_DEMAND_ACTIVE, rdp->mcs->userId, sec_flags);
4758
0
  Stream_Release(s);
4759
0
  return status;
4760
0
}
4761
4762
BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength)
4763
0
{
4764
0
  rdpSettings* settings = nullptr;
4765
0
  UINT16 lengthSourceDescriptor = 0;
4766
0
  UINT16 lengthCombinedCapabilities = 0;
4767
4768
0
  WINPR_ASSERT(rdp);
4769
0
  WINPR_ASSERT(s);
4770
0
  settings = rdp->settings;
4771
0
  WINPR_ASSERT(settings);
4772
4773
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 10))
4774
0
    return FALSE;
4775
4776
0
  Stream_Seek_UINT32(s);                             /* shareId (4 bytes) */
4777
0
  Stream_Seek_UINT16(s);                             /* originatorId (2 bytes) */
4778
0
  Stream_Read_UINT16(s, lengthSourceDescriptor);     /* lengthSourceDescriptor (2 bytes) */
4779
0
  Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4780
4781
0
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, lengthSourceDescriptor + 4U))
4782
0
    return FALSE;
4783
4784
0
  Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor */
4785
0
  if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4786
0
                                lengthCombinedCapabilities))
4787
0
    return FALSE;
4788
4789
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4790
0
  {
4791
    /* client does not support surface commands */
4792
0
    settings->SurfaceCommandsEnabled = FALSE;
4793
0
    settings->SurfaceFrameMarkerEnabled = FALSE;
4794
0
  }
4795
4796
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4797
0
  {
4798
    /* client does not support frame acks */
4799
0
    settings->FrameAcknowledge = 0;
4800
0
  }
4801
4802
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4803
0
  {
4804
    /* client does not support bitmap cache v3 */
4805
0
    settings->BitmapCacheV3Enabled = FALSE;
4806
0
  }
4807
4808
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4809
0
  {
4810
    /* client does not support bitmap codecs */
4811
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, FALSE))
4812
0
      return FALSE;
4813
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, FALSE))
4814
0
      return FALSE;
4815
0
    if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
4816
0
      return FALSE;
4817
0
  }
4818
4819
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4820
0
  {
4821
    /* client does not support multi fragment updates - make sure packages are not fragmented */
4822
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
4823
0
                                     FASTPATH_FRAGMENT_SAFE_SIZE))
4824
0
      return FALSE;
4825
0
  }
4826
4827
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4828
0
  {
4829
    /* client does not support large pointers */
4830
0
    settings->LargePointerFlag = 0;
4831
0
  }
4832
4833
0
  return tpkt_ensure_stream_consumed(rdp->log, s, pduLength);
4834
0
}
4835
4836
static BOOL rdp_write_confirm_active(wLog* log, wStream* s, rdpSettings* settings)
4837
0
{
4838
0
  size_t bm = 0;
4839
0
  size_t em = 0;
4840
0
  size_t lm = 0;
4841
0
  UINT16 numberCapabilities = 0;
4842
0
  UINT16 lengthSourceDescriptor = 0;
4843
0
  size_t lengthCombinedCapabilities = 0;
4844
0
  BOOL ret = 0;
4845
4846
0
  WINPR_ASSERT(settings);
4847
4848
0
  lengthSourceDescriptor = sizeof(SOURCE_DESCRIPTOR);
4849
0
  Stream_Write_UINT32(s, settings->ShareId);      /* shareId (4 bytes) */
4850
0
  Stream_Write_UINT16(s, 0x03EA);                 /* originatorId (2 bytes) */
4851
0
  Stream_Write_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4852
0
  lm = Stream_GetPosition(s);
4853
0
  Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4854
0
  Stream_Write(s, SOURCE_DESCRIPTOR, lengthSourceDescriptor); /* sourceDescriptor */
4855
0
  bm = Stream_GetPosition(s);
4856
0
  Stream_Seek_UINT16(s);     /* numberCapabilities (2 bytes) */
4857
0
  Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4858
  /* Capability Sets */
4859
0
  numberCapabilities = 15;
4860
4861
0
  if (!rdp_write_general_capability_set(log, s, settings) ||
4862
0
      !rdp_write_bitmap_capability_set(log, s, settings) ||
4863
0
      !rdp_write_order_capability_set(log, s, settings))
4864
0
    return FALSE;
4865
4866
0
  if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
4867
0
    ret = rdp_write_bitmap_cache_v2_capability_set(log, s, settings);
4868
0
  else
4869
0
    ret = rdp_write_bitmap_cache_capability_set(log, s, settings);
4870
4871
0
  if (!ret)
4872
0
    return FALSE;
4873
4874
0
  if (!rdp_write_pointer_capability_set(log, s, settings) ||
4875
0
      !rdp_write_input_capability_set(log, s, settings) ||
4876
0
      !rdp_write_brush_capability_set(log, s, settings) ||
4877
0
      !rdp_write_glyph_cache_capability_set(log, s, settings) ||
4878
0
      !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4879
0
      !rdp_write_sound_capability_set(log, s, settings) ||
4880
0
      !rdp_write_share_capability_set(log, s, settings) ||
4881
0
      !rdp_write_font_capability_set(log, s, settings) ||
4882
0
      !rdp_write_control_capability_set(log, s, settings) ||
4883
0
      !rdp_write_color_cache_capability_set(log, s, settings) ||
4884
0
      !rdp_write_window_activation_capability_set(log, s, settings))
4885
0
  {
4886
0
    return FALSE;
4887
0
  }
4888
4889
0
  {
4890
0
    numberCapabilities++;
4891
4892
0
    if (!rdp_write_offscreen_bitmap_cache_capability_set(log, s, settings))
4893
0
      return FALSE;
4894
0
  }
4895
4896
0
  if (settings->DrawNineGridEnabled)
4897
0
  {
4898
0
    numberCapabilities++;
4899
4900
0
    if (!rdp_write_draw_nine_grid_cache_capability_set(log, s, settings))
4901
0
      return FALSE;
4902
0
  }
4903
4904
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4905
0
  {
4906
0
    if (settings->LargePointerFlag)
4907
0
    {
4908
0
      numberCapabilities++;
4909
4910
0
      if (!rdp_write_large_pointer_capability_set(log, s, settings))
4911
0
        return FALSE;
4912
0
    }
4913
0
  }
4914
4915
0
  if (settings->RemoteApplicationMode)
4916
0
  {
4917
0
    numberCapabilities += 2;
4918
4919
0
    if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4920
0
        !rdp_write_window_list_capability_set(log, s, settings))
4921
0
      return FALSE;
4922
0
  }
4923
4924
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4925
0
  {
4926
0
    numberCapabilities++;
4927
4928
0
    if (!rdp_write_multifragment_update_capability_set(log, s, settings))
4929
0
      return FALSE;
4930
0
  }
4931
4932
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4933
0
  {
4934
0
    numberCapabilities++;
4935
4936
0
    if (!rdp_write_surface_commands_capability_set(log, s, settings))
4937
0
      return FALSE;
4938
0
  }
4939
4940
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4941
0
  {
4942
0
    numberCapabilities++;
4943
4944
0
    if (!rdp_write_bitmap_codecs_capability_set(log, s, settings))
4945
0
      return FALSE;
4946
0
  }
4947
4948
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4949
0
    settings->FrameAcknowledge = 0;
4950
4951
0
  if (settings->FrameAcknowledge)
4952
0
  {
4953
0
    numberCapabilities++;
4954
4955
0
    if (!rdp_write_frame_acknowledge_capability_set(log, s, settings))
4956
0
      return FALSE;
4957
0
  }
4958
4959
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4960
0
  {
4961
0
    if (settings->BitmapCacheV3CodecId != 0)
4962
0
    {
4963
0
      numberCapabilities++;
4964
4965
0
      if (!rdp_write_bitmap_cache_v3_codec_id_capability_set(log, s, settings))
4966
0
        return FALSE;
4967
0
    }
4968
0
  }
4969
4970
0
  em = Stream_GetPosition(s);
4971
0
  if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4972
0
    return FALSE;
4973
0
  lengthCombinedCapabilities = (em - bm);
4974
0
  if (lengthCombinedCapabilities > UINT16_MAX)
4975
0
    return FALSE;
4976
0
  Stream_Write_UINT16(
4977
0
      s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4978
0
  if (!Stream_SetPosition(s, bm))             /* go back to numberCapabilities */
4979
0
    return FALSE;
4980
0
  Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4981
#ifdef WITH_DEBUG_CAPABILITIES
4982
  rdp_print_capability_sets(log, s, bm, FALSE);
4983
#endif
4984
0
  return Stream_SetPosition(s, em);
4985
0
}
4986
4987
BOOL rdp_send_confirm_active(rdpRdp* rdp)
4988
0
{
4989
0
  UINT16 sec_flags = 0;
4990
0
  wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4991
0
  BOOL status = 0;
4992
4993
0
  if (!s)
4994
0
    return FALSE;
4995
4996
0
  status = rdp_write_confirm_active(rdp->log, s, rdp->settings) &&
4997
0
           rdp_send_pdu(rdp, s, PDU_TYPE_CONFIRM_ACTIVE, rdp->mcs->userId, sec_flags);
4998
0
  Stream_Release(s);
4999
0
  return status;
5000
0
}
5001
5002
const char* rdp_input_flag_string(UINT16 flags, char* buffer, size_t len)
5003
0
{
5004
0
  char prefix[16] = WINPR_C_ARRAY_INIT;
5005
5006
0
  (void)_snprintf(prefix, sizeof(prefix), "[0x%04" PRIx16 "][", flags);
5007
0
  winpr_str_append(prefix, buffer, len, "");
5008
0
  if ((flags & INPUT_FLAG_SCANCODES) != 0)
5009
0
    winpr_str_append("INPUT_FLAG_SCANCODES", buffer, len, "|");
5010
0
  if ((flags & INPUT_FLAG_MOUSEX) != 0)
5011
0
    winpr_str_append("INPUT_FLAG_MOUSEX", buffer, len, "|");
5012
0
  if ((flags & INPUT_FLAG_FASTPATH_INPUT) != 0)
5013
0
    winpr_str_append("INPUT_FLAG_FASTPATH_INPUT", buffer, len, "|");
5014
0
  if ((flags & INPUT_FLAG_UNICODE) != 0)
5015
0
    winpr_str_append("INPUT_FLAG_UNICODE", buffer, len, "|");
5016
0
  if ((flags & INPUT_FLAG_FASTPATH_INPUT2) != 0)
5017
0
    winpr_str_append("INPUT_FLAG_FASTPATH_INPUT2", buffer, len, "|");
5018
0
  if ((flags & INPUT_FLAG_UNUSED1) != 0)
5019
0
    winpr_str_append("INPUT_FLAG_UNUSED1", buffer, len, "|");
5020
0
  if ((flags & INPUT_FLAG_MOUSE_RELATIVE) != 0)
5021
0
    winpr_str_append("INPUT_FLAG_MOUSE_RELATIVE", buffer, len, "|");
5022
0
  if ((flags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0)
5023
0
    winpr_str_append("TS_INPUT_FLAG_MOUSE_HWHEEL", buffer, len, "|");
5024
0
  if ((flags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0)
5025
0
    winpr_str_append("TS_INPUT_FLAG_QOE_TIMESTAMPS", buffer, len, "|");
5026
0
  winpr_str_append("]", buffer, len, "");
5027
0
  return buffer;
5028
0
}