Coverage Report

Created: 2026-05-30 06:46

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
1.69k
{
68
1.69k
  if (type > CAPSET_TYPE_FRAME_ACKNOWLEDGE)
69
1.51k
    return "<unknown>";
70
71
183
  return CAPSET_TYPE_STRINGS[type];
72
1.69k
}
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
84.5k
{
112
84.5k
  WINPR_ASSERT(s);
113
84.5k
  WINPR_ASSERT(length);
114
84.5k
  WINPR_ASSERT(type);
115
116
84.5k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
117
0
    return FALSE;
118
84.5k
  Stream_Read_UINT16(s, *type);   /* capabilitySetType */
119
84.5k
  Stream_Read_UINT16(s, *length); /* lengthCapability */
120
84.5k
  return (*length >= 4);
121
84.5k
}
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
1.77k
{
158
1.77k
  WINPR_ASSERT(settings);
159
1.77k
  WINPR_ASSERT(src);
160
161
1.77k
  if (settings->ServerMode)
162
600
  {
163
600
    settings->OsMajorType = src->OsMajorType;
164
600
    settings->OsMinorType = src->OsMinorType;
165
600
  }
166
167
1.77k
  settings->CapsProtocolVersion = src->CapsProtocolVersion;
168
1.77k
  settings->NoBitmapCompressionHeader = src->NoBitmapCompressionHeader;
169
1.77k
  settings->LongCredentialsSupported = src->LongCredentialsSupported;
170
1.77k
  settings->AutoReconnectionPacketSupported = src->AutoReconnectionPacketSupported;
171
1.77k
  if (!src->FastPathOutput)
172
1.00k
    settings->FastPathOutput = FALSE;
173
174
1.77k
  if (!src->SaltedChecksum)
175
768
    settings->SaltedChecksum = FALSE;
176
177
1.77k
  if (!settings->ServerMode)
178
1.17k
  {
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
1.17k
    if (!src->RefreshRect)
185
701
      settings->RefreshRect = FALSE;
186
187
1.17k
    if (!src->SuppressOutput)
188
1.03k
      settings->SuppressOutput = FALSE;
189
1.17k
  }
190
1.77k
  return TRUE;
191
1.77k
}
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
1.82k
{
200
1.82k
  UINT16 extraFlags = 0;
201
1.82k
  BYTE refreshRectSupport = 0;
202
1.82k
  BYTE suppressOutputSupport = 0;
203
204
1.82k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
205
7
    return FALSE;
206
207
1.82k
  WINPR_ASSERT(settings);
208
1.82k
  Stream_Read_UINT16(s, settings->OsMajorType); /* osMajorType (2 bytes) */
209
1.82k
  Stream_Read_UINT16(s, settings->OsMinorType); /* osMinorType (2 bytes) */
210
211
1.82k
  Stream_Read_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
212
1.82k
  if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
213
1.58k
  {
214
1.58k
    WLog_Print(log, WLOG_ERROR,
215
1.58k
               "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
216
1.58k
               ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
217
1.58k
               settings->CapsProtocolVersion,
218
1.58k
               WINPR_CXX_COMPAT_CAST(UINT32, TS_CAPS_PROTOCOLVERSION));
219
1.58k
    if (settings->CapsProtocolVersion == 0x0000)
220
1.53k
    {
221
1.53k
      WLog_Print(log, WLOG_WARN,
222
1.53k
                 "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
223
1.53k
                 " assuming old FreeRDP, ignoring protocol violation, correcting value.",
224
1.53k
                 settings->CapsProtocolVersion);
225
1.53k
      settings->CapsProtocolVersion = TS_CAPS_PROTOCOLVERSION;
226
1.53k
    }
227
41
    else
228
41
      return FALSE;
229
1.58k
  }
230
1.77k
  Stream_Seek_UINT16(s);                                /* pad2OctetsA (2 bytes) */
231
1.77k
  Stream_Read_UINT16(
232
1.77k
      s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
233
1.77k
  Stream_Read_UINT16(s, extraFlags);             /* extraFlags (2 bytes) */
234
1.77k
  Stream_Read_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
235
1.77k
  Stream_Read_UINT16(s, settings->CapsRemoteUnshareFlag);    /* remoteUnshareFlag (2 bytes) */
236
1.77k
  Stream_Read_UINT16(
237
1.77k
      s, settings->CapsGeneralCompressionLevel); /* generalCompressionLevel (2 bytes) */
238
1.77k
  Stream_Read_UINT8(s, refreshRectSupport);      /* refreshRectSupport (1 byte) */
239
1.77k
  Stream_Read_UINT8(s, suppressOutputSupport);   /* suppressOutputSupport (1 byte) */
240
1.77k
  settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) != 0;
241
1.77k
  settings->LongCredentialsSupported = (extraFlags & LONG_CREDENTIALS_SUPPORTED) != 0;
242
243
1.77k
  settings->AutoReconnectionPacketSupported = (extraFlags & AUTORECONNECT_SUPPORTED) != 0;
244
1.77k
  settings->FastPathOutput = (extraFlags & FASTPATH_OUTPUT_SUPPORTED) != 0;
245
1.77k
  settings->SaltedChecksum = (extraFlags & ENC_SALTED_CHECKSUM) != 0;
246
1.77k
  settings->RefreshRect = refreshRectSupport;
247
1.77k
  settings->SuppressOutput = suppressOutputSupport;
248
249
1.77k
  return TRUE;
250
1.82k
}
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
2.90k
{
354
2.90k
  WINPR_ASSERT(settings);
355
2.90k
  WINPR_ASSERT(src);
356
357
2.90k
  if (!settings->ServerMode)
358
1.14k
  {
359
1.14k
    if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
360
1.14k
                                     freerdp_settings_get_uint32(src, FreeRDP_ColorDepth)))
361
0
      return FALSE;
362
1.14k
  }
363
364
2.90k
  if (!src->DesktopResize)
365
2.63k
    settings->DesktopResize = FALSE;
366
367
2.90k
  if (!settings->ServerMode && settings->DesktopResize)
368
108
  {
369
    /* The server may request a different desktop size during Deactivation-Reactivation sequence
370
     */
371
108
    settings->DesktopWidth = src->DesktopWidth;
372
108
    settings->DesktopHeight = src->DesktopHeight;
373
108
  }
374
375
2.90k
  if (settings->DrawAllowSkipAlpha)
376
572
    settings->DrawAllowSkipAlpha = src->DrawAllowSkipAlpha;
377
378
2.90k
  if (settings->DrawAllowDynamicColorFidelity)
379
978
    settings->DrawAllowDynamicColorFidelity = src->DrawAllowDynamicColorFidelity;
380
381
2.90k
  if (settings->DrawAllowColorSubsampling)
382
0
    settings->DrawAllowColorSubsampling = src->DrawAllowColorSubsampling;
383
384
2.90k
  return TRUE;
385
2.90k
}
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
2.91k
{
394
2.91k
  BYTE drawingFlags = 0;
395
2.91k
  UINT16 desktopWidth = 0;
396
2.91k
  UINT16 desktopHeight = 0;
397
2.91k
  UINT16 desktopResizeFlag = 0;
398
2.91k
  UINT16 preferredBitsPerPixel = 0;
399
400
2.91k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 24))
401
9
    return FALSE;
402
403
2.90k
  Stream_Read_UINT16(s, preferredBitsPerPixel); /* preferredBitsPerPixel (2 bytes) */
404
2.90k
  Stream_Seek_UINT16(s);                        /* receive1BitPerPixel (2 bytes) */
405
2.90k
  Stream_Seek_UINT16(s);                        /* receive4BitsPerPixel (2 bytes) */
406
2.90k
  Stream_Seek_UINT16(s);                        /* receive8BitsPerPixel (2 bytes) */
407
2.90k
  Stream_Read_UINT16(s, desktopWidth);          /* desktopWidth (2 bytes) */
408
2.90k
  Stream_Read_UINT16(s, desktopHeight);         /* desktopHeight (2 bytes) */
409
2.90k
  Stream_Seek_UINT16(s);                        /* pad2Octets (2 bytes) */
410
2.90k
  Stream_Read_UINT16(s, desktopResizeFlag);     /* desktopResizeFlag (2 bytes) */
411
2.90k
  Stream_Seek_UINT16(s);                        /* bitmapCompressionFlag (2 bytes) */
412
2.90k
  Stream_Seek_UINT8(s);                         /* highColorFlags (1 byte) */
413
2.90k
  Stream_Read_UINT8(s, drawingFlags);           /* drawingFlags (1 byte) */
414
2.90k
  Stream_Seek_UINT16(s);                        /* multipleRectangleSupport (2 bytes) */
415
2.90k
  Stream_Seek_UINT16(s);                        /* pad2OctetsB (2 bytes) */
416
417
2.90k
  if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, preferredBitsPerPixel))
418
0
    return FALSE;
419
2.90k
  settings->DesktopResize = desktopResizeFlag;
420
2.90k
  settings->DesktopWidth = desktopWidth;
421
2.90k
  settings->DesktopHeight = desktopHeight;
422
2.90k
  settings->DrawAllowSkipAlpha = (drawingFlags & DRAW_ALLOW_SKIP_ALPHA) != 0;
423
2.90k
  settings->DrawAllowDynamicColorFidelity =
424
2.90k
      (drawingFlags & DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY) != 0;
425
2.90k
  settings->DrawAllowColorSubsampling = (drawingFlags & DRAW_ALLOW_COLOR_SUBSAMPLING) != 0;
426
427
2.90k
  return TRUE;
428
2.90k
}
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
2.42k
{
543
2.42k
  WINPR_ASSERT(settings);
544
2.42k
  WINPR_ASSERT(src);
545
546
2.42k
  BOOL BitmapCacheV3Enabled = FALSE;
547
2.42k
  BOOL FrameMarkerCommandEnabled = FALSE;
548
549
80.0k
  for (size_t i = 0; i < 32; i++)
550
77.6k
  {
551
77.6k
    if (!src->OrderSupport[i])
552
46.9k
      settings->OrderSupport[i] = FALSE;
553
77.6k
  }
554
555
2.42k
  if (src->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
556
622
  {
557
622
    if (src->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT)
558
245
      BitmapCacheV3Enabled = TRUE;
559
560
622
    if (src->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT)
561
143
      FrameMarkerCommandEnabled = TRUE;
562
622
  }
563
564
2.42k
  if (BitmapCacheV3Enabled && settings->BitmapCacheV3Enabled)
565
0
  {
566
0
    settings->BitmapCacheV3Enabled = src->BitmapCacheV3Enabled;
567
0
    settings->BitmapCacheVersion = src->BitmapCacheVersion;
568
0
  }
569
2.42k
  else
570
2.42k
    settings->BitmapCacheV3Enabled = FALSE;
571
572
2.42k
  settings->FrameMarkerCommandEnabled =
573
2.42k
      (FrameMarkerCommandEnabled && src->FrameMarkerCommandEnabled);
574
575
2.42k
  return TRUE;
576
2.42k
}
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
2.43k
{
585
2.43k
  char terminalDescriptor[17] = WINPR_C_ARRAY_INIT;
586
2.43k
  BYTE orderSupport[32] = WINPR_C_ARRAY_INIT;
587
2.43k
  BOOL BitmapCacheV3Enabled = FALSE;
588
2.43k
  BOOL FrameMarkerCommandEnabled = FALSE;
589
590
2.43k
  WINPR_ASSERT(settings);
591
2.43k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
592
7
    return FALSE;
593
594
2.42k
  Stream_Read(s, terminalDescriptor, 16);               /* terminalDescriptor (16 bytes) */
595
2.42k
  Stream_Seek_UINT32(s);                                /* pad4OctetsA (4 bytes) */
596
2.42k
  Stream_Seek_UINT16(s);                                /* desktopSaveXGranularity (2 bytes) */
597
2.42k
  Stream_Seek_UINT16(s);                                /* desktopSaveYGranularity (2 bytes) */
598
2.42k
  Stream_Seek_UINT16(s);                                /* pad2OctetsA (2 bytes) */
599
2.42k
  Stream_Seek_UINT16(s);                                /* maximumOrderLevel (2 bytes) */
600
2.42k
  Stream_Seek_UINT16(s);                                /* numberFonts (2 bytes) */
601
2.42k
  Stream_Read_UINT16(s, settings->OrderSupportFlags);   /* orderFlags (2 bytes) */
602
2.42k
  Stream_Read(s, orderSupport, 32);                     /* orderSupport (32 bytes) */
603
2.42k
  Stream_Seek_UINT16(s);                                /* textFlags (2 bytes) */
604
2.42k
  Stream_Read_UINT16(s, settings->OrderSupportFlagsEx); /* orderSupportExFlags (2 bytes) */
605
2.42k
  Stream_Seek_UINT32(s);                                /* pad4OctetsB (4 bytes) */
606
2.42k
  Stream_Seek_UINT32(s);                                /* desktopSaveSize (4 bytes) */
607
2.42k
  Stream_Seek_UINT16(s);                                /* pad2OctetsC (2 bytes) */
608
2.42k
  Stream_Seek_UINT16(s);                                /* pad2OctetsD (2 bytes) */
609
2.42k
  Stream_Read_UINT16(s, settings->TextANSICodePage);    /* textANSICodePage (2 bytes) */
610
2.42k
  Stream_Seek_UINT16(s);                                /* pad2OctetsE (2 bytes) */
611
612
2.42k
  if (!freerdp_settings_set_string(settings, FreeRDP_TerminalDescriptor, terminalDescriptor))
613
0
    return FALSE;
614
615
80.0k
  for (size_t i = 0; i < ARRAYSIZE(orderSupport); i++)
616
77.6k
    settings->OrderSupport[i] = orderSupport[i];
617
618
2.42k
  if (settings->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
619
622
  {
620
622
    BitmapCacheV3Enabled = (settings->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT) != 0;
621
622
    FrameMarkerCommandEnabled =
622
622
        (settings->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT) != 0;
623
622
  }
624
625
2.42k
  settings->BitmapCacheV3Enabled = BitmapCacheV3Enabled;
626
2.42k
  if (BitmapCacheV3Enabled)
627
245
    settings->BitmapCacheVersion = 3;
628
629
2.42k
  settings->FrameMarkerCommandEnabled = FrameMarkerCommandEnabled;
630
631
2.42k
  return TRUE;
632
2.42k
}
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
82
{
818
82
  WINPR_ASSERT(settings);
819
82
  WINPR_ASSERT(src);
820
82
  return TRUE;
821
82
}
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
94
{
830
94
  WINPR_UNUSED(settings);
831
94
  WINPR_ASSERT(settings);
832
833
94
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
834
12
    return FALSE;
835
836
82
  Stream_Seek_UINT32(s); /* pad1 (4 bytes) */
837
82
  Stream_Seek_UINT32(s); /* pad2 (4 bytes) */
838
82
  Stream_Seek_UINT32(s); /* pad3 (4 bytes) */
839
82
  Stream_Seek_UINT32(s); /* pad4 (4 bytes) */
840
82
  Stream_Seek_UINT32(s); /* pad5 (4 bytes) */
841
82
  Stream_Seek_UINT32(s); /* pad6 (4 bytes) */
842
82
  Stream_Seek_UINT16(s); /* Cache0Entries (2 bytes) */
843
82
  Stream_Seek_UINT16(s); /* Cache0MaximumCellSize (2 bytes) */
844
82
  Stream_Seek_UINT16(s); /* Cache1Entries (2 bytes) */
845
82
  Stream_Seek_UINT16(s); /* Cache1MaximumCellSize (2 bytes) */
846
82
  Stream_Seek_UINT16(s); /* Cache2Entries (2 bytes) */
847
82
  Stream_Seek_UINT16(s); /* Cache2MaximumCellSize (2 bytes) */
848
82
  return TRUE;
849
94
}
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
13
{
942
13
  WINPR_ASSERT(settings);
943
13
  WINPR_ASSERT(src);
944
945
13
  return TRUE;
946
13
}
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
17
{
955
17
  WINPR_UNUSED(settings);
956
17
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
957
4
    return FALSE;
958
959
13
  Stream_Seek_UINT16(s); /* controlFlags (2 bytes) */
960
13
  Stream_Seek_UINT16(s); /* remoteDetachFlag (2 bytes) */
961
13
  Stream_Seek_UINT16(s); /* controlInterest (2 bytes) */
962
13
  Stream_Seek_UINT16(s); /* detachInterest (2 bytes) */
963
13
  return TRUE;
964
17
}
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
56
{
1013
56
  WINPR_ASSERT(settings);
1014
56
  WINPR_ASSERT(src);
1015
1016
56
  return TRUE;
1017
56
}
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
62
{
1026
62
  WINPR_UNUSED(settings);
1027
62
  WINPR_ASSERT(settings);
1028
62
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1029
6
    return FALSE;
1030
1031
56
  Stream_Seek_UINT16(s); /* helpKeyFlag (2 bytes) */
1032
56
  Stream_Seek_UINT16(s); /* helpKeyIndexFlag (2 bytes) */
1033
56
  Stream_Seek_UINT16(s); /* helpExtendedKeyFlag (2 bytes) */
1034
56
  Stream_Seek_UINT16(s); /* windowManagerKeyFlag (2 bytes) */
1035
56
  return TRUE;
1036
62
}
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
11.3k
{
1086
11.3k
  WINPR_ASSERT(settings);
1087
11.3k
  WINPR_ASSERT(src);
1088
1089
11.3k
  const UINT32 pointerCacheSize = freerdp_settings_get_uint32(src, FreeRDP_PointerCacheSize);
1090
11.3k
  const UINT32 colorPointerCacheSize =
1091
11.3k
      freerdp_settings_get_uint32(src, FreeRDP_ColorPointerCacheSize);
1092
11.3k
  const UINT32 dstPointerCacheSize =
1093
11.3k
      freerdp_settings_get_uint32(settings, FreeRDP_PointerCacheSize);
1094
11.3k
  const UINT32 dstColorPointerCacheSize =
1095
11.3k
      freerdp_settings_get_uint32(settings, FreeRDP_ColorPointerCacheSize);
1096
1097
  /* We want the minimum of our setting and the remote announced value. */
1098
11.3k
  const UINT32 actualPointerCacheSize = MIN(pointerCacheSize, dstPointerCacheSize);
1099
11.3k
  const UINT32 actualColorPointerCacheSize = MIN(colorPointerCacheSize, dstColorPointerCacheSize);
1100
1101
11.3k
  return !(
1102
11.3k
      !freerdp_settings_set_uint32(settings, FreeRDP_PointerCacheSize, actualPointerCacheSize) ||
1103
11.3k
      !freerdp_settings_set_uint32(settings, FreeRDP_ColorPointerCacheSize,
1104
11.3k
                                   actualColorPointerCacheSize));
1105
11.3k
}
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
11.4k
{
1114
11.4k
  UINT16 colorPointerFlag = 0;
1115
11.4k
  UINT16 colorPointerCacheSize = 0;
1116
11.4k
  UINT16 pointerCacheSize = 0;
1117
1118
11.4k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1119
16
    return FALSE;
1120
1121
11.3k
  Stream_Read_UINT16(s, colorPointerFlag);      /* colorPointerFlag (2 bytes) */
1122
11.3k
  Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1123
1124
11.3k
  if (colorPointerFlag == 0)
1125
668
  {
1126
668
    WLog_Print(log, WLOG_WARN,
1127
668
               "[MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set "
1128
668
               "(TS_POINTER_CAPABILITYSET)::colorPointerFlag received is %" PRIu16
1129
668
               ". Value is ignored and always assumed to be TRUE",
1130
668
               colorPointerFlag);
1131
668
  }
1132
1133
  /* pointerCacheSize is optional */
1134
11.3k
  if (Stream_GetRemainingLength(s) >= 2)
1135
1.00k
    Stream_Read_UINT16(s, pointerCacheSize); /* pointerCacheSize (2 bytes) */
1136
1137
11.3k
  WINPR_ASSERT(settings);
1138
11.3k
  settings->PointerCacheSize = pointerCacheSize;
1139
11.3k
  settings->ColorPointerCacheSize = colorPointerCacheSize;
1140
1141
11.3k
  return TRUE;
1142
11.4k
}
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
335
{
1197
335
  WINPR_ASSERT(settings);
1198
335
  WINPR_ASSERT(src);
1199
1200
335
  return TRUE;
1201
335
}
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
339
{
1210
339
  WINPR_UNUSED(settings);
1211
339
  WINPR_ASSERT(settings);
1212
1213
339
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1214
4
    return FALSE;
1215
1216
335
  Stream_Seek_UINT16(s); /* nodeId (2 bytes) */
1217
335
  Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1218
335
  return TRUE;
1219
339
}
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
2.14k
{
1262
2.14k
  WINPR_ASSERT(settings);
1263
2.14k
  WINPR_ASSERT(src);
1264
2.14k
  return TRUE;
1265
2.14k
}
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
2.16k
{
1274
2.16k
  WINPR_UNUSED(settings);
1275
2.16k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1276
19
    return FALSE;
1277
1278
2.14k
  Stream_Seek_UINT16(s); /* colorTableCacheSize (2 bytes) */
1279
2.14k
  Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1280
2.14k
  return TRUE;
1281
2.16k
}
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
343
{
1321
343
  WINPR_ASSERT(settings);
1322
343
  WINPR_ASSERT(src);
1323
1324
343
  settings->SoundBeepsEnabled = src->SoundBeepsEnabled;
1325
1326
343
  return TRUE;
1327
343
}
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
346
{
1336
346
  UINT16 soundFlags = 0;
1337
1338
346
  WINPR_ASSERT(settings);
1339
346
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1340
3
    return FALSE;
1341
1342
343
  Stream_Read_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1343
343
  Stream_Seek_UINT16(s);             /* pad2OctetsA (2 bytes) */
1344
343
  settings->SoundBeepsEnabled = (soundFlags & SOUND_BEEPS_FLAG) != 0;
1345
343
  return TRUE;
1346
346
}
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
26.4k
{
1387
26.4k
  WINPR_ASSERT(settings);
1388
26.4k
  WINPR_ASSERT(src);
1389
1390
26.4k
  if (settings->ServerMode)
1391
11.2k
  {
1392
11.2k
    settings->KeyboardLayout = src->KeyboardLayout;
1393
11.2k
    settings->KeyboardType = src->KeyboardType;
1394
11.2k
    settings->KeyboardSubType = src->KeyboardSubType;
1395
11.2k
    settings->KeyboardFunctionKey = src->KeyboardFunctionKey;
1396
11.2k
  }
1397
1398
26.4k
  if (!freerdp_settings_set_string(settings, FreeRDP_ImeFileName, src->ImeFileName))
1399
0
    return FALSE;
1400
1401
26.4k
  if (!settings->ServerMode)
1402
15.2k
  {
1403
15.2k
    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
15.2k
    if (settings->HasHorizontalWheel)
1410
256
      settings->HasHorizontalWheel = src->HasHorizontalWheel;
1411
15.2k
    const BOOL UnicodeInput = freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput);
1412
15.2k
    if (UnicodeInput)
1413
15.2k
    {
1414
15.2k
      const BOOL srcVal = freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput);
1415
15.2k
      if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, srcVal))
1416
0
        return FALSE;
1417
15.2k
    }
