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
3632 const UINT32 q = freerdp_settings_get_uint32(settings, FreeRDP_JpegQuality);
3633 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, q));
3634 return TRUE;
3635}
3636#endif
3637
3638/*
3639 * Write RemoteFX Server Capability Container.
3640 */
3641static BOOL rdp_write_rfx_server_capability_container(wStream* s, const rdpSettings* settings)
3642{
3643 WINPR_UNUSED(settings);
3644 WINPR_ASSERT(settings);
3645
3646 if (!Stream_EnsureRemainingCapacity(s, 8))
3647 return FALSE;
3648
3649 Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3650 Stream_Write_UINT32(s, 0); /* reserved */
3651 return TRUE;
3652}
3653
3654#if defined(WITH_JPEG)
3655static BOOL rdp_write_jpeg_server_capability_container(wStream* s, const rdpSettings* settings)
3656{
3657 WINPR_UNUSED(settings);
3658 WINPR_ASSERT(settings);
3659
3660 if (!Stream_EnsureRemainingCapacity(s, 8))
3661 return FALSE;
3662
3663 Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3664 Stream_Write_UINT8(s, 75);
3665 return TRUE;
3666}
3667#endif
3668
3669/*
3670 * Write NSCODEC Server Capability Container.
3671 */
3672static BOOL rdp_write_nsc_server_capability_container(wStream* s, const rdpSettings* settings)
3673{
3674 WINPR_UNUSED(settings);
3675 WINPR_ASSERT(settings);
3676
3677 if (!Stream_EnsureRemainingCapacity(s, 8))
3678 return FALSE;
3679
3680 Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3681 Stream_Write_UINT32(s, 0); /* reserved */
3682 return TRUE;
3683}
3684
3685/*
3686 * Write bitmap codecs capability set.
3687 * msdn{dd891377}
3688 */
3689
3690static BOOL rdp_write_bitmap_codecs_capability_set(wLog* log, wStream* s,
3691 const rdpSettings* settings)
3692{
3693 WINPR_ASSERT(settings);
3694 if (!Stream_EnsureRemainingCapacity(s, 64))
3695 return FALSE;
3696
3697 const size_t header = rdp_capability_set_start(log, s);
3698 BYTE bitmapCodecCount = 0;
3699
3700 if (settings->RemoteFxCodec)
3701 bitmapCodecCount++;
3702
3703 if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3704 bitmapCodecCount++;
3705
3706#if defined(WITH_JPEG)
3707
3708 if (settings->JpegCodec)
3709 bitmapCodecCount++;
3710
3711#endif
3712
3713 if (settings->RemoteFxImageCodec)
3714 bitmapCodecCount++;
3715
3716 Stream_Write_UINT8(s, bitmapCodecCount);
3717
3718 if (settings->RemoteFxCodec)
3719 {
3720 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_REMOTEFX); /* codecGUID */
3721
3722 if (settings->ServerMode)
3723 {
3724 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3725
3726 if (!rdp_write_rfx_server_capability_container(s, settings))
3727 return FALSE;
3728 }
3729 else
3730 {
3731 Stream_Write_UINT8(s, RDP_CODEC_ID_REMOTEFX); /* codecID */
3732
3733 if (!rdp_write_rfx_client_capability_container(s, settings))
3734 return FALSE;
3735 }
3736 }
3737
3738 if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3739 {
3740 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_NSCODEC); /* codecGUID */
3741
3742 if (settings->ServerMode)
3743 {
3744 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3745
3746 if (!rdp_write_nsc_server_capability_container(s, settings))
3747 return FALSE;
3748 }
3749 else
3750 {
3751 Stream_Write_UINT8(s, RDP_CODEC_ID_NSCODEC); /* codecID */
3752
3753 if (!rdp_write_nsc_client_capability_container(s, settings))
3754 return FALSE;
3755 }
3756 }
3757
3758#if defined(WITH_JPEG)
3759
3760 if (settings->JpegCodec)
3761 {
3762 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_JPEG); /* codecGUID */
3763
3764 if (settings->ServerMode)
3765 {
3766 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3767
3768 if (!rdp_write_jpeg_server_capability_container(s, settings))
3769 return FALSE;
3770 }
3771 else
3772 {
3773 Stream_Write_UINT8(s, RDP_CODEC_ID_JPEG); /* codecID */
3774
3775 if (!rdp_write_jpeg_client_capability_container(s, settings))
3776 return FALSE;
3777 }
3778 }
3779
3780#endif
3781
3782 if (settings->RemoteFxImageCodec)
3783 {
3784 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_IMAGE_REMOTEFX); /* codecGUID */
3785
3786 if (settings->ServerMode)
3787 {
3788 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3789
3790 if (!rdp_write_rfx_server_capability_container(s, settings))
3791 return FALSE;
3792 }
3793 else
3794 {
3795 Stream_Write_UINT8(s, RDP_CODEC_ID_IMAGE_REMOTEFX); /* codecID */
3796
3797 if (!rdp_write_rfx_client_capability_container(s, settings))
3798 return FALSE;
3799 }
3800 }
3801
3802 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CODECS);
3803}
3804
3805#ifdef WITH_DEBUG_CAPABILITIES
3806static BOOL rdp_print_bitmap_codecs_capability_set(wLog* log, wStream* s)
3807{
3808 GUID codecGuid = WINPR_C_ARRAY_INIT;
3809 BYTE bitmapCodecCount = 0;
3810 BYTE codecId = 0;
3811 UINT16 codecPropertiesLength = 0;
3812
3813 WLog_Print(log, WLOG_TRACE,
3814 "BitmapCodecsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3815
3816 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3817 return FALSE;
3818
3819 Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3820 WLog_Print(log, WLOG_TRACE, "\tbitmapCodecCount: %" PRIu8 "", bitmapCodecCount);
3821
3822 while (bitmapCodecCount > 0)
3823 {
3824 if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3825 return FALSE;
3826 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3827 return FALSE;
3828 Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3829 WLog_Print(log, WLOG_TRACE, "\tcodecGuid: 0x");
3830 rdp_print_bitmap_codec_guid(log, &codecGuid);
3831 WLog_Print(log, WLOG_TRACE, " (%s)", rdp_get_bitmap_codec_guid_name(&codecGuid));
3832 WLog_Print(log, WLOG_TRACE, "\tcodecId: %" PRIu8 "", codecId);
3833 Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3834 WLog_Print(log, WLOG_TRACE, "\tcodecPropertiesLength: %" PRIu16 "", codecPropertiesLength);
3835
3836 if (!Stream_SafeSeek(s, codecPropertiesLength)) /* codecProperties */
3837 return FALSE;
3838 bitmapCodecCount--;
3839 }
3840
3841 return TRUE;
3842}
3843#endif
3844
3845static BOOL rdp_apply_frame_acknowledge_capability_set(rdpSettings* settings,
3846 const rdpSettings* src)
3847{
3848 WINPR_ASSERT(settings);
3849 WINPR_ASSERT(src);
3850
3851 if (settings->ServerMode)
3852 settings->FrameAcknowledge = src->FrameAcknowledge;
3853
3854 return TRUE;
3855}
3856
3857/*
3858 * Read frame acknowledge capability set.
3859 */
3860
3861static BOOL rdp_read_frame_acknowledge_capability_set(wLog* log, wStream* s, rdpSettings* settings)
3862{
3863 WINPR_ASSERT(settings);
3864 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3865 return FALSE;
3866
3867 Stream_Read_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3868
3869 return TRUE;
3870}
3871
3872/*
3873 * Write frame acknowledge capability set.
3874 */
3875
3876static BOOL rdp_write_frame_acknowledge_capability_set(wLog* log, wStream* s,
3877 const rdpSettings* settings)
3878{
3879 WINPR_ASSERT(settings);
3880 if (!Stream_EnsureRemainingCapacity(s, 32))
3881 return FALSE;
3882
3883 const size_t header = rdp_capability_set_start(log, s);
3884 Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3885 return rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE);
3886}
3887
3888#ifdef WITH_DEBUG_CAPABILITIES
3889static BOOL rdp_print_frame_acknowledge_capability_set(wLog* log, wStream* s)
3890{
3891 UINT32 frameAcknowledge = 0;
3892 WLog_Print(log, WLOG_TRACE,
3893 "FrameAcknowledgeCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3894
3895 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3896 return FALSE;
3897
3898 Stream_Read_UINT32(s, frameAcknowledge); /* frameAcknowledge (4 bytes) */
3899 WLog_Print(log, WLOG_TRACE, "\tframeAcknowledge: 0x%08" PRIX32 "", frameAcknowledge);
3900 return TRUE;
3901}
3902#endif
3903
3904static BOOL rdp_apply_bitmap_cache_v3_codec_id_capability_set(rdpSettings* settings,
3905 const rdpSettings* src)
3906{
3907 WINPR_ASSERT(settings);
3908 WINPR_ASSERT(src);
3909
3910 settings->BitmapCacheV3CodecId = src->BitmapCacheV3CodecId;
3911 return TRUE;
3912}
3913
3914static BOOL rdp_read_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3915 rdpSettings* settings)
3916{
3917 BYTE bitmapCacheV3CodecId = 0;
3918
3919 WINPR_ASSERT(settings);
3920 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3921 return FALSE;
3922
3923 Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3924 settings->BitmapCacheV3CodecId = bitmapCacheV3CodecId;
3925 return TRUE;
3926}
3927
3928static BOOL rdp_write_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3929 const rdpSettings* settings)
3930{
3931 WINPR_ASSERT(settings);
3932 if (!Stream_EnsureRemainingCapacity(s, 32))
3933 return FALSE;
3934
3935 const size_t header = rdp_capability_set_start(log, s);
3936 if (settings->BitmapCacheV3CodecId > UINT8_MAX)
3937 return FALSE;
3938 Stream_Write_UINT8(s, (UINT8)settings->BitmapCacheV3CodecId);
3939 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID);
3940}
3941
3942#ifdef WITH_DEBUG_CAPABILITIES
3943static BOOL rdp_print_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s)
3944{
3945 BYTE bitmapCacheV3CodecId = 0;
3946 WLog_Print(log, WLOG_TRACE, "BitmapCacheV3CodecIdCapabilitySet (length %" PRIuz "):",
3947 Stream_GetRemainingLength(s));
3948
3949 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3950 return FALSE;
3951
3952 Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3953 WLog_Print(log, WLOG_TRACE, "\tbitmapCacheV3CodecId: 0x%02" PRIX8 "", bitmapCacheV3CodecId);
3954 return TRUE;
3955}
3956
3957BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving)
3958{
3959 BOOL rc = FALSE;
3960 UINT16 type = 0;
3961 UINT16 length = 0;
3962 UINT16 numberCapabilities = 0;
3963
3964 size_t pos = Stream_GetPosition(s);
3965
3966 if (!Stream_SetPosition(s, start))
3967 goto fail;
3968
3969 if (receiving)
3970 {
3971 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3972 goto fail;
3973 }
3974 else
3975 {
3976 if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), 4))
3977 goto fail;
3978 }
3979
3980 Stream_Read_UINT16(s, numberCapabilities);
3981 Stream_Seek(s, 2);
3982
3983 while (numberCapabilities > 0)
3984 {
3985 size_t rest = 0;
3986 wStream subBuffer;
3987 wStream* sub = nullptr;
3988
3989 if (!rdp_read_capability_set_header(log, s, &length, &type))
3990 goto fail;
3991
3992 WLog_Print(log, WLOG_TRACE, "%s ", receiving ? "Receiving" : "Sending");
3993 sub = Stream_StaticInit(&subBuffer, Stream_Pointer(s), length - 4);
3994 if (!Stream_SafeSeek(s, length - 4))
3995 goto fail;
3996
3997 switch (type)
3998 {
3999 case CAPSET_TYPE_GENERAL:
4000 if (!rdp_print_general_capability_set(log, sub))
4001 goto fail;
4002
4003 break;
4004
4005 case CAPSET_TYPE_BITMAP:
4006 if (!rdp_print_bitmap_capability_set(log, sub))
4007 goto fail;
4008
4009 break;
4010
4011 case CAPSET_TYPE_ORDER:
4012 if (!rdp_print_order_capability_set(log, sub))
4013 goto fail;
4014
4015 break;
4016
4017 case CAPSET_TYPE_BITMAP_CACHE:
4018 if (!rdp_print_bitmap_cache_capability_set(log, sub))
4019 goto fail;
4020
4021 break;
4022
4023 case CAPSET_TYPE_CONTROL:
4024 if (!rdp_print_control_capability_set(log, sub))
4025 goto fail;
4026
4027 break;
4028
4029 case CAPSET_TYPE_ACTIVATION:
4030 if (!rdp_print_window_activation_capability_set(log, sub))
4031 goto fail;
4032
4033 break;
4034
4035 case CAPSET_TYPE_POINTER:
4036 if (!rdp_print_pointer_capability_set(log, sub))
4037 goto fail;
4038
4039 break;
4040
4041 case CAPSET_TYPE_SHARE:
4042 if (!rdp_print_share_capability_set(log, sub))
4043 goto fail;
4044
4045 break;
4046
4047 case CAPSET_TYPE_COLOR_CACHE:
4048 if (!rdp_print_color_cache_capability_set(log, sub))
4049 goto fail;
4050
4051 break;
4052
4053 case CAPSET_TYPE_SOUND:
4054 if (!rdp_print_sound_capability_set(log, sub))
4055 goto fail;
4056
4057 break;
4058
4059 case CAPSET_TYPE_INPUT:
4060 if (!rdp_print_input_capability_set(log, sub))
4061 goto fail;
4062
4063 break;
4064
4065 case CAPSET_TYPE_FONT:
4066 if (!rdp_print_font_capability_set(log, sub))
4067 goto fail;
4068
4069 break;
4070
4071 case CAPSET_TYPE_BRUSH:
4072 if (!rdp_print_brush_capability_set(log, sub))
4073 goto fail;
4074
4075 break;
4076
4077 case CAPSET_TYPE_GLYPH_CACHE:
4078 if (!rdp_print_glyph_cache_capability_set(log, sub))
4079 goto fail;
4080
4081 break;
4082
4083 case CAPSET_TYPE_OFFSCREEN_CACHE:
4084 if (!rdp_print_offscreen_bitmap_cache_capability_set(log, sub))
4085 goto fail;
4086
4087 break;
4088
4089 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4090 if (!rdp_print_bitmap_cache_host_support_capability_set(log, sub))
4091 goto fail;
4092
4093 break;
4094
4095 case CAPSET_TYPE_BITMAP_CACHE_V2:
4096 if (!rdp_print_bitmap_cache_v2_capability_set(log, sub))
4097 goto fail;
4098
4099 break;
4100
4101 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4102 if (!rdp_print_virtual_channel_capability_set(log, sub))
4103 goto fail;
4104
4105 break;
4106
4107 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4108 if (!rdp_print_draw_nine_grid_cache_capability_set(log, sub))
4109 goto fail;
4110
4111 break;
4112
4113 case CAPSET_TYPE_DRAW_GDI_PLUS:
4114 if (!rdp_print_draw_gdiplus_cache_capability_set(log, sub))
4115 goto fail;
4116
4117 break;
4118
4119 case CAPSET_TYPE_RAIL:
4120 if (!rdp_print_remote_programs_capability_set(log, sub))
4121 goto fail;
4122
4123 break;
4124
4125 case CAPSET_TYPE_WINDOW:
4126 if (!rdp_print_window_list_capability_set(log, sub))
4127 goto fail;
4128
4129 break;
4130
4131 case CAPSET_TYPE_COMP_DESK:
4132 if (!rdp_print_desktop_composition_capability_set(log, sub))
4133 goto fail;
4134
4135 break;
4136
4137 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4138 if (!rdp_print_multifragment_update_capability_set(log, sub))
4139 goto fail;
4140
4141 break;
4142
4143 case CAPSET_TYPE_LARGE_POINTER:
4144 if (!rdp_print_large_pointer_capability_set(log, sub))
4145 goto fail;
4146
4147 break;
4148
4149 case CAPSET_TYPE_SURFACE_COMMANDS:
4150 if (!rdp_print_surface_commands_capability_set(log, sub))
4151 goto fail;
4152
4153 break;
4154
4155 case CAPSET_TYPE_BITMAP_CODECS:
4156 if (!rdp_print_bitmap_codecs_capability_set(log, sub))
4157 goto fail;
4158
4159 break;
4160
4161 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4162 if (!rdp_print_frame_acknowledge_capability_set(log, sub))
4163 goto fail;
4164
4165 break;
4166
4167 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4168 if (!rdp_print_bitmap_cache_v3_codec_id_capability_set(log, sub))
4169 goto fail;
4170
4171 break;
4172
4173 default:
4174 WLog_Print(log, WLOG_ERROR, "unknown capability type %" PRIu16 "", type);
4175 break;
4176 }
4177
4178 rest = Stream_GetRemainingLength(sub);
4179 if (rest > 0)
4180 {
4181 WLog_Print(log, WLOG_WARN,
4182 "incorrect capability offset, type:0x%04" PRIX16 " %" PRIu16
4183 " bytes expected, %" PRIuz "bytes remaining",
4184 type, length, rest);
4185 }
4186
4187 numberCapabilities--;
4188 }
4189
4190 rc = TRUE;
4191fail:
4192 if (!Stream_SetPosition(s, pos))
4193 return FALSE;
4194
4195 return rc;
4196}
4197#endif
4198
4199static BOOL rdp_apply_from_received(UINT16 type, rdpSettings* dst, const rdpSettings* src)
4200{
4201 switch (type)
4202 {
4203 case CAPSET_TYPE_GENERAL:
4204 return rdp_apply_general_capability_set(dst, src);
4205 case CAPSET_TYPE_BITMAP:
4206 return rdp_apply_bitmap_capability_set(dst, src);
4207 case CAPSET_TYPE_ORDER:
4208 return rdp_apply_order_capability_set(dst, src);
4209 case CAPSET_TYPE_POINTER:
4210 return rdp_apply_pointer_capability_set(dst, src);
4211 case CAPSET_TYPE_INPUT:
4212 return rdp_apply_input_capability_set(dst, src);
4213 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4214 return rdp_apply_virtual_channel_capability_set(dst, src);
4215 case CAPSET_TYPE_SHARE:
4216 return rdp_apply_share_capability_set(dst, src);
4217 case CAPSET_TYPE_COLOR_CACHE:
4218 return rdp_apply_color_cache_capability_set(dst, src);
4219 case CAPSET_TYPE_FONT:
4220 return rdp_apply_font_capability_set(dst, src);
4221 case CAPSET_TYPE_DRAW_GDI_PLUS:
4222 return rdp_apply_draw_gdiplus_cache_capability_set(dst, src);
4223 case CAPSET_TYPE_RAIL:
4224 return rdp_apply_remote_programs_capability_set(dst, src);
4225 case CAPSET_TYPE_WINDOW:
4226 return rdp_apply_window_list_capability_set(dst, src);
4227 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4228 return rdp_apply_multifragment_update_capability_set(dst, src);
4229 case CAPSET_TYPE_LARGE_POINTER:
4230 return rdp_apply_large_pointer_capability_set(dst, src);
4231 case CAPSET_TYPE_COMP_DESK:
4232 return rdp_apply_desktop_composition_capability_set(dst, src);
4233 case CAPSET_TYPE_SURFACE_COMMANDS:
4234 return rdp_apply_surface_commands_capability_set(dst, src);
4235 case CAPSET_TYPE_BITMAP_CODECS:
4236 return rdp_apply_bitmap_codecs_capability_set(dst, src);
4237 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4238 return rdp_apply_frame_acknowledge_capability_set(dst, src);
4239 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4240 return rdp_apply_bitmap_cache_v3_codec_id_capability_set(dst, src);
4241 case CAPSET_TYPE_BITMAP_CACHE:
4242 return rdp_apply_bitmap_cache_capability_set(dst, src);
4243 case CAPSET_TYPE_BITMAP_CACHE_V2:
4244 return rdp_apply_bitmap_cache_v2_capability_set(dst, src);
4245 case CAPSET_TYPE_BRUSH:
4246 return rdp_apply_brush_capability_set(dst, src);
4247 case CAPSET_TYPE_GLYPH_CACHE:
4248 return rdp_apply_glyph_cache_capability_set(dst, src);
4249 case CAPSET_TYPE_OFFSCREEN_CACHE:
4250 return rdp_apply_offscreen_bitmap_cache_capability_set(dst, src);
4251 case CAPSET_TYPE_SOUND:
4252 return rdp_apply_sound_capability_set(dst, src);
4253 case CAPSET_TYPE_CONTROL:
4254 return rdp_apply_control_capability_set(dst, src);
4255 case CAPSET_TYPE_ACTIVATION:
4256 return rdp_apply_window_activation_capability_set(dst, src);
4257 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4258 return rdp_apply_draw_nine_grid_cache_capability_set(dst, src);
4259 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4260 return rdp_apply_bitmap_cache_host_support_capability_set(dst, src);
4261 default:
4262 return TRUE;
4263 }
4264}
4265
4266BOOL rdp_read_capability_set(wLog* log, wStream* sub, UINT16 type, rdpSettings* settings,
4267 BOOL isServer)
4268{
4269 WINPR_ASSERT(settings);
4270
4271 if (type <= CAPSET_TYPE_FRAME_ACKNOWLEDGE)
4272 {
4273 const size_t size = Stream_Length(sub);
4274 if (size > UINT32_MAX)
4275 return FALSE;
4276
4277 WINPR_ASSERT(settings->ReceivedCapabilities);
4278 settings->ReceivedCapabilities[type] = TRUE;
4279
4280 WINPR_ASSERT(settings->ReceivedCapabilityDataSizes);
4281 settings->ReceivedCapabilityDataSizes[type] = (UINT32)size;
4282
4283 WINPR_ASSERT(settings->ReceivedCapabilityData);
4284 void* tmp = realloc(settings->ReceivedCapabilityData[type], size);
4285 if (!tmp && (size > 0))
4286 return FALSE;
4287 memcpy(tmp, Stream_Buffer(sub), size);
4288 settings->ReceivedCapabilityData[type] = tmp;
4289 }
4290 else
4291 WLog_Print(log, WLOG_WARN, "not handling capability type %" PRIu16 " yet", type);
4292
4293 BOOL treated = TRUE;
4294
4295 switch (type)
4296 {
4297 case CAPSET_TYPE_GENERAL:
4298 if (!rdp_read_general_capability_set(log, sub, settings))
4299 return FALSE;
4300
4301 break;
4302
4303 case CAPSET_TYPE_BITMAP:
4304 if (!rdp_read_bitmap_capability_set(log, sub, settings))
4305 return FALSE;
4306
4307 break;
4308
4309 case CAPSET_TYPE_ORDER:
4310 if (!rdp_read_order_capability_set(log, sub, settings))
4311 return FALSE;
4312
4313 break;
4314
4315 case CAPSET_TYPE_POINTER:
4316 if (!rdp_read_pointer_capability_set(log, sub, settings))
4317 return FALSE;
4318
4319 break;
4320
4321 case CAPSET_TYPE_INPUT:
4322 if (!rdp_read_input_capability_set(log, sub, settings))
4323 return FALSE;
4324
4325 break;
4326
4327 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4328 if (!rdp_read_virtual_channel_capability_set(log, sub, settings))
4329 return FALSE;
4330
4331 break;
4332
4333 case CAPSET_TYPE_SHARE:
4334 if (!rdp_read_share_capability_set(log, sub, settings))
4335 return FALSE;
4336
4337 break;
4338
4339 case CAPSET_TYPE_COLOR_CACHE:
4340 if (!rdp_read_color_cache_capability_set(log, sub, settings))
4341 return FALSE;
4342
4343 break;
4344
4345 case CAPSET_TYPE_FONT:
4346 if (!rdp_read_font_capability_set(log, sub, settings))
4347 return FALSE;
4348
4349 break;
4350
4351 case CAPSET_TYPE_DRAW_GDI_PLUS:
4352 if (!rdp_read_draw_gdiplus_cache_capability_set(log, sub, settings))
4353 return FALSE;
4354
4355 break;
4356
4357 case CAPSET_TYPE_RAIL:
4358 if (!rdp_read_remote_programs_capability_set(log, sub, settings))
4359 return FALSE;
4360
4361 break;
4362
4363 case CAPSET_TYPE_WINDOW:
4364 if (!rdp_read_window_list_capability_set(log, sub, settings))
4365 return FALSE;
4366
4367 break;
4368
4369 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4370 if (!rdp_read_multifragment_update_capability_set(log, sub, settings))
4371 return FALSE;
4372
4373 break;
4374
4375 case CAPSET_TYPE_LARGE_POINTER:
4376 if (!rdp_read_large_pointer_capability_set(log, sub, settings))
4377 return FALSE;
4378
4379 break;
4380
4381 case CAPSET_TYPE_COMP_DESK:
4382 if (!rdp_read_desktop_composition_capability_set(log, sub, settings))
4383 return FALSE;
4384
4385 break;
4386
4387 case CAPSET_TYPE_SURFACE_COMMANDS:
4388 if (!rdp_read_surface_commands_capability_set(log, sub, settings))
4389 return FALSE;
4390
4391 break;
4392
4393 case CAPSET_TYPE_BITMAP_CODECS:
4394 if (!rdp_read_bitmap_codecs_capability_set(log, sub, settings, isServer))
4395 return FALSE;
4396
4397 break;
4398
4399 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4400 if (!rdp_read_frame_acknowledge_capability_set(log, sub, settings))
4401 return FALSE;
4402
4403 break;
4404
4405 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4406 if (!rdp_read_bitmap_cache_v3_codec_id_capability_set(log, sub, settings))
4407 return FALSE;
4408
4409 break;
4410
4411 default:
4412 treated = FALSE;
4413 break;
4414 }
4415
4416 if (!treated)
4417 {
4418 if (isServer)
4419 {
4420 /* treating capabilities that are supposed to be send only from the client */
4421 switch (type)
4422 {
4423 case CAPSET_TYPE_BITMAP_CACHE:
4424 if (!rdp_read_bitmap_cache_capability_set(log, sub, settings))
4425 return FALSE;
4426
4427 break;
4428
4429 case CAPSET_TYPE_BITMAP_CACHE_V2:
4430 if (!rdp_read_bitmap_cache_v2_capability_set(log, sub, settings))
4431 return FALSE;
4432
4433 break;
4434
4435 case CAPSET_TYPE_BRUSH:
4436 if (!rdp_read_brush_capability_set(log, sub, settings))
4437 return FALSE;
4438
4439 break;
4440
4441 case CAPSET_TYPE_GLYPH_CACHE:
4442 if (!rdp_read_glyph_cache_capability_set(log, sub, settings))
4443 return FALSE;
4444
4445 break;
4446
4447 case CAPSET_TYPE_OFFSCREEN_CACHE:
4448 if (!rdp_read_offscreen_bitmap_cache_capability_set(log, sub, settings))
4449 return FALSE;
4450
4451 break;
4452
4453 case CAPSET_TYPE_SOUND:
4454 if (!rdp_read_sound_capability_set(log, sub, settings))
4455 return FALSE;
4456
4457 break;
4458
4459 case CAPSET_TYPE_CONTROL:
4460 if (!rdp_read_control_capability_set(log, sub, settings))
4461 return FALSE;
4462
4463 break;
4464
4465 case CAPSET_TYPE_ACTIVATION:
4466 if (!rdp_read_window_activation_capability_set(log, sub, settings))
4467 return FALSE;
4468
4469 break;
4470
4471 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4472 if (!rdp_read_draw_nine_grid_cache_capability_set(log, sub, settings))
4473 return FALSE;
4474
4475 break;
4476
4477 default:
4478 WLog_Print(log, WLOG_ERROR,
4479 "capability %s(%" PRIu16 ") not expected from client",
4480 get_capability_name(type), type);
4481 return FALSE;
4482 }
4483 }
4484 else
4485 {
4486 /* treating capabilities that are supposed to be send only from the server */
4487 switch (type)
4488 {
4489 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4490 if (!rdp_read_bitmap_cache_host_support_capability_set(log, sub, settings))
4491 return FALSE;
4492
4493 break;
4494
4495 default:
4496 WLog_Print(log, WLOG_ERROR,
4497 "capability %s(%" PRIu16 ") not expected from server",
4498 get_capability_name(type), type);
4499 return FALSE;
4500 }
4501 }
4502 }
4503
4504 const size_t rest = Stream_GetRemainingLength(sub);
4505 if (rest > 0)
4506 {
4507 const size_t length = Stream_Capacity(sub);
4508 WLog_Print(log, WLOG_ERROR,
4509 "incorrect offset, type:0x%04" PRIx16 " actual:%" PRIuz " expected:%" PRIuz "",
4510 type, length - rest, length);
4511 }
4512 return TRUE;
4513}
4514
4515static BOOL rdp_read_capability_sets(wLog* log, wStream* s, rdpSettings* settings,
4516 rdpSettings* rcvSettings, UINT16 totalLength)
4517{
4518 BOOL rc = FALSE;
4519 size_t start = 0;
4520 size_t end = 0;
4521 size_t len = 0;
4522 UINT16 numberCapabilities = 0;
4523 UINT16 count = 0;
4524
4525#ifdef WITH_DEBUG_CAPABILITIES
4526 const size_t capstart = Stream_GetPosition(s);
4527#endif
4528
4529 WINPR_ASSERT(s);
4530 WINPR_ASSERT(settings);
4531
4532 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4533 return FALSE;
4534
4535 Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4536 Stream_Seek(s, 2); /* pad2Octets (2 bytes) */
4537 count = numberCapabilities;
4538
4539 start = Stream_GetPosition(s);
4540 while (numberCapabilities > 0 && Stream_GetRemainingLength(s) >= 4)
4541 {
4542 UINT16 type = 0;
4543 UINT16 length = 0;
4544 wStream subbuffer;
4545 wStream* sub = nullptr;
4546
4547 if (!rdp_read_capability_set_header(log, s, &length, &type))
4548 goto fail;
4549 sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), length - 4);
4550 if (!Stream_SafeSeek(s, length - 4))
4551 goto fail;
4552
4553 if (!rdp_read_capability_set(log, sub, type, rcvSettings, settings->ServerMode))
4554 goto fail;
4555
4556 if (!rdp_apply_from_received(type, settings, rcvSettings))
4557 goto fail;
4558 numberCapabilities--;
4559 }
4560
4561 end = Stream_GetPosition(s);
4562 len = end - start;
4563
4564 if (numberCapabilities)
4565 {
4566 WLog_Print(log, WLOG_ERROR,
4567 "strange we haven't read the number of announced capacity sets, read=%d "
4568 "expected=%" PRIu16 "",
4569 count - numberCapabilities, count);
4570 }
4571
4572#ifdef WITH_DEBUG_CAPABILITIES
4573 rdp_print_capability_sets(log, s, capstart, TRUE);
4574#endif
4575
4576 if (len > totalLength)
4577 {
4578 WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIuz,
4579 totalLength, len);
4580 goto fail;
4581 }
4582 rc = freerdp_capability_buffer_copy(settings, rcvSettings);
4583fail:
4584 return rc;
4585}
4586
4587BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId, UINT16* length)
4588{
4589 WINPR_ASSERT(rdp);
4590 WINPR_ASSERT(rdp->context);
4591
4592 if (!rdp_read_header(rdp, s, length, pChannelId))
4593 return FALSE;
4594
4595 if (freerdp_shall_disconnect_context(rdp->context))
4596 return TRUE;
4597
4598 if (*pChannelId != MCS_GLOBAL_CHANNEL_ID)
4599 {
4600 UINT16 mcsMessageChannelId = rdp->mcs->messageChannelId;
4601
4602 if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId))
4603 {
4604 WLog_Print(rdp->log, WLOG_ERROR, "unexpected MCS channel id %04" PRIx16 " received",
4605 *pChannelId);
4606 return FALSE;
4607 }
4608 }
4609
4610 return TRUE;
4611}
4612
4613BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s, UINT16 pduSource, UINT16 length)
4614{
4615 UINT16 lengthSourceDescriptor = 0;
4616 UINT16 lengthCombinedCapabilities = 0;
4617
4618 WINPR_ASSERT(rdp);
4619 WINPR_ASSERT(rdp->settings);
4620 WINPR_ASSERT(rdp->context);
4621 WINPR_ASSERT(s);
4622
4623 rdp->settings->PduSource = pduSource;
4624
4625 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 8))
4626 return FALSE;
4627
4628 Stream_Read_UINT32(s, rdp->settings->ShareId); /* shareId (4 bytes) */
4629 Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4630 Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4631
4632 if (!Stream_SafeSeek(s, lengthSourceDescriptor) ||
4633 !Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4)) /* sourceDescriptor */
4634 return FALSE;
4635
4636 /* capabilitySets */
4637 if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4638 lengthCombinedCapabilities))
4639 {
4640 WLog_Print(rdp->log, WLOG_ERROR, "rdp_read_capability_sets failed");
4641 return FALSE;
4642 }
4643
4644 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4))
4645 return FALSE;
4646
4647 /* [MS-RDPBCGR] 2.2.1.13.1.1 Demand Active PDU Data (TS_DEMAND_ACTIVE_PDU)::sessionId
4648 * is ignored by client */
4649 Stream_Seek_UINT32(s); /* SessionId */
4650
4651 {
4652 rdp_secondary_update_internal* secondary = secondary_update_cast(rdp->update->secondary);
4653 secondary->glyph_v2 = (rdp->settings->GlyphSupportLevel > GLYPH_SUPPORT_FULL);
4654 }
4655
4656 return tpkt_ensure_stream_consumed(rdp->log, s, length);
4657}
4658
4659static BOOL rdp_write_demand_active(wLog* log, wStream* s, rdpSettings* settings)
4660{
4661 size_t bm = 0;
4662 size_t em = 0;
4663 size_t lm = 0;
4664 UINT16 numberCapabilities = 0;
4665 size_t lengthCombinedCapabilities = 0;
4666
4667 if (!Stream_EnsureRemainingCapacity(s, 64))
4668 return FALSE;
4669
4670 Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4671 Stream_Write_UINT16(s, 4); /* lengthSourceDescriptor (2 bytes) */
4672 lm = Stream_GetPosition(s);
4673 Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4674 Stream_Write(s, "RDP", 4); /* sourceDescriptor */
4675 bm = Stream_GetPosition(s);
4676 Stream_Seek_UINT16(s); /* numberCapabilities (2 bytes) */
4677 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4678 numberCapabilities = 14;
4679
4680 if (!rdp_write_general_capability_set(log, s, settings) ||
4681 !rdp_write_bitmap_capability_set(log, s, settings) ||
4682 !rdp_write_order_capability_set(log, s, settings) ||
4683 !rdp_write_pointer_capability_set(log, s, settings) ||
4684 !rdp_write_input_capability_set(log, s, settings) ||
4685 !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4686 !rdp_write_share_capability_set(log, s, settings) ||
4687 !rdp_write_font_capability_set(log, s, settings) ||
4688 !rdp_write_multifragment_update_capability_set(log, s, settings) ||
4689 !rdp_write_large_pointer_capability_set(log, s, settings) ||
4690 !rdp_write_desktop_composition_capability_set(log, s, settings) ||
4691 !rdp_write_surface_commands_capability_set(log, s, settings) ||
4692 !rdp_write_bitmap_codecs_capability_set(log, s, settings) ||
4693 !rdp_write_frame_acknowledge_capability_set(log, s, settings))
4694 {
4695 return FALSE;
4696 }
4697
4698 if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
4699 {
4700 numberCapabilities++;
4701
4702 if (!rdp_write_bitmap_cache_host_support_capability_set(log, s, settings))
4703 return FALSE;
4704 }
4705
4706 if (settings->RemoteApplicationMode)
4707 {
4708 numberCapabilities += 2;
4709
4710 if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4711 !rdp_write_window_list_capability_set(log, s, settings))
4712 return FALSE;
4713 }
4714
4715 em = Stream_GetPosition(s);
4716 if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4717 return FALSE;
4718 lengthCombinedCapabilities = (em - bm);
4719 if (lengthCombinedCapabilities > UINT16_MAX)
4720 return FALSE;
4721 Stream_Write_UINT16(
4722 s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4723 if (!Stream_SetPosition(s, bm)) /* go back to numberCapabilities */
4724 return FALSE;
4725 Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4726#ifdef WITH_DEBUG_CAPABILITIES
4727 rdp_print_capability_sets(log, s, bm, FALSE);
4728#endif
4729 if (!Stream_SetPosition(s, em))
4730 return FALSE;
4731 Stream_Write_UINT32(s, 0); /* sessionId */
4732 return TRUE;
4733}
4734
4735BOOL rdp_send_demand_active(rdpRdp* rdp)
4736{
4737 UINT16 sec_flags = 0;
4738 wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4739 BOOL status = 0;
4740
4741 if (!s)
4742 return FALSE;
4743
4744 rdp->settings->ShareId = 0x10000 + rdp->mcs->userId;
4745 status = rdp_write_demand_active(rdp->log, s, rdp->settings) &&
4746 rdp_send_pdu(rdp, s, PDU_TYPE_DEMAND_ACTIVE, rdp->mcs->userId, sec_flags);
4747 Stream_Release(s);
4748 return status;
4749}
4750
4751BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength)
4752{
4753 rdpSettings* settings = nullptr;
4754 UINT16 lengthSourceDescriptor = 0;
4755 UINT16 lengthCombinedCapabilities = 0;
4756
4757 WINPR_ASSERT(rdp);
4758 WINPR_ASSERT(s);
4759 settings = rdp->settings;
4760 WINPR_ASSERT(settings);
4761
4762 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 10))
4763 return FALSE;
4764
4765 Stream_Seek_UINT32(s); /* shareId (4 bytes) */
4766 Stream_Seek_UINT16(s); /* originatorId (2 bytes) */
4767 Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4768 Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4769
4770 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, lengthSourceDescriptor + 4U))
4771 return FALSE;
4772
4773 Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor */
4774 if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4775 lengthCombinedCapabilities))
4776 return FALSE;
4777
4778 if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4779 {
4780 /* client does not support surface commands */
4781 settings->SurfaceCommandsEnabled = FALSE;
4782 settings->SurfaceFrameMarkerEnabled = FALSE;
4783 }
4784
4785 if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4786 {
4787 /* client does not support frame acks */
4788 settings->FrameAcknowledge = 0;
4789 }
4790
4791 if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4792 {
4793 /* client does not support bitmap cache v3 */
4794 settings->BitmapCacheV3Enabled = FALSE;
4795 }
4796
4797 if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4798 {
4799 /* client does not support bitmap codecs */
4800 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, FALSE))
4801 return FALSE;
4802 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, FALSE))
4803 return FALSE;
4804 if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
4805 return FALSE;
4806 }
4807
4808 if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4809 {
4810 /* client does not support multi fragment updates - make sure packages are not fragmented */
4811 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
4812 FASTPATH_FRAGMENT_SAFE_SIZE))
4813 return FALSE;
4814 }
4815
4816 if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4817 {
4818 /* client does not support large pointers */
4819 settings->LargePointerFlag = 0;
4820 }
4821
4822 return tpkt_ensure_stream_consumed(rdp->log, s, pduLength);
4823}
4824
4825static BOOL rdp_write_confirm_active(wLog* log, wStream* s, rdpSettings* settings)
4826{
4827 size_t bm = 0;
4828 size_t em = 0;
4829 size_t lm = 0;
4830 UINT16 numberCapabilities = 0;
4831 UINT16 lengthSourceDescriptor = 0;
4832 size_t lengthCombinedCapabilities = 0;
4833 BOOL ret = 0;
4834
4835 WINPR_ASSERT(settings);
4836
4837 lengthSourceDescriptor = sizeof(SOURCE_DESCRIPTOR);
4838 Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4839 Stream_Write_UINT16(s, 0x03EA); /* originatorId (2 bytes) */
4840 Stream_Write_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4841 lm = Stream_GetPosition(s);
4842 Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4843 Stream_Write(s, SOURCE_DESCRIPTOR, lengthSourceDescriptor); /* sourceDescriptor */
4844 bm = Stream_GetPosition(s);
4845 Stream_Seek_UINT16(s); /* numberCapabilities (2 bytes) */
4846 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4847 /* Capability Sets */
4848 numberCapabilities = 15;
4849
4850 if (!rdp_write_general_capability_set(log, s, settings) ||
4851 !rdp_write_bitmap_capability_set(log, s, settings) ||
4852 !rdp_write_order_capability_set(log, s, settings))
4853 return FALSE;
4854
4855 if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
4856 ret = rdp_write_bitmap_cache_v2_capability_set(log, s, settings);
4857 else
4858 ret = rdp_write_bitmap_cache_capability_set(log, s, settings);
4859
4860 if (!ret)
4861 return FALSE;
4862
4863 if (!rdp_write_pointer_capability_set(log, s, settings) ||
4864 !rdp_write_input_capability_set(log, s, settings) ||
4865 !rdp_write_brush_capability_set(log, s, settings) ||
4866 !rdp_write_glyph_cache_capability_set(log, s, settings) ||
4867 !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4868 !rdp_write_sound_capability_set(log, s, settings) ||
4869 !rdp_write_share_capability_set(log, s, settings) ||
4870 !rdp_write_font_capability_set(log, s, settings) ||
4871 !rdp_write_control_capability_set(log, s, settings) ||
4872 !rdp_write_color_cache_capability_set(log, s, settings) ||
4873 !rdp_write_window_activation_capability_set(log, s, settings))
4874 {
4875 return FALSE;
4876 }
4877
4878 {
4879 numberCapabilities++;
4880
4881 if (!rdp_write_offscreen_bitmap_cache_capability_set(log, s, settings))
4882 return FALSE;
4883 }
4884
4885 if (settings->DrawNineGridEnabled)
4886 {
4887 numberCapabilities++;
4888
4889 if (!rdp_write_draw_nine_grid_cache_capability_set(log, s, settings))
4890 return FALSE;
4891 }
4892
4893 if (settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4894 {
4895 if (settings->LargePointerFlag)
4896 {
4897 numberCapabilities++;
4898
4899 if (!rdp_write_large_pointer_capability_set(log, s, settings))
4900 return FALSE;
4901 }
4902 }
4903
4904 if (settings->RemoteApplicationMode)
4905 {
4906 numberCapabilities += 2;
4907
4908 if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4909 !rdp_write_window_list_capability_set(log, s, settings))
4910 return FALSE;
4911 }
4912
4913 if (settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4914 {
4915 numberCapabilities++;
4916
4917 if (!rdp_write_multifragment_update_capability_set(log, s, settings))
4918 return FALSE;
4919 }
4920
4921 if (settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4922 {
4923 numberCapabilities++;
4924
4925 if (!rdp_write_surface_commands_capability_set(log, s, settings))
4926 return FALSE;
4927 }
4928
4929 if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4930 {
4931 numberCapabilities++;
4932
4933 if (!rdp_write_bitmap_codecs_capability_set(log, s, settings))
4934 return FALSE;
4935 }
4936
4937 if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4938 settings->FrameAcknowledge = 0;
4939
4940 if (settings->FrameAcknowledge)
4941 {
4942 numberCapabilities++;
4943
4944 if (!rdp_write_frame_acknowledge_capability_set(log, s, settings))
4945 return FALSE;
4946 }
4947
4948 if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4949 {
4950 if (settings->BitmapCacheV3CodecId != 0)
4951 {
4952 numberCapabilities++;
4953
4954 if (!rdp_write_bitmap_cache_v3_codec_id_capability_set(log, s, settings))
4955 return FALSE;
4956 }
4957 }
4958
4959 em = Stream_GetPosition(s);
4960 if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4961 return FALSE;
4962 lengthCombinedCapabilities = (em - bm);
4963 if (lengthCombinedCapabilities > UINT16_MAX)
4964 return FALSE;
4965 Stream_Write_UINT16(
4966 s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4967 if (!Stream_SetPosition(s, bm)) /* go back to numberCapabilities */
4968 return FALSE;
4969 Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4970#ifdef WITH_DEBUG_CAPABILITIES
4971 rdp_print_capability_sets(log, s, bm, FALSE);
4972#endif
4973 return Stream_SetPosition(s, em);
4974}
4975
4976BOOL rdp_send_confirm_active(rdpRdp* rdp)
4977{
4978 UINT16 sec_flags = 0;
4979 wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4980 BOOL status = 0;
4981
4982 if (!s)
4983 return FALSE;
4984
4985 status = rdp_write_confirm_active(rdp->log, s, rdp->settings) &&
4986 rdp_send_pdu(rdp, s, PDU_TYPE_CONFIRM_ACTIVE, rdp->mcs->userId, sec_flags);
4987 Stream_Release(s);
4988 return status;
4989}
4990
4991const char* rdp_input_flag_string(UINT16 flags, char* buffer, size_t len)
4992{
4993 char prefix[16] = WINPR_C_ARRAY_INIT;
4994
4995 (void)_snprintf(prefix, sizeof(prefix), "[0x%04" PRIx16 "][", flags);
4996 winpr_str_append(prefix, buffer, len, "");
4997 if ((flags & INPUT_FLAG_SCANCODES) != 0)
4998 winpr_str_append("INPUT_FLAG_SCANCODES", buffer, len, "|");
4999 if ((flags & INPUT_FLAG_MOUSEX) != 0)
5000 winpr_str_append("INPUT_FLAG_MOUSEX", buffer, len, "|");
5001 if ((flags & INPUT_FLAG_FASTPATH_INPUT) != 0)
5002 winpr_str_append("INPUT_FLAG_FASTPATH_INPUT", buffer, len, "|");
5003 if ((flags & INPUT_FLAG_UNICODE) != 0)
5004 winpr_str_append("INPUT_FLAG_UNICODE", buffer, len, "|");
5005 if ((flags & INPUT_FLAG_FASTPATH_INPUT2) != 0)
5006 winpr_str_append("INPUT_FLAG_FASTPATH_INPUT2", buffer, len, "|");
5007 if ((flags & INPUT_FLAG_UNUSED1) != 0)
5008 winpr_str_append("INPUT_FLAG_UNUSED1", buffer, len, "|");
5009 if ((flags & INPUT_FLAG_MOUSE_RELATIVE) != 0)
5010 winpr_str_append("INPUT_FLAG_MOUSE_RELATIVE", buffer, len, "|");
5011 if ((flags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0)
5012 winpr_str_append("TS_INPUT_FLAG_MOUSE_HWHEEL", buffer, len, "|");
5013 if ((flags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0)
5014 winpr_str_append("TS_INPUT_FLAG_QOE_TIMESTAMPS", buffer, len, "|");
5015 winpr_str_append("]", buffer, len, "");
5016 return buffer;
5017}
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.
WINPR_ATTR_NODISCARD 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 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.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD 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_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
Definition wtypes.h:254