FreeRDP
Loading...
Searching...
No Matches
capabilities.c
1
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
34static 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
66static const char* get_capability_name(UINT16 type)
67{
68 if (type > CAPSET_TYPE_FRAME_ACKNOWLEDGE)
69 return "<unknown>";
70
71 return CAPSET_TYPE_STRINGS[type];
72}
73
74#ifdef WITH_DEBUG_CAPABILITIES
75static BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving);
76#endif
77
78/* CODEC_GUID_REMOTEFX: 0x76772F12BD724463AFB3B73C9C6F7886 */
79
80static 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
86static 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
92static 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
98static 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
105static const GUID CODEC_GUID_JPEG = {
106 0x430C9EED, 0x1BAF, 0x4CE6, { 0x86, 0x9A, 0xCB, 0x8B, 0x37, 0xB6, 0x62, 0x37 }
107};
108#endif
109
110static BOOL rdp_read_capability_set_header(wLog* log, wStream* s, UINT16* length, UINT16* type)
111{
112 WINPR_ASSERT(s);
113 WINPR_ASSERT(length);
114 WINPR_ASSERT(type);
115
116 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
117 return FALSE;
118 Stream_Read_UINT16(s, *type); /* capabilitySetType */
119 Stream_Read_UINT16(s, *length); /* lengthCapability */
120 return (*length >= 4);
121}
122
123static void rdp_write_capability_set_header(wStream* s, UINT16 length, UINT16 type)
124{
125 WINPR_ASSERT(s);
126 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 4);
127 Stream_Write_UINT16(s, type); /* capabilitySetType */
128 Stream_Write_UINT16(s, length); /* lengthCapability */
129}
130
131static size_t rdp_capability_set_start(wLog* log, wStream* s)
132{
133 size_t header = Stream_GetPosition(s);
134 if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), CAPSET_HEADER_LENGTH))
135 return SIZE_MAX;
136 Stream_Zero(s, CAPSET_HEADER_LENGTH);
137 return header;
138}
139
140static BOOL rdp_capability_set_finish(wStream* s, size_t header, UINT16 type)
141{
142 const size_t footer = Stream_GetPosition(s);
143 if (header > footer)
144 return FALSE;
145 if (header > UINT16_MAX)
146 return FALSE;
147 const size_t length = footer - header;
148 if ((Stream_Capacity(s) < header + 4ULL) || (length > UINT16_MAX))
149 return FALSE;
150 if (!Stream_SetPosition(s, header))
151 return FALSE;
152 rdp_write_capability_set_header(s, (UINT16)length, type);
153 return Stream_SetPosition(s, footer);
154}
155
156static BOOL rdp_apply_general_capability_set(rdpSettings* settings, const rdpSettings* src)
157{
158 WINPR_ASSERT(settings);
159 WINPR_ASSERT(src);
160
161 if (settings->ServerMode)
162 {
163 settings->OsMajorType = src->OsMajorType;
164 settings->OsMinorType = src->OsMinorType;
165 }
166
167 settings->CapsProtocolVersion = src->CapsProtocolVersion;
168 settings->NoBitmapCompressionHeader = src->NoBitmapCompressionHeader;
169 settings->LongCredentialsSupported = src->LongCredentialsSupported;
170 settings->AutoReconnectionPacketSupported = src->AutoReconnectionPacketSupported;
171 if (!src->FastPathOutput)
172 settings->FastPathOutput = FALSE;
173
174 if (!src->SaltedChecksum)
175 settings->SaltedChecksum = FALSE;
176
177 if (!settings->ServerMode)
178 {
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 if (!src->RefreshRect)
185 settings->RefreshRect = FALSE;
186
187 if (!src->SuppressOutput)
188 settings->SuppressOutput = FALSE;
189 }
190 return TRUE;
191}
192
193/*
194 * Read general capability set.
195 * msdn{cc240549}
196 */
197
198static BOOL rdp_read_general_capability_set(wLog* log, wStream* s, rdpSettings* settings)
199{
200 UINT16 extraFlags = 0;
201 BYTE refreshRectSupport = 0;
202 BYTE suppressOutputSupport = 0;
203
204 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
205 return FALSE;
206
207 WINPR_ASSERT(settings);
208 Stream_Read_UINT16(s, settings->OsMajorType); /* osMajorType (2 bytes) */
209 Stream_Read_UINT16(s, settings->OsMinorType); /* osMinorType (2 bytes) */
210
211 Stream_Read_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
212 if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
213 {
214 WLog_Print(log, WLOG_ERROR,
215 "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
216 ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
217 settings->CapsProtocolVersion,
218 WINPR_CXX_COMPAT_CAST(UINT32, TS_CAPS_PROTOCOLVERSION));
219 if (settings->CapsProtocolVersion == 0x0000)
220 {
221 WLog_Print(log, WLOG_WARN,
222 "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
223 " assuming old FreeRDP, ignoring protocol violation, correcting value.",
224 settings->CapsProtocolVersion);
225 settings->CapsProtocolVersion = TS_CAPS_PROTOCOLVERSION;
226 }
227 else
228 return FALSE;
229 }
230 Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */
231 Stream_Read_UINT16(
232 s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
233 Stream_Read_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
234 Stream_Read_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
235 Stream_Read_UINT16(s, settings->CapsRemoteUnshareFlag); /* remoteUnshareFlag (2 bytes) */
236 Stream_Read_UINT16(
237 s, settings->CapsGeneralCompressionLevel); /* generalCompressionLevel (2 bytes) */
238 Stream_Read_UINT8(s, refreshRectSupport); /* refreshRectSupport (1 byte) */
239 Stream_Read_UINT8(s, suppressOutputSupport); /* suppressOutputSupport (1 byte) */
240 settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) != 0;
241 settings->LongCredentialsSupported = (extraFlags & LONG_CREDENTIALS_SUPPORTED) != 0;
242
243 settings->AutoReconnectionPacketSupported = (extraFlags & AUTORECONNECT_SUPPORTED) != 0;
244 settings->FastPathOutput = (extraFlags & FASTPATH_OUTPUT_SUPPORTED) != 0;
245 settings->SaltedChecksum = (extraFlags & ENC_SALTED_CHECKSUM) != 0;
246 settings->RefreshRect = refreshRectSupport;
247 settings->SuppressOutput = suppressOutputSupport;
248
249 return TRUE;
250}
251
252/*
253 * Write general capability set.
254 * msdn{cc240549}
255 */
256
257static BOOL rdp_write_general_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
258{
259 if (!Stream_EnsureRemainingCapacity(s, 64))
260 return FALSE;
261
262 const size_t header = rdp_capability_set_start(log, s);
263 UINT16 extraFlags = 0;
264
265 WINPR_ASSERT(settings);
266 if (settings->LongCredentialsSupported)
267 extraFlags |= LONG_CREDENTIALS_SUPPORTED;
268
269 if (settings->NoBitmapCompressionHeader)
270 extraFlags |= NO_BITMAP_COMPRESSION_HDR;
271
272 if (settings->AutoReconnectionPacketSupported)
273 extraFlags |= AUTORECONNECT_SUPPORTED;
274
275 if (settings->FastPathOutput)
276 extraFlags |= FASTPATH_OUTPUT_SUPPORTED;
277
278 if (settings->SaltedChecksum)
279 extraFlags |= ENC_SALTED_CHECKSUM;
280
281 if ((settings->OsMajorType > UINT16_MAX) || (settings->OsMinorType > UINT16_MAX))
282 {
283 WLog_Print(log, WLOG_ERROR,
284 "OsMajorType=%08" PRIx32 ", OsMinorType=%08" PRIx32
285 " they need to be smaller %04" PRIx32,
286 settings->OsMajorType, settings->OsMinorType,
287 WINPR_CXX_COMPAT_CAST(UINT32, UINT16_MAX));
288 return FALSE;
289 }
290 if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
291 {
292 WLog_Print(log, WLOG_ERROR,
293 "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
294 ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
295 settings->CapsProtocolVersion,
296 WINPR_CXX_COMPAT_CAST(UINT32, TS_CAPS_PROTOCOLVERSION));
297 return FALSE;
298 }
299 Stream_Write_UINT16(s, (UINT16)settings->OsMajorType); /* osMajorType (2 bytes) */
300 Stream_Write_UINT16(s, (UINT16)settings->OsMinorType); /* osMinorType (2 bytes) */
301 Stream_Write_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
302 Stream_Write_UINT16(s, 0); /* pad2OctetsA (2 bytes) */
303 Stream_Write_UINT16(
304 s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
305 Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
306 Stream_Write_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
307 Stream_Write_UINT16(s, settings->CapsRemoteUnshareFlag); /* remoteUnshareFlag (2 bytes) */
308 Stream_Write_UINT16(
309 s, settings->CapsGeneralCompressionLevel); /* generalCompressionLevel (2 bytes) */
310 Stream_Write_UINT8(s, settings->RefreshRect ? 1 : 0); /* refreshRectSupport (1 byte) */
311 Stream_Write_UINT8(s, settings->SuppressOutput ? 1 : 0); /* suppressOutputSupport (1 byte) */
312 return rdp_capability_set_finish(s, header, CAPSET_TYPE_GENERAL);
313}
314
315#ifdef WITH_DEBUG_CAPABILITIES
316static 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
352static BOOL rdp_apply_bitmap_capability_set(rdpSettings* settings, const rdpSettings* src)
353{
354 WINPR_ASSERT(settings);
355 WINPR_ASSERT(src);
356
357 if (!settings->ServerMode)
358 {
359 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
360 freerdp_settings_get_uint32(src, FreeRDP_ColorDepth)))
361 return FALSE;
362 }
363
364 if (!src->DesktopResize)
365 settings->DesktopResize = FALSE;
366
367 if (!settings->ServerMode && settings->DesktopResize)
368 {
369 /* The server may request a different desktop size during Deactivation-Reactivation sequence
370 */
371 settings->DesktopWidth = src->DesktopWidth;
372 settings->DesktopHeight = src->DesktopHeight;
373 }
374
375 if (settings->DrawAllowSkipAlpha)
376 settings->DrawAllowSkipAlpha = src->DrawAllowSkipAlpha;
377
378 if (settings->DrawAllowDynamicColorFidelity)
379 settings->DrawAllowDynamicColorFidelity = src->DrawAllowDynamicColorFidelity;
380
381 if (settings->DrawAllowColorSubsampling)
382 settings->DrawAllowColorSubsampling = src->DrawAllowColorSubsampling;
383
384 return TRUE;
385}
386
387/*
388 * Read bitmap capability set.
389 * msdn{cc240554}
390 */
391
392static BOOL rdp_read_bitmap_capability_set(wLog* log, wStream* s, rdpSettings* settings)
393{
394 BYTE drawingFlags = 0;
395 UINT16 desktopWidth = 0;
396 UINT16 desktopHeight = 0;
397 UINT16 desktopResizeFlag = 0;
398 UINT16 preferredBitsPerPixel = 0;
399
400 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 24))
401 return FALSE;
402
403 Stream_Read_UINT16(s, preferredBitsPerPixel); /* preferredBitsPerPixel (2 bytes) */
404 Stream_Seek_UINT16(s); /* receive1BitPerPixel (2 bytes) */
405 Stream_Seek_UINT16(s); /* receive4BitsPerPixel (2 bytes) */
406 Stream_Seek_UINT16(s); /* receive8BitsPerPixel (2 bytes) */
407 Stream_Read_UINT16(s, desktopWidth); /* desktopWidth (2 bytes) */
408 Stream_Read_UINT16(s, desktopHeight); /* desktopHeight (2 bytes) */
409 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
410 Stream_Read_UINT16(s, desktopResizeFlag); /* desktopResizeFlag (2 bytes) */
411 Stream_Seek_UINT16(s); /* bitmapCompressionFlag (2 bytes) */
412 Stream_Seek_UINT8(s); /* highColorFlags (1 byte) */
413 Stream_Read_UINT8(s, drawingFlags); /* drawingFlags (1 byte) */
414 Stream_Seek_UINT16(s); /* multipleRectangleSupport (2 bytes) */
415 Stream_Seek_UINT16(s); /* pad2OctetsB (2 bytes) */
416
417 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, preferredBitsPerPixel))
418 return FALSE;
419 settings->DesktopResize = desktopResizeFlag;
420 settings->DesktopWidth = desktopWidth;
421 settings->DesktopHeight = desktopHeight;
422 settings->DrawAllowSkipAlpha = (drawingFlags & DRAW_ALLOW_SKIP_ALPHA) != 0;
423 settings->DrawAllowDynamicColorFidelity =
424 (drawingFlags & DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY) != 0;
425 settings->DrawAllowColorSubsampling = (drawingFlags & DRAW_ALLOW_COLOR_SUBSAMPLING) != 0;
426
427 return TRUE;
428}
429
430/*
431 * Write bitmap capability set.
432 * msdn{cc240554}
433 */
434
435static BOOL rdp_write_bitmap_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
436{
437 BYTE drawingFlags = 0;
438 UINT16 preferredBitsPerPixel = 0;
439
440 if (!Stream_EnsureRemainingCapacity(s, 64))
441 return FALSE;
442
443 const size_t header = rdp_capability_set_start(log, s);
444
445 WINPR_ASSERT(settings);
446 if (settings->DrawAllowSkipAlpha)
447 drawingFlags |= DRAW_ALLOW_SKIP_ALPHA;
448
449 if (settings->DrawAllowDynamicColorFidelity)
450 drawingFlags |= DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY;
451
452 if (settings->DrawAllowColorSubsampling)
453 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 if ((freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) > UINT16_MAX) ||
465 (settings->DesktopWidth > UINT16_MAX) || (settings->DesktopHeight > UINT16_MAX))
466 return FALSE;
467
468 if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
469 preferredBitsPerPixel = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
470 else
471 preferredBitsPerPixel = 8;
472
473 Stream_Write_UINT16(s, preferredBitsPerPixel); /* preferredBitsPerPixel (2 bytes) */
474 Stream_Write_UINT16(s, 1); /* receive1BitPerPixel (2 bytes) */
475 Stream_Write_UINT16(s, 1); /* receive4BitsPerPixel (2 bytes) */
476 Stream_Write_UINT16(s, 1); /* receive8BitsPerPixel (2 bytes) */
477 Stream_Write_UINT16(s, (UINT16)settings->DesktopWidth); /* desktopWidth (2 bytes) */
478 Stream_Write_UINT16(s, (UINT16)settings->DesktopHeight); /* desktopHeight (2 bytes) */
479 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
480 Stream_Write_UINT16(s, (UINT16)settings->DesktopResize); /* desktopResizeFlag (2 bytes) */
481 Stream_Write_UINT16(s, 1); /* bitmapCompressionFlag (2 bytes) */
482 Stream_Write_UINT8(s, 0); /* highColorFlags (1 byte) */
483 Stream_Write_UINT8(s, drawingFlags); /* drawingFlags (1 byte) */
484 Stream_Write_UINT16(s, 1); /* multipleRectangleSupport (2 bytes) */
485 Stream_Write_UINT16(s, 0); /* pad2OctetsB (2 bytes) */
486 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP);
487}
488
489#ifdef WITH_DEBUG_CAPABILITIES
490static 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
541static BOOL rdp_apply_order_capability_set(rdpSettings* settings, const rdpSettings* src)
542{
543 WINPR_ASSERT(settings);
544 WINPR_ASSERT(src);
545
546 BOOL BitmapCacheV3Enabled = FALSE;
547 BOOL FrameMarkerCommandEnabled = FALSE;
548
549 for (size_t i = 0; i < 32; i++)
550 {
551 if (!src->OrderSupport[i])
552 settings->OrderSupport[i] = FALSE;
553 }
554
555 if (src->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
556 {
557 if (src->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT)
558 BitmapCacheV3Enabled = TRUE;
559
560 if (src->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT)
561 FrameMarkerCommandEnabled = TRUE;
562 }
563
564 if (BitmapCacheV3Enabled && settings->BitmapCacheV3Enabled)
565 {
566 settings->BitmapCacheV3Enabled = src->BitmapCacheV3Enabled;
567 settings->BitmapCacheVersion = src->BitmapCacheVersion;
568 }
569 else
570 settings->BitmapCacheV3Enabled = FALSE;
571
572 settings->FrameMarkerCommandEnabled =
573 (FrameMarkerCommandEnabled && src->FrameMarkerCommandEnabled);
574
575 return TRUE;
576}
577
578/*
579 * Read order capability set.
580 * msdn{cc240556}
581 */
582
583static BOOL rdp_read_order_capability_set(wLog* log, wStream* s, rdpSettings* settings)
584{
585 char terminalDescriptor[17] = WINPR_C_ARRAY_INIT;
586 BYTE orderSupport[32] = WINPR_C_ARRAY_INIT;
587 BOOL BitmapCacheV3Enabled = FALSE;
588 BOOL FrameMarkerCommandEnabled = FALSE;
589
590 WINPR_ASSERT(settings);
591 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
592 return FALSE;
593
594 Stream_Read(s, terminalDescriptor, 16); /* terminalDescriptor (16 bytes) */
595 Stream_Seek_UINT32(s); /* pad4OctetsA (4 bytes) */
596 Stream_Seek_UINT16(s); /* desktopSaveXGranularity (2 bytes) */
597 Stream_Seek_UINT16(s); /* desktopSaveYGranularity (2 bytes) */
598 Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */
599 Stream_Seek_UINT16(s); /* maximumOrderLevel (2 bytes) */
600 Stream_Seek_UINT16(s); /* numberFonts (2 bytes) */
601 Stream_Read_UINT16(s, settings->OrderSupportFlags); /* orderFlags (2 bytes) */
602 Stream_Read(s, orderSupport, 32); /* orderSupport (32 bytes) */
603 Stream_Seek_UINT16(s); /* textFlags (2 bytes) */
604 Stream_Read_UINT16(s, settings->OrderSupportFlagsEx); /* orderSupportExFlags (2 bytes) */
605 Stream_Seek_UINT32(s); /* pad4OctetsB (4 bytes) */
606 Stream_Seek_UINT32(s); /* desktopSaveSize (4 bytes) */
607 Stream_Seek_UINT16(s); /* pad2OctetsC (2 bytes) */
608 Stream_Seek_UINT16(s); /* pad2OctetsD (2 bytes) */
609 Stream_Read_UINT16(s, settings->TextANSICodePage); /* textANSICodePage (2 bytes) */
610 Stream_Seek_UINT16(s); /* pad2OctetsE (2 bytes) */
611
612 if (!freerdp_settings_set_string(settings, FreeRDP_TerminalDescriptor, terminalDescriptor))
613 return FALSE;
614
615 for (size_t i = 0; i < ARRAYSIZE(orderSupport); i++)
616 settings->OrderSupport[i] = orderSupport[i];
617
618 if (settings->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
619 {
620 BitmapCacheV3Enabled = (settings->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT) != 0;
621 FrameMarkerCommandEnabled =
622 (settings->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT) != 0;
623 }
624
625 settings->BitmapCacheV3Enabled = BitmapCacheV3Enabled;
626 if (BitmapCacheV3Enabled)
627 settings->BitmapCacheVersion = 3;
628
629 settings->FrameMarkerCommandEnabled = FrameMarkerCommandEnabled;
630
631 return TRUE;
632}
633
634/*
635 * Write order capability set.
636 * msdn{cc240556}
637 */
638
639static BOOL rdp_write_order_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
640{
641 char terminalDescriptor[16] = WINPR_C_ARRAY_INIT;
642
643 WINPR_ASSERT(settings);
644 if (!Stream_EnsureRemainingCapacity(s, 64))
645 return FALSE;
646
647 const size_t header = rdp_capability_set_start(log, s);
648
649 UINT16 orderSupportExFlags = settings->OrderSupportFlagsEx;
650 UINT16 orderFlags = settings->OrderSupportFlags;
651
652 if (settings->BitmapCacheV3Enabled)
653 {
654 if ((orderSupportExFlags & CACHE_BITMAP_V3_SUPPORT) == 0)
655 {
656 WLog_Print(log, WLOG_WARN,
657 "rdpSettings::BitmapCacheV3Enabled=TRUE, but CACHE_BITMAP_V3_SUPPORT not "
658 "set in rdpSettings::OrderSupportEx, aborting.");
659 }
660 if ((orderFlags & ORDER_FLAGS_EXTRA_SUPPORT) == 0)
661 {
662 WLog_Print(log, WLOG_WARN,
663 "rdpSettings::BitmapCacheV3Enabled=TRUE, but ORDER_FLAGS_EXTRA_SUPPORT not "
664 "set in rdpSettings::OrderSupport, aborting.");
665 }
666 }
667
668 if (settings->FrameMarkerCommandEnabled)
669 {
670 if ((orderSupportExFlags & ALTSEC_FRAME_MARKER_SUPPORT) == 0)
671 {
672 WLog_Print(
673 log, WLOG_WARN,
674 "rdpSettings::FrameMarkerCommandEnabled=TRUE, but "
675 "ALTSEC_FRAME_MARKER_SUPPORT not set in rdpSettings::OrderSupportEx, aborting.");
676 }
677 if ((orderFlags & ORDER_FLAGS_EXTRA_SUPPORT) == 0)
678 {
679 WLog_Print(log, WLOG_WARN,
680 "rdpSettings::FrameMarkerCommandEnabled=TRUE, but ORDER_FLAGS_EXTRA_SUPPORT "
681 "not set in rdpSettings::OrderSupport, aborting.");
682 }
683 }
684
685 const char* dsc = freerdp_settings_get_string(settings, FreeRDP_TerminalDescriptor);
686 if (dsc)
687 {
688 const size_t len = strnlen(dsc, ARRAYSIZE(terminalDescriptor));
689 strncpy(terminalDescriptor, dsc, len);
690 }
691 Stream_Write(s, terminalDescriptor,
692 sizeof(terminalDescriptor)); /* terminalDescriptor (16 bytes) */
693 Stream_Write_UINT32(s, 0); /* pad4OctetsA (4 bytes) */
694 Stream_Write_UINT16(s, 1); /* desktopSaveXGranularity (2 bytes) */
695 Stream_Write_UINT16(s, 20); /* desktopSaveYGranularity (2 bytes) */
696 Stream_Write_UINT16(s, 0); /* pad2OctetsA (2 bytes) */
697 Stream_Write_UINT16(s, 1); /* maximumOrderLevel (2 bytes) */
698 Stream_Write_UINT16(s, 0); /* numberFonts (2 bytes) */
699 Stream_Write_UINT16(s, orderFlags); /* orderFlags (2 bytes) */
700 Stream_Write(s, settings->OrderSupport, 32); /* orderSupport (32 bytes) */
701 Stream_Write_UINT16(s, 0); /* textFlags (2 bytes) */
702 Stream_Write_UINT16(s, orderSupportExFlags); /* orderSupportExFlags (2 bytes) */
703 Stream_Write_UINT32(s, 0); /* pad4OctetsB (4 bytes) */
704 Stream_Write_UINT32(s, 230400); /* desktopSaveSize (4 bytes) */
705 Stream_Write_UINT16(s, 0); /* pad2OctetsC (2 bytes) */
706 Stream_Write_UINT16(s, 0); /* pad2OctetsD (2 bytes) */
707 Stream_Write_UINT16(s, settings->TextANSICodePage); /* textANSICodePage (2 bytes) */
708 Stream_Write_UINT16(s, 0); /* pad2OctetsE (2 bytes) */
709 return rdp_capability_set_finish(s, header, CAPSET_TYPE_ORDER);
710}
711
712#ifdef WITH_DEBUG_CAPABILITIES
713static 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
815static BOOL rdp_apply_bitmap_cache_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
816 WINPR_ATTR_UNUSED const rdpSettings* src)
817{
818 WINPR_ASSERT(settings);
819 WINPR_ASSERT(src);
820 return TRUE;
821}
822
823/*
824 * Read bitmap cache capability set.
825 * msdn{cc240559}
826 */
827
828static BOOL rdp_read_bitmap_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
829{
830 WINPR_UNUSED(settings);
831 WINPR_ASSERT(settings);
832
833 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
834 return FALSE;
835
836 Stream_Seek_UINT32(s); /* pad1 (4 bytes) */
837 Stream_Seek_UINT32(s); /* pad2 (4 bytes) */
838 Stream_Seek_UINT32(s); /* pad3 (4 bytes) */
839 Stream_Seek_UINT32(s); /* pad4 (4 bytes) */
840 Stream_Seek_UINT32(s); /* pad5 (4 bytes) */
841 Stream_Seek_UINT32(s); /* pad6 (4 bytes) */
842 Stream_Seek_UINT16(s); /* Cache0Entries (2 bytes) */
843 Stream_Seek_UINT16(s); /* Cache0MaximumCellSize (2 bytes) */
844 Stream_Seek_UINT16(s); /* Cache1Entries (2 bytes) */
845 Stream_Seek_UINT16(s); /* Cache1MaximumCellSize (2 bytes) */
846 Stream_Seek_UINT16(s); /* Cache2Entries (2 bytes) */
847 Stream_Seek_UINT16(s); /* Cache2MaximumCellSize (2 bytes) */
848 return TRUE;
849}
850
851/*
852 * Write bitmap cache capability set.
853 * msdn{cc240559}
854 */
855
856static BOOL rdp_write_bitmap_cache_capability_set(wLog* log, wStream* s,
857 const rdpSettings* settings)
858{
859 if (!Stream_EnsureRemainingCapacity(s, 64))
860 return FALSE;
861
862 const size_t header = rdp_capability_set_start(log, s);
863 const UINT32 bpp = (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) + 7) / 8;
864 if (bpp > UINT16_MAX)
865 return FALSE;
866 Stream_Write_UINT32(s, 0); /* pad1 (4 bytes) */
867 Stream_Write_UINT32(s, 0); /* pad2 (4 bytes) */
868 Stream_Write_UINT32(s, 0); /* pad3 (4 bytes) */
869 Stream_Write_UINT32(s, 0); /* pad4 (4 bytes) */
870 Stream_Write_UINT32(s, 0); /* pad5 (4 bytes) */
871 Stream_Write_UINT32(s, 0); /* pad6 (4 bytes) */
872 UINT32 size = bpp * 256;
873 if (size > UINT16_MAX)
874 return FALSE;
875 Stream_Write_UINT16(s, 200); /* Cache0Entries (2 bytes) */
876 Stream_Write_UINT16(s, (UINT16)size); /* Cache0MaximumCellSize (2 bytes) */
877 size = bpp * 1024;
878 if (size > UINT16_MAX)
879 return FALSE;
880 Stream_Write_UINT16(s, 600); /* Cache1Entries (2 bytes) */
881 Stream_Write_UINT16(s, (UINT16)size); /* Cache1MaximumCellSize (2 bytes) */
882 size = bpp * 4096;
883 if (size > UINT16_MAX)
884 return FALSE;
885 Stream_Write_UINT16(s, 1000); /* Cache2Entries (2 bytes) */
886 Stream_Write_UINT16(s, (UINT16)size); /* Cache2MaximumCellSize (2 bytes) */
887 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE);
888}
889
890#ifdef WITH_DEBUG_CAPABILITIES
891static 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
939static BOOL rdp_apply_control_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
940 WINPR_ATTR_UNUSED const rdpSettings* src)
941{
942 WINPR_ASSERT(settings);
943 WINPR_ASSERT(src);
944
945 return TRUE;
946}
947
948/*
949 * Read control capability set.
950 * msdn{cc240568}
951 */
952
953static BOOL rdp_read_control_capability_set(wLog* log, wStream* s, rdpSettings* settings)
954{
955 WINPR_UNUSED(settings);
956 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
957 return FALSE;
958
959 Stream_Seek_UINT16(s); /* controlFlags (2 bytes) */
960 Stream_Seek_UINT16(s); /* remoteDetachFlag (2 bytes) */
961 Stream_Seek_UINT16(s); /* controlInterest (2 bytes) */
962 Stream_Seek_UINT16(s); /* detachInterest (2 bytes) */
963 return TRUE;
964}
965
966/*
967 * Write control capability set.
968 * msdn{cc240568}
969 */
970
971static BOOL rdp_write_control_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
972{
973 WINPR_UNUSED(settings);
974 if (!Stream_EnsureRemainingCapacity(s, 32))
975 return FALSE;
976
977 const size_t header = rdp_capability_set_start(log, s);
978 Stream_Write_UINT16(s, 0); /* controlFlags (2 bytes) */
979 Stream_Write_UINT16(s, 0); /* remoteDetachFlag (2 bytes) */
980 Stream_Write_UINT16(s, 2); /* controlInterest (2 bytes) */
981 Stream_Write_UINT16(s, 2); /* detachInterest (2 bytes) */
982 return rdp_capability_set_finish(s, header, CAPSET_TYPE_CONTROL);
983}
984
985#ifdef WITH_DEBUG_CAPABILITIES
986static 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
1010static BOOL rdp_apply_window_activation_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1011 WINPR_ATTR_UNUSED const rdpSettings* src)
1012{
1013 WINPR_ASSERT(settings);
1014 WINPR_ASSERT(src);
1015
1016 return TRUE;
1017}
1018
1019/*
1020 * Read window activation capability set.
1021 * msdn{cc240569}
1022 */
1023
1024static BOOL rdp_read_window_activation_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1025{
1026 WINPR_UNUSED(settings);
1027 WINPR_ASSERT(settings);
1028 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1029 return FALSE;
1030
1031 Stream_Seek_UINT16(s); /* helpKeyFlag (2 bytes) */
1032 Stream_Seek_UINT16(s); /* helpKeyIndexFlag (2 bytes) */
1033 Stream_Seek_UINT16(s); /* helpExtendedKeyFlag (2 bytes) */
1034 Stream_Seek_UINT16(s); /* windowManagerKeyFlag (2 bytes) */
1035 return TRUE;
1036}
1037
1038/*
1039 * Write window activation capability set.
1040 * msdn{cc240569}
1041 */
1042
1043static BOOL rdp_write_window_activation_capability_set(wLog* log, wStream* s,
1044 const rdpSettings* settings)
1045{
1046 WINPR_UNUSED(settings);
1047 WINPR_ASSERT(settings);
1048 if (!Stream_EnsureRemainingCapacity(s, 32))
1049 return FALSE;
1050
1051 const size_t header = rdp_capability_set_start(log, s);
1052 Stream_Write_UINT16(s, 0); /* helpKeyFlag (2 bytes) */
1053 Stream_Write_UINT16(s, 0); /* helpKeyIndexFlag (2 bytes) */
1054 Stream_Write_UINT16(s, 0); /* helpExtendedKeyFlag (2 bytes) */
1055 Stream_Write_UINT16(s, 0); /* windowManagerKeyFlag (2 bytes) */
1056 return rdp_capability_set_finish(s, header, CAPSET_TYPE_ACTIVATION);
1057}
1058
1059#ifdef WITH_DEBUG_CAPABILITIES
1060static 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
1084static BOOL rdp_apply_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
1085{
1086 WINPR_ASSERT(settings);
1087 WINPR_ASSERT(src);
1088
1089 const UINT32 pointerCacheSize = freerdp_settings_get_uint32(src, FreeRDP_PointerCacheSize);
1090 const UINT32 colorPointerCacheSize =
1091 freerdp_settings_get_uint32(src, FreeRDP_ColorPointerCacheSize);
1092 const UINT32 dstPointerCacheSize =
1093 freerdp_settings_get_uint32(settings, FreeRDP_PointerCacheSize);
1094 const UINT32 dstColorPointerCacheSize =
1095 freerdp_settings_get_uint32(settings, FreeRDP_ColorPointerCacheSize);
1096
1097 /* We want the minimum of our setting and the remote announced value. */
1098 const UINT32 actualPointerCacheSize = MIN(pointerCacheSize, dstPointerCacheSize);
1099 const UINT32 actualColorPointerCacheSize = MIN(colorPointerCacheSize, dstColorPointerCacheSize);
1100
1101 return !(
1102 !freerdp_settings_set_uint32(settings, FreeRDP_PointerCacheSize, actualPointerCacheSize) ||
1103 !freerdp_settings_set_uint32(settings, FreeRDP_ColorPointerCacheSize,
1104 actualColorPointerCacheSize));
1105}
1106
1107/*
1108 * Read pointer capability set.
1109 * msdn{cc240562}
1110 */
1111
1112static BOOL rdp_read_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1113{
1114 UINT16 colorPointerFlag = 0;
1115 UINT16 colorPointerCacheSize = 0;
1116 UINT16 pointerCacheSize = 0;
1117
1118 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1119 return FALSE;
1120
1121 Stream_Read_UINT16(s, colorPointerFlag); /* colorPointerFlag (2 bytes) */
1122 Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1123
1124 if (colorPointerFlag == 0)
1125 {
1126 WLog_Print(log, WLOG_WARN,
1127 "[MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set "
1128 "(TS_POINTER_CAPABILITYSET)::colorPointerFlag received is %" PRIu16
1129 ". Value is ignored and always assumed to be TRUE",
1130 colorPointerFlag);
1131 }
1132
1133 /* pointerCacheSize is optional */
1134 if (Stream_GetRemainingLength(s) >= 2)
1135 Stream_Read_UINT16(s, pointerCacheSize); /* pointerCacheSize (2 bytes) */
1136
1137 WINPR_ASSERT(settings);
1138 settings->PointerCacheSize = pointerCacheSize;
1139 settings->ColorPointerCacheSize = colorPointerCacheSize;
1140
1141 return TRUE;
1142}
1143
1144/*
1145 * Write pointer capability set.
1146 * msdn{cc240562}
1147 */
1148
1149static BOOL rdp_write_pointer_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1150{
1151 if (!Stream_EnsureRemainingCapacity(s, 32))
1152 return FALSE;
1153
1154 const size_t header = rdp_capability_set_start(log, s);
1155 if (settings->PointerCacheSize > UINT16_MAX)
1156 return FALSE;
1157 if (settings->ColorPointerCacheSize > UINT16_MAX)
1158 return FALSE;
1159
1160 WINPR_ASSERT(settings);
1161 const UINT32 colorPointerFlag =
1162 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 Stream_Write_UINT16(s, colorPointerFlag); /* colorPointerFlag (2 bytes) */
1165 Stream_Write_UINT16(
1166 s, (UINT16)settings->ColorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1167 Stream_Write_UINT16(s, (UINT16)settings->PointerCacheSize); /* pointerCacheSize (2 bytes) */
1168
1169 return rdp_capability_set_finish(s, header, CAPSET_TYPE_POINTER);
1170}
1171
1172#ifdef WITH_DEBUG_CAPABILITIES
1173static 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
1194static BOOL rdp_apply_share_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1195 WINPR_ATTR_UNUSED const rdpSettings* src)
1196{
1197 WINPR_ASSERT(settings);
1198 WINPR_ASSERT(src);
1199
1200 return TRUE;
1201}
1202
1203/*
1204 * Read share capability set.
1205 * msdn{cc240570}
1206 */
1207
1208static BOOL rdp_read_share_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1209{
1210 WINPR_UNUSED(settings);
1211 WINPR_ASSERT(settings);
1212
1213 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1214 return FALSE;
1215
1216 Stream_Seek_UINT16(s); /* nodeId (2 bytes) */
1217 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1218 return TRUE;
1219}
1220
1221/*
1222 * Write share capability set.
1223 * msdn{cc240570}
1224 */
1225
1226static BOOL rdp_write_share_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1227{
1228 if (!Stream_EnsureRemainingCapacity(s, 32))
1229 return FALSE;
1230
1231 const size_t header = rdp_capability_set_start(log, s);
1232
1233 WINPR_ASSERT(settings);
1234 const UINT16 nodeId = (settings->ServerMode) ? 0x03EA : 0;
1235 Stream_Write_UINT16(s, nodeId); /* nodeId (2 bytes) */
1236 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1237 return rdp_capability_set_finish(s, header, CAPSET_TYPE_SHARE);
1238}
1239
1240#ifdef WITH_DEBUG_CAPABILITIES
1241static 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
1259static BOOL rdp_apply_color_cache_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1260 WINPR_ATTR_UNUSED const rdpSettings* src)
1261{
1262 WINPR_ASSERT(settings);
1263 WINPR_ASSERT(src);
1264 return TRUE;
1265}
1266
1267/*
1268 * Read color cache capability set.
1269 * msdn{cc241564}
1270 */
1271
1272static BOOL rdp_read_color_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1273{
1274 WINPR_UNUSED(settings);
1275 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1276 return FALSE;
1277
1278 Stream_Seek_UINT16(s); /* colorTableCacheSize (2 bytes) */
1279 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1280 return TRUE;
1281}
1282
1283/*
1284 * Write color cache capability set.
1285 * msdn{cc241564}
1286 */
1287
1288static BOOL rdp_write_color_cache_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1289{
1290 WINPR_UNUSED(settings);
1291 if (!Stream_EnsureRemainingCapacity(s, 32))
1292 return FALSE;
1293
1294 const size_t header = rdp_capability_set_start(log, s);
1295 Stream_Write_UINT16(s, 6); /* colorTableCacheSize (2 bytes) */
1296 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1297 return rdp_capability_set_finish(s, header, CAPSET_TYPE_COLOR_CACHE);
1298}
1299
1300#ifdef WITH_DEBUG_CAPABILITIES
1301static 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
1319static BOOL rdp_apply_sound_capability_set(rdpSettings* settings, const rdpSettings* src)
1320{
1321 WINPR_ASSERT(settings);
1322 WINPR_ASSERT(src);
1323
1324 settings->SoundBeepsEnabled = src->SoundBeepsEnabled;
1325
1326 return TRUE;
1327}
1328
1329/*
1330 * Read sound capability set.
1331 * msdn{cc240552}
1332 */
1333
1334static BOOL rdp_read_sound_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1335{
1336 UINT16 soundFlags = 0;
1337
1338 WINPR_ASSERT(settings);
1339 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1340 return FALSE;
1341
1342 Stream_Read_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1343 Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */
1344 settings->SoundBeepsEnabled = (soundFlags & SOUND_BEEPS_FLAG) != 0;
1345 return TRUE;
1346}
1347
1348/*
1349 * Write sound capability set.
1350 * msdn{cc240552}
1351 */
1352
1353static BOOL rdp_write_sound_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1354{
1355 WINPR_ASSERT(settings);
1356 if (!Stream_EnsureRemainingCapacity(s, 32))
1357 return FALSE;
1358
1359 const size_t header = rdp_capability_set_start(log, s);
1360 const UINT16 soundFlags = (settings->SoundBeepsEnabled) ? SOUND_BEEPS_FLAG : 0;
1361 Stream_Write_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1362 Stream_Write_UINT16(s, 0); /* pad2OctetsA (2 bytes) */
1363 return rdp_capability_set_finish(s, header, CAPSET_TYPE_SOUND);
1364}
1365
1366#ifdef WITH_DEBUG_CAPABILITIES
1367static 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
1385static BOOL rdp_apply_input_capability_set(rdpSettings* settings, const rdpSettings* src)
1386{
1387 WINPR_ASSERT(settings);
1388 WINPR_ASSERT(src);
1389
1390 if (settings->ServerMode)
1391 {
1392 settings->KeyboardLayout = src->KeyboardLayout;
1393 settings->KeyboardType = src->KeyboardType;
1394 settings->KeyboardSubType = src->KeyboardSubType;
1395 settings->KeyboardFunctionKey = src->KeyboardFunctionKey;
1396 }
1397
1398 if (!freerdp_settings_set_string(settings, FreeRDP_ImeFileName, src->ImeFileName))
1399 return FALSE;
1400
1401 if (!settings->ServerMode)
1402 {
1403 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 if (settings->HasHorizontalWheel)
1410 settings->HasHorizontalWheel = src->HasHorizontalWheel;
1411 const BOOL UnicodeInput = freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput);
1412 if (UnicodeInput)
1413 {
1414 const BOOL srcVal = freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput);
1415 if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, srcVal))
1416 return FALSE;
1417 }
1418 if (settings->HasExtendedMouseEvent)
1419 settings->HasExtendedMouseEvent = src->HasExtendedMouseEvent;
1420 if (settings->HasRelativeMouseEvent)
1421 settings->HasRelativeMouseEvent = src->HasRelativeMouseEvent;
1422 if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1423 settings->HasQoeEvent = freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent);
1424 }
1425 return TRUE;
1426}
1427
1428/*
1429 * Read input capability set.
1430 * msdn{cc240563}
1431 */
1432
1433static BOOL rdp_read_input_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1434{
1435 UINT16 inputFlags = 0;
1436
1437 WINPR_ASSERT(settings);
1438 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1439 return FALSE;
1440
1441 Stream_Read_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1442 Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */
1443
1444 Stream_Read_UINT32(s, settings->KeyboardLayout); /* keyboardLayout (4 bytes) */
1445 Stream_Read_UINT32(s, settings->KeyboardType); /* keyboardType (4 bytes) */
1446 Stream_Read_UINT32(s, settings->KeyboardSubType); /* keyboardSubType (4 bytes) */
1447 Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1448
1449 {
1450 WCHAR wstr[32] = WINPR_C_ARRAY_INIT;
1451 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 if (!Stream_Read_UTF16_String(s, wstr, ARRAYSIZE(wstr)))
1458 return FALSE;
1459
1460 if (ConvertWCharNToUtf8(wstr, ARRAYSIZE(wstr), str, ARRAYSIZE(str)) < 0)
1461 memset(str, 0, sizeof(str));
1462
1463 if (!freerdp_settings_set_string_len(settings, FreeRDP_ImeFileName, str, ARRAYSIZE(str)))
1464 return FALSE;
1465 }
1466
1467 if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathInput,
1468 inputFlags &
1469 (INPUT_FLAG_FASTPATH_INPUT | INPUT_FLAG_FASTPATH_INPUT2)))
1470 return FALSE;
1471 if (!freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel,
1472 (inputFlags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0))
1473 return FALSE;
1474 if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput,
1475 (inputFlags & INPUT_FLAG_UNICODE) != 0))
1476 return FALSE;
1477 if (!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent,
1478 (inputFlags & INPUT_FLAG_MOUSE_RELATIVE) != 0))
1479 return FALSE;
1480 if (!freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent,
1481 (inputFlags & INPUT_FLAG_MOUSEX) != 0))
1482 return FALSE;
1483 if (!freerdp_settings_set_bool(settings, FreeRDP_HasQoeEvent,
1484 (inputFlags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0))
1485 return FALSE;
1486
1487 return TRUE;
1488}
1489
1490/*
1491 * Write input capability set.
1492 * msdn{cc240563}
1493 */
1494
1495static BOOL rdp_write_input_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1496{
1497 WINPR_ASSERT(settings);
1498 if (!Stream_EnsureRemainingCapacity(s, 128))
1499 return FALSE;
1500
1501 const size_t header = rdp_capability_set_start(log, s);
1502 UINT16 inputFlags = INPUT_FLAG_SCANCODES;
1503
1504 if (settings->FastPathInput)
1505 {
1506 inputFlags |= INPUT_FLAG_FASTPATH_INPUT;
1507 inputFlags |= INPUT_FLAG_FASTPATH_INPUT2;
1508 }
1509
1510 if (freerdp_settings_get_bool(settings, FreeRDP_HasRelativeMouseEvent))
1511 inputFlags |= INPUT_FLAG_MOUSE_RELATIVE;
1512
1513 if (freerdp_settings_get_bool(settings, FreeRDP_HasHorizontalWheel))
1514 inputFlags |= TS_INPUT_FLAG_MOUSE_HWHEEL;
1515
1516 if (freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput))
1517 inputFlags |= INPUT_FLAG_UNICODE;
1518
1519 if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1520 inputFlags |= TS_INPUT_FLAG_QOE_TIMESTAMPS;
1521
1522 if (settings->HasExtendedMouseEvent)
1523 inputFlags |= INPUT_FLAG_MOUSEX;
1524
1525 Stream_Write_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1526 Stream_Write_UINT16(s, 0); /* pad2OctetsA (2 bytes) */
1527 Stream_Write_UINT32(s, settings->KeyboardLayout); /* keyboardLayout (4 bytes) */
1528 Stream_Write_UINT32(s, settings->KeyboardType); /* keyboardType (4 bytes) */
1529 Stream_Write_UINT32(s, settings->KeyboardSubType); /* keyboardSubType (4 bytes) */
1530 Stream_Write_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1531 Stream_Zero(s, 64); /* imeFileName (64 bytes) */
1532 return rdp_capability_set_finish(s, header, CAPSET_TYPE_INPUT);
1533}
1534
1535#ifdef WITH_DEBUG_CAPABILITIES
1536static 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
1567static BOOL rdp_apply_font_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1568 WINPR_ATTR_UNUSED const rdpSettings* src)
1569{
1570 WINPR_ASSERT(settings);
1571 WINPR_ASSERT(src);
1572 return TRUE;
1573}
1574
1575/*
1576 * Read font capability set.
1577 * msdn{cc240571}
1578 */
1579
1580static BOOL rdp_read_font_capability_set(WINPR_ATTR_UNUSED wLog* log, wStream* s,
1581 rdpSettings* settings)
1582{
1583 WINPR_UNUSED(settings);
1584 if (Stream_GetRemainingLength(s) >= 2)
1585 Stream_Seek_UINT16(s); /* fontSupportFlags (2 bytes) */
1586
1587 if (Stream_GetRemainingLength(s) >= 2)
1588 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1589
1590 return TRUE;
1591}
1592
1593/*
1594 * Write font capability set.
1595 * msdn{cc240571}
1596 */
1597
1598static BOOL rdp_write_font_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1599{
1600 WINPR_UNUSED(settings);
1601 if (!Stream_EnsureRemainingCapacity(s, 32))
1602 return FALSE;
1603
1604 const size_t header = rdp_capability_set_start(log, s);
1605 Stream_Write_UINT16(s, FONTSUPPORT_FONTLIST); /* fontSupportFlags (2 bytes) */
1606 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1607 return rdp_capability_set_finish(s, header, CAPSET_TYPE_FONT);
1608}
1609
1610#ifdef WITH_DEBUG_CAPABILITIES
1611static 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
1630static BOOL rdp_apply_brush_capability_set(rdpSettings* settings, const rdpSettings* src)
1631{
1632 WINPR_ASSERT(settings);
1633 WINPR_ASSERT(src);
1634
1635 // TODO: Minimum of what?
1636 settings->BrushSupportLevel = src->BrushSupportLevel;
1637 return TRUE;
1638}
1639
1640/*
1641 * Read brush capability set.
1642 * msdn{cc240564}
1643 */
1644
1645static BOOL rdp_read_brush_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1646{
1647 WINPR_UNUSED(settings);
1648 WINPR_ASSERT(settings);
1649
1650 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1651 return FALSE;
1652 Stream_Read_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1653 return TRUE;
1654}
1655
1656/*
1657 * Write brush capability set.
1658 * msdn{cc240564}
1659 */
1660
1661static BOOL rdp_write_brush_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1662{
1663 WINPR_ASSERT(settings);
1664 if (!Stream_EnsureRemainingCapacity(s, 32))
1665 return FALSE;
1666
1667 const size_t header = rdp_capability_set_start(log, s);
1668 Stream_Write_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1669 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BRUSH);
1670}
1671
1672#ifdef WITH_DEBUG_CAPABILITIES
1673static 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 */
1692static void rdp_read_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_definition)
1693{
1694 WINPR_ASSERT(cache_definition);
1695 Stream_Read_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1696 Stream_Read_UINT16(s,
1697 cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1698}
1699
1700/*
1701 * Write cache definition (glyph).
1702 * msdn{cc240566}
1703 */
1704static void rdp_write_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_definition)
1705{
1706 WINPR_ASSERT(cache_definition);
1707 Stream_Write_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1708 Stream_Write_UINT16(
1709 s, cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1710}
1711
1712static BOOL rdp_apply_glyph_cache_capability_set(rdpSettings* settings, const rdpSettings* src)
1713{
1714 WINPR_ASSERT(settings);
1715 WINPR_ASSERT(src);
1716
1717 WINPR_ASSERT(src->GlyphCache);
1718 WINPR_ASSERT(settings->GlyphCache);
1719 for (size_t x = 0; x < 10; x++)
1720 settings->GlyphCache[x] = src->GlyphCache[x];
1721
1722 WINPR_ASSERT(src->FragCache);
1723 WINPR_ASSERT(settings->FragCache);
1724 settings->FragCache[0] = src->FragCache[0];
1725 settings->GlyphSupportLevel = src->GlyphSupportLevel;
1726
1727 return TRUE;
1728}
1729
1730/*
1731 * Read glyph cache capability set.
1732 * msdn{cc240565}
1733 */
1734
1735static BOOL rdp_read_glyph_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1736{
1737 WINPR_ASSERT(settings);
1738 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1739 return FALSE;
1740
1741 /* glyphCache (40 bytes) */
1742 for (size_t x = 0; x < 10; x++)
1743 rdp_read_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1744 rdp_read_cache_definition(s, settings->FragCache); /* fragCache (4 bytes) */
1745 Stream_Read_UINT16(s, settings->GlyphSupportLevel); /* glyphSupportLevel (2 bytes) */
1746 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1747 return TRUE;
1748}
1749
1750/*
1751 * Write glyph cache capability set.
1752 * msdn{cc240565}
1753 */
1754
1755static BOOL rdp_write_glyph_cache_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1756{
1757 WINPR_ASSERT(settings);
1758 if (!Stream_EnsureRemainingCapacity(s, 64))
1759 return FALSE;
1760
1761 const size_t header = rdp_capability_set_start(log, s);
1762 if (settings->GlyphSupportLevel > UINT16_MAX)
1763 return FALSE;
1764 /* glyphCache (40 bytes) */
1765 for (size_t x = 0; x < 10; x++)
1766 rdp_write_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1767 rdp_write_cache_definition(s, settings->FragCache); /* fragCache (4 bytes) */
1768 Stream_Write_UINT16(s, (UINT16)settings->GlyphSupportLevel); /* glyphSupportLevel (2 bytes) */
1769 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1770 return rdp_capability_set_finish(s, header, CAPSET_TYPE_GLYPH_CACHE);
1771}
1772
1773#ifdef WITH_DEBUG_CAPABILITIES
1774static 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
1828static BOOL rdp_apply_offscreen_bitmap_cache_capability_set(rdpSettings* settings,
1829 const rdpSettings* src)
1830{
1831 WINPR_ASSERT(settings);
1832 WINPR_ASSERT(src);
1833
1834 settings->OffscreenCacheSize = src->OffscreenCacheSize;
1835 settings->OffscreenCacheEntries = src->OffscreenCacheEntries;
1836 settings->OffscreenSupportLevel = src->OffscreenSupportLevel;
1837
1838 return TRUE;
1839}
1840
1841/*
1842 * Read offscreen bitmap cache capability set.
1843 * msdn{cc240550}
1844 */
1845
1846static BOOL rdp_read_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s,
1847 rdpSettings* settings)
1848{
1849 UINT32 offscreenSupportLevel = 0;
1850
1851 WINPR_ASSERT(settings);
1852 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1853 return FALSE;
1854
1855 Stream_Read_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */
1856 Stream_Read_UINT16(s, settings->OffscreenCacheSize); /* offscreenCacheSize (2 bytes) */
1857 Stream_Read_UINT16(s, settings->OffscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1858
1859 settings->OffscreenSupportLevel = offscreenSupportLevel & 0x01;
1860
1861 return TRUE;
1862}
1863
1864/*
1865 * Write offscreen bitmap cache capability set.
1866 * msdn{cc240550}
1867 */
1868
1869static BOOL rdp_write_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s,
1870 const rdpSettings* settings)
1871{
1872 UINT32 offscreenSupportLevel = 0x00;
1873
1874 WINPR_ASSERT(settings);
1875 if (!Stream_EnsureRemainingCapacity(s, 32))
1876 return FALSE;
1877
1878 const size_t header = rdp_capability_set_start(log, s);
1879 if (settings->OffscreenSupportLevel)
1880 {
1881 offscreenSupportLevel = 0x01;
1882 Stream_Write_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */
1883 Stream_Write_UINT16(
1884 s, WINPR_ASSERTING_INT_CAST(
1885 uint16_t, settings->OffscreenCacheSize)); /* offscreenCacheSize (2 bytes) */
1886 Stream_Write_UINT16(
1887 s,
1888 WINPR_ASSERTING_INT_CAST(
1889 uint16_t, settings->OffscreenCacheEntries)); /* offscreenCacheEntries (2 bytes) */
1890 }
1891 else
1892 Stream_Zero(s, 8);
1893
1894 return rdp_capability_set_finish(s, header, CAPSET_TYPE_OFFSCREEN_CACHE);
1895}
1896
1897#ifdef WITH_DEBUG_CAPABILITIES
1898static 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
1919static BOOL rdp_apply_bitmap_cache_host_support_capability_set(rdpSettings* settings,
1920 const rdpSettings* src)
1921{
1922 const BOOL val = (freerdp_settings_get_bool(src, FreeRDP_BitmapCachePersistEnabled) &&
1923 freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled));
1924 return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, val);
1925}
1926
1927/*
1928 * Read bitmap cache host support capability set.
1929 * msdn{cc240557}
1930 */
1931
1932static BOOL rdp_read_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
1933 rdpSettings* settings)
1934{
1935 BYTE cacheVersion = 0;
1936
1937 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1938 return FALSE;
1939
1940 Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1941 Stream_Seek_UINT8(s); /* pad1 (1 byte) */
1942 Stream_Seek_UINT16(s); /* pad2 (2 bytes) */
1943
1944 return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
1945 cacheVersion & BITMAP_CACHE_V2);
1946}
1947
1948/*
1949 * Write bitmap cache host support capability set.
1950 * msdn{cc240557}
1951 */
1952
1953static BOOL rdp_write_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
1954 const rdpSettings* settings)
1955{
1956 UINT8 cacheVersion = 0;
1957
1958 if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled))
1959 cacheVersion |= BITMAP_CACHE_V2;
1960
1961 if (!Stream_EnsureRemainingCapacity(s, 32))
1962 return FALSE;
1963
1964 const size_t header = rdp_capability_set_start(log, s);
1965 Stream_Write_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1966 Stream_Write_UINT8(s, 0); /* pad1 (1 byte) */
1967 Stream_Write_UINT16(s, 0); /* pad2 (2 bytes) */
1968 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT);
1969}
1970
1971#ifdef WITH_DEBUG_CAPABILITIES
1972static 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
1993static BOOL rdp_read_bitmap_cache_cell_info(wLog* log, wStream* s,
1994 BITMAP_CACHE_V2_CELL_INFO* cellInfo)
1995{
1996 UINT32 info = 0;
1997
1998 WINPR_ASSERT(cellInfo);
1999 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2000 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 Stream_Read_UINT32(s, info);
2007 cellInfo->numEntries = (info & 0x7FFFFFFF);
2008 cellInfo->persistent = (info & 0x80000000) ? 1 : 0;
2009 return TRUE;
2010}
2011
2012static void rdp_write_bitmap_cache_cell_info(wStream* s, BITMAP_CACHE_V2_CELL_INFO* cellInfo)
2013{
2014 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 WINPR_ASSERT(cellInfo);
2020 info = (cellInfo->numEntries | (((UINT32)cellInfo->persistent << 31) & 0xFF000000));
2021 Stream_Write_UINT32(s, info);
2022}
2023
2024static BOOL rdp_apply_bitmap_cache_v2_capability_set(rdpSettings* settings, const rdpSettings* src)
2025{
2026 const FreeRDP_Settings_Keys_Bool keys[] = { FreeRDP_BitmapCacheEnabled,
2027 FreeRDP_BitmapCachePersistEnabled };
2028
2029 for (size_t x = 0; x < ARRAYSIZE(keys); x++)
2030 {
2031 const FreeRDP_Settings_Keys_Bool id = keys[x];
2032 const BOOL val = freerdp_settings_get_bool(src, id);
2033 if (!freerdp_settings_set_bool(settings, id, val))
2034 return FALSE;
2035 }
2036
2037 {
2038 const UINT32 BitmapCacheV2NumCells =
2039 freerdp_settings_get_uint32(src, FreeRDP_BitmapCacheV2NumCells);
2040 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_BitmapCacheV2CellInfo, nullptr,
2041 BitmapCacheV2NumCells))
2042 return FALSE;
2043
2044 for (size_t x = 0; x < BitmapCacheV2NumCells; x++)
2045 {
2046 const BITMAP_CACHE_V2_CELL_INFO* cdata =
2047 freerdp_settings_get_pointer_array(src, FreeRDP_BitmapCacheV2CellInfo, x);
2048 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, x,
2049 cdata))
2050 return FALSE;
2051 }
2052 }
2053
2054 return TRUE;
2055}
2056
2057/*
2058 * Read bitmap cache v2 capability set.
2059 * msdn{cc240560}
2060 */
2061
2062static BOOL rdp_read_bitmap_cache_v2_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2063{
2064 UINT16 cacheFlags = 0;
2065 WINPR_UNUSED(settings);
2066 WINPR_ASSERT(settings);
2067
2068 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2069 return FALSE;
2070
2071 Stream_Read_UINT16(s, cacheFlags); /* cacheFlags (2 bytes) */
2072
2073 if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE))
2074 return FALSE;
2075 if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
2076 cacheFlags & PERSISTENT_KEYS_EXPECTED_FLAG))
2077 return FALSE;
2078
2079 Stream_Seek_UINT8(s); /* pad2 (1 byte) */
2080 Stream_Read_UINT8(s, settings->BitmapCacheV2NumCells); /* numCellCaches (1 byte) */
2081 if (settings->BitmapCacheV2NumCells > 5)
2082 {
2083 WLog_Print(log, WLOG_ERROR,
2084 "Invalid TS_BITMAPCACHE_CAPABILITYSET_REV2::numCellCaches %" PRIu32 " > 5",
2085 settings->BitmapCacheV2NumCells);
2086 return FALSE;
2087 }
2088
2089 for (size_t x = 0; x < settings->BitmapCacheV2NumCells; x++)
2090 {
2092 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_BitmapCacheV2CellInfo, x);
2093 if (!rdp_read_bitmap_cache_cell_info(log, s, info))
2094 return FALSE;
2095 }
2096
2097 /* Input must always have 5 BitmapCacheV2CellInfo values */
2098 for (size_t x = settings->BitmapCacheV2NumCells; x < 5; x++)
2099 {
2100 if (!Stream_SafeSeek(s, 4))
2101 return FALSE;
2102 }
2103 Stream_Seek(s, 12); /* pad3 (12 bytes) */
2104 return TRUE;
2105}
2106
2107/*
2108 * Write bitmap cache v2 capability set.
2109 * msdn{cc240560}
2110 */
2111
2112static BOOL rdp_write_bitmap_cache_v2_capability_set(wLog* log, wStream* s,
2113 const rdpSettings* settings)
2114{
2115 WINPR_ASSERT(settings);
2116 if (!Stream_EnsureRemainingCapacity(s, 64))
2117 return FALSE;
2118
2119 const size_t header = rdp_capability_set_start(log, s);
2120 UINT16 cacheFlags = ALLOW_CACHE_WAITING_LIST_FLAG;
2121
2122 if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
2123 {
2124 cacheFlags |= PERSISTENT_KEYS_EXPECTED_FLAG;
2125 settings->BitmapCacheV2CellInfo[0].persistent = 1;
2126 settings->BitmapCacheV2CellInfo[1].persistent = 1;
2127 settings->BitmapCacheV2CellInfo[2].persistent = 1;
2128 settings->BitmapCacheV2CellInfo[3].persistent = 1;
2129 settings->BitmapCacheV2CellInfo[4].persistent = 1;
2130 }
2131
2132 Stream_Write_UINT16(s, cacheFlags); /* cacheFlags (2 bytes) */
2133 Stream_Write_UINT8(s, 0); /* pad2 (1 byte) */
2134 Stream_Write_UINT8(
2135 s, WINPR_ASSERTING_INT_CAST(uint8_t,
2136 settings->BitmapCacheV2NumCells)); /* numCellCaches (1 byte) */
2137 rdp_write_bitmap_cache_cell_info(
2138 s, &settings->BitmapCacheV2CellInfo[0]); /* bitmapCache0CellInfo (4 bytes) */
2139 rdp_write_bitmap_cache_cell_info(
2140 s, &settings->BitmapCacheV2CellInfo[1]); /* bitmapCache1CellInfo (4 bytes) */
2141 rdp_write_bitmap_cache_cell_info(
2142 s, &settings->BitmapCacheV2CellInfo[2]); /* bitmapCache2CellInfo (4 bytes) */
2143 rdp_write_bitmap_cache_cell_info(
2144 s, &settings->BitmapCacheV2CellInfo[3]); /* bitmapCache3CellInfo (4 bytes) */
2145 rdp_write_bitmap_cache_cell_info(
2146 s, &settings->BitmapCacheV2CellInfo[4]); /* bitmapCache4CellInfo (4 bytes) */
2147 Stream_Zero(s, 12); /* pad3 (12 bytes) */
2148 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V2);
2149}
2150
2151#ifdef WITH_DEBUG_CAPABILITIES
2152static 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
2190static BOOL rdp_apply_virtual_channel_capability_set(rdpSettings* settings, const rdpSettings* src)
2191{
2192 WINPR_ASSERT(settings);
2193 WINPR_ASSERT(src);
2194
2195 /* MS servers and clients disregard in advertising what is relevant for their own side */
2196 if (settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_SC) &&
2197 (src->VCFlags & VCCAPS_COMPR_SC))
2198 settings->VCFlags |= VCCAPS_COMPR_SC;
2199 else
2200 settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_SC;
2201
2202 if (!settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_CS_8K) &&
2203 (src->VCFlags & VCCAPS_COMPR_CS_8K))
2204 settings->VCFlags |= VCCAPS_COMPR_CS_8K;
2205 else
2206 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 if (!settings->ServerMode)
2214 {
2215 if ((src->VCChunkSize > CHANNEL_CHUNK_MAX_LENGTH) || (src->VCChunkSize == 0))
2216 settings->VCChunkSize = CHANNEL_CHUNK_LENGTH;
2217 else
2218 {
2219 settings->VCChunkSize = src->VCChunkSize;
2220 }
2221 }
2222
2223 return TRUE;
2224}
2225
2226/*
2227 * Read virtual channel capability set.
2228 * msdn{cc240551}
2229 */
2230
2231static BOOL rdp_read_virtual_channel_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2232{
2233 UINT32 flags = 0;
2234 UINT32 VCChunkSize = 0;
2235
2236 WINPR_ASSERT(settings);
2237 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2238 return FALSE;
2239
2240 Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2241
2242 if (Stream_GetRemainingLength(s) >= 4)
2243 Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2244 else
2245 VCChunkSize = UINT32_MAX; /* Use an invalid value to determine that value is not present */
2246
2247 settings->VCFlags = flags;
2248 settings->VCChunkSize = VCChunkSize;
2249
2250 return TRUE;
2251}
2252
2253/*
2254 * Write virtual channel capability set.
2255 * msdn{cc240551}
2256 */
2257
2258static BOOL rdp_write_virtual_channel_capability_set(wLog* log, wStream* s,
2259 const rdpSettings* settings)
2260{
2261 WINPR_ASSERT(settings);
2262 if (!Stream_EnsureRemainingCapacity(s, 32))
2263 return FALSE;
2264
2265 const size_t header = rdp_capability_set_start(log, s);
2266 Stream_Write_UINT32(s, settings->VCFlags); /* flags (4 bytes) */
2267 Stream_Write_UINT32(s, settings->VCChunkSize); /* VCChunkSize (4 bytes) */
2268 return rdp_capability_set_finish(s, header, CAPSET_TYPE_VIRTUAL_CHANNEL);
2269}
2270
2271#ifdef WITH_DEBUG_CAPABILITIES
2272static 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
2295static BOOL rdp_apply_draw_nine_grid_cache_capability_set(rdpSettings* settings,
2296 const rdpSettings* src)
2297{
2298 WINPR_ASSERT(settings);
2299 WINPR_ASSERT(src);
2300
2301 settings->DrawNineGridCacheSize = src->DrawNineGridCacheSize;
2302 settings->DrawNineGridCacheEntries = src->DrawNineGridCacheEntries;
2303 settings->DrawNineGridEnabled = src->DrawNineGridEnabled;
2304
2305 return TRUE;
2306}
2307
2308/*
2309 * Read drawn nine grid cache capability set.
2310 * msdn{cc241565}
2311 */
2312
2313static BOOL rdp_read_draw_nine_grid_cache_capability_set(wLog* log, wStream* s,
2314 rdpSettings* settings)
2315{
2316 UINT32 drawNineGridSupportLevel = 0;
2317
2318 WINPR_ASSERT(settings);
2319 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2320 return FALSE;
2321
2322 Stream_Read_UINT32(s, drawNineGridSupportLevel); /* drawNineGridSupportLevel (4 bytes) */
2323 Stream_Read_UINT16(s, settings->DrawNineGridCacheSize); /* drawNineGridCacheSize (2 bytes) */
2324 Stream_Read_UINT16(s,
2325 settings->DrawNineGridCacheEntries); /* drawNineGridCacheEntries (2 bytes) */
2326
2327 settings->DrawNineGridEnabled =
2328 (drawNineGridSupportLevel & (DRAW_NINEGRID_SUPPORTED | DRAW_NINEGRID_SUPPORTED_V2)) != 0;
2329
2330 return TRUE;
2331}
2332
2333/*
2334 * Write drawn nine grid cache capability set.
2335 * msdn{cc241565}
2336 */
2337
2338static BOOL rdp_write_draw_nine_grid_cache_capability_set(wLog* log, wStream* s,
2339 const rdpSettings* settings)
2340{
2341 WINPR_ASSERT(settings);
2342 if (!Stream_EnsureRemainingCapacity(s, 32))
2343 return FALSE;
2344
2345 const size_t header = rdp_capability_set_start(log, s);
2346 const UINT32 drawNineGridSupportLevel =
2347 (settings->DrawNineGridEnabled) ? DRAW_NINEGRID_SUPPORTED_V2 : DRAW_NINEGRID_NO_SUPPORT;
2348 Stream_Write_UINT32(s, drawNineGridSupportLevel); /* drawNineGridSupportLevel (4 bytes) */
2349 Stream_Write_UINT16(
2350 s, WINPR_ASSERTING_INT_CAST(
2351 uint16_t, settings->DrawNineGridCacheSize)); /* drawNineGridCacheSize (2 bytes) */
2352 Stream_Write_UINT16(
2353 s,
2354 WINPR_ASSERTING_INT_CAST(
2355 uint16_t, settings->DrawNineGridCacheEntries)); /* drawNineGridCacheEntries (2 bytes) */
2356 return rdp_capability_set_finish(s, header, CAPSET_TYPE_DRAW_NINE_GRID_CACHE);
2357}
2358
2359#ifdef WITH_DEBUG_CAPABILITIES
2360static 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
2381static BOOL rdp_apply_draw_gdiplus_cache_capability_set(rdpSettings* settings,
2382 const rdpSettings* src)
2383{
2384 WINPR_ASSERT(settings);
2385 WINPR_ASSERT(src);
2386
2387 if (src->DrawGdiPlusEnabled)
2388 settings->DrawGdiPlusEnabled = TRUE;
2389
2390 if (src->DrawGdiPlusCacheEnabled)
2391 settings->DrawGdiPlusCacheEnabled = TRUE;
2392
2393 return TRUE;
2394}
2395
2396/*
2397 * Read GDI+ cache capability set.
2398 * msdn{cc241566}
2399 */
2400
2401static BOOL rdp_read_draw_gdiplus_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2402{
2403 UINT32 drawGDIPlusSupportLevel = 0;
2404 UINT32 drawGdiplusCacheLevel = 0;
2405
2406 WINPR_ASSERT(settings);
2407 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2408 return FALSE;
2409
2410 Stream_Read_UINT32(s, drawGDIPlusSupportLevel); /* drawGDIPlusSupportLevel (4 bytes) */
2411 Stream_Seek_UINT32(s); /* GdipVersion (4 bytes) */
2412 Stream_Read_UINT32(s, drawGdiplusCacheLevel); /* drawGdiplusCacheLevel (4 bytes) */
2413 Stream_Seek(s, 10); /* GdipCacheEntries (10 bytes) */
2414 Stream_Seek(s, 8); /* GdipCacheChunkSize (8 bytes) */
2415 Stream_Seek(s, 6); /* GdipImageCacheProperties (6 bytes) */
2416
2417 settings->DrawGdiPlusEnabled = (drawGDIPlusSupportLevel & DRAW_GDIPLUS_SUPPORTED) != 0;
2418 settings->DrawGdiPlusCacheEnabled = (drawGdiplusCacheLevel & DRAW_GDIPLUS_CACHE_LEVEL_ONE) != 0;
2419
2420 return TRUE;
2421}
2422
2423#ifdef WITH_DEBUG_CAPABILITIES
2424static 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
2478static BOOL rdp_apply_remote_programs_capability_set(rdpSettings* settings, const rdpSettings* src)
2479{
2480 WINPR_ASSERT(settings);
2481 WINPR_ASSERT(src);
2482
2483 if (settings->RemoteApplicationMode)
2484 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 UINT32 supportLevel = src->RemoteApplicationSupportLevel;
2490 if (settings->RemoteApplicationMode)
2491 supportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2492
2493 settings->RemoteApplicationSupportLevel = supportLevel & settings->RemoteApplicationSupportMask;
2494
2495 return TRUE;
2496}
2497
2498/*
2499 * Read remote programs capability set.
2500 * msdn{cc242518}
2501 */
2502
2503static BOOL rdp_read_remote_programs_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2504{
2505 UINT32 railSupportLevel = 0;
2506
2507 WINPR_ASSERT(settings);
2508 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2509 return FALSE;
2510
2511 Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2512
2513 settings->RemoteApplicationMode = (railSupportLevel & RAIL_LEVEL_SUPPORTED) != 0;
2514 settings->RemoteApplicationSupportLevel = railSupportLevel;
2515 return TRUE;
2516}
2517
2518/*
2519 * Write remote programs capability set.
2520 * msdn{cc242518}
2521 */
2522
2523static BOOL rdp_write_remote_programs_capability_set(wLog* log, wStream* s,
2524 const rdpSettings* settings)
2525{
2526 WINPR_ASSERT(settings);
2527 if (!Stream_EnsureRemainingCapacity(s, 64))
2528 return FALSE;
2529
2530 const size_t header = rdp_capability_set_start(log, s);
2531 UINT32 railSupportLevel = RAIL_LEVEL_SUPPORTED;
2532
2533 if (settings->RemoteApplicationSupportLevel & RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED)
2534 {
2535 if (settings->RemoteAppLanguageBarSupported)
2536 railSupportLevel |= RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED;
2537 }
2538
2539 railSupportLevel |= RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED;
2540 railSupportLevel |= RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED;
2541 railSupportLevel |= RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED;
2542 railSupportLevel |= RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED;
2543 railSupportLevel |= RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED;
2544 railSupportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2545 /* Mask out everything the server does not support. */
2546 railSupportLevel &= settings->RemoteApplicationSupportLevel;
2547 Stream_Write_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2548 return rdp_capability_set_finish(s, header, CAPSET_TYPE_RAIL);
2549}
2550
2551#ifdef WITH_DEBUG_CAPABILITIES
2552static 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
2567static BOOL rdp_apply_window_list_capability_set(rdpSettings* settings, const rdpSettings* src)
2568{
2569 WINPR_ASSERT(settings);
2570 WINPR_ASSERT(src);
2571
2572 settings->RemoteWndSupportLevel = src->RemoteWndSupportLevel;
2573 settings->RemoteAppNumIconCaches = src->RemoteAppNumIconCaches;
2574 settings->RemoteAppNumIconCacheEntries = src->RemoteAppNumIconCacheEntries;
2575
2576 return TRUE;
2577}
2578
2579/*
2580 * Read window list capability set.
2581 * msdn{cc242564}
2582 */
2583
2584static BOOL rdp_read_window_list_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2585{
2586 WINPR_ASSERT(settings);
2587 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2588 return FALSE;
2589
2590 Stream_Read_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2591 Stream_Read_UINT8(s, settings->RemoteAppNumIconCaches); /* numIconCaches (1 byte) */
2592 Stream_Read_UINT16(s,
2593 settings->RemoteAppNumIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2594 return TRUE;
2595}
2596
2597/*
2598 * Write window list capability set.
2599 * msdn{cc242564}
2600 */
2601
2602static BOOL rdp_write_window_list_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
2603{
2604 WINPR_ASSERT(settings);
2605 if (!Stream_EnsureRemainingCapacity(s, 32))
2606 return FALSE;
2607
2608 const size_t header = rdp_capability_set_start(log, s);
2609 Stream_Write_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2610 Stream_Write_UINT8(
2611 s, WINPR_ASSERTING_INT_CAST(uint8_t,
2612 settings->RemoteAppNumIconCaches)); /* numIconCaches (1 byte) */
2613 Stream_Write_UINT16(
2614 s,
2615 WINPR_ASSERTING_INT_CAST(
2616 uint16_t, settings->RemoteAppNumIconCacheEntries)); /* numIconCacheEntries (2 bytes) */
2617 return rdp_capability_set_finish(s, header, CAPSET_TYPE_WINDOW);
2618}
2619
2620#ifdef WITH_DEBUG_CAPABILITIES
2621static 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
2642static BOOL rdp_apply_desktop_composition_capability_set(rdpSettings* settings,
2643 const rdpSettings* src)
2644{
2645 WINPR_ASSERT(settings);
2646 WINPR_ASSERT(src);
2647
2648 settings->CompDeskSupportLevel = src->CompDeskSupportLevel;
2649 return TRUE;
2650}
2651
2652/*
2653 * Read desktop composition capability set.
2654 * msdn{cc240855}
2655 */
2656
2657static BOOL rdp_read_desktop_composition_capability_set(wLog* log, wStream* s,
2658 rdpSettings* settings)
2659{
2660 WINPR_UNUSED(settings);
2661 WINPR_ASSERT(settings);
2662
2663 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2664 return FALSE;
2665
2666 Stream_Read_UINT16(s, settings->CompDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2667 return TRUE;
2668}
2669
2670/*
2671 * Write desktop composition capability set.
2672 * msdn{cc240855}
2673 */
2674
2675static BOOL rdp_write_desktop_composition_capability_set(wLog* log, wStream* s,
2676 const rdpSettings* settings)
2677{
2678 WINPR_ASSERT(settings);
2679
2680 if (!Stream_EnsureRemainingCapacity(s, 32))
2681 return FALSE;
2682
2683 const size_t header = rdp_capability_set_start(log, s);
2684 const UINT16 compDeskSupportLevel =
2685 (settings->AllowDesktopComposition) ? COMPDESK_SUPPORTED : COMPDESK_NOT_SUPPORTED;
2686 Stream_Write_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2687 return rdp_capability_set_finish(s, header, CAPSET_TYPE_COMP_DESK);
2688}
2689
2690#ifdef WITH_DEBUG_CAPABILITIES
2691static 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
2706static BOOL rdp_apply_multifragment_update_capability_set(rdpSettings* settings,
2707 const rdpSettings* src)
2708{
2709 WINPR_ASSERT(settings);
2710 WINPR_ASSERT(src);
2711
2712 UINT32 multifragMaxRequestSize =
2713 freerdp_settings_get_uint32(src, FreeRDP_MultifragMaxRequestSize);
2714
2715 if (settings->ServerMode)
2716 {
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 if (multifragMaxRequestSize < FASTPATH_MAX_PACKET_SIZE)
2726 multifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE;
2727
2728 if (settings->RemoteFxCodec)
2729 {
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 if (multifragMaxRequestSize <
2736 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize))
2737 {
2738 /*
2739 * If it happens to be smaller we honor the client's value but
2740 * have to disable RemoteFX
2741 */
2742 settings->RemoteFxCodec = FALSE;
2743 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2744 multifragMaxRequestSize))
2745 return FALSE;
2746 }
2747 else
2748 {
2749 /* no need to increase server's max request size setting here */
2750 }
2751 }
2752 else
2753 {
2754 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2755 multifragMaxRequestSize))
2756 return FALSE;
2757 }
2758 }
2759 else
2760 {
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 if (multifragMaxRequestSize >
2767 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize))
2768 {
2769 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2770 multifragMaxRequestSize))
2771 return FALSE;
2772 }
2773 }
2774 return TRUE;
2775}
2776
2777/*
2778 * Read multifragment update capability set.
2779 * msdn{cc240649}
2780 */
2781
2782static BOOL rdp_read_multifragment_update_capability_set(wLog* log, wStream* s,
2783 rdpSettings* settings)
2784{
2785 WINPR_ASSERT(settings);
2786 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2787 return FALSE;
2788
2789 const UINT32 multifragMaxRequestSize = Stream_Get_UINT32(s); /* MaxRequestSize (4 bytes) */
2790 return freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2791 multifragMaxRequestSize);
2792}
2793
2794/*
2795 * Write multifragment update capability set.
2796 * msdn{cc240649}
2797 */
2798
2799static BOOL rdp_write_multifragment_update_capability_set(wLog* log, wStream* s,
2800 rdpSettings* settings)
2801{
2802 WINPR_ASSERT(settings);
2803 if (settings->ServerMode &&
2804 (freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize) == 0))
2805 {
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 const UINT32 tileNumX = (settings->DesktopWidth + 63) / 64;
2818 const UINT32 tileNumY = (settings->DesktopHeight + 63) / 64;
2819
2820 WINPR_ASSERT(tileNumX < UINT32_MAX / tileNumY);
2821 WINPR_ASSERT(tileNumY < UINT32_MAX / tileNumX);
2822 WINPR_ASSERT(tileNumX * tileNumY < UINT32_MAX / 16384u);
2823
2824 /* and add room for headers, regions, frame markers, etc. */
2825 const UINT32 MultifragMaxRequestSize = (tileNumX * tileNumY + 1u) * 16384u;
2826
2827 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2828 MultifragMaxRequestSize))
2829 return FALSE;
2830 }
2831
2832 if (!Stream_EnsureRemainingCapacity(s, 32))
2833 return FALSE;
2834 const size_t header = rdp_capability_set_start(log, s);
2835 Stream_Write_UINT32(s, settings->MultifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
2836 return rdp_capability_set_finish(s, header, CAPSET_TYPE_MULTI_FRAGMENT_UPDATE);
2837}
2838
2839#ifdef WITH_DEBUG_CAPABILITIES
2840static 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
2855static BOOL rdp_apply_large_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
2856{
2857 WINPR_ASSERT(settings);
2858 WINPR_ASSERT(src);
2859
2860 settings->LargePointerFlag = src->LargePointerFlag;
2861 return TRUE;
2862}
2863
2864/*
2865 * Read large pointer capability set.
2866 * msdn{cc240650}
2867 */
2868
2869static BOOL rdp_read_large_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2870{
2871 UINT16 largePointerSupportFlags = 0;
2872
2873 WINPR_ASSERT(settings);
2874 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2875 return FALSE;
2876
2877 Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2878 settings->LargePointerFlag &= largePointerSupportFlags;
2879 if ((largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) != 0)
2880 {
2881 WLog_Print(
2882 log, WLOG_WARN,
2883 "TS_LARGE_POINTER_CAPABILITYSET with unsupported flags %04X (all flags %04X) received",
2884 WINPR_CXX_COMPAT_CAST(UINT32, largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 |
2885 LARGE_POINTER_FLAG_384x384)),
2886 largePointerSupportFlags);
2887 }
2888 return TRUE;
2889}
2890
2891/*
2892 * Write large pointer capability set.
2893 * msdn{cc240650}
2894 */
2895
2896static BOOL rdp_write_large_pointer_capability_set(wLog* log, wStream* s,
2897 const rdpSettings* settings)
2898{
2899 WINPR_ASSERT(settings);
2900 if (!Stream_EnsureRemainingCapacity(s, 32))
2901 return FALSE;
2902
2903 const size_t header = rdp_capability_set_start(log, s);
2904 const UINT16 largePointerSupportFlags =
2905 settings->LargePointerFlag & (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
2906 Stream_Write_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2907 return rdp_capability_set_finish(s, header, CAPSET_TYPE_LARGE_POINTER);
2908}
2909
2910#ifdef WITH_DEBUG_CAPABILITIES
2911static 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
2927static BOOL rdp_apply_surface_commands_capability_set(rdpSettings* settings, const rdpSettings* src)
2928{
2929 WINPR_ASSERT(settings);
2930 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 if (src->FastPathOutput)
2937 {
2938 settings->SurfaceCommandsSupported &= src->SurfaceCommandsSupported;
2939 settings->SurfaceCommandsEnabled = src->SurfaceCommandsEnabled;
2940 settings->SurfaceFrameMarkerEnabled = src->SurfaceFrameMarkerEnabled;
2941 }
2942 else
2943 {
2944 settings->SurfaceCommandsSupported = 0;
2945 settings->SurfaceCommandsEnabled = FALSE;
2946 settings->SurfaceFrameMarkerEnabled = FALSE;
2947 }
2948
2949 return TRUE;
2950}
2951
2952/*
2953 * Read surface commands capability set.
2954 * msdn{dd871563}
2955 */
2956
2957static BOOL rdp_read_surface_commands_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2958{
2959 UINT32 cmdFlags = 0;
2960
2961 WINPR_ASSERT(settings);
2962 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2963 return FALSE;
2964
2965 Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
2966 Stream_Seek_UINT32(s); /* reserved (4 bytes) */
2967 settings->SurfaceCommandsSupported = cmdFlags;
2968 settings->SurfaceCommandsEnabled =
2969 (cmdFlags & (SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS)) != 0;
2970 settings->SurfaceFrameMarkerEnabled = (cmdFlags & SURFCMDS_FRAME_MARKER) != 0;
2971 return TRUE;
2972}
2973
2974/*
2975 * Write surface commands capability set.
2976 * msdn{dd871563}
2977 */
2978
2979static BOOL rdp_write_surface_commands_capability_set(wLog* log, wStream* s,
2980 const rdpSettings* settings)
2981{
2982 WINPR_ASSERT(settings);
2983 if (!Stream_EnsureRemainingCapacity(s, 32))
2984 return FALSE;
2985
2986 const size_t header = rdp_capability_set_start(log, s);
2987 // TODO: Make these configurable too
2988 UINT32 cmdFlags = freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
2989
2990 if (settings->SurfaceFrameMarkerEnabled)
2991 cmdFlags |= SURFCMDS_FRAME_MARKER;
2992
2993 Stream_Write_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
2994 Stream_Write_UINT32(s, 0); /* reserved (4 bytes) */
2995 return rdp_capability_set_finish(s, header, CAPSET_TYPE_SURFACE_COMMANDS);
2996}
2997
2998static bool sUuidEqual(const UUID* Uuid1, const UUID* Uuid2)
2999{
3000 if (!Uuid1 && !Uuid2)
3001 return false;
3002
3003 if (Uuid1 && !Uuid2)
3004 return false;
3005
3006 if (!Uuid1 && Uuid2)
3007 return true;
3008
3009 if (Uuid1->Data1 != Uuid2->Data1)
3010 return false;
3011
3012 if (Uuid1->Data2 != Uuid2->Data2)
3013 return false;
3014
3015 if (Uuid1->Data3 != Uuid2->Data3)
3016 return false;
3017
3018 for (int index = 0; index < 8; index++)
3019 {
3020 if (Uuid1->Data4[index] != Uuid2->Data4[index])
3021 return false;
3022 }
3023
3024 return true;
3025}
3026
3027#ifdef WITH_DEBUG_CAPABILITIES
3028static 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
3046static 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
3057static 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
3078static BOOL rdp_read_bitmap_codec_guid(wLog* log, wStream* s, GUID* guid)
3079{
3080 BYTE g[16] = WINPR_C_ARRAY_INIT;
3081
3082 WINPR_ASSERT(guid);
3083 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16))
3084 return FALSE;
3085 Stream_Read(s, g, 16);
3086 guid->Data1 = ((UINT32)g[3] << 24U) | ((UINT32)g[2] << 16U) | (UINT32)(g[1] << 8U) | g[0];
3087 guid->Data2 = ((g[5] << 8U) | g[4]) & 0xFFFF;
3088 guid->Data3 = ((g[7] << 8U) | g[6]) & 0xFFFF;
3089 guid->Data4[0] = g[8];
3090 guid->Data4[1] = g[9];
3091 guid->Data4[2] = g[10];
3092 guid->Data4[3] = g[11];
3093 guid->Data4[4] = g[12];
3094 guid->Data4[5] = g[13];
3095 guid->Data4[6] = g[14];
3096 guid->Data4[7] = g[15];
3097 return TRUE;
3098}
3099
3100static void rdp_write_bitmap_codec_guid(wStream* s, const GUID* guid)
3101{
3102 BYTE g[16] = WINPR_C_ARRAY_INIT;
3103 WINPR_ASSERT(guid);
3104 g[0] = guid->Data1 & 0xFF;
3105 g[1] = (guid->Data1 >> 8) & 0xFF;
3106 g[2] = (guid->Data1 >> 16) & 0xFF;
3107 g[3] = (guid->Data1 >> 24) & 0xFF;
3108 g[4] = (guid->Data2) & 0xFF;
3109 g[5] = (guid->Data2 >> 8) & 0xFF;
3110 g[6] = (guid->Data3) & 0xFF;
3111 g[7] = (guid->Data3 >> 8) & 0xFF;
3112 g[8] = guid->Data4[0];
3113 g[9] = guid->Data4[1];
3114 g[10] = guid->Data4[2];
3115 g[11] = guid->Data4[3];
3116 g[12] = guid->Data4[4];
3117 g[13] = guid->Data4[5];
3118 g[14] = guid->Data4[6];
3119 g[15] = guid->Data4[7];
3120 Stream_Write(s, g, 16);
3121}
3122
3123static BOOL rdp_apply_bitmap_codecs_capability_set(rdpSettings* settings, const rdpSettings* src)
3124{
3125 WINPR_ASSERT(settings);
3126 WINPR_ASSERT(src);
3127
3128 if (settings->ServerMode)
3129 {
3130
3131 settings->RemoteFxCodecId = src->RemoteFxCodecId;
3132 settings->RemoteFxCaptureFlags = src->RemoteFxCaptureFlags;
3133 settings->RemoteFxOnly = src->RemoteFxOnly;
3134 settings->RemoteFxRlgrMode = src->RemoteFxRlgrMode;
3135 settings->RemoteFxCodecMode = src->RemoteFxCodecMode;
3136 settings->NSCodecId = src->NSCodecId;
3137 settings->NSCodecAllowDynamicColorFidelity = src->NSCodecAllowDynamicColorFidelity;
3138 settings->NSCodecAllowSubsampling = src->NSCodecAllowSubsampling;
3139 settings->NSCodecColorLossLevel = src->NSCodecColorLossLevel;
3140
3141 /* only enable a codec if we've announced/enabled it before */
3142 settings->RemoteFxCodec = settings->RemoteFxCodec && src->RemoteFxCodecId;
3143 settings->RemoteFxImageCodec = settings->RemoteFxImageCodec && src->RemoteFxImageCodec;
3144 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec,
3145 settings->NSCodec && src->NSCodec))
3146 return FALSE;
3147 settings->JpegCodec = src->JpegCodec;
3148 }
3149 return TRUE;
3150}
3151
3152static BOOL rdp_read_codec_ts_rfx_icap(wLog* log, wStream* sub, rdpSettings* settings,
3153 UINT16 icapLen)
3154{
3155 UINT16 version = 0;
3156 UINT16 tileSize = 0;
3157 BYTE codecFlags = 0;
3158 BYTE colConvBits = 0;
3159 BYTE transformBits = 0;
3160 BYTE entropyBits = 0;
3161 /* TS_RFX_ICAP */
3162 if (icapLen != 8)
3163 {
3164 WLog_Print(log, WLOG_ERROR,
3165 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP size %" PRIu16
3166 " unsupported, expecting size %" PRIu16 " not supported",
3167 icapLen, 8u);
3168 return FALSE;
3169 }
3170
3171 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3172 return FALSE;
3173
3174 Stream_Read_UINT16(sub, version); /* version (2 bytes) */
3175 Stream_Read_UINT16(sub, tileSize); /* tileSize (2 bytes) */
3176 Stream_Read_UINT8(sub, codecFlags); /* flags (1 byte) */
3177 Stream_Read_UINT8(sub, colConvBits); /* colConvBits (1 byte) */
3178 Stream_Read_UINT8(sub, transformBits); /* transformBits (1 byte) */
3179 Stream_Read_UINT8(sub, entropyBits); /* entropyBits (1 byte) */
3180
3181 if (version == 0x0009)
3182 {
3183 /* Version 0.9 */
3184 if (tileSize != 0x0080)
3185 {
3186 WLog_Print(log, WLOG_ERROR,
3187 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3188 " tile size %" PRIu16 " not supported",
3189 version, tileSize);
3190 return FALSE;
3191 }
3192 }
3193 else if (version == 0x0100)
3194 {
3195 /* Version 1.0 */
3196 if (tileSize != 0x0040)
3197 {
3198 WLog_Print(log, WLOG_ERROR,
3199 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3200 " tile size %" PRIu16 " not supported",
3201 version, tileSize);
3202 return FALSE;
3203 }
3204 }
3205 else
3206 {
3207 WLog_Print(log, WLOG_ERROR,
3208 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16 " not supported",
3209 version);
3210 return FALSE;
3211 }
3212
3213 /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_COL_CONV_ICT (0x1) */
3214 if (colConvBits != 1)
3215 {
3216 WLog_Print(log, WLOG_ERROR,
3217 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::colConvBits %" PRIu8
3218 " not supported, must be CLW_COL_CONV_ICT (0x1)",
3219 colConvBits);
3220 return FALSE;
3221 }
3222
3223 /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_XFORM_DWT_53_A (0x1) */
3224 if (transformBits != 1)
3225 {
3226 WLog_Print(log, WLOG_ERROR,
3227 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::transformBits %" PRIu8
3228 " not supported, must be CLW_XFORM_DWT_53_A (0x1)",
3229 colConvBits);
3230 return FALSE;
3231 }
3232
3233 const UINT8 CODEC_MODE = 0x02; /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP */
3234 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x00))
3235 return FALSE;
3236
3237 if ((codecFlags & CODEC_MODE) != 0)
3238 {
3239 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x02))
3240 return FALSE;
3241 }
3242 else if ((codecFlags & ~CODEC_MODE) != 0)
3243 WLog_Print(log, WLOG_WARN,
3244 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::flags unknown value "
3245 "0x%02" PRIx32,
3246 WINPR_CXX_COMPAT_CAST(UINT32, (codecFlags & ~CODEC_MODE)));
3247
3248 switch (entropyBits)
3249 {
3250 case CLW_ENTROPY_RLGR1:
3251 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR1))
3252 return FALSE;
3253 break;
3254 case CLW_ENTROPY_RLGR3:
3255 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3))
3256 return FALSE;
3257 break;
3258 default:
3259 WLog_Print(log, WLOG_ERROR,
3260 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::entropyBits "
3261 "unsupported value 0x%02" PRIx8
3262 ", must be CLW_ENTROPY_RLGR1 (0x01) or CLW_ENTROPY_RLGR3 "
3263 "(0x04)",
3264 entropyBits);
3265 return FALSE;
3266 }
3267 return TRUE;
3268}
3269
3270static BOOL rdp_read_codec_ts_rfx_capset(wLog* log, wStream* s, rdpSettings* settings)
3271{
3272 UINT16 blockType = 0;
3273 UINT32 blockLen = 0;
3274 BYTE rfxCodecId = 0;
3275 UINT16 capsetType = 0;
3276 UINT16 numIcaps = 0;
3277 UINT16 icapLen = 0;
3278
3279 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
3280 return FALSE;
3281
3282 /* TS_RFX_CAPSET */
3283 Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
3284 Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */
3285 if (blockType != 0xCBC1)
3286 {
3287 WLog_Print(log, WLOG_ERROR,
3288 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockType[0x%04" PRIx16
3289 "] != CBY_CAPSET (0xCBC1)",
3290 blockType);
3291 return FALSE;
3292 }
3293 if (blockLen < 6ull)
3294 {
3295 WLog_Print(log, WLOG_ERROR,
3296 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockLen[%" PRIu16 "] < 6", blockLen);
3297 return FALSE;
3298 }
3299 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, blockLen - 6ull))
3300 return FALSE;
3301
3302 wStream sbuffer = WINPR_C_ARRAY_INIT;
3303 wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), blockLen - 6ull);
3304 WINPR_ASSERT(sub);
3305
3306 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 7))
3307 return FALSE;
3308
3309 Stream_Read_UINT8(sub, rfxCodecId); /* codecId (1 byte) */
3310 Stream_Read_UINT16(sub, capsetType); /* capsetType (2 bytes) */
3311 Stream_Read_UINT16(sub, numIcaps); /* numIcaps (2 bytes) */
3312 Stream_Read_UINT16(sub, icapLen); /* icapLen (2 bytes) */
3313
3314 if (rfxCodecId != 1)
3315 {
3316 WLog_Print(log, WLOG_ERROR,
3317 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::codecId[%" PRIu16 "] != 1", rfxCodecId);
3318 return FALSE;
3319 }
3320
3321 if (capsetType != 0xCFC0)
3322 {
3323 WLog_Print(log, WLOG_ERROR,
3324 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::capsetType[0x%04" PRIx16
3325 "] != CLY_CAPSET (0xCFC0)",
3326 capsetType);
3327 return FALSE;
3328 }
3329
3330 while (numIcaps--)
3331 {
3332 if (!rdp_read_codec_ts_rfx_icap(log, sub, settings, icapLen))
3333 return FALSE;
3334 }
3335 return TRUE;
3336}
3337
3338static BOOL rdp_read_codec_ts_rfx_caps(wLog* log, wStream* sub, rdpSettings* settings)
3339{
3340 if (Stream_GetRemainingLength(sub) == 0)
3341 return TRUE;
3342
3343 UINT16 blockType = 0;
3344 UINT32 blockLen = 0;
3345 UINT16 numCapsets = 0;
3346
3347 /* TS_RFX_CAPS */
3348 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3349 return FALSE;
3350 Stream_Read_UINT16(sub, blockType); /* blockType (2 bytes) */
3351 Stream_Read_UINT32(sub, blockLen); /* blockLen (4 bytes) */
3352 Stream_Read_UINT16(sub, numCapsets); /* numCapsets (2 bytes) */
3353
3354 if (blockType != 0xCBC0)
3355 {
3356 WLog_Print(log, WLOG_ERROR,
3357 "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockType[0x%04" PRIx16
3358 "] != CBY_CAPS (0xCBC0)",
3359 blockType);
3360 return FALSE;
3361 }
3362
3363 if (blockLen != 8)
3364 {
3365 WLog_Print(log, WLOG_ERROR, "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockLen[%" PRIu16 "] != 8",
3366 blockLen);
3367 return FALSE;
3368 }
3369
3370 if (numCapsets != 1)
3371 {
3372 WLog_Print(log, WLOG_ERROR,
3373 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::numIcaps[%" PRIu16 "] != 1", numCapsets);
3374 return FALSE;
3375 }
3376
3377 for (UINT16 x = 0; x < numCapsets; x++)
3378 {
3379 if (!rdp_read_codec_ts_rfx_capset(log, sub, settings))
3380 return FALSE;
3381 }
3382
3383 return TRUE;
3384}
3385
3386static BOOL rdp_read_codec_ts_rfx_clnt_caps_container(wLog* log, wStream* s, rdpSettings* settings)
3387{
3388 UINT32 rfxCapsLength = 0;
3389 UINT32 rfxPropsLength = 0;
3390 UINT32 captureFlags = 0;
3391
3392 /* [MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER */
3393 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3394 return FALSE;
3395 Stream_Read_UINT32(s, rfxPropsLength); /* length (4 bytes) */
3396 if (rfxPropsLength < 4)
3397 {
3398 WLog_Print(log, WLOG_ERROR,
3399 "[MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER::length %" PRIu32
3400 " too short, require at least 4 bytes",
3401 rfxPropsLength);
3402 return FALSE;
3403 }
3404 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, rfxPropsLength - 4ull))
3405 return FALSE;
3406
3407 wStream sbuffer = WINPR_C_ARRAY_INIT;
3408 wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), rfxPropsLength - 4ull);
3409 WINPR_ASSERT(sub);
3410
3411 Stream_Seek(s, rfxPropsLength - 4ull);
3412
3413 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3414 return FALSE;
3415
3416 Stream_Read_UINT32(sub, captureFlags); /* captureFlags (4 bytes) */
3417 Stream_Read_UINT32(sub, rfxCapsLength); /* capsLength (4 bytes) */
3418 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, rfxCapsLength))
3419 return FALSE;
3420
3421 settings->RemoteFxCaptureFlags = captureFlags;
3422 settings->RemoteFxOnly = !(captureFlags & CARDP_CAPS_CAPTURE_NON_CAC);
3423
3424 /* [MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS */
3425 wStream tsbuffer = WINPR_C_ARRAY_INIT;
3426 wStream* ts_sub = Stream_StaticConstInit(&tsbuffer, Stream_Pointer(sub), rfxCapsLength);
3427 WINPR_ASSERT(ts_sub);
3428 return rdp_read_codec_ts_rfx_caps(log, ts_sub, settings);
3429}
3430
3431/*
3432 * Read bitmap codecs capability set.
3433 * msdn{dd891377}
3434 */
3435
3436static BOOL rdp_read_bitmap_codecs_capability_set(wLog* log, wStream* s, rdpSettings* settings,
3437 BOOL isServer)
3438{
3439 BYTE codecId = 0;
3440 GUID codecGuid = WINPR_C_ARRAY_INIT;
3441 BYTE bitmapCodecCount = 0;
3442 UINT16 codecPropertiesLength = 0;
3443
3444 BOOL guidNSCodec = FALSE;
3445 BOOL guidRemoteFx = FALSE;
3446 BOOL guidRemoteFxImage = FALSE;
3447
3448 WINPR_ASSERT(settings);
3449 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3450 return FALSE;
3451
3452 Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3453
3454 while (bitmapCodecCount > 0)
3455 {
3456 wStream subbuffer = WINPR_C_ARRAY_INIT;
3457
3458 if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3459 return FALSE;
3460 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3461 return FALSE;
3462 Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3463 Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3464
3465 wStream* sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), codecPropertiesLength);
3466 if (!Stream_SafeSeek(s, codecPropertiesLength))
3467 return FALSE;
3468
3469 if (isServer)
3470 {
3471 if (sUuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX))
3472 {
3473 guidRemoteFx = TRUE;
3474 settings->RemoteFxCodecId = codecId;
3475 if (!rdp_read_codec_ts_rfx_clnt_caps_container(log, sub, settings))
3476 return FALSE;
3477 }
3478 else if (sUuidEqual(&codecGuid, &CODEC_GUID_IMAGE_REMOTEFX))
3479 {
3480 /* Microsoft RDP servers ignore CODEC_GUID_IMAGE_REMOTEFX codec properties */
3481 guidRemoteFxImage = TRUE;
3482 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3483 return FALSE;
3484 }
3485 else if (sUuidEqual(&codecGuid, &CODEC_GUID_NSCODEC))
3486 {
3487 BYTE colorLossLevel = 0;
3488 BYTE fAllowSubsampling = 0;
3489 BYTE fAllowDynamicFidelity = 0;
3490 guidNSCodec = TRUE;
3491 settings->NSCodecId = codecId;
3492 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 3))
3493 return FALSE;
3494 Stream_Read_UINT8(sub, fAllowDynamicFidelity); /* fAllowDynamicFidelity (1 byte) */
3495 Stream_Read_UINT8(sub, fAllowSubsampling); /* fAllowSubsampling (1 byte) */
3496 Stream_Read_UINT8(sub, colorLossLevel); /* colorLossLevel (1 byte) */
3497
3498 if (colorLossLevel < 1)
3499 colorLossLevel = 1;
3500
3501 if (colorLossLevel > 7)
3502 colorLossLevel = 7;
3503
3504 settings->NSCodecAllowDynamicColorFidelity = fAllowDynamicFidelity;
3505 settings->NSCodecAllowSubsampling = fAllowSubsampling;
3506 settings->NSCodecColorLossLevel = colorLossLevel;
3507 }
3508 else if (sUuidEqual(&codecGuid, &CODEC_GUID_IGNORE))
3509 {
3510 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3511 return FALSE;
3512 }
3513 else
3514 {
3515 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3516 return FALSE;
3517 }
3518 }
3519 else
3520 {
3521 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3522 return FALSE;
3523 }
3524
3525 const size_t rest = Stream_GetRemainingLength(sub);
3526 if (rest > 0)
3527 {
3528 WLog_Print(log, WLOG_ERROR,
3529 "error while reading codec properties: actual size: %" PRIuz
3530 " expected size: %" PRIu32 "",
3531 rest + codecPropertiesLength, codecPropertiesLength);
3532 }
3533 bitmapCodecCount--;
3534
3535 /* only enable a codec if we've announced/enabled it before */
3536 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, guidRemoteFx))
3537 return FALSE;
3538 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, guidRemoteFxImage))
3539 return FALSE;
3540 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, guidNSCodec))
3541 return FALSE;
3542 if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
3543 return FALSE;
3544 }
3545
3546 return TRUE;
3547}
3548
3549/*
3550 * Write RemoteFX Client Capability Container.
3551 */
3552static BOOL rdp_write_rfx_client_capability_container(wStream* s, const rdpSettings* settings)
3553{
3554 WINPR_ASSERT(settings);
3555 if (!Stream_EnsureRemainingCapacity(s, 64))
3556 return FALSE;
3557
3558 const UINT32 captureFlags = settings->RemoteFxOnly ? 0 : CARDP_CAPS_CAPTURE_NON_CAC;
3559
3560 WINPR_ASSERT(settings->RemoteFxCodecMode <= UINT8_MAX);
3561 const UINT8 codecMode = (UINT8)settings->RemoteFxCodecMode;
3562 Stream_Write_UINT16(s, 49); /* codecPropertiesLength */
3563 /* TS_RFX_CLNT_CAPS_CONTAINER */
3564 Stream_Write_UINT32(s, 49); /* length */
3565 Stream_Write_UINT32(s, captureFlags); /* captureFlags */
3566 Stream_Write_UINT32(s, 37); /* capsLength */
3567 /* TS_RFX_CAPS */
3568 Stream_Write_UINT16(s, CBY_CAPS); /* blockType */
3569 Stream_Write_UINT32(s, 8); /* blockLen */
3570 Stream_Write_UINT16(s, 1); /* numCapsets */
3571 /* TS_RFX_CAPSET */
3572 Stream_Write_UINT16(s, CBY_CAPSET); /* blockType */
3573 Stream_Write_UINT32(s, 29); /* blockLen */
3574 Stream_Write_UINT8(s, 0x01); /* codecId (MUST be set to 0x01) */
3575 Stream_Write_UINT16(s, CLY_CAPSET); /* capsetType */
3576 Stream_Write_UINT16(s, 2); /* numIcaps */
3577 Stream_Write_UINT16(s, 8); /* icapLen */
3578 /* TS_RFX_ICAP (RLGR1) */
3579 Stream_Write_UINT16(s, CLW_VERSION_1_0); /* version */
3580 Stream_Write_UINT16(s, CT_TILE_64x64); /* tileSize */
3581 Stream_Write_UINT8(s, codecMode); /* flags */
3582 Stream_Write_UINT8(s, CLW_COL_CONV_ICT); /* colConvBits */
3583 Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3584 Stream_Write_UINT8(s, CLW_ENTROPY_RLGR1); /* entropyBits */
3585 /* TS_RFX_ICAP (RLGR3) */
3586 Stream_Write_UINT16(s, CLW_VERSION_1_0); /* version */
3587 Stream_Write_UINT16(s, CT_TILE_64x64); /* tileSize */
3588 Stream_Write_UINT8(s, codecMode); /* flags */
3589 Stream_Write_UINT8(s, CLW_COL_CONV_ICT); /* colConvBits */
3590 Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3591 Stream_Write_UINT8(s, CLW_ENTROPY_RLGR3); /* entropyBits */
3592 return TRUE;
3593}
3594
3595/*
3596 * Write NSCODEC Client Capability Container.
3597 */
3598static BOOL rdp_write_nsc_client_capability_container(wStream* s, const rdpSettings* settings)
3599{
3600 WINPR_ASSERT(settings);
3601
3602 const BOOL fAllowDynamicFidelity = settings->NSCodecAllowDynamicColorFidelity;
3603 const BOOL fAllowSubsampling = settings->NSCodecAllowSubsampling;
3604 UINT32 colorLossLevel = settings->NSCodecColorLossLevel;
3605
3606 if (colorLossLevel < 1)
3607 colorLossLevel = 1;
3608
3609 if (colorLossLevel > 7)
3610 colorLossLevel = 7;
3611
3612 if (!Stream_EnsureRemainingCapacity(s, 8))
3613 return FALSE;
3614
3615 Stream_Write_UINT16(s, 3); /* codecPropertiesLength */
3616 /* TS_NSCODEC_CAPABILITYSET */
3617 Stream_Write_UINT8(s, fAllowDynamicFidelity != 0); /* fAllowDynamicFidelity (1 byte) */
3618 Stream_Write_UINT8(s, fAllowSubsampling != 0); /* fAllowSubsampling (1 byte) */
3619 Stream_Write_UINT8(s, (UINT8)colorLossLevel); /* colorLossLevel (1 byte) */
3620 return TRUE;
3621}
3622
3623#if defined(WITH_JPEG)
3624static 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 Stream_Write_UINT8(s, settings->JpegQuality);
3632 return TRUE;
3633}
3634#endif
3635
3636/*
3637 * Write RemoteFX Server Capability Container.
3638 */
3639static BOOL rdp_write_rfx_server_capability_container(wStream* s, const rdpSettings* settings)
3640{
3641 WINPR_UNUSED(settings);
3642 WINPR_ASSERT(settings);
3643
3644 if (!Stream_EnsureRemainingCapacity(s, 8))
3645 return FALSE;
3646
3647 Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3648 Stream_Write_UINT32(s, 0); /* reserved */
3649 return TRUE;
3650}
3651
3652#if defined(WITH_JPEG)
3653static BOOL rdp_write_jpeg_server_capability_container(wStream* s, const rdpSettings* settings)
3654{
3655 WINPR_UNUSED(settings);
3656 WINPR_ASSERT(settings);
3657
3658 if (!Stream_EnsureRemainingCapacity(s, 8))
3659 return FALSE;
3660
3661 Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3662 Stream_Write_UINT8(s, 75);
3663 return TRUE;
3664}
3665#endif
3666
3667/*
3668 * Write NSCODEC Server Capability Container.
3669 */
3670static BOOL rdp_write_nsc_server_capability_container(wStream* s, const rdpSettings* settings)
3671{
3672 WINPR_UNUSED(settings);
3673 WINPR_ASSERT(settings);
3674
3675 if (!Stream_EnsureRemainingCapacity(s, 8))
3676 return FALSE;
3677
3678 Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3679 Stream_Write_UINT32(s, 0); /* reserved */
3680 return TRUE;
3681}
3682
3683/*
3684 * Write bitmap codecs capability set.
3685 * msdn{dd891377}
3686 */
3687
3688static BOOL rdp_write_bitmap_codecs_capability_set(wLog* log, wStream* s,
3689 const rdpSettings* settings)
3690{
3691 WINPR_ASSERT(settings);
3692 if (!Stream_EnsureRemainingCapacity(s, 64))
3693 return FALSE;
3694
3695 const size_t header = rdp_capability_set_start(log, s);
3696 BYTE bitmapCodecCount = 0;
3697
3698 if (settings->RemoteFxCodec)
3699 bitmapCodecCount++;
3700
3701 if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3702 bitmapCodecCount++;
3703
3704#if defined(WITH_JPEG)
3705
3706 if (settings->JpegCodec)
3707 bitmapCodecCount++;
3708
3709#endif
3710
3711 if (settings->RemoteFxImageCodec)
3712 bitmapCodecCount++;
3713
3714 Stream_Write_UINT8(s, bitmapCodecCount);
3715
3716 if (settings->RemoteFxCodec)
3717 {
3718 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_REMOTEFX); /* codecGUID */
3719
3720 if (settings->ServerMode)
3721 {
3722 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3723
3724 if (!rdp_write_rfx_server_capability_container(s, settings))
3725 return FALSE;
3726 }
3727 else
3728 {
3729 Stream_Write_UINT8(s, RDP_CODEC_ID_REMOTEFX); /* codecID */
3730
3731 if (!rdp_write_rfx_client_capability_container(s, settings))
3732 return FALSE;
3733 }
3734 }
3735
3736 if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3737 {
3738 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_NSCODEC); /* codecGUID */
3739
3740 if (settings->ServerMode)
3741 {
3742 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3743
3744 if (!rdp_write_nsc_server_capability_container(s, settings))
3745 return FALSE;
3746 }
3747 else
3748 {
3749 Stream_Write_UINT8(s, RDP_CODEC_ID_NSCODEC); /* codecID */
3750
3751 if (!rdp_write_nsc_client_capability_container(s, settings))
3752 return FALSE;
3753 }
3754 }
3755
3756#if defined(WITH_JPEG)
3757
3758 if (settings->JpegCodec)
3759 {
3760 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_JPEG); /* codecGUID */
3761
3762 if (settings->ServerMode)
3763 {
3764 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3765
3766 if (!rdp_write_jpeg_server_capability_container(s, settings))
3767 return FALSE;
3768 }
3769 else
3770 {
3771 Stream_Write_UINT8(s, RDP_CODEC_ID_JPEG); /* codecID */
3772
3773 if (!rdp_write_jpeg_client_capability_container(s, settings))
3774 return FALSE;
3775 }
3776 }
3777
3778#endif
3779
3780 if (settings->RemoteFxImageCodec)
3781 {
3782 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_IMAGE_REMOTEFX); /* codecGUID */
3783
3784 if (settings->ServerMode)
3785 {
3786 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3787
3788 if (!rdp_write_rfx_server_capability_container(s, settings))
3789 return FALSE;
3790 }
3791 else
3792 {
3793 Stream_Write_UINT8(s, RDP_CODEC_ID_IMAGE_REMOTEFX); /* codecID */
3794
3795 if (!rdp_write_rfx_client_capability_container(s, settings))
3796 return FALSE;
3797 }
3798 }
3799
3800 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CODECS);
3801}
3802
3803#ifdef WITH_DEBUG_CAPABILITIES
3804static BOOL rdp_print_bitmap_codecs_capability_set(wLog* log, wStream* s)
3805{
3806 GUID codecGuid = WINPR_C_ARRAY_INIT;
3807 BYTE bitmapCodecCount = 0;
3808 BYTE codecId = 0;
3809 UINT16 codecPropertiesLength = 0;
3810
3811 WLog_Print(log, WLOG_TRACE,
3812 "BitmapCodecsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3813
3814 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3815 return FALSE;
3816
3817 Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3818 WLog_Print(log, WLOG_TRACE, "\tbitmapCodecCount: %" PRIu8 "", bitmapCodecCount);
3819
3820 while (bitmapCodecCount > 0)
3821 {
3822 if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3823 return FALSE;
3824 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3825 return FALSE;
3826 Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3827 WLog_Print(log, WLOG_TRACE, "\tcodecGuid: 0x");
3828 rdp_print_bitmap_codec_guid(log, &codecGuid);
3829 WLog_Print(log, WLOG_TRACE, " (%s)", rdp_get_bitmap_codec_guid_name(&codecGuid));
3830 WLog_Print(log, WLOG_TRACE, "\tcodecId: %" PRIu8 "", codecId);
3831 Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3832 WLog_Print(log, WLOG_TRACE, "\tcodecPropertiesLength: %" PRIu16 "", codecPropertiesLength);
3833
3834 if (!Stream_SafeSeek(s, codecPropertiesLength)) /* codecProperties */
3835 return FALSE;
3836 bitmapCodecCount--;
3837 }
3838
3839 return TRUE;
3840}
3841#endif
3842
3843static BOOL rdp_apply_frame_acknowledge_capability_set(rdpSettings* settings,
3844 const rdpSettings* src)
3845{
3846 WINPR_ASSERT(settings);
3847 WINPR_ASSERT(src);
3848
3849 if (settings->ServerMode)
3850 settings->FrameAcknowledge = src->FrameAcknowledge;
3851
3852 return TRUE;
3853}
3854
3855/*
3856 * Read frame acknowledge capability set.
3857 */
3858
3859static BOOL rdp_read_frame_acknowledge_capability_set(wLog* log, wStream* s, rdpSettings* settings)
3860{
3861 WINPR_ASSERT(settings);
3862 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3863 return FALSE;
3864
3865 Stream_Read_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3866
3867 return TRUE;
3868}
3869
3870/*
3871 * Write frame acknowledge capability set.
3872 */
3873
3874static BOOL rdp_write_frame_acknowledge_capability_set(wLog* log, wStream* s,
3875 const rdpSettings* settings)
3876{
3877 WINPR_ASSERT(settings);
3878 if (!Stream_EnsureRemainingCapacity(s, 32))
3879 return FALSE;
3880
3881 const size_t header = rdp_capability_set_start(log, s);
3882 Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3883 return rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE);
3884}
3885
3886#ifdef WITH_DEBUG_CAPABILITIES
3887static BOOL rdp_print_frame_acknowledge_capability_set(wLog* log, wStream* s)
3888{
3889 UINT32 frameAcknowledge = 0;
3890 WLog_Print(log, WLOG_TRACE,
3891 "FrameAcknowledgeCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3892
3893 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3894 return FALSE;
3895
3896 Stream_Read_UINT32(s, frameAcknowledge); /* frameAcknowledge (4 bytes) */
3897 WLog_Print(log, WLOG_TRACE, "\tframeAcknowledge: 0x%08" PRIX32 "", frameAcknowledge);
3898 return TRUE;
3899}
3900#endif
3901
3902static BOOL rdp_apply_bitmap_cache_v3_codec_id_capability_set(rdpSettings* settings,
3903 const rdpSettings* src)
3904{
3905 WINPR_ASSERT(settings);
3906 WINPR_ASSERT(src);
3907
3908 settings->BitmapCacheV3CodecId = src->BitmapCacheV3CodecId;
3909 return TRUE;
3910}
3911
3912static BOOL rdp_read_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3913 rdpSettings* settings)
3914{
3915 BYTE bitmapCacheV3CodecId = 0;
3916
3917 WINPR_ASSERT(settings);
3918 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3919 return FALSE;
3920
3921 Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3922 settings->BitmapCacheV3CodecId = bitmapCacheV3CodecId;
3923 return TRUE;
3924}
3925
3926static BOOL rdp_write_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3927 const rdpSettings* settings)
3928{
3929 WINPR_ASSERT(settings);
3930 if (!Stream_EnsureRemainingCapacity(s, 32))
3931 return FALSE;
3932
3933 const size_t header = rdp_capability_set_start(log, s);
3934 if (settings->BitmapCacheV3CodecId > UINT8_MAX)
3935 return FALSE;
3936 Stream_Write_UINT8(s, (UINT8)settings->BitmapCacheV3CodecId);
3937 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID);
3938}
3939
3940#ifdef WITH_DEBUG_CAPABILITIES
3941static BOOL rdp_print_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s)
3942{
3943 BYTE bitmapCacheV3CodecId = 0;
3944 WLog_Print(log, WLOG_TRACE, "BitmapCacheV3CodecIdCapabilitySet (length %" PRIuz "):",
3945 Stream_GetRemainingLength(s));
3946
3947 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3948 return FALSE;
3949
3950 Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3951 WLog_Print(log, WLOG_TRACE, "\tbitmapCacheV3CodecId: 0x%02" PRIX8 "", bitmapCacheV3CodecId);
3952 return TRUE;
3953}
3954
3955BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving)
3956{
3957 BOOL rc = FALSE;
3958 UINT16 type = 0;
3959 UINT16 length = 0;
3960 UINT16 numberCapabilities = 0;
3961
3962 size_t pos = Stream_GetPosition(s);
3963
3964 if (!Stream_SetPosition(s, start))
3965 goto fail;
3966
3967 if (receiving)
3968 {
3969 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3970 goto fail;
3971 }
3972 else
3973 {
3974 if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), 4))
3975 goto fail;
3976 }
3977
3978 Stream_Read_UINT16(s, numberCapabilities);
3979 Stream_Seek(s, 2);
3980
3981 while (numberCapabilities > 0)
3982 {
3983 size_t rest = 0;
3984 wStream subBuffer;
3985 wStream* sub = nullptr;
3986
3987 if (!rdp_read_capability_set_header(log, s, &length, &type))
3988 goto fail;
3989
3990 WLog_Print(log, WLOG_TRACE, "%s ", receiving ? "Receiving" : "Sending");
3991 sub = Stream_StaticInit(&subBuffer, Stream_Pointer(s), length - 4);
3992 if (!Stream_SafeSeek(s, length - 4))
3993 goto fail;
3994
3995 switch (type)
3996 {
3997 case CAPSET_TYPE_GENERAL:
3998 if (!rdp_print_general_capability_set(log, sub))
3999 goto fail;
4000
4001 break;
4002
4003 case CAPSET_TYPE_BITMAP:
4004 if (!rdp_print_bitmap_capability_set(log, sub))
4005 goto fail;
4006
4007 break;
4008
4009 case CAPSET_TYPE_ORDER:
4010 if (!rdp_print_order_capability_set(log, sub))
4011 goto fail;
4012
4013 break;
4014
4015 case CAPSET_TYPE_BITMAP_CACHE:
4016 if (!rdp_print_bitmap_cache_capability_set(log, sub))
4017 goto fail;
4018
4019 break;
4020
4021 case CAPSET_TYPE_CONTROL:
4022 if (!rdp_print_control_capability_set(log, sub))
4023 goto fail;
4024
4025 break;
4026
4027 case CAPSET_TYPE_ACTIVATION:
4028 if (!rdp_print_window_activation_capability_set(log, sub))
4029 goto fail;
4030
4031 break;
4032
4033 case CAPSET_TYPE_POINTER:
4034 if (!rdp_print_pointer_capability_set(log, sub))
4035 goto fail;
4036
4037 break;
4038
4039 case CAPSET_TYPE_SHARE:
4040 if (!rdp_print_share_capability_set(log, sub))
4041 goto fail;
4042
4043 break;
4044
4045 case CAPSET_TYPE_COLOR_CACHE:
4046 if (!rdp_print_color_cache_capability_set(log, sub))
4047 goto fail;
4048
4049 break;
4050
4051 case CAPSET_TYPE_SOUND:
4052 if (!rdp_print_sound_capability_set(log, sub))
4053 goto fail;
4054
4055 break;
4056
4057 case CAPSET_TYPE_INPUT:
4058 if (!rdp_print_input_capability_set(log, sub))
4059 goto fail;
4060
4061 break;
4062
4063 case CAPSET_TYPE_FONT:
4064 if (!rdp_print_font_capability_set(log, sub))
4065 goto fail;
4066
4067 break;
4068
4069 case CAPSET_TYPE_BRUSH:
4070 if (!rdp_print_brush_capability_set(log, sub))
4071 goto fail;
4072
4073 break;
4074
4075 case CAPSET_TYPE_GLYPH_CACHE:
4076 if (!rdp_print_glyph_cache_capability_set(log, sub))
4077 goto fail;
4078
4079 break;
4080
4081 case CAPSET_TYPE_OFFSCREEN_CACHE:
4082 if (!rdp_print_offscreen_bitmap_cache_capability_set(log, sub))
4083 goto fail;
4084
4085 break;
4086
4087 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4088 if (!rdp_print_bitmap_cache_host_support_capability_set(log, sub))
4089 goto fail;
4090
4091 break;
4092
4093 case CAPSET_TYPE_BITMAP_CACHE_V2:
4094 if (!rdp_print_bitmap_cache_v2_capability_set(log, sub))
4095 goto fail;
4096
4097 break;
4098
4099 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4100 if (!rdp_print_virtual_channel_capability_set(log, sub))
4101 goto fail;
4102
4103 break;
4104
4105 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4106 if (!rdp_print_draw_nine_grid_cache_capability_set(log, sub))
4107 goto fail;
4108
4109 break;
4110
4111 case CAPSET_TYPE_DRAW_GDI_PLUS:
4112 if (!rdp_print_draw_gdiplus_cache_capability_set(log, sub))
4113 goto fail;
4114
4115 break;
4116
4117 case CAPSET_TYPE_RAIL:
4118 if (!rdp_print_remote_programs_capability_set(log, sub))
4119 goto fail;
4120
4121 break;
4122
4123 case CAPSET_TYPE_WINDOW:
4124 if (!rdp_print_window_list_capability_set(log, sub))
4125 goto fail;
4126
4127 break;
4128
4129 case CAPSET_TYPE_COMP_DESK:
4130 if (!rdp_print_desktop_composition_capability_set(log, sub))
4131 goto fail;
4132
4133 break;
4134
4135 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4136 if (!rdp_print_multifragment_update_capability_set(log, sub))
4137 goto fail;
4138
4139 break;
4140
4141 case CAPSET_TYPE_LARGE_POINTER:
4142 if (!rdp_print_large_pointer_capability_set(log, sub))
4143 goto fail;
4144
4145 break;
4146
4147 case CAPSET_TYPE_SURFACE_COMMANDS:
4148 if (!rdp_print_surface_commands_capability_set(log, sub))
4149 goto fail;
4150
4151 break;
4152
4153 case CAPSET_TYPE_BITMAP_CODECS:
4154 if (!rdp_print_bitmap_codecs_capability_set(log, sub))
4155 goto fail;
4156
4157 break;
4158
4159 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4160 if (!rdp_print_frame_acknowledge_capability_set(log, sub))
4161 goto fail;
4162
4163 break;
4164
4165 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4166 if (!rdp_print_bitmap_cache_v3_codec_id_capability_set(log, sub))
4167 goto fail;
4168
4169 break;
4170
4171 default:
4172 WLog_Print(log, WLOG_ERROR, "unknown capability type %" PRIu16 "", type);
4173 break;
4174 }
4175
4176 rest = Stream_GetRemainingLength(sub);
4177 if (rest > 0)
4178 {
4179 WLog_Print(log, WLOG_WARN,
4180 "incorrect capability offset, type:0x%04" PRIX16 " %" PRIu16
4181 " bytes expected, %" PRIuz "bytes remaining",
4182 type, length, rest);
4183 }
4184
4185 numberCapabilities--;
4186 }
4187
4188 rc = TRUE;
4189fail:
4190 if (!Stream_SetPosition(s, pos))
4191 return FALSE;
4192
4193 return rc;
4194}
4195#endif
4196
4197static BOOL rdp_apply_from_received(UINT16 type, rdpSettings* dst, const rdpSettings* src)
4198{
4199 switch (type)
4200 {
4201 case CAPSET_TYPE_GENERAL:
4202 return rdp_apply_general_capability_set(dst, src);
4203 case CAPSET_TYPE_BITMAP:
4204 return rdp_apply_bitmap_capability_set(dst, src);
4205 case CAPSET_TYPE_ORDER:
4206 return rdp_apply_order_capability_set(dst, src);
4207 case CAPSET_TYPE_POINTER:
4208 return rdp_apply_pointer_capability_set(dst, src);
4209 case CAPSET_TYPE_INPUT:
4210 return rdp_apply_input_capability_set(dst, src);
4211 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4212 return rdp_apply_virtual_channel_capability_set(dst, src);
4213 case CAPSET_TYPE_SHARE:
4214 return rdp_apply_share_capability_set(dst, src);
4215 case CAPSET_TYPE_COLOR_CACHE:
4216 return rdp_apply_color_cache_capability_set(dst, src);
4217 case CAPSET_TYPE_FONT:
4218 return rdp_apply_font_capability_set(dst, src);
4219 case CAPSET_TYPE_DRAW_GDI_PLUS:
4220 return rdp_apply_draw_gdiplus_cache_capability_set(dst, src);
4221 case CAPSET_TYPE_RAIL:
4222 return rdp_apply_remote_programs_capability_set(dst, src);
4223 case CAPSET_TYPE_WINDOW:
4224 return rdp_apply_window_list_capability_set(dst, src);
4225 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4226 return rdp_apply_multifragment_update_capability_set(dst, src);
4227 case CAPSET_TYPE_LARGE_POINTER:
4228 return rdp_apply_large_pointer_capability_set(dst, src);
4229 case CAPSET_TYPE_COMP_DESK:
4230 return rdp_apply_desktop_composition_capability_set(dst, src);
4231 case CAPSET_TYPE_SURFACE_COMMANDS:
4232 return rdp_apply_surface_commands_capability_set(dst, src);
4233 case CAPSET_TYPE_BITMAP_CODECS:
4234 return rdp_apply_bitmap_codecs_capability_set(dst, src);
4235 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4236 return rdp_apply_frame_acknowledge_capability_set(dst, src);
4237 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4238 return rdp_apply_bitmap_cache_v3_codec_id_capability_set(dst, src);
4239 case CAPSET_TYPE_BITMAP_CACHE:
4240 return rdp_apply_bitmap_cache_capability_set(dst, src);
4241 case CAPSET_TYPE_BITMAP_CACHE_V2:
4242 return rdp_apply_bitmap_cache_v2_capability_set(dst, src);
4243 case CAPSET_TYPE_BRUSH:
4244 return rdp_apply_brush_capability_set(dst, src);
4245 case CAPSET_TYPE_GLYPH_CACHE:
4246 return rdp_apply_glyph_cache_capability_set(dst, src);
4247 case CAPSET_TYPE_OFFSCREEN_CACHE:
4248 return rdp_apply_offscreen_bitmap_cache_capability_set(dst, src);
4249 case CAPSET_TYPE_SOUND:
4250 return rdp_apply_sound_capability_set(dst, src);
4251 case CAPSET_TYPE_CONTROL:
4252 return rdp_apply_control_capability_set(dst, src);
4253 case CAPSET_TYPE_ACTIVATION:
4254 return rdp_apply_window_activation_capability_set(dst, src);
4255 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4256 return rdp_apply_draw_nine_grid_cache_capability_set(dst, src);
4257 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4258 return rdp_apply_bitmap_cache_host_support_capability_set(dst, src);
4259 default:
4260 return TRUE;
4261 }
4262}
4263
4264BOOL rdp_read_capability_set(wLog* log, wStream* sub, UINT16 type, rdpSettings* settings,
4265 BOOL isServer)
4266{
4267 WINPR_ASSERT(settings);
4268
4269 if (type <= CAPSET_TYPE_FRAME_ACKNOWLEDGE)
4270 {
4271 const size_t size = Stream_Length(sub);
4272 if (size > UINT32_MAX)
4273 return FALSE;
4274
4275 WINPR_ASSERT(settings->ReceivedCapabilities);
4276 settings->ReceivedCapabilities[type] = TRUE;
4277
4278 WINPR_ASSERT(settings->ReceivedCapabilityDataSizes);
4279 settings->ReceivedCapabilityDataSizes[type] = (UINT32)size;
4280
4281 WINPR_ASSERT(settings->ReceivedCapabilityData);
4282 void* tmp = realloc(settings->ReceivedCapabilityData[type], size);
4283 if (!tmp && (size > 0))
4284 return FALSE;
4285 memcpy(tmp, Stream_Buffer(sub), size);
4286 settings->ReceivedCapabilityData[type] = tmp;
4287 }
4288 else
4289 WLog_Print(log, WLOG_WARN, "not handling capability type %" PRIu16 " yet", type);
4290
4291 BOOL treated = TRUE;
4292
4293 switch (type)
4294 {
4295 case CAPSET_TYPE_GENERAL:
4296 if (!rdp_read_general_capability_set(log, sub, settings))
4297 return FALSE;
4298
4299 break;
4300
4301 case CAPSET_TYPE_BITMAP:
4302 if (!rdp_read_bitmap_capability_set(log, sub, settings))
4303 return FALSE;
4304
4305 break;
4306
4307 case CAPSET_TYPE_ORDER:
4308 if (!rdp_read_order_capability_set(log, sub, settings))
4309 return FALSE;
4310
4311 break;
4312
4313 case CAPSET_TYPE_POINTER:
4314 if (!rdp_read_pointer_capability_set(log, sub, settings))
4315 return FALSE;
4316
4317 break;
4318
4319 case CAPSET_TYPE_INPUT:
4320 if (!rdp_read_input_capability_set(log, sub, settings))
4321 return FALSE;
4322
4323 break;
4324
4325 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4326 if (!rdp_read_virtual_channel_capability_set(log, sub, settings))
4327 return FALSE;
4328
4329 break;
4330
4331 case CAPSET_TYPE_SHARE:
4332 if (!rdp_read_share_capability_set(log, sub, settings))
4333 return FALSE;
4334
4335 break;
4336
4337 case CAPSET_TYPE_COLOR_CACHE:
4338 if (!rdp_read_color_cache_capability_set(log, sub, settings))
4339 return FALSE;
4340
4341 break;
4342
4343 case CAPSET_TYPE_FONT:
4344 if (!rdp_read_font_capability_set(log, sub, settings))
4345 return FALSE;
4346
4347 break;
4348
4349 case CAPSET_TYPE_DRAW_GDI_PLUS:
4350 if (!rdp_read_draw_gdiplus_cache_capability_set(log, sub, settings))
4351 return FALSE;
4352
4353 break;
4354
4355 case CAPSET_TYPE_RAIL:
4356 if (!rdp_read_remote_programs_capability_set(log, sub, settings))
4357 return FALSE;
4358
4359 break;
4360
4361 case CAPSET_TYPE_WINDOW:
4362 if (!rdp_read_window_list_capability_set(log, sub, settings))
4363 return FALSE;
4364
4365 break;
4366
4367 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4368 if (!rdp_read_multifragment_update_capability_set(log, sub, settings))
4369 return FALSE;
4370
4371 break;
4372
4373 case CAPSET_TYPE_LARGE_POINTER:
4374 if (!rdp_read_large_pointer_capability_set(log, sub, settings))
4375 return FALSE;
4376
4377 break;
4378
4379 case CAPSET_TYPE_COMP_DESK:
4380 if (!rdp_read_desktop_composition_capability_set(log, sub, settings))
4381 return FALSE;
4382
4383 break;
4384
4385 case CAPSET_TYPE_SURFACE_COMMANDS:
4386 if (!rdp_read_surface_commands_capability_set(log, sub, settings))
4387 return FALSE;
4388
4389 break;
4390
4391 case CAPSET_TYPE_BITMAP_CODECS:
4392 if (!rdp_read_bitmap_codecs_capability_set(log, sub, settings, isServer))
4393 return FALSE;
4394
4395 break;
4396
4397 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4398 if (!rdp_read_frame_acknowledge_capability_set(log, sub, settings))
4399 return FALSE;
4400
4401 break;
4402
4403 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4404 if (!rdp_read_bitmap_cache_v3_codec_id_capability_set(log, sub, settings))
4405 return FALSE;
4406
4407 break;
4408
4409 default:
4410 treated = FALSE;
4411 break;
4412 }
4413
4414 if (!treated)
4415 {
4416 if (isServer)
4417 {
4418 /* treating capabilities that are supposed to be send only from the client */
4419 switch (type)
4420 {
4421 case CAPSET_TYPE_BITMAP_CACHE:
4422 if (!rdp_read_bitmap_cache_capability_set(log, sub, settings))
4423 return FALSE;
4424
4425 break;
4426
4427 case CAPSET_TYPE_BITMAP_CACHE_V2:
4428 if (!rdp_read_bitmap_cache_v2_capability_set(log, sub, settings))
4429 return FALSE;
4430
4431 break;
4432
4433 case CAPSET_TYPE_BRUSH:
4434 if (!rdp_read_brush_capability_set(log, sub, settings))
4435 return FALSE;
4436
4437 break;
4438
4439 case CAPSET_TYPE_GLYPH_CACHE:
4440 if (!rdp_read_glyph_cache_capability_set(log, sub, settings))
4441 return FALSE;
4442
4443 break;
4444
4445 case CAPSET_TYPE_OFFSCREEN_CACHE:
4446 if (!rdp_read_offscreen_bitmap_cache_capability_set(log, sub, settings))
4447 return FALSE;
4448
4449 break;
4450
4451 case CAPSET_TYPE_SOUND:
4452 if (!rdp_read_sound_capability_set(log, sub, settings))
4453 return FALSE;
4454
4455 break;
4456
4457 case CAPSET_TYPE_CONTROL:
4458 if (!rdp_read_control_capability_set(log, sub, settings))
4459 return FALSE;
4460
4461 break;
4462
4463 case CAPSET_TYPE_ACTIVATION:
4464 if (!rdp_read_window_activation_capability_set(log, sub, settings))
4465 return FALSE;
4466
4467 break;
4468
4469 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4470 if (!rdp_read_draw_nine_grid_cache_capability_set(log, sub, settings))
4471 return FALSE;
4472
4473 break;
4474
4475 default:
4476 WLog_Print(log, WLOG_ERROR,
4477 "capability %s(%" PRIu16 ") not expected from client",
4478 get_capability_name(type), type);
4479 return FALSE;
4480 }
4481 }
4482 else
4483 {
4484 /* treating capabilities that are supposed to be send only from the server */
4485 switch (type)
4486 {
4487 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4488 if (!rdp_read_bitmap_cache_host_support_capability_set(log, sub, settings))
4489 return FALSE;
4490
4491 break;
4492
4493 default:
4494 WLog_Print(log, WLOG_ERROR,
4495 "capability %s(%" PRIu16 ") not expected from server",
4496 get_capability_name(type), type);
4497 return FALSE;
4498 }
4499 }
4500 }
4501
4502 const size_t rest = Stream_GetRemainingLength(sub);
4503 if (rest > 0)
4504 {
4505 const size_t length = Stream_Capacity(sub);
4506 WLog_Print(log, WLOG_ERROR,
4507 "incorrect offset, type:0x%04" PRIx16 " actual:%" PRIuz " expected:%" PRIuz "",
4508 type, length - rest, length);
4509 }
4510 return TRUE;
4511}
4512
4513static BOOL rdp_read_capability_sets(wLog* log, wStream* s, rdpSettings* settings,
4514 rdpSettings* rcvSettings, UINT16 totalLength)
4515{
4516 BOOL rc = FALSE;
4517 size_t start = 0;
4518 size_t end = 0;
4519 size_t len = 0;
4520 UINT16 numberCapabilities = 0;
4521 UINT16 count = 0;
4522
4523#ifdef WITH_DEBUG_CAPABILITIES
4524 const size_t capstart = Stream_GetPosition(s);
4525#endif
4526
4527 WINPR_ASSERT(s);
4528 WINPR_ASSERT(settings);
4529
4530 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4531 return FALSE;
4532
4533 Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4534 Stream_Seek(s, 2); /* pad2Octets (2 bytes) */
4535 count = numberCapabilities;
4536
4537 start = Stream_GetPosition(s);
4538 while (numberCapabilities > 0 && Stream_GetRemainingLength(s) >= 4)
4539 {
4540 UINT16 type = 0;
4541 UINT16 length = 0;
4542 wStream subbuffer;
4543 wStream* sub = nullptr;
4544
4545 if (!rdp_read_capability_set_header(log, s, &length, &type))
4546 goto fail;
4547 sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), length - 4);
4548 if (!Stream_SafeSeek(s, length - 4))
4549 goto fail;
4550
4551 if (!rdp_read_capability_set(log, sub, type, rcvSettings, settings->ServerMode))
4552 goto fail;
4553
4554 if (!rdp_apply_from_received(type, settings, rcvSettings))
4555 goto fail;
4556 numberCapabilities--;
4557 }
4558
4559 end = Stream_GetPosition(s);
4560 len = end - start;
4561
4562 if (numberCapabilities)
4563 {
4564 WLog_Print(log, WLOG_ERROR,
4565 "strange we haven't read the number of announced capacity sets, read=%d "
4566 "expected=%" PRIu16 "",
4567 count - numberCapabilities, count);
4568 }
4569
4570#ifdef WITH_DEBUG_CAPABILITIES
4571 rdp_print_capability_sets(log, s, capstart, TRUE);
4572#endif
4573
4574 if (len > totalLength)
4575 {
4576 WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIuz,
4577 totalLength, len);
4578 goto fail;
4579 }
4580 rc = freerdp_capability_buffer_copy(settings, rcvSettings);
4581fail:
4582 return rc;
4583}
4584
4585BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId, UINT16* length)
4586{
4587 WINPR_ASSERT(rdp);
4588 WINPR_ASSERT(rdp->context);
4589
4590 if (!rdp_read_header(rdp, s, length, pChannelId))
4591 return FALSE;
4592
4593 if (freerdp_shall_disconnect_context(rdp->context))
4594 return TRUE;
4595
4596 if (*pChannelId != MCS_GLOBAL_CHANNEL_ID)
4597 {
4598 UINT16 mcsMessageChannelId = rdp->mcs->messageChannelId;
4599
4600 if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId))
4601 {
4602 WLog_Print(rdp->log, WLOG_ERROR, "unexpected MCS channel id %04" PRIx16 " received",
4603 *pChannelId);
4604 return FALSE;
4605 }
4606 }
4607
4608 return TRUE;
4609}
4610
4611BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s, UINT16 pduSource, UINT16 length)
4612{
4613 UINT16 lengthSourceDescriptor = 0;
4614 UINT16 lengthCombinedCapabilities = 0;
4615
4616 WINPR_ASSERT(rdp);
4617 WINPR_ASSERT(rdp->settings);
4618 WINPR_ASSERT(rdp->context);
4619 WINPR_ASSERT(s);
4620
4621 rdp->settings->PduSource = pduSource;
4622
4623 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 8))
4624 return FALSE;
4625
4626 Stream_Read_UINT32(s, rdp->settings->ShareId); /* shareId (4 bytes) */
4627 Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4628 Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4629
4630 if (!Stream_SafeSeek(s, lengthSourceDescriptor) ||
4631 !Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4)) /* sourceDescriptor */
4632 return FALSE;
4633
4634 /* capabilitySets */
4635 if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4636 lengthCombinedCapabilities))
4637 {
4638 WLog_Print(rdp->log, WLOG_ERROR, "rdp_read_capability_sets failed");
4639 return FALSE;
4640 }
4641
4642 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4))
4643 return FALSE;
4644
4645 /* [MS-RDPBCGR] 2.2.1.13.1.1 Demand Active PDU Data (TS_DEMAND_ACTIVE_PDU)::sessionId
4646 * is ignored by client */
4647 Stream_Seek_UINT32(s); /* SessionId */
4648
4649 {
4650 rdp_secondary_update_internal* secondary = secondary_update_cast(rdp->update->secondary);
4651 secondary->glyph_v2 = (rdp->settings->GlyphSupportLevel > GLYPH_SUPPORT_FULL);
4652 }
4653
4654 return tpkt_ensure_stream_consumed(rdp->log, s, length);
4655}
4656
4657static BOOL rdp_write_demand_active(wLog* log, wStream* s, rdpSettings* settings)
4658{
4659 size_t bm = 0;
4660 size_t em = 0;
4661 size_t lm = 0;
4662 UINT16 numberCapabilities = 0;
4663 size_t lengthCombinedCapabilities = 0;
4664
4665 if (!Stream_EnsureRemainingCapacity(s, 64))
4666 return FALSE;
4667
4668 Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4669 Stream_Write_UINT16(s, 4); /* lengthSourceDescriptor (2 bytes) */
4670 lm = Stream_GetPosition(s);
4671 Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4672 Stream_Write(s, "RDP", 4); /* sourceDescriptor */
4673 bm = Stream_GetPosition(s);
4674 Stream_Seek_UINT16(s); /* numberCapabilities (2 bytes) */
4675 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4676 numberCapabilities = 14;
4677
4678 if (!rdp_write_general_capability_set(log, s, settings) ||
4679 !rdp_write_bitmap_capability_set(log, s, settings) ||
4680 !rdp_write_order_capability_set(log, s, settings) ||
4681 !rdp_write_pointer_capability_set(log, s, settings) ||
4682 !rdp_write_input_capability_set(log, s, settings) ||
4683 !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4684 !rdp_write_share_capability_set(log, s, settings) ||
4685 !rdp_write_font_capability_set(log, s, settings) ||
4686 !rdp_write_multifragment_update_capability_set(log, s, settings) ||
4687 !rdp_write_large_pointer_capability_set(log, s, settings) ||
4688 !rdp_write_desktop_composition_capability_set(log, s, settings) ||
4689 !rdp_write_surface_commands_capability_set(log, s, settings) ||
4690 !rdp_write_bitmap_codecs_capability_set(log, s, settings) ||
4691 !rdp_write_frame_acknowledge_capability_set(log, s, settings))
4692 {
4693 return FALSE;
4694 }
4695
4696 if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
4697 {
4698 numberCapabilities++;
4699
4700 if (!rdp_write_bitmap_cache_host_support_capability_set(log, s, settings))
4701 return FALSE;
4702 }
4703
4704 if (settings->RemoteApplicationMode)
4705 {
4706 numberCapabilities += 2;
4707
4708 if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4709 !rdp_write_window_list_capability_set(log, s, settings))
4710 return FALSE;
4711 }
4712
4713 em = Stream_GetPosition(s);
4714 if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4715 return FALSE;
4716 lengthCombinedCapabilities = (em - bm);
4717 if (lengthCombinedCapabilities > UINT16_MAX)
4718 return FALSE;
4719 Stream_Write_UINT16(
4720 s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4721 if (!Stream_SetPosition(s, bm)) /* go back to numberCapabilities */
4722 return FALSE;
4723 Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4724#ifdef WITH_DEBUG_CAPABILITIES
4725 rdp_print_capability_sets(log, s, bm, FALSE);
4726#endif
4727 if (!Stream_SetPosition(s, em))
4728 return FALSE;
4729 Stream_Write_UINT32(s, 0); /* sessionId */
4730 return TRUE;
4731}
4732
4733BOOL rdp_send_demand_active(rdpRdp* rdp)
4734{
4735 UINT16 sec_flags = 0;
4736 wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4737 BOOL status = 0;
4738
4739 if (!s)
4740 return FALSE;
4741
4742 rdp->settings->ShareId = 0x10000 + rdp->mcs->userId;
4743 status = rdp_write_demand_active(rdp->log, s, rdp->settings) &&
4744 rdp_send_pdu(rdp, s, PDU_TYPE_DEMAND_ACTIVE, rdp->mcs->userId, sec_flags);
4745 Stream_Release(s);
4746 return status;
4747}
4748
4749BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength)
4750{
4751 rdpSettings* settings = nullptr;
4752 UINT16 lengthSourceDescriptor = 0;
4753 UINT16 lengthCombinedCapabilities = 0;
4754
4755 WINPR_ASSERT(rdp);
4756 WINPR_ASSERT(s);
4757 settings = rdp->settings;
4758 WINPR_ASSERT(settings);
4759
4760 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 10))
4761 return FALSE;
4762
4763 Stream_Seek_UINT32(s); /* shareId (4 bytes) */
4764 Stream_Seek_UINT16(s); /* originatorId (2 bytes) */
4765 Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4766 Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4767
4768 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, lengthSourceDescriptor + 4U))
4769 return FALSE;
4770
4771 Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor */
4772 if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4773 lengthCombinedCapabilities))
4774 return FALSE;
4775
4776 if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4777 {
4778 /* client does not support surface commands */
4779 settings->SurfaceCommandsEnabled = FALSE;
4780 settings->SurfaceFrameMarkerEnabled = FALSE;
4781 }
4782
4783 if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4784 {
4785 /* client does not support frame acks */
4786 settings->FrameAcknowledge = 0;
4787 }
4788
4789 if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4790 {
4791 /* client does not support bitmap cache v3 */
4792 settings->BitmapCacheV3Enabled = FALSE;
4793 }
4794
4795 if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4796 {
4797 /* client does not support bitmap codecs */
4798 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, FALSE))
4799 return FALSE;
4800 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, FALSE))
4801 return FALSE;
4802 if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
4803 return FALSE;
4804 }
4805
4806 if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4807 {
4808 /* client does not support multi fragment updates - make sure packages are not fragmented */
4809 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
4810 FASTPATH_FRAGMENT_SAFE_SIZE))
4811 return FALSE;
4812 }
4813
4814 if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4815 {
4816 /* client does not support large pointers */
4817 settings->LargePointerFlag = 0;
4818 }
4819
4820 return tpkt_ensure_stream_consumed(rdp->log, s, pduLength);
4821}
4822
4823static BOOL rdp_write_confirm_active(wLog* log, wStream* s, rdpSettings* settings)
4824{
4825 size_t bm = 0;
4826 size_t em = 0;
4827 size_t lm = 0;
4828 UINT16 numberCapabilities = 0;
4829 UINT16 lengthSourceDescriptor = 0;
4830 size_t lengthCombinedCapabilities = 0;
4831 BOOL ret = 0;
4832
4833 WINPR_ASSERT(settings);
4834
4835 lengthSourceDescriptor = sizeof(SOURCE_DESCRIPTOR);
4836 Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4837 Stream_Write_UINT16(s, 0x03EA); /* originatorId (2 bytes) */
4838 Stream_Write_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4839 lm = Stream_GetPosition(s);
4840 Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4841 Stream_Write(s, SOURCE_DESCRIPTOR, lengthSourceDescriptor); /* sourceDescriptor */
4842 bm = Stream_GetPosition(s);
4843 Stream_Seek_UINT16(s); /* numberCapabilities (2 bytes) */
4844 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4845 /* Capability Sets */
4846 numberCapabilities = 15;
4847
4848 if (!rdp_write_general_capability_set(log, s, settings) ||
4849 !rdp_write_bitmap_capability_set(log, s, settings) ||
4850 !rdp_write_order_capability_set(log, s, settings))
4851 return FALSE;
4852
4853 if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
4854 ret = rdp_write_bitmap_cache_v2_capability_set(log, s, settings);
4855 else
4856 ret = rdp_write_bitmap_cache_capability_set(log, s, settings);
4857
4858 if (!ret)
4859 return FALSE;
4860
4861 if (!rdp_write_pointer_capability_set(log, s, settings) ||
4862 !rdp_write_input_capability_set(log, s, settings) ||
4863 !rdp_write_brush_capability_set(log, s, settings) ||
4864 !rdp_write_glyph_cache_capability_set(log, s, settings) ||
4865 !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4866 !rdp_write_sound_capability_set(log, s, settings) ||
4867 !rdp_write_share_capability_set(log, s, settings) ||
4868 !rdp_write_font_capability_set(log, s, settings) ||
4869 !rdp_write_control_capability_set(log, s, settings) ||
4870 !rdp_write_color_cache_capability_set(log, s, settings) ||
4871 !rdp_write_window_activation_capability_set(log, s, settings))
4872 {
4873 return FALSE;
4874 }
4875
4876 {
4877 numberCapabilities++;
4878
4879 if (!rdp_write_offscreen_bitmap_cache_capability_set(log, s, settings))
4880 return FALSE;
4881 }
4882
4883 if (settings->DrawNineGridEnabled)
4884 {
4885 numberCapabilities++;
4886
4887 if (!rdp_write_draw_nine_grid_cache_capability_set(log, s, settings))
4888 return FALSE;
4889 }
4890
4891 if (settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4892 {
4893 if (settings->LargePointerFlag)
4894 {
4895 numberCapabilities++;
4896
4897 if (!rdp_write_large_pointer_capability_set(log, s, settings))
4898 return FALSE;
4899 }
4900 }
4901
4902 if (settings->RemoteApplicationMode)
4903 {
4904 numberCapabilities += 2;
4905
4906 if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4907 !rdp_write_window_list_capability_set(log, s, settings))
4908 return FALSE;
4909 }
4910
4911 if (settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4912 {
4913 numberCapabilities++;
4914
4915 if (!rdp_write_multifragment_update_capability_set(log, s, settings))
4916 return FALSE;
4917 }
4918
4919 if (settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4920 {
4921 numberCapabilities++;
4922
4923 if (!rdp_write_surface_commands_capability_set(log, s, settings))
4924 return FALSE;
4925 }
4926
4927 if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4928 {
4929 numberCapabilities++;
4930
4931 if (!rdp_write_bitmap_codecs_capability_set(log, s, settings))
4932 return FALSE;
4933 }
4934
4935 if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4936 settings->FrameAcknowledge = 0;
4937
4938 if (settings->FrameAcknowledge)
4939 {
4940 numberCapabilities++;
4941
4942 if (!rdp_write_frame_acknowledge_capability_set(log, s, settings))
4943 return FALSE;
4944 }
4945
4946 if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4947 {
4948 if (settings->BitmapCacheV3CodecId != 0)
4949 {
4950 numberCapabilities++;
4951
4952 if (!rdp_write_bitmap_cache_v3_codec_id_capability_set(log, s, settings))
4953 return FALSE;
4954 }
4955 }
4956
4957 em = Stream_GetPosition(s);
4958 if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4959 return FALSE;
4960 lengthCombinedCapabilities = (em - bm);
4961 if (lengthCombinedCapabilities > UINT16_MAX)
4962 return FALSE;
4963 Stream_Write_UINT16(
4964 s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4965 if (!Stream_SetPosition(s, bm)) /* go back to numberCapabilities */
4966 return FALSE;
4967 Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4968#ifdef WITH_DEBUG_CAPABILITIES
4969 rdp_print_capability_sets(log, s, bm, FALSE);
4970#endif
4971 return Stream_SetPosition(s, em);
4972}
4973
4974BOOL rdp_send_confirm_active(rdpRdp* rdp)
4975{
4976 UINT16 sec_flags = 0;
4977 wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4978 BOOL status = 0;
4979
4980 if (!s)
4981 return FALSE;
4982
4983 status = rdp_write_confirm_active(rdp->log, s, rdp->settings) &&
4984 rdp_send_pdu(rdp, s, PDU_TYPE_CONFIRM_ACTIVE, rdp->mcs->userId, sec_flags);
4985 Stream_Release(s);
4986 return status;
4987}
4988
4989const char* rdp_input_flag_string(UINT16 flags, char* buffer, size_t len)
4990{
4991 char prefix[16] = WINPR_C_ARRAY_INIT;
4992
4993 (void)_snprintf(prefix, sizeof(prefix), "[0x%04" PRIx16 "][", flags);
4994 winpr_str_append(prefix, buffer, len, "");
4995 if ((flags & INPUT_FLAG_SCANCODES) != 0)
4996 winpr_str_append("INPUT_FLAG_SCANCODES", buffer, len, "|");
4997 if ((flags & INPUT_FLAG_MOUSEX) != 0)
4998 winpr_str_append("INPUT_FLAG_MOUSEX", buffer, len, "|");
4999 if ((flags & INPUT_FLAG_FASTPATH_INPUT) != 0)
5000 winpr_str_append("INPUT_FLAG_FASTPATH_INPUT", buffer, len, "|");
5001 if ((flags & INPUT_FLAG_UNICODE) != 0)
5002 winpr_str_append("INPUT_FLAG_UNICODE", buffer, len, "|");
5003 if ((flags & INPUT_FLAG_FASTPATH_INPUT2) != 0)
5004 winpr_str_append("INPUT_FLAG_FASTPATH_INPUT2", buffer, len, "|");
5005 if ((flags & INPUT_FLAG_UNUSED1) != 0)
5006 winpr_str_append("INPUT_FLAG_UNUSED1", buffer, len, "|");
5007 if ((flags & INPUT_FLAG_MOUSE_RELATIVE) != 0)
5008 winpr_str_append("INPUT_FLAG_MOUSE_RELATIVE", buffer, len, "|");
5009 if ((flags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0)
5010 winpr_str_append("TS_INPUT_FLAG_MOUSE_HWHEEL", buffer, len, "|");
5011 if ((flags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0)
5012 winpr_str_append("TS_INPUT_FLAG_QOE_TIMESTAMPS", buffer, len, "|");
5013 winpr_str_append("]", buffer, len, "");
5014 return buffer;
5015}
FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_pointer_len(rdpSettings *settings, FreeRDP_Settings_Keys_Pointer id, const void *data, size_t len)
Set a pointer to value data.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API BOOL freerdp_settings_set_string_len(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val, size_t len)
Sets a string settings value. The val is copied.
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
Definition wtypes.h:254