1418
15.2k
    if (settings->HasExtendedMouseEvent)
1419
252
      settings->HasExtendedMouseEvent = src->HasExtendedMouseEvent;
1420
15.2k
    if (settings->HasRelativeMouseEvent)
1421
302
      settings->HasRelativeMouseEvent = src->HasRelativeMouseEvent;
1422
15.2k
    if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1423
15.2k
      settings->HasQoeEvent = freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent);
1424
15.2k
  }
1425
26.4k
  return TRUE;
1426
26.4k
}
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
26.4k
{
1435
26.4k
  UINT16 inputFlags = 0;
1436
1437
26.4k
  WINPR_ASSERT(settings);
1438
26.4k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1439
8
    return FALSE;
1440
1441
26.4k
  Stream_Read_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1442
26.4k
  Stream_Seek_UINT16(s);             /* pad2OctetsA (2 bytes) */
1443
1444
26.4k
  Stream_Read_UINT32(s, settings->KeyboardLayout);      /* keyboardLayout (4 bytes) */
1445
26.4k
  Stream_Read_UINT32(s, settings->KeyboardType);        /* keyboardType (4 bytes) */
1446
26.4k
  Stream_Read_UINT32(s, settings->KeyboardSubType);     /* keyboardSubType (4 bytes) */
1447
26.4k
  Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1448
1449
26.4k
  {
1450
26.4k
    WCHAR wstr[32] = WINPR_C_ARRAY_INIT;
1451
26.4k
    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
26.4k
    if (!Stream_Read_UTF16_String(s, wstr, ARRAYSIZE(wstr)))
1458
0
      return FALSE;
1459
1460
26.4k
    if (ConvertWCharNToUtf8(wstr, ARRAYSIZE(wstr), str, ARRAYSIZE(str)) < 0)
1461
12.6k
      memset(str, 0, sizeof(str));
1462
1463
26.4k
    if (!freerdp_settings_set_string_len(settings, FreeRDP_ImeFileName, str, ARRAYSIZE(str)))
1464
0
      return FALSE;
1465
26.4k
  }
1466
1467
26.4k
  if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathInput,
1468
26.4k
                                 inputFlags &
1469
26.4k
                                     (INPUT_FLAG_FASTPATH_INPUT | INPUT_FLAG_FASTPATH_INPUT2)))
1470
0
    return FALSE;
1471
26.4k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel,
1472
26.4k
                                 (inputFlags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0))
1473
0
    return FALSE;
1474
26.4k
  if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput,
1475
26.4k
                                 (inputFlags & INPUT_FLAG_UNICODE) != 0))
1476
0
    return FALSE;
1477
26.4k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent,
1478
26.4k
                                 (inputFlags & INPUT_FLAG_MOUSE_RELATIVE) != 0))
1479
0
    return FALSE;
1480
26.4k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent,
1481
26.4k
                                 (inputFlags & INPUT_FLAG_MOUSEX) != 0))
1482
0
    return FALSE;
1483
26.4k
  if (!freerdp_settings_set_bool(settings, FreeRDP_HasQoeEvent,
1484
26.4k
                                 (inputFlags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0))
1485
0
    return FALSE;
1486
1487
26.4k
  return TRUE;
1488
26.4k
}
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
1.59k
{
1570
1.59k
  WINPR_ASSERT(settings);
1571
1.59k
  WINPR_ASSERT(src);
1572
1.59k
  return TRUE;
1573
1.59k
}
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
1.59k
{
1583
1.59k
  WINPR_UNUSED(settings);
1584
1.59k
  if (Stream_GetRemainingLength(s) >= 2)
1585
334
    Stream_Seek_UINT16(s); /* fontSupportFlags (2 bytes) */
1586
1587
1.59k
  if (Stream_GetRemainingLength(s) >= 2)
1588
333
    Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1589
1590
1.59k
  return TRUE;
1591
1.59k
}
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
531
{
1632
531
  WINPR_ASSERT(settings);
1633
531
  WINPR_ASSERT(src);
1634
1635
  // TODO: Minimum of what?
1636
531
  settings->BrushSupportLevel = src->BrushSupportLevel;
1637
531
  return TRUE;
1638
531
}
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
534
{
1647
534
  WINPR_UNUSED(settings);
1648
534
  WINPR_ASSERT(settings);
1649
1650
534
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1651
3
    return FALSE;
1652
531
  Stream_Read_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1653
531
  return TRUE;
1654
534
}
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
627
{
1694
627
  WINPR_ASSERT(cache_definition);
1695
627
  Stream_Read_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1696
627
  Stream_Read_UINT16(s,
1697
627
                     cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1698
627
}
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
57
{
1714
57
  WINPR_ASSERT(settings);
1715
57
  WINPR_ASSERT(src);
1716
1717
57
  WINPR_ASSERT(src->GlyphCache);
1718
57
  WINPR_ASSERT(settings->GlyphCache);
1719
627
  for (size_t x = 0; x < 10; x++)
1720
570
    settings->GlyphCache[x] = src->GlyphCache[x];
1721
1722
57
  WINPR_ASSERT(src->FragCache);
1723
57
  WINPR_ASSERT(settings->FragCache);
1724
57
  settings->FragCache[0] = src->FragCache[0];
1725
57
  settings->GlyphSupportLevel = src->GlyphSupportLevel;
1726
1727
57
  return TRUE;
1728
57
}
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
61
{
1737
61
  WINPR_ASSERT(settings);
1738
61
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1739
4
    return FALSE;
1740
1741
  /* glyphCache (40 bytes) */
1742
627
  for (size_t x = 0; x < 10; x++)
1743
570
    rdp_read_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1744
57
  rdp_read_cache_definition(s, settings->FragCache);            /* fragCache (4 bytes) */
1745
57
  Stream_Read_UINT16(s, settings->GlyphSupportLevel);           /* glyphSupportLevel (2 bytes) */
1746
57
  Stream_Seek_UINT16(s);                                        /* pad2Octets (2 bytes) */
1747
57
  return TRUE;
1748
61
}
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
124
{
1831
124
  WINPR_ASSERT(settings);
1832
124
  WINPR_ASSERT(src);
1833
1834
124
  settings->OffscreenCacheSize = src->OffscreenCacheSize;
1835
124
  settings->OffscreenCacheEntries = src->OffscreenCacheEntries;
1836
124
  settings->OffscreenSupportLevel = src->OffscreenSupportLevel;
1837
1838
124
  return TRUE;
1839
124
}
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
129
{
1849
129
  UINT32 offscreenSupportLevel = 0;
1850
1851
129
  WINPR_ASSERT(settings);
1852
129
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1853
5
    return FALSE;
1854
1855
124
  Stream_Read_UINT32(s, offscreenSupportLevel);           /* offscreenSupportLevel (4 bytes) */
1856
124
  Stream_Read_UINT16(s, settings->OffscreenCacheSize);    /* offscreenCacheSize (2 bytes) */
1857
124
  Stream_Read_UINT16(s, settings->OffscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1858
1859
124
  settings->OffscreenSupportLevel = offscreenSupportLevel & 0x01;
1860
1861
124
  return TRUE;
1862
129
}
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
9.12k
{
1922
9.12k
  const BOOL val = (freerdp_settings_get_bool(src, FreeRDP_BitmapCachePersistEnabled) &&
1923
8.36k
                    freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled));
1924
9.12k
  return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, val);
1925
9.12k
}
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
9.13k
{
1935
9.13k
  BYTE cacheVersion = 0;
1936
1937
9.13k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1938
4
    return FALSE;
1939
1940
9.12k
  Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1941
9.12k
  Stream_Seek_UINT8(s);               /* pad1 (1 byte) */
1942
9.12k
  Stream_Seek_UINT16(s);              /* pad2 (2 bytes) */
1943
1944
9.12k
  return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
1945
9.12k
                                   cacheVersion & BITMAP_CACHE_V2);
1946
9.13k
}
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
14.3k
{
1996
14.3k
  UINT32 info = 0;
1997
1998
14.3k
  WINPR_ASSERT(cellInfo);
1999
14.3k
  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
14.3k
  Stream_Read_UINT32(s, info);
2007
14.3k
  cellInfo->numEntries = (info & 0x7FFFFFFF);
2008
14.3k
  cellInfo->persistent = (info & 0x80000000) ? 1 : 0;
2009
14.3k
  return TRUE;
2010
14.3k
}
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
9.55k
{
2026
9.55k
  const FreeRDP_Settings_Keys_Bool keys[] = { FreeRDP_BitmapCacheEnabled,
2027
9.55k
                                            FreeRDP_BitmapCachePersistEnabled };
2028
2029
28.6k
  for (size_t x = 0; x < ARRAYSIZE(keys); x++)
2030
19.1k
  {
2031
19.1k
    const FreeRDP_Settings_Keys_Bool id = keys[x];
2032
19.1k
    const BOOL val = freerdp_settings_get_bool(src, id);
2033
19.1k
    if (!freerdp_settings_set_bool(settings, id, val))
2034
0
      return FALSE;
2035
19.1k
  }
2036
2037
9.55k
  {
2038
9.55k
    const UINT32 BitmapCacheV2NumCells =
2039
9.55k
        freerdp_settings_get_uint32(src, FreeRDP_BitmapCacheV2NumCells);
2040
9.55k
    if (!freerdp_settings_set_pointer_len(settings, FreeRDP_BitmapCacheV2CellInfo, nullptr,
2041
9.55k
                                          BitmapCacheV2NumCells))
2042
0
      return FALSE;
2043
2044
23.8k
    for (size_t x = 0; x < BitmapCacheV2NumCells; x++)
2045
14.3k
    {
2046
14.3k
      const BITMAP_CACHE_V2_CELL_INFO* cdata =
2047
14.3k
          freerdp_settings_get_pointer_array(src, FreeRDP_BitmapCacheV2CellInfo, x);
2048
14.3k
      if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, x,
2049
14.3k
                                              cdata))
2050
0
        return FALSE;
2051
14.3k
    }
2052
9.55k
  }
2053
2054
9.55k
  return TRUE;
2055
9.55k
}
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
9.56k
{
2064
9.56k
  UINT16 cacheFlags = 0;
2065
9.56k
  WINPR_UNUSED(settings);
2066
9.56k
  WINPR_ASSERT(settings);
2067
2068
9.56k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2069
4
    return FALSE;
2070
2071
9.56k
  Stream_Read_UINT16(s, cacheFlags); /* cacheFlags (2 bytes) */
2072
2073
9.56k
  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE))
2074
0
    return FALSE;
2075
9.56k
  if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
2076
9.56k
                                 cacheFlags & PERSISTENT_KEYS_EXPECTED_FLAG))
2077
0
    return FALSE;
2078
2079
9.56k
  Stream_Seek_UINT8(s);                                  /* pad2 (1 byte) */
2080
9.56k
  Stream_Read_UINT8(s, settings->BitmapCacheV2NumCells); /* numCellCaches (1 byte) */
2081
9.56k
  if (settings->BitmapCacheV2NumCells > 5)
2082
5
  {
2083
5
    WLog_Print(log, WLOG_ERROR,
2084
5
               "Invalid TS_BITMAPCACHE_CAPABILITYSET_REV2::numCellCaches %" PRIu32 " > 5",
2085
5
               settings->BitmapCacheV2NumCells);
2086
5
    return FALSE;
2087
5
  }
2088
2089
23.8k
  for (size_t x = 0; x < settings->BitmapCacheV2NumCells; x++)
2090
14.3k
  {
2091
14.3k
    BITMAP_CACHE_V2_CELL_INFO* info =
2092
14.3k
        freerdp_settings_get_pointer_array_writable(settings, FreeRDP_BitmapCacheV2CellInfo, x);
2093
14.3k
    if (!rdp_read_bitmap_cache_cell_info(log, s, info))
2094
0
      return FALSE;
2095
14.3k
  }
2096
2097
  /* Input must always have 5 BitmapCacheV2CellInfo values */
2098
43.0k
  for (size_t x = settings->BitmapCacheV2NumCells; x < 5; x++)
2099
33.4k
  {
2100
33.4k
    if (!Stream_SafeSeek(s, 4))
2101
0
      return FALSE;
2102
33.4k
  }
2103
9.55k
  Stream_Seek(s, 12); /* pad3 (12 bytes) */
2104
9.55k
  return TRUE;
2105
9.55k
}
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
1.86k
{
2192
1.86k
  WINPR_ASSERT(settings);
2193
1.86k
  WINPR_ASSERT(src);
2194
2195
  /* MS servers and clients disregard in advertising what is relevant for their own side */
2196
1.86k
  if (settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_SC) &&
2197
0
      (src->VCFlags & VCCAPS_COMPR_SC))
2198
0
    settings->VCFlags |= VCCAPS_COMPR_SC;
2199
1.86k
  else
2200
1.86k
    settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_SC;
2201
2202
1.86k
  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
1.86k
  else
2206
1.86k
    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
1.86k
  if (!settings->ServerMode)
2214
1.11k
  {
2215
1.11k
    if ((src->VCChunkSize > CHANNEL_CHUNK_MAX_LENGTH) || (src->VCChunkSize == 0))
2216
1.08k
      settings->VCChunkSize = CHANNEL_CHUNK_LENGTH;
2217
33
    else
2218
33
    {
2219
33
      settings->VCChunkSize = src->VCChunkSize;
2220
33
    }
2221
1.11k
  }
2222
2223
1.86k
  return TRUE;
2224
1.86k
}
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
1.86k
{
2233
1.86k
  UINT32 flags = 0;
2234
1.86k
  UINT32 VCChunkSize = 0;
2235
2236
1.86k
  WINPR_ASSERT(settings);
2237
1.86k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2238
5
    return FALSE;
2239
2240
1.86k
  Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2241
2242
1.86k
  if (Stream_GetRemainingLength(s) >= 4)
2243
1.11k
    Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2244
750
  else
2245
750
    VCChunkSize = UINT32_MAX; /* Use an invalid value to determine that value is not present */
2246
2247
1.86k
  settings->VCFlags = flags;
2248
1.86k
  settings->VCChunkSize = VCChunkSize;
2249
2250
1.86k
  return TRUE;
2251
1.86k
}
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
78
{
2298
78
  WINPR_ASSERT(settings);
2299
78
  WINPR_ASSERT(src);
2300
2301
78
  settings->DrawNineGridCacheSize = src->DrawNineGridCacheSize;
2302
78
  settings->DrawNineGridCacheEntries = src->DrawNineGridCacheEntries;
2303
78
  settings->DrawNineGridEnabled = src->DrawNineGridEnabled;
2304
2305
78
  return TRUE;
2306
78
}
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
81
{
2316
81
  UINT32 drawNineGridSupportLevel = 0;
2317
2318
81
  WINPR_ASSERT(settings);
2319
81
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2320
3
    return FALSE;
2321
2322
78
  Stream_Read_UINT32(s, drawNineGridSupportLevel);        /* drawNineGridSupportLevel (4 bytes) */
2323
78
  Stream_Read_UINT16(s, settings->DrawNineGridCacheSize); /* drawNineGridCacheSize (2 bytes) */
2324
78
  Stream_Read_UINT16(s,
2325
78
                     settings->DrawNineGridCacheEntries); /* drawNineGridCacheEntries (2 bytes) */
2326
2327
78
  settings->DrawNineGridEnabled =
2328
78
      (drawNineGridSupportLevel & (DRAW_NINEGRID_SUPPORTED | DRAW_NINEGRID_SUPPORTED_V2)) != 0;
2329
2330
78
  return TRUE;
2331
81
}
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
427
{
2384
427
  WINPR_ASSERT(settings);
2385
427
  WINPR_ASSERT(src);
2386
2387
427
  if (src->DrawGdiPlusEnabled)
2388
163
    settings->DrawGdiPlusEnabled = TRUE;
2389
2390
427
  if (src->DrawGdiPlusCacheEnabled)
2391
258
    settings->DrawGdiPlusCacheEnabled = TRUE;
2392
2393
427
  return TRUE;
2394
427
}
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
433
{
2403
433
  UINT32 drawGDIPlusSupportLevel = 0;
2404
433
  UINT32 drawGdiplusCacheLevel = 0;
2405
2406
433
  WINPR_ASSERT(settings);
2407
433
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2408
6
    return FALSE;
2409
2410
427
  Stream_Read_UINT32(s, drawGDIPlusSupportLevel); /* drawGDIPlusSupportLevel (4 bytes) */
2411
427
  Stream_Seek_UINT32(s);                          /* GdipVersion (4 bytes) */
2412
427
  Stream_Read_UINT32(s, drawGdiplusCacheLevel);   /* drawGdiplusCacheLevel (4 bytes) */
2413
427
  Stream_Seek(s, 10);                             /* GdipCacheEntries (10 bytes) */
2414
427
  Stream_Seek(s, 8);                              /* GdipCacheChunkSize (8 bytes) */
2415
427
  Stream_Seek(s, 6);                              /* GdipImageCacheProperties (6 bytes) */
2416
2417
427
  settings->DrawGdiPlusEnabled = (drawGDIPlusSupportLevel & DRAW_GDIPLUS_SUPPORTED) != 0;
2418
427
  settings->DrawGdiPlusCacheEnabled = (drawGdiplusCacheLevel & DRAW_GDIPLUS_CACHE_LEVEL_ONE) != 0;
2419
2420
427
  return TRUE;
2421
433
}
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
861
{
2480
861
  WINPR_ASSERT(settings);
2481
861
  WINPR_ASSERT(src);
2482
2483
861
  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
861
  UINT32 supportLevel = src->RemoteApplicationSupportLevel;
2490
861
  if (settings->RemoteApplicationMode)
2491
0
    supportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2492
2493
861
  settings->RemoteApplicationSupportLevel = supportLevel & settings->RemoteApplicationSupportMask;
2494
2495
861
  return TRUE;
2496
861
}
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
865
{
2505
865
  UINT32 railSupportLevel = 0;
2506
2507
865
  WINPR_ASSERT(settings);
2508
865
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2509
4
    return FALSE;
2510
2511
861
  Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2512
2513
861
  settings->RemoteApplicationMode = (railSupportLevel & RAIL_LEVEL_SUPPORTED) != 0;
2514
861
  settings->RemoteApplicationSupportLevel = railSupportLevel;
2515
861
  return TRUE;
2516
865
}
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
508
{
2569
508
  WINPR_ASSERT(settings);
2570
508
  WINPR_ASSERT(src);
2571
2572
508
  settings->RemoteWndSupportLevel = src->RemoteWndSupportLevel;
2573
508
  settings->RemoteAppNumIconCaches = src->RemoteAppNumIconCaches;
2574
508
  settings->RemoteAppNumIconCacheEntries = src->RemoteAppNumIconCacheEntries;
2575
2576
508
  return TRUE;
2577
508
}
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
514
{
2586
514
  WINPR_ASSERT(settings);
2587
514
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2588
6
    return FALSE;
2589
2590
508
  Stream_Read_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2591
508
  Stream_Read_UINT8(s, settings->RemoteAppNumIconCaches); /* numIconCaches (1 byte) */
2592
508
  Stream_Read_UINT16(s,
2593
508
                     settings->RemoteAppNumIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2594
508
  return TRUE;
2595
514
}
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
106
{
2645
106
  WINPR_ASSERT(settings);
2646
106
  WINPR_ASSERT(src);
2647
2648
106
  settings->CompDeskSupportLevel = src->CompDeskSupportLevel;
2649
106
  return TRUE;
2650
106
}
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
110
{
2660
110
  WINPR_UNUSED(settings);
2661
110
  WINPR_ASSERT(settings);
2662
2663
110
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2664
4
    return FALSE;
2665
2666
106
  Stream_Read_UINT16(s, settings->CompDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2667
106
  return TRUE;
2668
110
}
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
2.13k
{
2709
2.13k
  WINPR_ASSERT(settings);
2710
2.13k
  WINPR_ASSERT(src);
2711
2712
2.13k
  UINT32 multifragMaxRequestSize =
2713
2.13k
      freerdp_settings_get_uint32(src, FreeRDP_MultifragMaxRequestSize);
2714
2715
2.13k
  if (settings->ServerMode)
2716
1.30k
  {
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
1.30k
    if (multifragMaxRequestSize < FASTPATH_MAX_PACKET_SIZE)
2726
199
      multifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE;
2727
2728
1.30k
    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
1.30k
    else
2753
1.30k
    {
2754
1.30k
      if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2755
1.30k
                                       multifragMaxRequestSize))
2756
0
        return FALSE;
2757
1.30k
    }
2758
1.30k
  }
2759
829
  else
2760
829
  {
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
829
    if (multifragMaxRequestSize >
2767
829
        freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize))
2768
122
    {
2769
122
      if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2770
122
                                       multifragMaxRequestSize))
2771
0
        return FALSE;
2772
122
    }
2773
829
  }
2774
2.13k
  return TRUE;
2775
2.13k
}
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
2.14k
{
2785
2.14k
  WINPR_ASSERT(settings);
2786
2.14k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2787
6
    return FALSE;
2788
2789
2.13k
  const UINT32 multifragMaxRequestSize = Stream_Get_UINT32(s); /* MaxRequestSize (4 bytes) */
2790
2.13k
  return freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2791
2.13k
                                     multifragMaxRequestSize);
2792
2.14k
}
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
2820
0
    WINPR_ASSERT(tileNumX < UINT32_MAX / tileNumY);
2821
0
    WINPR_ASSERT(tileNumY < UINT32_MAX / tileNumX);
2822
0
    WINPR_ASSERT(tileNumX * tileNumY < UINT32_MAX / 16384u);
2823
2824
    /* and add room for headers, regions, frame markers, etc. */
2825
0
    const UINT32 MultifragMaxRequestSize = (tileNumX * tileNumY + 1u) * 16384u;
2826
2827
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2828
0
                                     MultifragMaxRequestSize))
2829
0
      return FALSE;
2830
0
  }
2831
2832
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2833
0
    return FALSE;
2834
0
  const size_t header = rdp_capability_set_start(log, s);
2835
0
  Stream_Write_UINT32(s, settings->MultifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
2836
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_MULTI_FRAGMENT_UPDATE);
2837
0
}
2838
2839
#ifdef WITH_DEBUG_CAPABILITIES
2840
static BOOL rdp_print_multifragment_update_capability_set(wLog* log, wStream* s)
2841
{
2842
  UINT32 maxRequestSize = 0;
2843
  WLog_Print(log, WLOG_TRACE, "MultifragmentUpdateCapabilitySet (length %" PRIuz "):",
2844
             Stream_GetRemainingLength(s));
2845
2846
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2847
    return FALSE;
2848
2849
  Stream_Read_UINT32(s, maxRequestSize); /* maxRequestSize (4 bytes) */
2850
  WLog_Print(log, WLOG_TRACE, "\tmaxRequestSize: 0x%08" PRIX32 "", maxRequestSize);
2851
  return TRUE;
2852
}
2853
#endif
2854
2855
static BOOL rdp_apply_large_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
2856
1.00k
{
2857
1.00k
  WINPR_ASSERT(settings);
2858
1.00k
  WINPR_ASSERT(src);
2859
2860
1.00k
  settings->LargePointerFlag = src->LargePointerFlag;
2861
1.00k
  return TRUE;
2862
1.00k
}
2863
2864
/*
2865
 * Read large pointer capability set.
2866
 * msdn{cc240650}
2867
 */
2868
2869
static BOOL rdp_read_large_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2870
1.00k
{
2871
1.00k
  UINT16 largePointerSupportFlags = 0;
2872
2873
1.00k
  WINPR_ASSERT(settings);
2874
1.00k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2875
4
    return FALSE;
2876
2877
1.00k
  Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2878
1.00k
  settings->LargePointerFlag &= largePointerSupportFlags;
2879
1.00k
  if ((largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) != 0)
2880
492
  {
2881
492
    WLog_Print(
2882
492
        log, WLOG_WARN,
2883
492
        "TS_LARGE_POINTER_CAPABILITYSET with unsupported flags %04X (all flags %04X) received",
2884
492
        WINPR_CXX_COMPAT_CAST(UINT32, largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 |
2885
492
                                                                   LARGE_POINTER_FLAG_384x384)),
2886
492
        largePointerSupportFlags);
2887
492
  }
2888
1.00k
  return TRUE;
2889
1.00k
}
2890
2891
/*
2892
 * Write large pointer capability set.
2893
 * msdn{cc240650}
2894
 */
2895
2896
static BOOL rdp_write_large_pointer_capability_set(wLog* log, wStream* s,
2897
                                                   const rdpSettings* settings)
2898
0
{
2899
0
  WINPR_ASSERT(settings);
2900
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2901
0
    return FALSE;
2902
2903
0
  const size_t header = rdp_capability_set_start(log, s);
2904
0
  const UINT16 largePointerSupportFlags =
2905
0
      settings->LargePointerFlag & (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
2906
0
  Stream_Write_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2907
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_LARGE_POINTER);
2908
0
}
2909
2910
#ifdef WITH_DEBUG_CAPABILITIES
2911
static BOOL rdp_print_large_pointer_capability_set(wLog* log, wStream* s)
2912
{
2913
  UINT16 largePointerSupportFlags = 0;
2914
  WLog_Print(log, WLOG_TRACE,
2915
             "LargePointerCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2916
2917
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2918
    return FALSE;
2919
2920
  Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2921
  WLog_Print(log, WLOG_TRACE, "\tlargePointerSupportFlags: 0x%04" PRIX16 "",
2922
             largePointerSupportFlags);
2923
  return TRUE;
2924
}
2925
#endif
2926
2927
static BOOL rdp_apply_surface_commands_capability_set(rdpSettings* settings, const rdpSettings* src)
2928
1.58k
{
2929
1.58k
  WINPR_ASSERT(settings);
2930
1.58k
  WINPR_ASSERT(src);
2931
2932
  /* [MS-RDPBCGR] 2.2.7.2.9 Surface Commands Capability Set (TS_SURFCMDS_CAPABILITYSET)
2933
   *
2934
   * disable surface commands if the remote does not support fastpath
2935
   */
2936
1.58k
  if (src->FastPathOutput)
2937
1.10k
  {
2938
1.10k
    settings->SurfaceCommandsSupported &= src->SurfaceCommandsSupported;
2939
1.10k
    settings->SurfaceCommandsEnabled = src->SurfaceCommandsEnabled;
2940
1.10k
    settings->SurfaceFrameMarkerEnabled = src->SurfaceFrameMarkerEnabled;
2941
1.10k
  }
2942
485
  else
2943
485
  {
2944
485
    settings->SurfaceCommandsSupported = 0;
2945
485
    settings->SurfaceCommandsEnabled = FALSE;
2946
485
    settings->SurfaceFrameMarkerEnabled = FALSE;
2947
485
  }
2948
2949
1.58k
  return TRUE;
2950
1.58k
}
2951
2952
/*
2953
 * Read surface commands capability set.
2954
 * msdn{dd871563}
2955
 */
2956
2957
static BOOL rdp_read_surface_commands_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2958
1.59k
{
2959
1.59k
  UINT32 cmdFlags = 0;
2960
2961
1.59k
  WINPR_ASSERT(settings);
2962
1.59k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2963
9
    return FALSE;
2964
2965
1.58k
  Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
2966
1.58k
  Stream_Seek_UINT32(s);           /* reserved (4 bytes) */
2967
1.58k
  settings->SurfaceCommandsSupported = cmdFlags;
2968
1.58k
  settings->SurfaceCommandsEnabled =
2969
1.58k
      (cmdFlags & (SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS)) != 0;
2970
1.58k
  settings->SurfaceFrameMarkerEnabled = (cmdFlags & SURFCMDS_FRAME_MARKER) != 0;
2971
1.58k
  return TRUE;
2972
1.59k
}
2973
2974
/*
2975
 * Write surface commands capability set.
2976
 * msdn{dd871563}
2977
 */
2978
2979
static BOOL rdp_write_surface_commands_capability_set(wLog* log, wStream* s,
2980
                                                      const rdpSettings* settings)
2981
0
{
2982
0
  WINPR_ASSERT(settings);
2983
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
2984
0
    return FALSE;
2985
2986
0
  const size_t header = rdp_capability_set_start(log, s);
2987
  // TODO: Make these configurable too
2988
0
  UINT32 cmdFlags = freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
2989
2990
0
  if (settings->SurfaceFrameMarkerEnabled)
2991
0
    cmdFlags |= SURFCMDS_FRAME_MARKER;
2992
2993
0
  Stream_Write_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
2994
0
  Stream_Write_UINT32(s, 0);        /* reserved (4 bytes) */
2995
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_SURFACE_COMMANDS);
2996
0
}
2997
2998
static bool sUuidEqual(const UUID* Uuid1, const UUID* Uuid2)
2999
4.66k
{
3000
4.66k
  if (!Uuid1 && !Uuid2)
3001
0
    return false;
3002
3003
4.66k
  if (Uuid1 && !Uuid2)
3004
0
    return false;
3005
3006
4.66k
  if (!Uuid1 && Uuid2)
3007
0
    return false;
3008
3009
4.66k
  if (Uuid1->Data1 != Uuid2->Data1)
3010
4.10k
    return false;
3011
3012
566
  if (Uuid1->Data2 != Uuid2->Data2)
3013
548
    return false;
3014
3015
18
  if (Uuid1->Data3 != Uuid2->Data3)
3016
10
    return false;
3017
3018
9
  for (int index = 0; index < 8; index++)
3019
9
  {
3020
9
    if (Uuid1->Data4[index] != Uuid2->Data4[index])
3021
8
      return false;
3022
9
  }
3023
3024
0
  return true;
3025
8
}
3026
3027
#ifdef WITH_DEBUG_CAPABILITIES
3028
static BOOL rdp_print_surface_commands_capability_set(wLog* log, wStream* s)
3029
{
3030
  UINT32 cmdFlags = 0;
3031
  UINT32 reserved = 0;
3032
3033
  WLog_Print(log, WLOG_TRACE,
3034
             "SurfaceCommandsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3035
3036
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
3037
    return FALSE;
3038
3039
  Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3040
  Stream_Read_UINT32(s, reserved); /* reserved (4 bytes) */
3041
  WLog_Print(log, WLOG_TRACE, "\tcmdFlags: 0x%08" PRIX32 "", cmdFlags);
3042
  WLog_Print(log, WLOG_TRACE, "\treserved: 0x%08" PRIX32 "", reserved);
3043
  return TRUE;
3044
}
3045
3046
static void rdp_print_bitmap_codec_guid(wLog* log, const GUID* guid)
3047
{
3048
  WINPR_ASSERT(guid);
3049
  WLog_Print(log, WLOG_TRACE,
3050
             "%08" PRIX32 "%04" PRIX16 "%04" PRIX16 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8
3051
             "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "",
3052
             guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
3053
             guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6],
3054
             guid->Data4[7]);
3055
}
3056
3057
static char* rdp_get_bitmap_codec_guid_name(const GUID* guid)
3058
{
3059
  WINPR_ASSERT(guid);
3060
  if (sUuidEqual(guid, &CODEC_GUID_REMOTEFX))
3061
    return "CODEC_GUID_REMOTEFX";
3062
  else if (sUuidEqual(guid, &CODEC_GUID_NSCODEC))
3063
    return "CODEC_GUID_NSCODEC";
3064
  else if (sUuidEqual(guid, &CODEC_GUID_IGNORE))
3065
    return "CODEC_GUID_IGNORE";
3066
  else if (sUuidEqual(guid, &CODEC_GUID_IMAGE_REMOTEFX))
3067
    return "CODEC_GUID_IMAGE_REMOTEFX";
3068
3069
#if defined(WITH_JPEG)
3070
  else if (sUuidEqual(guid, &CODEC_GUID_JPEG))
3071
    return "CODEC_GUID_JPEG";
3072
3073
#endif
3074
  return "CODEC_GUID_UNKNOWN";
3075
}
3076
#endif
3077
3078
static BOOL rdp_read_bitmap_codec_guid(wLog* log, wStream* s, GUID* guid)
3079
1.55k
{
3080
1.55k
  BYTE g[16] = WINPR_C_ARRAY_INIT;
3081
3082
1.55k
  WINPR_ASSERT(guid);
3083
1.55k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16))
3084
99
    return FALSE;
3085
1.45k
  Stream_Read(s, g, 16);
3086
1.45k
  guid->Data1 = ((UINT32)g[3] << 24U) | ((UINT32)g[2] << 16U) | (UINT32)(g[1] << 8U) | g[0];
3087
1.45k
  guid->Data2 = ((g[5] << 8U) | g[4]) & 0xFFFF;
3088
1.45k
  guid->Data3 = ((g[7] << 8U) | g[6]) & 0xFFFF;
3089
1.45k
  guid->Data4[0] = g[8];
3090
1.45k
  guid->Data4[1] = g[9];
3091
1.45k
  guid->Data4[2] = g[10];
3092
1.45k
  guid->Data4[3] = g[11];
3093
1.45k
  guid->Data4[4] = g[12];
3094
1.45k
  guid->Data4[5] = g[13];
3095
1.45k
  guid->Data4[6] = g[14];
3096
1.45k
  guid->Data4[7] = g[15];
3097
1.45k
  return TRUE;
3098
1.55k
}
3099
3100
static void rdp_write_bitmap_codec_guid(wStream* s, const GUID* guid)
3101
0
{
3102
0
  BYTE g[16] = WINPR_C_ARRAY_INIT;
3103
0
  WINPR_ASSERT(guid);
3104
0
  g[0] = guid->Data1 & 0xFF;
3105
0
  g[1] = (guid->Data1 >> 8) & 0xFF;
3106
0
  g[2] = (guid->Data1 >> 16) & 0xFF;
3107
0
  g[3] = (guid->Data1 >> 24) & 0xFF;
3108
0
  g[4] = (guid->Data2) & 0xFF;
3109
0
  g[5] = (guid->Data2 >> 8) & 0xFF;
3110
0
  g[6] = (guid->Data3) & 0xFF;
3111
0
  g[7] = (guid->Data3 >> 8) & 0xFF;
3112
0
  g[8] = guid->Data4[0];
3113
0
  g[9] = guid->Data4[1];
3114
0
  g[10] = guid->Data4[2];
3115
0
  g[11] = guid->Data4[3];
3116
0
  g[12] = guid->Data4[4];
3117
0
  g[13] = guid->Data4[5];
3118
0
  g[14] = guid->Data4[6];
3119
0
  g[15] = guid->Data4[7];
3120
0
  Stream_Write(s, g, 16);
3121
0
}
3122
3123
static BOOL rdp_apply_bitmap_codecs_capability_set(rdpSettings* settings, const rdpSettings* src)
3124
922
{
3125
922
  WINPR_ASSERT(settings);
3126
922
  WINPR_ASSERT(src);
3127
3128
922
  if (settings->ServerMode)
3129
845
  {
3130
3131
845
    settings->RemoteFxCodecId = src->RemoteFxCodecId;
3132
845
    settings->RemoteFxCaptureFlags = src->RemoteFxCaptureFlags;
3133
845
    settings->RemoteFxOnly = src->RemoteFxOnly;
3134
845
    settings->RemoteFxRlgrMode = src->RemoteFxRlgrMode;
3135
845
    settings->RemoteFxCodecMode = src->RemoteFxCodecMode;
3136
845
    settings->NSCodecId = src->NSCodecId;
3137
845
    settings->NSCodecAllowDynamicColorFidelity = src->NSCodecAllowDynamicColorFidelity;
3138
845
    settings->NSCodecAllowSubsampling = src->NSCodecAllowSubsampling;
3139
845
    settings->NSCodecColorLossLevel = src->NSCodecColorLossLevel;
3140
3141
    /* only enable a codec if we've announced/enabled it before */
3142
845
    settings->RemoteFxCodec = settings->RemoteFxCodec && src->RemoteFxCodecId;
3143
845
    settings->RemoteFxImageCodec = settings->RemoteFxImageCodec && src->RemoteFxImageCodec;
3144
845
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec,
3145
845
                                   settings->NSCodec && src->NSCodec))
3146
0
      return FALSE;
3147
845
    settings->JpegCodec = src->JpegCodec;
3148
845
  }
3149
922
  return TRUE;
3150
922
}
3151
3152
static BOOL rdp_read_codec_ts_rfx_icap(wLog* log, wStream* sub, rdpSettings* settings,
3153
                                       UINT16 icapLen)
3154
0
{
3155
0
  UINT16 version = 0;
3156
0
  UINT16 tileSize = 0;
3157
0
  BYTE codecFlags = 0;
3158
0
  BYTE colConvBits = 0;
3159
0
  BYTE transformBits = 0;
3160
0
  BYTE entropyBits = 0;
3161
  /* TS_RFX_ICAP */
3162
0
  if (icapLen != 8)
3163
0
  {
3164
0
    WLog_Print(log, WLOG_ERROR,
3165
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP size %" PRIu16
3166
0
               " unsupported, expecting size %" PRIu16 " not supported",
3167
0
               icapLen, 8u);
3168
0
    return FALSE;
3169
0
  }
3170
3171
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3172
0
    return FALSE;
3173
3174
0
  Stream_Read_UINT16(sub, version);      /* version (2 bytes) */
3175
0
  Stream_Read_UINT16(sub, tileSize);     /* tileSize (2 bytes) */
3176
0
  Stream_Read_UINT8(sub, codecFlags);    /* flags (1 byte) */
3177
0
  Stream_Read_UINT8(sub, colConvBits);   /* colConvBits (1 byte) */
3178
0
  Stream_Read_UINT8(sub, transformBits); /* transformBits (1 byte) */
3179
0
  Stream_Read_UINT8(sub, entropyBits);   /* entropyBits (1 byte) */
3180
3181
0
  if (version == 0x0009)
3182
0
  {
3183
    /* Version 0.9 */
3184
0
    if (tileSize != 0x0080)
3185
0
    {
3186
0
      WLog_Print(log, WLOG_ERROR,
3187
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3188
0
                 " tile size %" PRIu16 " not supported",
3189
0
                 version, tileSize);
3190
0
      return FALSE;
3191
0
    }
3192
0
  }
3193
0
  else if (version == 0x0100)
3194
0
  {
3195
    /* Version 1.0 */
3196
0
    if (tileSize != 0x0040)
3197
0
    {
3198
0
      WLog_Print(log, WLOG_ERROR,
3199
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3200
0
                 " tile size %" PRIu16 " not supported",
3201
0
                 version, tileSize);
3202
0
      return FALSE;
3203
0
    }
3204
0
  }
3205
0
  else
3206
0
  {
3207
0
    WLog_Print(log, WLOG_ERROR,
3208
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16 " not supported",
3209
0
               version);
3210
0
    return FALSE;
3211
0
  }
3212
3213
  /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_COL_CONV_ICT (0x1) */
3214
0
  if (colConvBits != 1)
3215
0
  {
3216
0
    WLog_Print(log, WLOG_ERROR,
3217
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::colConvBits %" PRIu8
3218
0
               " not supported, must be CLW_COL_CONV_ICT (0x1)",
3219
0
               colConvBits);
3220
0
    return FALSE;
3221
0
  }
3222
3223
  /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_XFORM_DWT_53_A (0x1) */
3224
0
  if (transformBits != 1)
3225
0
  {
3226
0
    WLog_Print(log, WLOG_ERROR,
3227
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::transformBits %" PRIu8
3228
0
               " not supported, must be CLW_XFORM_DWT_53_A (0x1)",
3229
0
               colConvBits);
3230
0
    return FALSE;
3231
0
  }
3232
3233
0
  const UINT8 CODEC_MODE = 0x02; /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP */
3234
0
  if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x00))
3235
0
    return FALSE;
3236
3237
0
  if ((codecFlags & CODEC_MODE) != 0)
3238
0
  {
3239
0
    if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x02))
3240
0
      return FALSE;
3241
0
  }
3242
0
  else if ((codecFlags & ~CODEC_MODE) != 0)
3243
0
    WLog_Print(log, WLOG_WARN,
3244
0
               "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::flags unknown value "
3245
0
               "0x%02" PRIx32,
3246
0
               WINPR_CXX_COMPAT_CAST(UINT32, (codecFlags & ~CODEC_MODE)));
3247
3248
0
  switch (entropyBits)
3249
0
  {
3250
0
    case CLW_ENTROPY_RLGR1:
3251
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR1))
3252
0
        return FALSE;
3253
0
      break;
3254
0
    case CLW_ENTROPY_RLGR3:
3255
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3))
3256
0
        return FALSE;
3257
0
      break;
3258
0
    default:
3259
0
      WLog_Print(log, WLOG_ERROR,
3260
0
                 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::entropyBits "
3261
0
                 "unsupported value 0x%02" PRIx8
3262
0
                 ", must be CLW_ENTROPY_RLGR1 (0x01) or CLW_ENTROPY_RLGR3 "
3263
0
                 "(0x04)",
3264
0
                 entropyBits);
3265
0
      return FALSE;
3266
0
  }
3267
0
  return TRUE;
3268
0
}
3269
3270
static BOOL rdp_read_codec_ts_rfx_capset(wLog* log, wStream* s, rdpSettings* settings)
3271
0
{
3272
0
  UINT16 blockType = 0;
3273
0
  UINT32 blockLen = 0;
3274
0
  BYTE rfxCodecId = 0;
3275
0
  UINT16 capsetType = 0;
3276
0
  UINT16 numIcaps = 0;
3277
0
  UINT16 icapLen = 0;
3278
3279
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
3280
0
    return FALSE;
3281
3282
  /* TS_RFX_CAPSET */
3283
0
  Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
3284
0
  Stream_Read_UINT32(s, blockLen);  /* blockLen (4 bytes) */
3285
0
  if (blockType != 0xCBC1)
3286
0
  {
3287
0
    WLog_Print(log, WLOG_ERROR,
3288
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockType[0x%04" PRIx16
3289
0
               "] != CBY_CAPSET (0xCBC1)",
3290
0
               blockType);
3291
0
    return FALSE;
3292
0
  }
3293
0
  if (blockLen < 6ull)
3294
0
  {
3295
0
    WLog_Print(log, WLOG_ERROR,
3296
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockLen[%" PRIu16 "] < 6", blockLen);
3297
0
    return FALSE;
3298
0
  }
3299
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, blockLen - 6ull))
3300
0
    return FALSE;
3301
3302
0
  wStream sbuffer = WINPR_C_ARRAY_INIT;
3303
0
  wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), blockLen - 6ull);
3304
0
  WINPR_ASSERT(sub);
3305
3306
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 7))
3307
0
    return FALSE;
3308
3309
0
  Stream_Read_UINT8(sub, rfxCodecId);  /* codecId (1 byte) */
3310
0
  Stream_Read_UINT16(sub, capsetType); /* capsetType (2 bytes) */
3311
0
  Stream_Read_UINT16(sub, numIcaps);   /* numIcaps (2 bytes) */
3312
0
  Stream_Read_UINT16(sub, icapLen);    /* icapLen (2 bytes) */
3313
3314
0
  if (rfxCodecId != 1)
3315
0
  {
3316
0
    WLog_Print(log, WLOG_ERROR,
3317
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::codecId[%" PRIu16 "] != 1", rfxCodecId);
3318
0
    return FALSE;
3319
0
  }
3320
3321
0
  if (capsetType != 0xCFC0)
3322
0
  {
3323
0
    WLog_Print(log, WLOG_ERROR,
3324
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::capsetType[0x%04" PRIx16
3325
0
               "] != CLY_CAPSET (0xCFC0)",
3326
0
               capsetType);
3327
0
    return FALSE;
3328
0
  }
3329
3330
0
  while (numIcaps--)
3331
0
  {
3332
0
    if (!rdp_read_codec_ts_rfx_icap(log, sub, settings, icapLen))
3333
0
      return FALSE;
3334
0
  }
3335
0
  return TRUE;
3336
0
}
3337
3338
static BOOL rdp_read_codec_ts_rfx_caps(wLog* log, wStream* sub, rdpSettings* settings)
3339
0
{
3340
0
  if (Stream_GetRemainingLength(sub) == 0)
3341
0
    return TRUE;
3342
3343
0
  UINT16 blockType = 0;
3344
0
  UINT32 blockLen = 0;
3345
0
  UINT16 numCapsets = 0;
3346
3347
  /* TS_RFX_CAPS */
3348
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3349
0
    return FALSE;
3350
0
  Stream_Read_UINT16(sub, blockType);  /* blockType (2 bytes) */
3351
0
  Stream_Read_UINT32(sub, blockLen);   /* blockLen (4 bytes) */
3352
0
  Stream_Read_UINT16(sub, numCapsets); /* numCapsets (2 bytes) */
3353
3354
0
  if (blockType != 0xCBC0)
3355
0
  {
3356
0
    WLog_Print(log, WLOG_ERROR,
3357
0
               "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockType[0x%04" PRIx16
3358
0
               "] != CBY_CAPS (0xCBC0)",
3359
0
               blockType);
3360
0
    return FALSE;
3361
0
  }
3362
3363
0
  if (blockLen != 8)
3364
0
  {
3365
0
    WLog_Print(log, WLOG_ERROR, "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockLen[%" PRIu16 "] != 8",
3366
0
               blockLen);
3367
0
    return FALSE;
3368
0
  }
3369
3370
0
  if (numCapsets != 1)
3371
0
  {
3372
0
    WLog_Print(log, WLOG_ERROR,
3373
0
               "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::numIcaps[%" PRIu16 "] != 1", numCapsets);
3374
0
    return FALSE;
3375
0
  }
3376
3377
0
  for (UINT16 x = 0; x < numCapsets; x++)
3378
0
  {
3379
0
    if (!rdp_read_codec_ts_rfx_capset(log, sub, settings))
3380
0
      return FALSE;
3381
0
  }
3382
3383
0
  return TRUE;
3384
0
}
3385
3386
static BOOL rdp_read_codec_ts_rfx_clnt_caps_container(wLog* log, wStream* s, rdpSettings* settings)
3387
0
{
3388
0
  UINT32 rfxCapsLength = 0;
3389
0
  UINT32 rfxPropsLength = 0;
3390
0
  UINT32 captureFlags = 0;
3391
3392
  /* [MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER */
3393
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3394
0
    return FALSE;
3395
0
  Stream_Read_UINT32(s, rfxPropsLength); /* length (4 bytes) */
3396
0
  if (rfxPropsLength < 4)
3397
0
  {
3398
0
    WLog_Print(log, WLOG_ERROR,
3399
0
               "[MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER::length %" PRIu32
3400
0
               " too short, require at least 4 bytes",
3401
0
               rfxPropsLength);
3402
0
    return FALSE;
3403
0
  }
3404
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, rfxPropsLength - 4ull))
3405
0
    return FALSE;
3406
3407
0
  wStream sbuffer = WINPR_C_ARRAY_INIT;
3408
0
  wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), rfxPropsLength - 4ull);
3409
0
  WINPR_ASSERT(sub);
3410
3411
0
  Stream_Seek(s, rfxPropsLength - 4ull);
3412
3413
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3414
0
    return FALSE;
3415
3416
0
  Stream_Read_UINT32(sub, captureFlags);  /* captureFlags (4 bytes) */
3417
0
  Stream_Read_UINT32(sub, rfxCapsLength); /* capsLength (4 bytes) */
3418
0
  if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, rfxCapsLength))
3419
0
    return FALSE;
3420
3421
0
  settings->RemoteFxCaptureFlags = captureFlags;
3422
0
  settings->RemoteFxOnly = !(captureFlags & CARDP_CAPS_CAPTURE_NON_CAC);
3423
3424
  /* [MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS */
3425
0
  wStream tsbuffer = WINPR_C_ARRAY_INIT;
3426
0
  wStream* ts_sub = Stream_StaticConstInit(&tsbuffer, Stream_Pointer(sub), rfxCapsLength);
3427
0
  WINPR_ASSERT(ts_sub);
3428
0
  return rdp_read_codec_ts_rfx_caps(log, ts_sub, settings);
3429
0
}
3430
3431
/*
3432
 * Read bitmap codecs capability set.
3433
 * msdn{dd891377}
3434
 */
3435
3436
static BOOL rdp_read_bitmap_codecs_capability_set(wLog* log, wStream* s, rdpSettings* settings,
3437
                                                  BOOL isServer)
3438
1.05k
{
3439
1.05k
  BYTE codecId = 0;
3440
1.05k
  GUID codecGuid = WINPR_C_ARRAY_INIT;
3441
1.05k
  BYTE bitmapCodecCount = 0;
3442
1.05k
  UINT16 codecPropertiesLength = 0;
3443
3444
1.05k
  BOOL guidNSCodec = FALSE;
3445
1.05k
  BOOL guidRemoteFx = FALSE;
3446
1.05k
  BOOL guidRemoteFxImage = FALSE;
3447
3448
1.05k
  WINPR_ASSERT(settings);
3449
1.05k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3450
4
    return FALSE;
3451
3452
1.05k
  Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3453
3454
2.48k
  while (bitmapCodecCount > 0)
3455
1.55k
  {
3456
1.55k
    wStream subbuffer = WINPR_C_ARRAY_INIT;
3457
3458
1.55k
    if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3459
99
      return FALSE;
3460
1.45k
    if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3461
8
      return FALSE;
3462
1.45k
    Stream_Read_UINT8(s, codecId);                /* codecId (1 byte) */
3463
1.45k
    Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3464
3465
1.45k
    wStream* sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), codecPropertiesLength);
3466
1.45k
    if (!Stream_SafeSeek(s, codecPropertiesLength))
3467
22
      return FALSE;
3468
3469
1.42k
    if (isServer)
3470
1.16k
    {
3471
1.16k
      if (sUuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX))
3472
0
      {
3473
0
        guidRemoteFx = TRUE;
3474
0
        settings->RemoteFxCodecId = codecId;
3475
0
        if (!rdp_read_codec_ts_rfx_clnt_caps_container(log, sub, settings))
3476
0
          return FALSE;
3477
0
      }
3478
1.16k
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_IMAGE_REMOTEFX))
3479
0
      {
3480
        /* Microsoft RDP servers ignore CODEC_GUID_IMAGE_REMOTEFX codec properties */
3481
0
        guidRemoteFxImage = TRUE;
3482
0
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3483
0
          return FALSE;
3484
0
      }
3485
1.16k
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_NSCODEC))
3486
0
      {
3487
0
        BYTE colorLossLevel = 0;
3488
0
        BYTE fAllowSubsampling = 0;
3489
0
        BYTE fAllowDynamicFidelity = 0;
3490
0
        guidNSCodec = TRUE;
3491
0
        settings->NSCodecId = codecId;
3492
0
        if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 3))
3493
0
          return FALSE;
3494
0
        Stream_Read_UINT8(sub, fAllowDynamicFidelity); /* fAllowDynamicFidelity (1 byte) */
3495
0
        Stream_Read_UINT8(sub, fAllowSubsampling);     /* fAllowSubsampling (1 byte) */
3496
0
        Stream_Read_UINT8(sub, colorLossLevel);        /* colorLossLevel (1 byte) */
3497
3498
0
        if (colorLossLevel < 1)
3499
0
          colorLossLevel = 1;
3500
3501
0
        if (colorLossLevel > 7)
3502
0
          colorLossLevel = 7;
3503
3504
0
        settings->NSCodecAllowDynamicColorFidelity = fAllowDynamicFidelity;
3505
0
        settings->NSCodecAllowSubsampling = fAllowSubsampling;
3506
0
        settings->NSCodecColorLossLevel = colorLossLevel;
3507
0
      }
3508
1.16k
      else if (sUuidEqual(&codecGuid, &CODEC_GUID_IGNORE))
3509
0
      {
3510
0
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3511
0
          return FALSE;
3512
0
      }
3513
1.16k
      else
3514
1.16k
      {
3515
1.16k
        if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3516
0
          return FALSE;
3517
1.16k
      }
3518
1.16k
    }
3519
262
    else
3520
262
    {
3521
262
      if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3522
0
        return FALSE;
3523
262
    }
3524
3525
1.42k
    const size_t rest = Stream_GetRemainingLength(sub);
3526
1.42k
    if (rest > 0)
3527
0
    {
3528
0
      WLog_Print(log, WLOG_ERROR,
3529
0
                 "error while reading codec properties: actual size: %" PRIuz
3530
0
                 " expected size: %" PRIu32 "",
3531
0
                 rest + codecPropertiesLength, codecPropertiesLength);
3532
0
    }
3533
1.42k
    bitmapCodecCount--;
3534
3535
    /* only enable a codec if we've announced/enabled it before */
3536
1.42k
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, guidRemoteFx))
3537
0
      return FALSE;
3538
1.42k
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, guidRemoteFxImage))
3539
0
      return FALSE;
3540
1.42k
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, guidNSCodec))
3541
0
      return FALSE;
3542
1.42k
    if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
3543
0
      return FALSE;
3544
1.42k
  }
3545
3546
922
  return TRUE;
3547
1.05k
}
3548
3549
/*
3550
 * Write RemoteFX Client Capability Container.
3551
 */
3552
static BOOL rdp_write_rfx_client_capability_container(wStream* s, const rdpSettings* settings)
3553
0
{
3554
0
  WINPR_ASSERT(settings);
3555
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
3556
0
    return FALSE;
3557
3558
0
  const UINT32 captureFlags = settings->RemoteFxOnly ? 0 : CARDP_CAPS_CAPTURE_NON_CAC;
3559
3560
0
  WINPR_ASSERT(settings->RemoteFxCodecMode <= UINT8_MAX);
3561
0
  const UINT8 codecMode = (UINT8)settings->RemoteFxCodecMode;
3562
0
  Stream_Write_UINT16(s, 49); /* codecPropertiesLength */
3563
  /* TS_RFX_CLNT_CAPS_CONTAINER */
3564
0
  Stream_Write_UINT32(s, 49);           /* length */
3565
0
  Stream_Write_UINT32(s, captureFlags); /* captureFlags */
3566
0
  Stream_Write_UINT32(s, 37);           /* capsLength */
3567
  /* TS_RFX_CAPS */
3568
0
  Stream_Write_UINT16(s, CBY_CAPS); /* blockType */
3569
0
  Stream_Write_UINT32(s, 8);        /* blockLen */
3570
0
  Stream_Write_UINT16(s, 1);        /* numCapsets */
3571
  /* TS_RFX_CAPSET */
3572
0
  Stream_Write_UINT16(s, CBY_CAPSET); /* blockType */
3573
0
  Stream_Write_UINT32(s, 29);         /* blockLen */
3574
0
  Stream_Write_UINT8(s, 0x01);        /* codecId (MUST be set to 0x01) */
3575
0
  Stream_Write_UINT16(s, CLY_CAPSET); /* capsetType */
3576
0
  Stream_Write_UINT16(s, 2);          /* numIcaps */
3577
0
  Stream_Write_UINT16(s, 8);          /* icapLen */
3578
  /* TS_RFX_ICAP (RLGR1) */
3579
0
  Stream_Write_UINT16(s, CLW_VERSION_1_0);   /* version */
3580
0
  Stream_Write_UINT16(s, CT_TILE_64x64);     /* tileSize */
3581
0
  Stream_Write_UINT8(s, codecMode);          /* flags */
3582
0
  Stream_Write_UINT8(s, CLW_COL_CONV_ICT);   /* colConvBits */
3583
0
  Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3584
0
  Stream_Write_UINT8(s, CLW_ENTROPY_RLGR1);  /* entropyBits */
3585
  /* TS_RFX_ICAP (RLGR3) */
3586
0
  Stream_Write_UINT16(s, CLW_VERSION_1_0);   /* version */
3587
0
  Stream_Write_UINT16(s, CT_TILE_64x64);     /* tileSize */
3588
0
  Stream_Write_UINT8(s, codecMode);          /* flags */
3589
0
  Stream_Write_UINT8(s, CLW_COL_CONV_ICT);   /* colConvBits */
3590
0
  Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3591
0
  Stream_Write_UINT8(s, CLW_ENTROPY_RLGR3);  /* entropyBits */
3592
0
  return TRUE;
3593
0
}
3594
3595
/*
3596
 * Write NSCODEC Client Capability Container.
3597
 */
3598
static BOOL rdp_write_nsc_client_capability_container(wStream* s, const rdpSettings* settings)
3599
0
{
3600
0
  WINPR_ASSERT(settings);
3601
3602
0
  const BOOL fAllowDynamicFidelity = settings->NSCodecAllowDynamicColorFidelity;
3603
0
  const BOOL fAllowSubsampling = settings->NSCodecAllowSubsampling;
3604
0
  UINT32 colorLossLevel = settings->NSCodecColorLossLevel;
3605
3606
0
  if (colorLossLevel < 1)
3607
0
    colorLossLevel = 1;
3608
3609
0
  if (colorLossLevel > 7)
3610
0
    colorLossLevel = 7;
3611
3612
0
  if (!Stream_EnsureRemainingCapacity(s, 8))
3613
0
    return FALSE;
3614
3615
0
  Stream_Write_UINT16(s, 3); /* codecPropertiesLength */
3616
  /* TS_NSCODEC_CAPABILITYSET */
3617
0
  Stream_Write_UINT8(s, fAllowDynamicFidelity != 0);        /* fAllowDynamicFidelity (1 byte) */
3618
0
  Stream_Write_UINT8(s, fAllowSubsampling != 0);            /* fAllowSubsampling (1 byte) */
3619
0
  Stream_Write_UINT8(s, (UINT8)colorLossLevel);             /* colorLossLevel (1 byte) */
3620
0
  return TRUE;
3621
0
}
3622
3623
#if defined(WITH_JPEG)
3624
static BOOL rdp_write_jpeg_client_capability_container(wStream* s, const rdpSettings* settings)
3625
{
3626
  WINPR_ASSERT(settings);
3627
  if (!Stream_EnsureRemainingCapacity(s, 8))
3628
    return FALSE;
3629
3630
  Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3631
3632
  const UINT32 q = freerdp_settings_get_uint32(settings, FreeRDP_JpegQuality);
3633
  Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, q));
3634
  return TRUE;
3635
}
3636
#endif
3637
3638
/*
3639
 * Write RemoteFX Server Capability Container.
3640
 */
3641
static BOOL rdp_write_rfx_server_capability_container(wStream* s, const rdpSettings* settings)
3642
0
{
3643
0
  WINPR_UNUSED(settings);
3644
0
  WINPR_ASSERT(settings);
3645
3646
0
  if (!Stream_EnsureRemainingCapacity(s, 8))
3647
0
    return FALSE;
3648
3649
0
  Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3650
0
  Stream_Write_UINT32(s, 0); /* reserved */
3651
0
  return TRUE;
3652
0
}
3653
3654
#if defined(WITH_JPEG)
3655
static BOOL rdp_write_jpeg_server_capability_container(wStream* s, const rdpSettings* settings)
3656
{
3657
  WINPR_UNUSED(settings);
3658
  WINPR_ASSERT(settings);
3659
3660
  if (!Stream_EnsureRemainingCapacity(s, 8))
3661
    return FALSE;
3662
3663
  Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3664
  Stream_Write_UINT8(s, 75);
3665
  return TRUE;
3666
}
3667
#endif
3668
3669
/*
3670
 * Write NSCODEC Server Capability Container.
3671
 */
3672
static BOOL rdp_write_nsc_server_capability_container(wStream* s, const rdpSettings* settings)
3673
0
{
3674
0
  WINPR_UNUSED(settings);
3675
0
  WINPR_ASSERT(settings);
3676
3677
0
  if (!Stream_EnsureRemainingCapacity(s, 8))
3678
0
    return FALSE;
3679
3680
0
  Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3681
0
  Stream_Write_UINT32(s, 0); /* reserved */
3682
0
  return TRUE;
3683
0
}
3684
3685
/*
3686
 * Write bitmap codecs capability set.
3687
 * msdn{dd891377}
3688
 */
3689
3690
static BOOL rdp_write_bitmap_codecs_capability_set(wLog* log, wStream* s,
3691
                                                   const rdpSettings* settings)
3692
0
{
3693
0
  WINPR_ASSERT(settings);
3694
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
3695
0
    return FALSE;
3696
3697
0
  const size_t header = rdp_capability_set_start(log, s);
3698
0
  BYTE bitmapCodecCount = 0;
3699
3700
0
  if (settings->RemoteFxCodec)
3701
0
    bitmapCodecCount++;
3702
3703
0
  if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3704
0
    bitmapCodecCount++;
3705
3706
#if defined(WITH_JPEG)
3707
3708
  if (settings->JpegCodec)
3709
    bitmapCodecCount++;
3710
3711
#endif
3712
3713
0
  if (settings->RemoteFxImageCodec)
3714
0
    bitmapCodecCount++;
3715
3716
0
  Stream_Write_UINT8(s, bitmapCodecCount);
3717
3718
0
  if (settings->RemoteFxCodec)
3719
0
  {
3720
0
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_REMOTEFX); /* codecGUID */
3721
3722
0
    if (settings->ServerMode)
3723
0
    {
3724
0
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3725
3726
0
      if (!rdp_write_rfx_server_capability_container(s, settings))
3727
0
        return FALSE;
3728
0
    }
3729
0
    else
3730
0
    {
3731
0
      Stream_Write_UINT8(s, RDP_CODEC_ID_REMOTEFX); /* codecID */
3732
3733
0
      if (!rdp_write_rfx_client_capability_container(s, settings))
3734
0
        return FALSE;
3735
0
    }
3736
0
  }
3737
3738
0
  if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3739
0
  {
3740
0
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_NSCODEC); /* codecGUID */
3741
3742
0
    if (settings->ServerMode)
3743
0
    {
3744
0
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3745
3746
0
      if (!rdp_write_nsc_server_capability_container(s, settings))
3747
0
        return FALSE;
3748
0
    }
3749
0
    else
3750
0
    {
3751
0
      Stream_Write_UINT8(s, RDP_CODEC_ID_NSCODEC); /* codecID */
3752
3753
0
      if (!rdp_write_nsc_client_capability_container(s, settings))
3754
0
        return FALSE;
3755
0
    }
3756
0
  }
3757
3758
#if defined(WITH_JPEG)
3759
3760
  if (settings->JpegCodec)
3761
  {
3762
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_JPEG); /* codecGUID */
3763
3764
    if (settings->ServerMode)
3765
    {
3766
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3767
3768
      if (!rdp_write_jpeg_server_capability_container(s, settings))
3769
        return FALSE;
3770
    }
3771
    else
3772
    {
3773
      Stream_Write_UINT8(s, RDP_CODEC_ID_JPEG); /* codecID */
3774
3775
      if (!rdp_write_jpeg_client_capability_container(s, settings))
3776
        return FALSE;
3777
    }
3778
  }
3779
3780
#endif
3781
3782
0
  if (settings->RemoteFxImageCodec)
3783
0
  {
3784
0
    rdp_write_bitmap_codec_guid(s, &CODEC_GUID_IMAGE_REMOTEFX); /* codecGUID */
3785
3786
0
    if (settings->ServerMode)
3787
0
    {
3788
0
      Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3789
3790
0
      if (!rdp_write_rfx_server_capability_container(s, settings))
3791
0
        return FALSE;
3792
0
    }
3793
0
    else
3794
0
    {
3795
0
      Stream_Write_UINT8(s, RDP_CODEC_ID_IMAGE_REMOTEFX); /* codecID */
3796
3797
0
      if (!rdp_write_rfx_client_capability_container(s, settings))
3798
0
        return FALSE;
3799
0
    }
3800
0
  }
3801
3802
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CODECS);
3803
0
}
3804
3805
#ifdef WITH_DEBUG_CAPABILITIES
3806
static BOOL rdp_print_bitmap_codecs_capability_set(wLog* log, wStream* s)
3807
{
3808
  GUID codecGuid = WINPR_C_ARRAY_INIT;
3809
  BYTE bitmapCodecCount = 0;
3810
  BYTE codecId = 0;
3811
  UINT16 codecPropertiesLength = 0;
3812
3813
  WLog_Print(log, WLOG_TRACE,
3814
             "BitmapCodecsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3815
3816
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3817
    return FALSE;
3818
3819
  Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3820
  WLog_Print(log, WLOG_TRACE, "\tbitmapCodecCount: %" PRIu8 "", bitmapCodecCount);
3821
3822
  while (bitmapCodecCount > 0)
3823
  {
3824
    if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3825
      return FALSE;
3826
    if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3827
      return FALSE;
3828
    Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3829
    WLog_Print(log, WLOG_TRACE, "\tcodecGuid: 0x");
3830
    rdp_print_bitmap_codec_guid(log, &codecGuid);
3831
    WLog_Print(log, WLOG_TRACE, " (%s)", rdp_get_bitmap_codec_guid_name(&codecGuid));
3832
    WLog_Print(log, WLOG_TRACE, "\tcodecId: %" PRIu8 "", codecId);
3833
    Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3834
    WLog_Print(log, WLOG_TRACE, "\tcodecPropertiesLength: %" PRIu16 "", codecPropertiesLength);
3835
3836
    if (!Stream_SafeSeek(s, codecPropertiesLength)) /* codecProperties */
3837
      return FALSE;
3838
    bitmapCodecCount--;
3839
  }
3840
3841
  return TRUE;
3842
}
3843
#endif
3844
3845
static BOOL rdp_apply_frame_acknowledge_capability_set(rdpSettings* settings,
3846
                                                       const rdpSettings* src)
3847
1.05k
{
3848
1.05k
  WINPR_ASSERT(settings);
3849
1.05k
  WINPR_ASSERT(src);
3850
3851
1.05k
  if (settings->ServerMode)
3852
528
    settings->FrameAcknowledge = src->FrameAcknowledge;
3853
3854
1.05k
  return TRUE;
3855
1.05k
}
3856
3857
/*
3858
 * Read frame acknowledge capability set.
3859
 */
3860
3861
static BOOL rdp_read_frame_acknowledge_capability_set(wLog* log, wStream* s, rdpSettings* settings)
3862
1.06k
{
3863
1.06k
  WINPR_ASSERT(settings);
3864
1.06k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3865
6
    return FALSE;
3866
3867
1.05k
  Stream_Read_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3868
3869
1.05k
  return TRUE;
3870
1.06k
}
3871
3872
/*
3873
 * Write frame acknowledge capability set.
3874
 */
3875
3876
static BOOL rdp_write_frame_acknowledge_capability_set(wLog* log, wStream* s,
3877
                                                       const rdpSettings* settings)
3878
0
{
3879
0
  WINPR_ASSERT(settings);
3880
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
3881
0
    return FALSE;
3882
3883
0
  const size_t header = rdp_capability_set_start(log, s);
3884
0
  Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3885
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE);
3886
0
}
3887
3888
#ifdef WITH_DEBUG_CAPABILITIES
3889
static BOOL rdp_print_frame_acknowledge_capability_set(wLog* log, wStream* s)
3890
{
3891
  UINT32 frameAcknowledge = 0;
3892
  WLog_Print(log, WLOG_TRACE,
3893
             "FrameAcknowledgeCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3894
3895
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3896
    return FALSE;
3897
3898
  Stream_Read_UINT32(s, frameAcknowledge); /* frameAcknowledge (4 bytes) */
3899
  WLog_Print(log, WLOG_TRACE, "\tframeAcknowledge: 0x%08" PRIX32 "", frameAcknowledge);
3900
  return TRUE;
3901
}
3902
#endif
3903
3904
static BOOL rdp_apply_bitmap_cache_v3_codec_id_capability_set(rdpSettings* settings,
3905
                                                              const rdpSettings* src)
3906
592
{
3907
592
  WINPR_ASSERT(settings);
3908
592
  WINPR_ASSERT(src);
3909
3910
592
  settings->BitmapCacheV3CodecId = src->BitmapCacheV3CodecId;
3911
592
  return TRUE;
3912
592
}
3913
3914
static BOOL rdp_read_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3915
                                                             rdpSettings* settings)
3916
599
{
3917
599
  BYTE bitmapCacheV3CodecId = 0;
3918
3919
599
  WINPR_ASSERT(settings);
3920
599
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3921
7
    return FALSE;
3922
3923
592
  Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3924
592
  settings->BitmapCacheV3CodecId = bitmapCacheV3CodecId;
3925
592
  return TRUE;
3926
599
}
3927
3928
static BOOL rdp_write_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3929
                                                              const rdpSettings* settings)
3930
0
{
3931
0
  WINPR_ASSERT(settings);
3932
0
  if (!Stream_EnsureRemainingCapacity(s, 32))
3933
0
    return FALSE;
3934
3935
0
  const size_t header = rdp_capability_set_start(log, s);
3936
0
  if (settings->BitmapCacheV3CodecId > UINT8_MAX)
3937
0
    return FALSE;
3938
0
  Stream_Write_UINT8(s, (UINT8)settings->BitmapCacheV3CodecId);
3939
0
  return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID);
3940
0
}
3941
3942
#ifdef WITH_DEBUG_CAPABILITIES
3943
static BOOL rdp_print_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s)
3944
{
3945
  BYTE bitmapCacheV3CodecId = 0;
3946
  WLog_Print(log, WLOG_TRACE, "BitmapCacheV3CodecIdCapabilitySet (length %" PRIuz "):",
3947
             Stream_GetRemainingLength(s));
3948
3949
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3950
    return FALSE;
3951
3952
  Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3953
  WLog_Print(log, WLOG_TRACE, "\tbitmapCacheV3CodecId: 0x%02" PRIX8 "", bitmapCacheV3CodecId);
3954
  return TRUE;
3955
}
3956
3957
BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving)
3958
{
3959
  BOOL rc = FALSE;
3960
  UINT16 type = 0;
3961
  UINT16 length = 0;
3962
  UINT16 numberCapabilities = 0;
3963
3964
  size_t pos = Stream_GetPosition(s);
3965
3966
  if (!Stream_SetPosition(s, start))
3967
    goto fail;
3968
3969
  if (receiving)
3970
  {
3971
    if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3972
      goto fail;
3973
  }
3974
  else
3975
  {
3976
    if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), 4))
3977
      goto fail;
3978
  }
3979
3980
  Stream_Read_UINT16(s, numberCapabilities);
3981
  Stream_Seek(s, 2);
3982
3983
  while (numberCapabilities > 0)
3984
  {
3985
    size_t rest = 0;
3986
    wStream subBuffer;
3987
    wStream* sub = nullptr;
3988
3989
    if (!rdp_read_capability_set_header(log, s, &length, &type))
3990
      goto fail;
3991
3992
    WLog_Print(log, WLOG_TRACE, "%s ", receiving ? "Receiving" : "Sending");
3993
    sub = Stream_StaticInit(&subBuffer, Stream_Pointer(s), length - 4);
3994
    if (!Stream_SafeSeek(s, length - 4))
3995
      goto fail;
3996
3997
    switch (type)
3998
    {
3999
      case CAPSET_TYPE_GENERAL:
4000
        if (!rdp_print_general_capability_set(log, sub))
4001
          goto fail;
4002
4003
        break;
4004
4005
      case CAPSET_TYPE_BITMAP:
4006
        if (!rdp_print_bitmap_capability_set(log, sub))
4007
          goto fail;
4008
4009
        break;
4010
4011
      case CAPSET_TYPE_ORDER:
4012
        if (!rdp_print_order_capability_set(log, sub))
4013
          goto fail;
4014
4015
        break;
4016
4017
      case CAPSET_TYPE_BITMAP_CACHE:
4018
        if (!rdp_print_bitmap_cache_capability_set(log, sub))
4019
          goto fail;
4020
4021
        break;
4022
4023
      case CAPSET_TYPE_CONTROL:
4024
        if (!rdp_print_control_capability_set(log, sub))
4025
          goto fail;
4026
4027
        break;
4028
4029
      case CAPSET_TYPE_ACTIVATION:
4030
        if (!rdp_print_window_activation_capability_set(log, sub))
4031
          goto fail;
4032
4033
        break;
4034
4035
      case CAPSET_TYPE_POINTER:
4036
        if (!rdp_print_pointer_capability_set(log, sub))
4037
          goto fail;
4038
4039
        break;
4040
4041
      case CAPSET_TYPE_SHARE:
4042
        if (!rdp_print_share_capability_set(log, sub))
4043
          goto fail;
4044
4045
        break;
4046
4047
      case CAPSET_TYPE_COLOR_CACHE:
4048
        if (!rdp_print_color_cache_capability_set(log, sub))
4049
          goto fail;
4050
4051
        break;
4052
4053
      case CAPSET_TYPE_SOUND:
4054
        if (!rdp_print_sound_capability_set(log, sub))
4055
          goto fail;
4056
4057
        break;
4058
4059
      case CAPSET_TYPE_INPUT:
4060
        if (!rdp_print_input_capability_set(log, sub))
4061
          goto fail;
4062
4063
        break;
4064
4065
      case CAPSET_TYPE_FONT:
4066
        if (!rdp_print_font_capability_set(log, sub))
4067
          goto fail;
4068
4069
        break;
4070
4071
      case CAPSET_TYPE_BRUSH:
4072
        if (!rdp_print_brush_capability_set(log, sub))
4073
          goto fail;
4074
4075
        break;
4076
4077
      case CAPSET_TYPE_GLYPH_CACHE:
4078
        if (!rdp_print_glyph_cache_capability_set(log, sub))
4079
          goto fail;
4080
4081
        break;
4082
4083
      case CAPSET_TYPE_OFFSCREEN_CACHE:
4084
        if (!rdp_print_offscreen_bitmap_cache_capability_set(log, sub))
4085
          goto fail;
4086
4087
        break;
4088
4089
      case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4090
        if (!rdp_print_bitmap_cache_host_support_capability_set(log, sub))
4091
          goto fail;
4092
4093
        break;
4094
4095
      case CAPSET_TYPE_BITMAP_CACHE_V2:
4096
        if (!rdp_print_bitmap_cache_v2_capability_set(log, sub))
4097
          goto fail;
4098
4099
        break;
4100
4101
      case CAPSET_TYPE_VIRTUAL_CHANNEL:
4102
        if (!rdp_print_virtual_channel_capability_set(log, sub))
4103
          goto fail;
4104
4105
        break;
4106
4107
      case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4108
        if (!rdp_print_draw_nine_grid_cache_capability_set(log, sub))
4109
          goto fail;
4110
4111
        break;
4112
4113
      case CAPSET_TYPE_DRAW_GDI_PLUS:
4114
        if (!rdp_print_draw_gdiplus_cache_capability_set(log, sub))
4115
          goto fail;
4116
4117
        break;
4118
4119
      case CAPSET_TYPE_RAIL:
4120
        if (!rdp_print_remote_programs_capability_set(log, sub))
4121
          goto fail;
4122
4123
        break;
4124
4125
      case CAPSET_TYPE_WINDOW:
4126
        if (!rdp_print_window_list_capability_set(log, sub))
4127
          goto fail;
4128
4129
        break;
4130
4131
      case CAPSET_TYPE_COMP_DESK:
4132
        if (!rdp_print_desktop_composition_capability_set(log, sub))
4133
          goto fail;
4134
4135
        break;
4136
4137
      case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4138
        if (!rdp_print_multifragment_update_capability_set(log, sub))
4139
          goto fail;
4140
4141
        break;
4142
4143
      case CAPSET_TYPE_LARGE_POINTER:
4144
        if (!rdp_print_large_pointer_capability_set(log, sub))
4145
          goto fail;
4146
4147
        break;
4148
4149
      case CAPSET_TYPE_SURFACE_COMMANDS:
4150
        if (!rdp_print_surface_commands_capability_set(log, sub))
4151
          goto fail;
4152
4153
        break;
4154
4155
      case CAPSET_TYPE_BITMAP_CODECS:
4156
        if (!rdp_print_bitmap_codecs_capability_set(log, sub))
4157
          goto fail;
4158
4159
        break;
4160
4161
      case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4162
        if (!rdp_print_frame_acknowledge_capability_set(log, sub))
4163
          goto fail;
4164
4165
        break;
4166
4167
      case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4168
        if (!rdp_print_bitmap_cache_v3_codec_id_capability_set(log, sub))
4169
          goto fail;
4170
4171
        break;
4172
4173
      default:
4174
        WLog_Print(log, WLOG_ERROR, "unknown capability type %" PRIu16 "", type);
4175
        break;
4176
    }
4177
4178
    rest = Stream_GetRemainingLength(sub);
4179
    if (rest > 0)
4180
    {
4181
      WLog_Print(log, WLOG_WARN,
4182
                 "incorrect capability offset, type:0x%04" PRIX16 " %" PRIu16
4183
                 " bytes expected, %" PRIuz "bytes remaining",
4184
                 type, length, rest);
4185
    }
4186
4187
    numberCapabilities--;
4188
  }
4189
4190
  rc = TRUE;
4191
fail:
4192
  if (!Stream_SetPosition(s, pos))
4193
    return FALSE;
4194
4195
  return rc;
4196
}
4197
#endif
4198
4199
static BOOL rdp_apply_from_received(UINT16 type, rdpSettings* dst, const rdpSettings* src)
4200
80.0k
{
4201
80.0k
  switch (type)
4202
80.0k
  {
4203
1.77k
    case CAPSET_TYPE_GENERAL:
4204
1.77k
      return rdp_apply_general_capability_set(dst, src);
4205
2.90k
    case CAPSET_TYPE_BITMAP:
4206
2.90k
      return rdp_apply_bitmap_capability_set(dst, src);
4207
2.42k
    case CAPSET_TYPE_ORDER:
4208
2.42k
      return rdp_apply_order_capability_set(dst, src);
4209
11.3k
    case CAPSET_TYPE_POINTER:
4210
11.3k
      return rdp_apply_pointer_capability_set(dst, src);
4211
26.4k
    case CAPSET_TYPE_INPUT:
4212
26.4k
      return rdp_apply_input_capability_set(dst, src);
4213
1.86k
    case CAPSET_TYPE_VIRTUAL_CHANNEL:
4214
1.86k
      return rdp_apply_virtual_channel_capability_set(dst, src);
4215
335
    case CAPSET_TYPE_SHARE:
4216
335
      return rdp_apply_share_capability_set(dst, src);
4217
2.14k
    case CAPSET_TYPE_COLOR_CACHE:
4218
2.14k
      return rdp_apply_color_cache_capability_set(dst, src);
4219
1.59k
    case CAPSET_TYPE_FONT:
4220
1.59k
      return rdp_apply_font_capability_set(dst, src);
4221
427
    case CAPSET_TYPE_DRAW_GDI_PLUS:
4222
427
      return rdp_apply_draw_gdiplus_cache_capability_set(dst, src);
4223
861
    case CAPSET_TYPE_RAIL:
4224
861
      return rdp_apply_remote_programs_capability_set(dst, src);
4225
508
    case CAPSET_TYPE_WINDOW:
4226
508
      return rdp_apply_window_list_capability_set(dst, src);
4227
2.13k
    case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4228
2.13k
      return rdp_apply_multifragment_update_capability_set(dst, src);
4229
1.00k
    case CAPSET_TYPE_LARGE_POINTER:
4230
1.00k
      return rdp_apply_large_pointer_capability_set(dst, src);
4231
106
    case CAPSET_TYPE_COMP_DESK:
4232
106
      return rdp_apply_desktop_composition_capability_set(dst, src);
4233
1.58k
    case CAPSET_TYPE_SURFACE_COMMANDS:
4234
1.58k
      return rdp_apply_surface_commands_capability_set(dst, src);
4235
922
    case CAPSET_TYPE_BITMAP_CODECS:
4236
922
      return rdp_apply_bitmap_codecs_capability_set(dst, src);
4237
1.05k
    case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4238
1.05k
      return rdp_apply_frame_acknowledge_capability_set(dst, src);
4239
592
    case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4240
592
      return rdp_apply_bitmap_cache_v3_codec_id_capability_set(dst, src);
4241
82
    case CAPSET_TYPE_BITMAP_CACHE:
4242
82
      return rdp_apply_bitmap_cache_capability_set(dst, src);
4243
9.55k
    case CAPSET_TYPE_BITMAP_CACHE_V2:
4244
9.55k
      return rdp_apply_bitmap_cache_v2_capability_set(dst, src);
4245
531
    case CAPSET_TYPE_BRUSH:
4246
531
      return rdp_apply_brush_capability_set(dst, src);
4247
57
    case CAPSET_TYPE_GLYPH_CACHE:
4248
57
      return rdp_apply_glyph_cache_capability_set(dst, src);
4249
124
    case CAPSET_TYPE_OFFSCREEN_CACHE:
4250
124
      return rdp_apply_offscreen_bitmap_cache_capability_set(dst, src);
4251
343
    case CAPSET_TYPE_SOUND:
4252
343
      return rdp_apply_sound_capability_set(dst, src);
4253
13
    case CAPSET_TYPE_CONTROL:
4254
13
      return rdp_apply_control_capability_set(dst, src);
4255
56
    case CAPSET_TYPE_ACTIVATION:
4256
56
      return rdp_apply_window_activation_capability_set(dst, src);
4257
78
    case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4258
78
      return rdp_apply_draw_nine_grid_cache_capability_set(dst, src);
4259
9.12k
    case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4260
9.12k
      return rdp_apply_bitmap_cache_host_support_capability_set(dst, src);
4261
0
    default:
4262
0
      return TRUE;
4263
80.0k
  }
4264
80.0k
}
4265
4266
BOOL rdp_read_capability_set(wLog* log, wStream* sub, UINT16 type, rdpSettings* settings,
4267
                             BOOL isServer)
4268
82.1k
{
4269
82.1k
  WINPR_ASSERT(settings);
4270
4271
82.1k
  if (type <= CAPSET_TYPE_FRAME_ACKNOWLEDGE)
4272
80.5k
  {
4273
80.5k
    const size_t size = Stream_Length(sub);
4274
80.5k
    if (size > UINT32_MAX)
4275
0
      return FALSE;
4276
4277
80.5k
    WINPR_ASSERT(settings->ReceivedCapabilities);
4278
80.5k
    settings->ReceivedCapabilities[type] = TRUE;
4279
4280
80.5k
    WINPR_ASSERT(settings->ReceivedCapabilityDataSizes);
4281
80.5k
    settings->ReceivedCapabilityDataSizes[type] = (UINT32)size;
4282
4283
80.5k
    WINPR_ASSERT(settings->ReceivedCapabilityData);
4284
80.5k
    void* tmp = realloc(settings->ReceivedCapabilityData[type], size);
4285
80.5k
    if (!tmp && (size > 0))
4286
0
      return FALSE;
4287
80.5k
    memcpy(tmp, Stream_Buffer(sub), size);
4288
80.5k
    settings->ReceivedCapabilityData[type] = tmp;
4289
80.5k
  }
4290
1.51k
  else
4291
1.51k
    WLog_Print(log, WLOG_WARN, "not handling capability type %" PRIu16 " yet", type);
4292
4293
82.1k
  BOOL treated = TRUE;
4294
4295
82.1k
  switch (type)
4296
82.1k
  {
4297
1.82k
    case CAPSET_TYPE_GENERAL:
4298
1.82k
      if (!rdp_read_general_capability_set(log, sub, settings))
4299
48
        return FALSE;
4300
4301
1.77k
      break;
4302
4303
2.91k
    case CAPSET_TYPE_BITMAP:
4304
2.91k
      if (!rdp_read_bitmap_capability_set(log, sub, settings))
4305
9
        return FALSE;
4306
4307
2.90k
      break;
4308
4309
2.90k
    case CAPSET_TYPE_ORDER:
4310
2.43k
      if (!rdp_read_order_capability_set(log, sub, settings))
4311
7
        return FALSE;
4312
4313
2.42k
      break;
4314
4315
11.4k
    case CAPSET_TYPE_POINTER:
4316
11.4k
      if (!rdp_read_pointer_capability_set(log, sub, settings))
4317
16
        return FALSE;
4318
4319
11.3k
      break;
4320
4321
26.4k
    case CAPSET_TYPE_INPUT:
4322
26.4k
      if (!rdp_read_input_capability_set(log, sub, settings))
4323
8
        return FALSE;
4324
4325
26.4k
      break;
4326
4327
26.4k
    case CAPSET_TYPE_VIRTUAL_CHANNEL:
4328
1.86k
      if (!rdp_read_virtual_channel_capability_set(log, sub, settings))
4329
5
        return FALSE;
4330
4331
1.86k
      break;
4332
4333
1.86k
    case CAPSET_TYPE_SHARE:
4334
339
      if (!rdp_read_share_capability_set(log, sub, settings))
4335
4
        return FALSE;
4336
4337
335
      break;
4338
4339
2.16k
    case CAPSET_TYPE_COLOR_CACHE:
4340
2.16k
      if (!rdp_read_color_cache_capability_set(log, sub, settings))
4341
19
        return FALSE;
4342
4343
2.14k
      break;
4344
4345
2.14k
    case CAPSET_TYPE_FONT:
4346
1.59k
      if (!rdp_read_font_capability_set(log, sub, settings))
4347
0
        return FALSE;
4348
4349
1.59k
      break;
4350
4351
1.59k
    case CAPSET_TYPE_DRAW_GDI_PLUS:
4352
433
      if (!rdp_read_draw_gdiplus_cache_capability_set(log, sub, settings))
4353
6
        return FALSE;
4354
4355
427
      break;
4356
4357
865
    case CAPSET_TYPE_RAIL:
4358
865
      if (!rdp_read_remote_programs_capability_set(log, sub, settings))
4359
4
        return FALSE;
4360
4361
861
      break;
4362
4363
861
    case CAPSET_TYPE_WINDOW:
4364
514
      if (!rdp_read_window_list_capability_set(log, sub, settings))
4365
6
        return FALSE;
4366
4367
508
      break;
4368
4369
2.14k
    case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4370
2.14k
      if (!rdp_read_multifragment_update_capability_set(log, sub, settings))
4371
6
        return FALSE;
4372
4373
2.13k
      break;
4374
4375
2.13k
    case CAPSET_TYPE_LARGE_POINTER:
4376
1.00k
      if (!rdp_read_large_pointer_capability_set(log, sub, settings))
4377
4
        return FALSE;
4378
4379
1.00k
      break;
4380
4381
1.00k
    case CAPSET_TYPE_COMP_DESK:
4382
110
      if (!rdp_read_desktop_composition_capability_set(log, sub, settings))
4383
4
        return FALSE;
4384
4385
106
      break;
4386
4387
1.59k
    case CAPSET_TYPE_SURFACE_COMMANDS:
4388
1.59k
      if (!rdp_read_surface_commands_capability_set(log, sub, settings))
4389
9
        return FALSE;
4390
4391
1.58k
      break;
4392
4393
1.58k
    case CAPSET_TYPE_BITMAP_CODECS:
4394
1.05k
      if (!rdp_read_bitmap_codecs_capability_set(log, sub, settings, isServer))
4395
133
        return FALSE;
4396
4397
922
      break;
4398
4399
1.06k
    case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4400
1.06k
      if (!rdp_read_frame_acknowledge_capability_set(log, sub, settings))
4401
6
        return FALSE;
4402
4403
1.05k
      break;
4404
4405
1.05k
    case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4406
599
      if (!rdp_read_bitmap_cache_v3_codec_id_capability_set(log, sub, settings))
4407
7
        return FALSE;
4408
4409
592
      break;
4410
4411
21.7k
    default:
4412
21.7k
      treated = FALSE;
4413
21.7k
      break;
4414
82.1k
  }
4415
4416
81.8k
  if (!treated)
4417
21.7k
  {
4418
21.7k
    if (isServer)
4419
11.7k
    {
4420
      /* treating capabilities that are supposed to be send only from the client */
4421
11.7k
      switch (type)
4422
11.7k
      {
4423
94
        case CAPSET_TYPE_BITMAP_CACHE:
4424
94
          if (!rdp_read_bitmap_cache_capability_set(log, sub, settings))
4425
12
            return FALSE;
4426
4427
82
          break;
4428
4429
9.56k
        case CAPSET_TYPE_BITMAP_CACHE_V2:
4430
9.56k
          if (!rdp_read_bitmap_cache_v2_capability_set(log, sub, settings))
4431
9
            return FALSE;
4432
4433
9.55k
          break;
4434
4435
9.55k
        case CAPSET_TYPE_BRUSH:
4436
534
          if (!rdp_read_brush_capability_set(log, sub, settings))
4437
3
            return FALSE;
4438
4439
531
          break;
4440
4441
531
        case CAPSET_TYPE_GLYPH_CACHE:
4442
61
          if (!rdp_read_glyph_cache_capability_set(log, sub, settings))
4443
4
            return FALSE;
4444
4445
57
          break;
4446
4447
129
        case CAPSET_TYPE_OFFSCREEN_CACHE:
4448
129
          if (!rdp_read_offscreen_bitmap_cache_capability_set(log, sub, settings))
4449
5
            return FALSE;
4450
4451
124
          break;
4452
4453
346
        case CAPSET_TYPE_SOUND:
4454
346
          if (!rdp_read_sound_capability_set(log, sub, settings))
4455
3
            return FALSE;
4456
4457
343
          break;
4458
4459
343
        case CAPSET_TYPE_CONTROL:
4460
17
          if (!rdp_read_control_capability_set(log, sub, settings))
4461
4
            return FALSE;
4462
4463
13
          break;
4464
4465
62
        case CAPSET_TYPE_ACTIVATION:
4466
62
          if (!rdp_read_window_activation_capability_set(log, sub, settings))
4467
6
            return FALSE;
4468
4469
56
          break;
4470
4471
81
        case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4472
81
          if (!rdp_read_draw_nine_grid_cache_capability_set(log, sub, settings))
4473
3
            return FALSE;
4474
4475
78
          break;
4476
4477
888
        default:
4478
888
          WLog_Print(log, WLOG_ERROR,
4479
888
                     "capability %s(%" PRIu16 ") not expected from client",
4480
888
                     get_capability_name(type), type);
4481
888
          return FALSE;
4482
11.7k
      }
4483
11.7k
    }
4484
9.94k
    else
4485
9.94k
    {
4486
      /* treating capabilities that are supposed to be send only from the server */
4487
9.94k
      switch (type)
4488
9.94k
      {
4489
9.13k
        case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4490
9.13k
          if (!rdp_read_bitmap_cache_host_support_capability_set(log, sub, settings))
4491
4
            return FALSE;
4492
4493
9.12k
          break;
4494
4495
9.12k
        default:
4496
810
          WLog_Print(log, WLOG_ERROR,
4497
810
                     "capability %s(%" PRIu16 ") not expected from server",
4498
810
                     get_capability_name(type), type);
4499
810
          return FALSE;
4500
9.94k
      }
4501
9.94k
    }
4502
21.7k
  }
4503
4504
80.0k
  const size_t rest = Stream_GetRemainingLength(sub);
4505
80.0k
  if (rest > 0)
4506
41.6k
  {
4507
41.6k
    const size_t length = Stream_Capacity(sub);
4508
41.6k
    WLog_Print(log, WLOG_ERROR,
4509
41.6k
               "incorrect offset, type:0x%04" PRIx16 " actual:%" PRIuz " expected:%" PRIuz "",
4510
41.6k
               type, length - rest, length);
4511
41.6k
  }
4512
80.0k
  return TRUE;
4513
81.8k
}
4514
4515
static BOOL rdp_read_capability_sets(wLog* log, wStream* s, rdpSettings* settings,
4516
                                     rdpSettings* rcvSettings, UINT16 totalLength)
4517
7.96k
{
4518
7.96k
  BOOL rc = FALSE;
4519
7.96k
  size_t start = 0;
4520
7.96k
  size_t end = 0;
4521
7.96k
  size_t len = 0;
4522
7.96k
  UINT16 numberCapabilities = 0;
4523
7.96k
  UINT16 count = 0;
4524
4525
#ifdef WITH_DEBUG_CAPABILITIES
4526
  const size_t capstart = Stream_GetPosition(s);
4527
#endif
4528
4529
7.96k
  WINPR_ASSERT(s);
4530
7.96k
  WINPR_ASSERT(settings);
4531
4532
7.96k
  if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4533
0
    return FALSE;
4534
4535
7.96k
  Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4536
7.96k
  Stream_Seek(s, 2);                         /* pad2Octets (2 bytes) */
4537
7.96k
  count = numberCapabilities;
4538
4539
7.96k
  start = Stream_GetPosition(s);
4540
88.0k
  while (numberCapabilities > 0 && Stream_GetRemainingLength(s) >= 4)
4541
84.5k
  {
4542
84.5k
    UINT16 type = 0;
4543
84.5k
    UINT16 length = 0;
4544
84.5k
    wStream subbuffer;
4545
84.5k
    wStream* sub = nullptr;
4546
4547
84.5k
    if (!rdp_read_capability_set_header(log, s, &length, &type))
4548
1.04k
      goto fail;
4549
83.4k
    sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), length - 4);
4550
83.4k
    if (!Stream_SafeSeek(s, length - 4))
4551
1.38k
      goto fail;
4552
4553
82.1k
    if (!rdp_read_capability_set(log, sub, type, rcvSettings, settings->ServerMode))
4554
2.05k
      goto fail;
4555
4556
80.0k
    if (!rdp_apply_from_received(type, settings, rcvSettings))
4557
0
      goto fail;
4558
80.0k
    numberCapabilities--;
4559
80.0k
  }
4560
4561
3.48k
  end = Stream_GetPosition(s);
4562
3.48k
  len = end - start;
4563
4564
3.48k
  if (numberCapabilities)
4565
1.01k
  {
4566
1.01k
    WLog_Print(log, WLOG_ERROR,
4567
1.01k
               "strange we haven't read the number of announced capacity sets, read=%d "
4568
1.01k
               "expected=%" PRIu16 "",
4569
1.01k
               count - numberCapabilities, count);
4570
1.01k
  }
4571
4572
#ifdef WITH_DEBUG_CAPABILITIES
4573
  rdp_print_capability_sets(log, s, capstart, TRUE);
4574
#endif
4575
4576
3.48k
  if (len > totalLength)
4577
574
  {
4578
574
    WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIuz,
4579
574
               totalLength, len);
4580
574
    goto fail;
4581
574
  }
4582
2.91k
  rc = freerdp_capability_buffer_copy(settings, rcvSettings);
4583
7.96k
fail:
4584
7.96k
  return rc;
4585
2.91k
}
4586
4587
BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId, UINT16* length)
4588
18.0k
{
4589
18.0k
  WINPR_ASSERT(rdp);
4590
18.0k
  WINPR_ASSERT(rdp->context);
4591
4592
18.0k
  if (!rdp_read_header(rdp, s, length, pChannelId))
4593
17.9k
    return FALSE;
4594
4595
74
  if (freerdp_shall_disconnect_context(rdp->context))
4596
44
    return TRUE;
4597
4598
30
  if (*pChannelId != MCS_GLOBAL_CHANNEL_ID)
4599
29
  {
4600
29
    UINT16 mcsMessageChannelId = rdp->mcs->messageChannelId;
4601
4602
29
    if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId))
4603
29
    {
4604
29
      WLog_Print(rdp->log, WLOG_ERROR, "unexpected MCS channel id %04" PRIx16 " received",
4605
29
                 *pChannelId);
4606
29
      return FALSE;
4607
29
    }
4608
29
  }
4609
4610
1
  return TRUE;
4611
30
}
4612
4613
BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s, UINT16 pduSource, UINT16 length)
4614
18.0k
{
4615
18.0k
  UINT16 lengthSourceDescriptor = 0;
4616
18.0k
  UINT16 lengthCombinedCapabilities = 0;
4617
4618
18.0k
  WINPR_ASSERT(rdp);
4619
18.0k
  WINPR_ASSERT(rdp->settings);
4620
18.0k
  WINPR_ASSERT(rdp->context);
4621
18.0k
  WINPR_ASSERT(s);
4622
4623
18.0k
  rdp->settings->PduSource = pduSource;
4624
4625
18.0k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 8))
4626
9.11k
    return FALSE;
4627
4628
8.93k
  Stream_Read_UINT32(s, rdp->settings->ShareId);     /* shareId (4 bytes) */
4629
8.93k
  Stream_Read_UINT16(s, lengthSourceDescriptor);     /* lengthSourceDescriptor (2 bytes) */
4630
8.93k
  Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4631
4632
8.93k
  if (!Stream_SafeSeek(s, lengthSourceDescriptor) ||
4633
4.92k
      !Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4)) /* sourceDescriptor */
4634
4.03k
    return FALSE;
4635
4636
  /* capabilitySets */
4637
4.90k
  if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4638
4.90k
                                lengthCombinedCapabilities))
4639
3.33k
  {
4640
3.33k
    WLog_Print(rdp->log, WLOG_ERROR, "rdp_read_capability_sets failed");
4641
3.33k
    return FALSE;
4642
3.33k
  }
4643
4644
1.57k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4))
4645
499
    return FALSE;
4646
4647
  /* [MS-RDPBCGR] 2.2.1.13.1.1 Demand Active PDU Data (TS_DEMAND_ACTIVE_PDU)::sessionId
4648
   * is ignored by client */
4649
1.07k
  Stream_Seek_UINT32(s); /* SessionId */
4650
4651
1.07k
  {
4652
1.07k
    rdp_secondary_update_internal* secondary = secondary_update_cast(rdp->update->secondary);
4653
1.07k
    secondary->glyph_v2 = (rdp->settings->GlyphSupportLevel > GLYPH_SUPPORT_FULL);
4654
1.07k
  }
4655
4656
1.07k
  return tpkt_ensure_stream_consumed(rdp->log, s, length);
4657
1.57k
}
4658
4659
static BOOL rdp_write_demand_active(wLog* log, wStream* s, rdpSettings* settings)
4660
0
{
4661
0
  size_t bm = 0;
4662
0
  size_t em = 0;
4663
0
  size_t lm = 0;
4664
0
  UINT16 numberCapabilities = 0;
4665
0
  size_t lengthCombinedCapabilities = 0;
4666
4667
0
  if (!Stream_EnsureRemainingCapacity(s, 64))
4668
0
    return FALSE;
4669
4670
0
  Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4671
0
  Stream_Write_UINT16(s, 4);                 /* lengthSourceDescriptor (2 bytes) */
4672
0
  lm = Stream_GetPosition(s);
4673
0
  Stream_Seek_UINT16(s);     /* lengthCombinedCapabilities (2 bytes) */
4674
0
  Stream_Write(s, "RDP", 4); /* sourceDescriptor */
4675
0
  bm = Stream_GetPosition(s);
4676
0
  Stream_Seek_UINT16(s);     /* numberCapabilities (2 bytes) */
4677
0
  Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4678
0
  numberCapabilities = 14;
4679
4680
0
  if (!rdp_write_general_capability_set(log, s, settings) ||
4681
0
      !rdp_write_bitmap_capability_set(log, s, settings) ||
4682
0
      !rdp_write_order_capability_set(log, s, settings) ||
4683
0
      !rdp_write_pointer_capability_set(log, s, settings) ||
4684
0
      !rdp_write_input_capability_set(log, s, settings) ||
4685
0
      !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4686
0
      !rdp_write_share_capability_set(log, s, settings) ||
4687
0
      !rdp_write_font_capability_set(log, s, settings) ||
4688
0
      !rdp_write_multifragment_update_capability_set(log, s, settings) ||
4689
0
      !rdp_write_large_pointer_capability_set(log, s, settings) ||
4690
0
      !rdp_write_desktop_composition_capability_set(log, s, settings) ||
4691
0
      !rdp_write_surface_commands_capability_set(log, s, settings) ||
4692
0
      !rdp_write_bitmap_codecs_capability_set(log, s, settings) ||
4693
0
      !rdp_write_frame_acknowledge_capability_set(log, s, settings))
4694
0
  {
4695
0
    return FALSE;
4696
0
  }
4697
4698
0
  if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
4699
0
  {
4700
0
    numberCapabilities++;
4701
4702
0
    if (!rdp_write_bitmap_cache_host_support_capability_set(log, s, settings))
4703
0
      return FALSE;
4704
0
  }
4705
4706
0
  if (settings->RemoteApplicationMode)
4707
0
  {
4708
0
    numberCapabilities += 2;
4709
4710
0
    if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4711
0
        !rdp_write_window_list_capability_set(log, s, settings))
4712
0
      return FALSE;
4713
0
  }
4714
4715
0
  em = Stream_GetPosition(s);
4716
0
  if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4717
0
    return FALSE;
4718
0
  lengthCombinedCapabilities = (em - bm);
4719
0
  if (lengthCombinedCapabilities > UINT16_MAX)
4720
0
    return FALSE;
4721
0
  Stream_Write_UINT16(
4722
0
      s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4723
0
  if (!Stream_SetPosition(s, bm))             /* go back to numberCapabilities */
4724
0
    return FALSE;
4725
0
  Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4726
#ifdef WITH_DEBUG_CAPABILITIES
4727
  rdp_print_capability_sets(log, s, bm, FALSE);
4728
#endif
4729
0
  if (!Stream_SetPosition(s, em))
4730
0
    return FALSE;
4731
0
  Stream_Write_UINT32(s, 0); /* sessionId */
4732
0
  return TRUE;
4733
0
}
4734
4735
BOOL rdp_send_demand_active(rdpRdp* rdp)
4736
0
{
4737
0
  UINT16 sec_flags = 0;
4738
0
  wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4739
0
  BOOL status = 0;
4740
4741
0
  if (!s)
4742
0
    return FALSE;
4743
4744
0
  rdp->settings->ShareId = 0x10000 + rdp->mcs->userId;
4745
0
  status = rdp_write_demand_active(rdp->log, s, rdp->settings) &&
4746
0
           rdp_send_pdu(rdp, s, PDU_TYPE_DEMAND_ACTIVE, rdp->mcs->userId, sec_flags);
4747
0
  Stream_Release(s);
4748
0
  return status;
4749
0
}
4750
4751
BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength)
4752
18.0k
{
4753
18.0k
  rdpSettings* settings = nullptr;
4754
18.0k
  UINT16 lengthSourceDescriptor = 0;
4755
18.0k
  UINT16 lengthCombinedCapabilities = 0;
4756
4757
18.0k
  WINPR_ASSERT(rdp);
4758
18.0k
  WINPR_ASSERT(s);
4759
18.0k
  settings = rdp->settings;
4760
18.0k
  WINPR_ASSERT(settings);
4761
4762
18.0k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 10))
4763
10.7k
    return FALSE;
4764
4765
7.28k
  Stream_Seek_UINT32(s);                             /* shareId (4 bytes) */
4766
7.28k
  Stream_Seek_UINT16(s);                             /* originatorId (2 bytes) */
4767
7.28k
  Stream_Read_UINT16(s, lengthSourceDescriptor);     /* lengthSourceDescriptor (2 bytes) */
4768
7.28k
  Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4769
4770
7.28k
  if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, lengthSourceDescriptor + 4U))
4771
4.21k
    return FALSE;
4772
4773
3.06k
  Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor */
4774
3.06k
  if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4775
3.06k
                                lengthCombinedCapabilities))
4776
1.72k
    return FALSE;
4777
4778
1.34k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4779
1.34k
  {
4780
    /* client does not support surface commands */
4781
1.34k
    settings->SurfaceCommandsEnabled = FALSE;
4782
1.34k
    settings->SurfaceFrameMarkerEnabled = FALSE;
4783
1.34k
  }
4784
4785
1.34k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4786
1.33k
  {
4787
    /* client does not support frame acks */
4788
1.33k
    settings->FrameAcknowledge = 0;
4789
1.33k
  }
4790
4791
1.34k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4792
1.34k
  {
4793
    /* client does not support bitmap cache v3 */
4794
1.34k
    settings->BitmapCacheV3Enabled = FALSE;
4795
1.34k
  }
4796
4797
1.34k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4798
1.33k
  {
4799
    /* client does not support bitmap codecs */
4800
1.33k
    if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, FALSE))
4801
0
      return FALSE;
4802
1.33k
    if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, FALSE))
4803
0
      return FALSE;
4804
1.33k
    if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
4805
0
      return FALSE;
4806
1.33k
  }
4807
4808
1.34k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4809
1.33k
  {
4810
    /* client does not support multi fragment updates - make sure packages are not fragmented */
4811
1.33k
    if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
4812
1.33k
                                     FASTPATH_FRAGMENT_SAFE_SIZE))
4813
0
      return FALSE;
4814
1.33k
  }
4815
4816
1.34k
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4817
1.34k
  {
4818
    /* client does not support large pointers */
4819
1.34k
    settings->LargePointerFlag = 0;
4820
1.34k
  }
4821
4822
1.34k
  return tpkt_ensure_stream_consumed(rdp->log, s, pduLength);
4823
1.34k
}
4824
4825
static BOOL rdp_write_confirm_active(wLog* log, wStream* s, rdpSettings* settings)
4826
0
{
4827
0
  size_t bm = 0;
4828
0
  size_t em = 0;
4829
0
  size_t lm = 0;
4830
0
  UINT16 numberCapabilities = 0;
4831
0
  UINT16 lengthSourceDescriptor = 0;
4832
0
  size_t lengthCombinedCapabilities = 0;
4833
0
  BOOL ret = 0;
4834
4835
0
  WINPR_ASSERT(settings);
4836
4837
0
  lengthSourceDescriptor = sizeof(SOURCE_DESCRIPTOR);
4838
0
  Stream_Write_UINT32(s, settings->ShareId);      /* shareId (4 bytes) */
4839
0
  Stream_Write_UINT16(s, 0x03EA);                 /* originatorId (2 bytes) */
4840
0
  Stream_Write_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4841
0
  lm = Stream_GetPosition(s);
4842
0
  Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4843
0
  Stream_Write(s, SOURCE_DESCRIPTOR, lengthSourceDescriptor); /* sourceDescriptor */
4844
0
  bm = Stream_GetPosition(s);
4845
0
  Stream_Seek_UINT16(s);     /* numberCapabilities (2 bytes) */
4846
0
  Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4847
  /* Capability Sets */
4848
0
  numberCapabilities = 15;
4849
4850
0
  if (!rdp_write_general_capability_set(log, s, settings) ||
4851
0
      !rdp_write_bitmap_capability_set(log, s, settings) ||
4852
0
      !rdp_write_order_capability_set(log, s, settings))
4853
0
    return FALSE;
4854
4855
0
  if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
4856
0
    ret = rdp_write_bitmap_cache_v2_capability_set(log, s, settings);
4857
0
  else
4858
0
    ret = rdp_write_bitmap_cache_capability_set(log, s, settings);
4859
4860
0
  if (!ret)
4861
0
    return FALSE;
4862
4863
0
  if (!rdp_write_pointer_capability_set(log, s, settings) ||
4864
0
      !rdp_write_input_capability_set(log, s, settings) ||
4865
0
      !rdp_write_brush_capability_set(log, s, settings) ||
4866
0
      !rdp_write_glyph_cache_capability_set(log, s, settings) ||
4867
0
      !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4868
0
      !rdp_write_sound_capability_set(log, s, settings) ||
4869
0
      !rdp_write_share_capability_set(log, s, settings) ||
4870
0
      !rdp_write_font_capability_set(log, s, settings) ||
4871
0
      !rdp_write_control_capability_set(log, s, settings) ||
4872
0
      !rdp_write_color_cache_capability_set(log, s, settings) ||
4873
0
      !rdp_write_window_activation_capability_set(log, s, settings))
4874
0
  {
4875
0
    return FALSE;
4876
0
  }
4877
4878
0
  {
4879
0
    numberCapabilities++;
4880
4881
0
    if (!rdp_write_offscreen_bitmap_cache_capability_set(log, s, settings))
4882
0
      return FALSE;
4883
0
  }
4884
4885
0
  if (settings->DrawNineGridEnabled)
4886
0
  {
4887
0
    numberCapabilities++;
4888
4889
0
    if (!rdp_write_draw_nine_grid_cache_capability_set(log, s, settings))
4890
0
      return FALSE;
4891
0
  }
4892
4893
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4894
0
  {
4895
0
    if (settings->LargePointerFlag)
4896
0
    {
4897
0
      numberCapabilities++;
4898
4899
0
      if (!rdp_write_large_pointer_capability_set(log, s, settings))
4900
0
        return FALSE;
4901
0
    }
4902
0
  }
4903
4904
0
  if (settings->RemoteApplicationMode)
4905
0
  {
4906
0
    numberCapabilities += 2;
4907
4908
0
    if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4909
0
        !rdp_write_window_list_capability_set(log, s, settings))
4910
0
      return FALSE;
4911
0
  }
4912
4913
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4914
0
  {
4915
0
    numberCapabilities++;
4916
4917
0
    if (!rdp_write_multifragment_update_capability_set(log, s, settings))
4918
0
      return FALSE;
4919
0
  }
4920
4921
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4922
0
  {
4923
0
    numberCapabilities++;
4924
4925
0
    if (!rdp_write_surface_commands_capability_set(log, s, settings))
4926
0
      return FALSE;
4927
0
  }
4928
4929
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4930
0
  {
4931
0
    numberCapabilities++;
4932
4933
0
    if (!rdp_write_bitmap_codecs_capability_set(log, s, settings))
4934
0
      return FALSE;
4935
0
  }
4936
4937
0
  if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4938
0
    settings->FrameAcknowledge = 0;
4939
4940
0
  if (settings->FrameAcknowledge)
4941
0
  {
4942
0
    numberCapabilities++;
4943
4944
0
    if (!rdp_write_frame_acknowledge_capability_set(log, s, settings))
4945
0
      return FALSE;
4946
0
  }
4947
4948
0
  if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4949
0
  {
4950
0
    if (settings->BitmapCacheV3CodecId != 0)
4951
0
    {
4952
0
      numberCapabilities++;
4953
4954
0
      if (!rdp_write_bitmap_cache_v3_codec_id_capability_set(log, s, settings))
4955
0
        return FALSE;
4956
0
    }
4957
0
  }
4958
4959
0
  em = Stream_GetPosition(s);
4960
0
  if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4961
0
    return FALSE;
4962
0
  lengthCombinedCapabilities = (em - bm);
4963
0
  if (lengthCombinedCapabilities > UINT16_MAX)
4964
0
    return FALSE;
4965
0
  Stream_Write_UINT16(
4966
0
      s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4967
0
  if (!Stream_SetPosition(s, bm))             /* go back to numberCapabilities */
4968
0
    return FALSE;
4969
0
  Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4970
#ifdef WITH_DEBUG_CAPABILITIES
4971
  rdp_print_capability_sets(log, s, bm, FALSE);
4972
#endif
4973
0
  return Stream_SetPosition(s, em);
4974
0
}
4975
4976
BOOL rdp_send_confirm_active(rdpRdp* rdp)
4977
0
{
4978
0
  UINT16 sec_flags = 0;
4979
0
  wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4980
0
  BOOL status = 0;
4981
4982
0
  if (!s)
4983
0
    return FALSE;
4984
4985
0
  status = rdp_write_confirm_active(rdp->log, s, rdp->settings) &&
4986
0
           rdp_send_pdu(rdp, s, PDU_TYPE_CONFIRM_ACTIVE, rdp->mcs->userId, sec_flags);
4987
0
  Stream_Release(s);
4988
0
  return status;
4989
0
}
4990
4991
const char* rdp_input_flag_string(UINT16 flags, char* buffer, size_t len)
4992
0
{
4993
0
  char prefix[16] = WINPR_C_ARRAY_INIT;
4994
4995
0
  (void)_snprintf(prefix, sizeof(prefix), "[0x%04" PRIx16 "][", flags);
4996
0
  winpr_str_append(prefix, buffer, len, "");
4997
0
  if ((flags & INPUT_FLAG_SCANCODES) != 0)
4998
0
    winpr_str_append("INPUT_FLAG_SCANCODES", buffer, len, "|");
4999
0
  if ((flags & INPUT_FLAG_MOUSEX) != 0)
5000
0
    winpr_str_append("INPUT_FLAG_MOUSEX", buffer, len, "|");
5001
0
  if ((flags & INPUT_FLAG_FASTPATH_INPUT) != 0)
5002
0
    winpr_str_append("INPUT_FLAG_FASTPATH_INPUT", buffer, len, "|");
5003
0
  if ((flags & INPUT_FLAG_UNICODE) != 0)
5004
0
    winpr_str_append("INPUT_FLAG_UNICODE", buffer, len, "|");
5005
0
  if ((flags & INPUT_FLAG_FASTPATH_INPUT2) != 0)
5006
0
    winpr_str_append("INPUT_FLAG_FASTPATH_INPUT2", buffer, len, "|");
5007
0
  if ((flags & INPUT_FLAG_UNUSED1) != 0)
5008
0
    winpr_str_append("INPUT_FLAG_UNUSED1", buffer, len, "|");
5009
0
  if ((flags & INPUT_FLAG_MOUSE_RELATIVE) != 0)
5010
0
    winpr_str_append("INPUT_FLAG_MOUSE_RELATIVE", buffer, len, "|");
5011
0
  if ((flags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0)
5012
0
    winpr_str_append("TS_INPUT_FLAG_MOUSE_HWHEEL", buffer, len, "|");
5013
0
  if ((flags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0)
5014
0
    winpr_str_append("TS_INPUT_FLAG_QOE_TIMESTAMPS", buffer, len, "|");
5015
0
  winpr_str_append("]", buffer, len, "");
5016
0
  return buffer;
5017
0
}