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 const UINT32 limit = UINT32_MAX / 16384u;
2820
2821 if (tileNumX >= limit / tileNumY)
2822 {
2823 WLog_Print(log, WLOG_ERROR,
2824 "(DesktopWidth * DesktopHeigth) / 64 exceed limit of %" PRIu32, limit);
2825 return FALSE;
2826 }
2827 if (tileNumY >= limit / tileNumX)
2828 {
2829 WLog_Print(log, WLOG_ERROR,
2830 "(DesktopWidth * DesktopHeigth) / 64 exceed limit of %" PRIu32, limit);
2831 return FALSE;
2832 }
2833
2834 /* and add room for headers, regions, frame markers, etc. */
2835 const UINT32 MultifragMaxRequestSize = (tileNumX * tileNumY + 1u) * 16384u;
2836
2837 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2838 MultifragMaxRequestSize))
2839 return FALSE;
2840 }
2841
2842 if (!Stream_EnsureRemainingCapacity(s, 32))
2843 return FALSE;
2844 const size_t header = rdp_capability_set_start(log, s);
2845 Stream_Write_UINT32(s, settings->MultifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
2846 return rdp_capability_set_finish(s, header, CAPSET_TYPE_MULTI_FRAGMENT_UPDATE);
2847}
2848
2849#ifdef WITH_DEBUG_CAPABILITIES
2850static BOOL rdp_print_multifragment_update_capability_set(wLog* log, wStream* s)
2851{
2852 UINT32 maxRequestSize = 0;
2853 WLog_Print(log, WLOG_TRACE, "MultifragmentUpdateCapabilitySet (length %" PRIuz "):",
2854 Stream_GetRemainingLength(s));
2855
2856 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2857 return FALSE;
2858
2859 Stream_Read_UINT32(s, maxRequestSize); /* maxRequestSize (4 bytes) */
2860 WLog_Print(log, WLOG_TRACE, "\tmaxRequestSize: 0x%08" PRIX32 "", maxRequestSize);
2861 return TRUE;
2862}
2863#endif
2864
2865static BOOL rdp_apply_large_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
2866{
2867 WINPR_ASSERT(settings);
2868 WINPR_ASSERT(src);
2869
2870 settings->LargePointerFlag = src->LargePointerFlag;
2871 return TRUE;
2872}
2873
2874/*
2875 * Read large pointer capability set.
2876 * msdn{cc240650}
2877 */
2878
2879static BOOL rdp_read_large_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2880{
2881 UINT16 largePointerSupportFlags = 0;
2882
2883 WINPR_ASSERT(settings);
2884 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2885 return FALSE;
2886
2887 Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2888 settings->LargePointerFlag &= largePointerSupportFlags;
2889 if ((largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) != 0)
2890 {
2891 WLog_Print(
2892 log, WLOG_WARN,
2893 "TS_LARGE_POINTER_CAPABILITYSET with unsupported flags %04X (all flags %04X) received",
2894 WINPR_CXX_COMPAT_CAST(UINT32, largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 |
2895 LARGE_POINTER_FLAG_384x384)),
2896 largePointerSupportFlags);
2897 }
2898 return TRUE;
2899}
2900
2901/*
2902 * Write large pointer capability set.
2903 * msdn{cc240650}
2904 */
2905
2906static BOOL rdp_write_large_pointer_capability_set(wLog* log, wStream* s,
2907 const rdpSettings* settings)
2908{
2909 WINPR_ASSERT(settings);
2910 if (!Stream_EnsureRemainingCapacity(s, 32))
2911 return FALSE;
2912
2913 const size_t header = rdp_capability_set_start(log, s);
2914 const UINT16 largePointerSupportFlags =
2915 settings->LargePointerFlag & (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
2916 Stream_Write_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2917 return rdp_capability_set_finish(s, header, CAPSET_TYPE_LARGE_POINTER);
2918}
2919
2920#ifdef WITH_DEBUG_CAPABILITIES
2921static BOOL rdp_print_large_pointer_capability_set(wLog* log, wStream* s)
2922{
2923 UINT16 largePointerSupportFlags = 0;
2924 WLog_Print(log, WLOG_TRACE,
2925 "LargePointerCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2926
2927 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2928 return FALSE;
2929
2930 Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2931 WLog_Print(log, WLOG_TRACE, "\tlargePointerSupportFlags: 0x%04" PRIX16 "",
2932 largePointerSupportFlags);
2933 return TRUE;
2934}
2935#endif
2936
2937static BOOL rdp_apply_surface_commands_capability_set(rdpSettings* settings, const rdpSettings* src)
2938{
2939 WINPR_ASSERT(settings);
2940 WINPR_ASSERT(src);
2941
2942 /* [MS-RDPBCGR] 2.2.7.2.9 Surface Commands Capability Set (TS_SURFCMDS_CAPABILITYSET)
2943 *
2944 * disable surface commands if the remote does not support fastpath
2945 */
2946 if (src->FastPathOutput)
2947 {
2948 settings->SurfaceCommandsSupported &= src->SurfaceCommandsSupported;
2949 settings->SurfaceCommandsEnabled = src->SurfaceCommandsEnabled;
2950 settings->SurfaceFrameMarkerEnabled = src->SurfaceFrameMarkerEnabled;
2951 }
2952 else
2953 {
2954 settings->SurfaceCommandsSupported = 0;
2955 settings->SurfaceCommandsEnabled = FALSE;
2956 settings->SurfaceFrameMarkerEnabled = FALSE;
2957 }
2958
2959 return TRUE;
2960}
2961
2962/*
2963 * Read surface commands capability set.
2964 * msdn{dd871563}
2965 */
2966
2967static BOOL rdp_read_surface_commands_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2968{
2969 UINT32 cmdFlags = 0;
2970
2971 WINPR_ASSERT(settings);
2972 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2973 return FALSE;
2974
2975 Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
2976 Stream_Seek_UINT32(s); /* reserved (4 bytes) */
2977 settings->SurfaceCommandsSupported = cmdFlags;
2978 settings->SurfaceCommandsEnabled =
2979 (cmdFlags & (SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS)) != 0;
2980 settings->SurfaceFrameMarkerEnabled = (cmdFlags & SURFCMDS_FRAME_MARKER) != 0;
2981 return TRUE;
2982}
2983
2984/*
2985 * Write surface commands capability set.
2986 * msdn{dd871563}
2987 */
2988
2989static BOOL rdp_write_surface_commands_capability_set(wLog* log, wStream* s,
2990 const rdpSettings* settings)
2991{
2992 WINPR_ASSERT(settings);
2993 if (!Stream_EnsureRemainingCapacity(s, 32))
2994 return FALSE;
2995
2996 const size_t header = rdp_capability_set_start(log, s);
2997 // TODO: Make these configurable too
2998 UINT32 cmdFlags = freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
2999
3000 if (settings->SurfaceFrameMarkerEnabled)
3001 cmdFlags |= SURFCMDS_FRAME_MARKER;
3002
3003 Stream_Write_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3004 Stream_Write_UINT32(s, 0); /* reserved (4 bytes) */
3005 return rdp_capability_set_finish(s, header, CAPSET_TYPE_SURFACE_COMMANDS);
3006}
3007
3008static bool sUuidEqual(const UUID* Uuid1, const UUID* Uuid2)
3009{
3010 if (!Uuid1 && !Uuid2)
3011 return false;
3012
3013 if (Uuid1 && !Uuid2)
3014 return false;
3015
3016 if (!Uuid1 && Uuid2)
3017 return false;
3018
3019 if (Uuid1->Data1 != Uuid2->Data1)
3020 return false;
3021
3022 if (Uuid1->Data2 != Uuid2->Data2)
3023 return false;
3024
3025 if (Uuid1->Data3 != Uuid2->Data3)
3026 return false;
3027
3028 for (int index = 0; index < 8; index++)
3029 {
3030 if (Uuid1->Data4[index] != Uuid2->Data4[index])
3031 return false;
3032 }
3033
3034 return true;
3035}
3036
3037#ifdef WITH_DEBUG_CAPABILITIES
3038static BOOL rdp_print_surface_commands_capability_set(wLog* log, wStream* s)
3039{
3040 UINT32 cmdFlags = 0;
3041 UINT32 reserved = 0;
3042
3043 WLog_Print(log, WLOG_TRACE,
3044 "SurfaceCommandsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3045
3046 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
3047 return FALSE;
3048
3049 Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3050 Stream_Read_UINT32(s, reserved); /* reserved (4 bytes) */
3051 WLog_Print(log, WLOG_TRACE, "\tcmdFlags: 0x%08" PRIX32 "", cmdFlags);
3052 WLog_Print(log, WLOG_TRACE, "\treserved: 0x%08" PRIX32 "", reserved);
3053 return TRUE;
3054}
3055
3056static void rdp_print_bitmap_codec_guid(wLog* log, const GUID* guid)
3057{
3058 WINPR_ASSERT(guid);
3059 WLog_Print(log, WLOG_TRACE,
3060 "%08" PRIX32 "%04" PRIX16 "%04" PRIX16 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8
3061 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "",
3062 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
3063 guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6],
3064 guid->Data4[7]);
3065}
3066
3067static char* rdp_get_bitmap_codec_guid_name(const GUID* guid)
3068{
3069 WINPR_ASSERT(guid);
3070 if (sUuidEqual(guid, &CODEC_GUID_REMOTEFX))
3071 return "CODEC_GUID_REMOTEFX";
3072 else if (sUuidEqual(guid, &CODEC_GUID_NSCODEC))
3073 return "CODEC_GUID_NSCODEC";
3074 else if (sUuidEqual(guid, &CODEC_GUID_IGNORE))
3075 return "CODEC_GUID_IGNORE";
3076 else if (sUuidEqual(guid, &CODEC_GUID_IMAGE_REMOTEFX))
3077 return "CODEC_GUID_IMAGE_REMOTEFX";
3078
3079#if defined(WITH_JPEG)
3080 else if (sUuidEqual(guid, &CODEC_GUID_JPEG))
3081 return "CODEC_GUID_JPEG";
3082
3083#endif
3084 return "CODEC_GUID_UNKNOWN";
3085}
3086#endif
3087
3088static BOOL rdp_read_bitmap_codec_guid(wLog* log, wStream* s, GUID* guid)
3089{
3090 BYTE g[16] = WINPR_C_ARRAY_INIT;
3091
3092 WINPR_ASSERT(guid);
3093 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16))
3094 return FALSE;
3095 Stream_Read(s, g, 16);
3096 guid->Data1 = ((UINT32)g[3] << 24U) | ((UINT32)g[2] << 16U) | (UINT32)(g[1] << 8U) | g[0];
3097 guid->Data2 = ((g[5] << 8U) | g[4]) & 0xFFFF;
3098 guid->Data3 = ((g[7] << 8U) | g[6]) & 0xFFFF;
3099 guid->Data4[0] = g[8];
3100 guid->Data4[1] = g[9];
3101 guid->Data4[2] = g[10];
3102 guid->Data4[3] = g[11];
3103 guid->Data4[4] = g[12];
3104 guid->Data4[5] = g[13];
3105 guid->Data4[6] = g[14];
3106 guid->Data4[7] = g[15];
3107 return TRUE;
3108}
3109
3110static void rdp_write_bitmap_codec_guid(wStream* s, const GUID* guid)
3111{
3112 BYTE g[16] = WINPR_C_ARRAY_INIT;
3113 WINPR_ASSERT(guid);
3114 g[0] = guid->Data1 & 0xFF;
3115 g[1] = (guid->Data1 >> 8) & 0xFF;
3116 g[2] = (guid->Data1 >> 16) & 0xFF;
3117 g[3] = (guid->Data1 >> 24) & 0xFF;
3118 g[4] = (guid->Data2) & 0xFF;
3119 g[5] = (guid->Data2 >> 8) & 0xFF;
3120 g[6] = (guid->Data3) & 0xFF;
3121 g[7] = (guid->Data3 >> 8) & 0xFF;
3122 g[8] = guid->Data4[0];
3123 g[9] = guid->Data4[1];
3124 g[10] = guid->Data4[2];
3125 g[11] = guid->Data4[3];
3126 g[12] = guid->Data4[4];
3127 g[13] = guid->Data4[5];
3128 g[14] = guid->Data4[6];
3129 g[15] = guid->Data4[7];
3130 Stream_Write(s, g, 16);
3131}
3132
3133static BOOL rdp_apply_bitmap_codecs_capability_set(rdpSettings* settings, const rdpSettings* src)
3134{
3135 WINPR_ASSERT(settings);
3136 WINPR_ASSERT(src);
3137
3138 if (settings->ServerMode)
3139 {
3140
3141 settings->RemoteFxCodecId = src->RemoteFxCodecId;
3142 settings->RemoteFxCaptureFlags = src->RemoteFxCaptureFlags;
3143 settings->RemoteFxOnly = src->RemoteFxOnly;
3144 settings->RemoteFxRlgrMode = src->RemoteFxRlgrMode;
3145 settings->RemoteFxCodecMode = src->RemoteFxCodecMode;
3146 settings->NSCodecId = src->NSCodecId;
3147 settings->NSCodecAllowDynamicColorFidelity = src->NSCodecAllowDynamicColorFidelity;
3148 settings->NSCodecAllowSubsampling = src->NSCodecAllowSubsampling;
3149 settings->NSCodecColorLossLevel = src->NSCodecColorLossLevel;
3150
3151 /* only enable a codec if we've announced/enabled it before */
3152 settings->RemoteFxCodec = settings->RemoteFxCodec && src->RemoteFxCodecId;
3153 settings->RemoteFxImageCodec = settings->RemoteFxImageCodec && src->RemoteFxImageCodec;
3154 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec,
3155 settings->NSCodec && src->NSCodec))
3156 return FALSE;
3157 settings->JpegCodec = src->JpegCodec;
3158 }
3159 return TRUE;
3160}
3161
3162static BOOL rdp_read_codec_ts_rfx_icap(wLog* log, wStream* sub, rdpSettings* settings,
3163 UINT16 icapLen)
3164{
3165 UINT16 version = 0;
3166 UINT16 tileSize = 0;
3167 BYTE codecFlags = 0;
3168 BYTE colConvBits = 0;
3169 BYTE transformBits = 0;
3170 BYTE entropyBits = 0;
3171 /* TS_RFX_ICAP */
3172 if (icapLen != 8)
3173 {
3174 WLog_Print(log, WLOG_ERROR,
3175 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP size %" PRIu16
3176 " unsupported, expecting size %" PRIu16 " not supported",
3177 icapLen, 8u);
3178 return FALSE;
3179 }
3180
3181 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3182 return FALSE;
3183
3184 Stream_Read_UINT16(sub, version); /* version (2 bytes) */
3185 Stream_Read_UINT16(sub, tileSize); /* tileSize (2 bytes) */
3186 Stream_Read_UINT8(sub, codecFlags); /* flags (1 byte) */
3187 Stream_Read_UINT8(sub, colConvBits); /* colConvBits (1 byte) */
3188 Stream_Read_UINT8(sub, transformBits); /* transformBits (1 byte) */
3189 Stream_Read_UINT8(sub, entropyBits); /* entropyBits (1 byte) */
3190
3191 if (version == 0x0009)
3192 {
3193 /* Version 0.9 */
3194 if (tileSize != 0x0080)
3195 {
3196 WLog_Print(log, WLOG_ERROR,
3197 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3198 " tile size %" PRIu16 " not supported",
3199 version, tileSize);
3200 return FALSE;
3201 }
3202 }
3203 else if (version == 0x0100)
3204 {
3205 /* Version 1.0 */
3206 if (tileSize != 0x0040)
3207 {
3208 WLog_Print(log, WLOG_ERROR,
3209 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3210 " tile size %" PRIu16 " not supported",
3211 version, tileSize);
3212 return FALSE;
3213 }
3214 }
3215 else
3216 {
3217 WLog_Print(log, WLOG_ERROR,
3218 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16 " not supported",
3219 version);
3220 return FALSE;
3221 }
3222
3223 /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_COL_CONV_ICT (0x1) */
3224 if (colConvBits != 1)
3225 {
3226 WLog_Print(log, WLOG_ERROR,
3227 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::colConvBits %" PRIu8
3228 " not supported, must be CLW_COL_CONV_ICT (0x1)",
3229 colConvBits);
3230 return FALSE;
3231 }
3232
3233 /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_XFORM_DWT_53_A (0x1) */
3234 if (transformBits != 1)
3235 {
3236 WLog_Print(log, WLOG_ERROR,
3237 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::transformBits %" PRIu8
3238 " not supported, must be CLW_XFORM_DWT_53_A (0x1)",
3239 colConvBits);
3240 return FALSE;
3241 }
3242
3243 const UINT8 CODEC_MODE = 0x02; /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP */
3244 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x00))
3245 return FALSE;
3246
3247 if ((codecFlags & CODEC_MODE) != 0)
3248 {
3249 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x02))
3250 return FALSE;
3251 }
3252 else if ((codecFlags & ~CODEC_MODE) != 0)
3253 WLog_Print(log, WLOG_WARN,
3254 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::flags unknown value "
3255 "0x%02" PRIx32,
3256 WINPR_CXX_COMPAT_CAST(UINT32, (codecFlags & ~CODEC_MODE)));
3257
3258 switch (entropyBits)
3259 {
3260 case CLW_ENTROPY_RLGR1:
3261 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR1))
3262 return FALSE;
3263 break;
3264 case CLW_ENTROPY_RLGR3:
3265 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3))
3266 return FALSE;
3267 break;
3268 default:
3269 WLog_Print(log, WLOG_ERROR,
3270 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::entropyBits "
3271 "unsupported value 0x%02" PRIx8
3272 ", must be CLW_ENTROPY_RLGR1 (0x01) or CLW_ENTROPY_RLGR3 "
3273 "(0x04)",
3274 entropyBits);
3275 return FALSE;
3276 }
3277 return TRUE;
3278}
3279
3280static BOOL rdp_read_codec_ts_rfx_capset(wLog* log, wStream* s, rdpSettings* settings)
3281{
3282 UINT16 blockType = 0;
3283 UINT32 blockLen = 0;
3284 BYTE rfxCodecId = 0;
3285 UINT16 capsetType = 0;
3286 UINT16 numIcaps = 0;
3287 UINT16 icapLen = 0;
3288
3289 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
3290 return FALSE;
3291
3292 /* TS_RFX_CAPSET */
3293 Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
3294 Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */
3295 if (blockType != 0xCBC1)
3296 {
3297 WLog_Print(log, WLOG_ERROR,
3298 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockType[0x%04" PRIx16
3299 "] != CBY_CAPSET (0xCBC1)",
3300 blockType);
3301 return FALSE;
3302 }
3303 if (blockLen < 6ull)
3304 {
3305 WLog_Print(log, WLOG_ERROR,
3306 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockLen[%" PRIu32 "] < 6", blockLen);
3307 return FALSE;
3308 }
3309 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, blockLen - 6ull))
3310 return FALSE;
3311
3312 wStream sbuffer = WINPR_C_ARRAY_INIT;
3313 wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), blockLen - 6ull);
3314 WINPR_ASSERT(sub);
3315
3316 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 7))
3317 return FALSE;
3318
3319 Stream_Read_UINT8(sub, rfxCodecId); /* codecId (1 byte) */
3320 Stream_Read_UINT16(sub, capsetType); /* capsetType (2 bytes) */
3321 Stream_Read_UINT16(sub, numIcaps); /* numIcaps (2 bytes) */
3322 Stream_Read_UINT16(sub, icapLen); /* icapLen (2 bytes) */
3323
3324 if (rfxCodecId != 1)
3325 {
3326 WLog_Print(log, WLOG_ERROR,
3327 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::codecId[%" PRIu16 "] != 1", rfxCodecId);
3328 return FALSE;
3329 }
3330
3331 if (capsetType != 0xCFC0)
3332 {
3333 WLog_Print(log, WLOG_ERROR,
3334 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::capsetType[0x%04" PRIx16
3335 "] != CLY_CAPSET (0xCFC0)",
3336 capsetType);
3337 return FALSE;
3338 }
3339
3340 while (numIcaps--)
3341 {
3342 if (!rdp_read_codec_ts_rfx_icap(log, sub, settings, icapLen))
3343 return FALSE;
3344 }
3345 return TRUE;
3346}
3347
3348static BOOL rdp_read_codec_ts_rfx_caps(wLog* log, wStream* sub, rdpSettings* settings)
3349{
3350 if (Stream_GetRemainingLength(sub) == 0)
3351 return TRUE;
3352
3353 UINT16 blockType = 0;
3354 UINT32 blockLen = 0;
3355 UINT16 numCapsets = 0;
3356
3357 /* TS_RFX_CAPS */
3358 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3359 return FALSE;
3360 Stream_Read_UINT16(sub, blockType); /* blockType (2 bytes) */
3361 Stream_Read_UINT32(sub, blockLen); /* blockLen (4 bytes) */
3362 Stream_Read_UINT16(sub, numCapsets); /* numCapsets (2 bytes) */
3363
3364 if (blockType != 0xCBC0)
3365 {
3366 WLog_Print(log, WLOG_ERROR,
3367 "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockType[0x%04" PRIx16
3368 "] != CBY_CAPS (0xCBC0)",
3369 blockType);
3370 return FALSE;
3371 }
3372
3373 if (blockLen != 8)
3374 {
3375 WLog_Print(log, WLOG_ERROR, "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockLen[%" PRIu16 "] != 8",
3376 blockLen);
3377 return FALSE;
3378 }
3379
3380 if (numCapsets != 1)
3381 {
3382 WLog_Print(log, WLOG_ERROR,
3383 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::numIcaps[%" PRIu16 "] != 1", numCapsets);
3384 return FALSE;
3385 }
3386
3387 for (UINT16 x = 0; x < numCapsets; x++)
3388 {
3389 if (!rdp_read_codec_ts_rfx_capset(log, sub, settings))
3390 return FALSE;
3391 }
3392
3393 return TRUE;
3394}
3395
3396static BOOL rdp_read_codec_ts_rfx_clnt_caps_container(wLog* log, wStream* s, rdpSettings* settings)
3397{
3398 UINT32 rfxCapsLength = 0;
3399 UINT32 rfxPropsLength = 0;
3400 UINT32 captureFlags = 0;
3401
3402 /* [MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER */
3403 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3404 return FALSE;
3405 Stream_Read_UINT32(s, rfxPropsLength); /* length (4 bytes) */
3406 if (rfxPropsLength < 4)
3407 {
3408 WLog_Print(log, WLOG_ERROR,
3409 "[MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER::length %" PRIu32
3410 " too short, require at least 4 bytes",
3411 rfxPropsLength);
3412 return FALSE;
3413 }
3414 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, rfxPropsLength - 4ull))
3415 return FALSE;
3416
3417 wStream sbuffer = WINPR_C_ARRAY_INIT;
3418 wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), rfxPropsLength - 4ull);
3419 WINPR_ASSERT(sub);
3420
3421 Stream_Seek(s, rfxPropsLength - 4ull);
3422
3423 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3424 return FALSE;
3425
3426 Stream_Read_UINT32(sub, captureFlags); /* captureFlags (4 bytes) */
3427 Stream_Read_UINT32(sub, rfxCapsLength); /* capsLength (4 bytes) */
3428 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, rfxCapsLength))
3429 return FALSE;
3430
3431 settings->RemoteFxCaptureFlags = captureFlags;
3432 settings->RemoteFxOnly = !(captureFlags & CARDP_CAPS_CAPTURE_NON_CAC);
3433
3434 /* [MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS */
3435 wStream tsbuffer = WINPR_C_ARRAY_INIT;
3436 wStream* ts_sub = Stream_StaticConstInit(&tsbuffer, Stream_Pointer(sub), rfxCapsLength);
3437 WINPR_ASSERT(ts_sub);
3438 return rdp_read_codec_ts_rfx_caps(log, ts_sub, settings);
3439}
3440
3441/*
3442 * Read bitmap codecs capability set.
3443 * msdn{dd891377}
3444 */
3445
3446static BOOL rdp_read_bitmap_codecs_capability_set(wLog* log, wStream* s, rdpSettings* settings,
3447 BOOL isServer)
3448{
3449 BYTE codecId = 0;
3450 GUID codecGuid = WINPR_C_ARRAY_INIT;
3451 BYTE bitmapCodecCount = 0;
3452 UINT16 codecPropertiesLength = 0;
3453
3454 BOOL guidNSCodec = FALSE;
3455 BOOL guidRemoteFx = FALSE;
3456 BOOL guidRemoteFxImage = FALSE;
3457
3458 WINPR_ASSERT(settings);
3459 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3460 return FALSE;
3461
3462 Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3463
3464 while (bitmapCodecCount > 0)
3465 {
3466 wStream subbuffer = WINPR_C_ARRAY_INIT;
3467
3468 if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3469 return FALSE;
3470 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3471 return FALSE;
3472 Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3473 Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3474
3475 wStream* sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), codecPropertiesLength);
3476 if (!Stream_SafeSeek(s, codecPropertiesLength))
3477 return FALSE;
3478
3479 if (isServer)
3480 {
3481 if (sUuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX))
3482 {
3483 guidRemoteFx = TRUE;
3484 settings->RemoteFxCodecId = codecId;
3485 if (!rdp_read_codec_ts_rfx_clnt_caps_container(log, sub, settings))
3486 return FALSE;
3487 }
3488 else if (sUuidEqual(&codecGuid, &CODEC_GUID_IMAGE_REMOTEFX))
3489 {
3490 /* Microsoft RDP servers ignore CODEC_GUID_IMAGE_REMOTEFX codec properties */
3491 guidRemoteFxImage = TRUE;
3492 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3493 return FALSE;
3494 }
3495 else if (sUuidEqual(&codecGuid, &CODEC_GUID_NSCODEC))
3496 {
3497 BYTE colorLossLevel = 0;
3498 BYTE fAllowSubsampling = 0;
3499 BYTE fAllowDynamicFidelity = 0;
3500 guidNSCodec = TRUE;
3501 settings->NSCodecId = codecId;
3502 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 3))
3503 return FALSE;
3504 Stream_Read_UINT8(sub, fAllowDynamicFidelity); /* fAllowDynamicFidelity (1 byte) */
3505 Stream_Read_UINT8(sub, fAllowSubsampling); /* fAllowSubsampling (1 byte) */
3506 Stream_Read_UINT8(sub, colorLossLevel); /* colorLossLevel (1 byte) */
3507
3508 if (colorLossLevel < 1)
3509 colorLossLevel = 1;
3510
3511 if (colorLossLevel > 7)
3512 colorLossLevel = 7;
3513
3514 settings->NSCodecAllowDynamicColorFidelity = fAllowDynamicFidelity;
3515 settings->NSCodecAllowSubsampling = fAllowSubsampling;
3516 settings->NSCodecColorLossLevel = colorLossLevel;
3517 }
3518 else if (sUuidEqual(&codecGuid, &CODEC_GUID_IGNORE))
3519 {
3520 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3521 return FALSE;
3522 }
3523 else
3524 {
3525 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3526 return FALSE;
3527 }
3528 }
3529 else
3530 {
3531 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3532 return FALSE;
3533 }
3534
3535 const size_t rest = Stream_GetRemainingLength(sub);
3536 if (rest > 0)
3537 {
3538 WLog_Print(log, WLOG_ERROR,
3539 "error while reading codec properties: actual size: %" PRIuz
3540 " expected size: %" PRIu32 "",
3541 rest + codecPropertiesLength, codecPropertiesLength);
3542 }
3543 bitmapCodecCount--;
3544
3545 /* only enable a codec if we've announced/enabled it before */
3546 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, guidRemoteFx))
3547 return FALSE;
3548 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, guidRemoteFxImage))
3549 return FALSE;
3550 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, guidNSCodec))
3551 return FALSE;
3552 if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
3553 return FALSE;
3554 }
3555
3556 return TRUE;
3557}
3558
3559/*
3560 * Write RemoteFX Client Capability Container.
3561 */
3562static BOOL rdp_write_rfx_client_capability_container(wStream* s, const rdpSettings* settings)
3563{
3564 WINPR_ASSERT(settings);
3565 if (!Stream_EnsureRemainingCapacity(s, 64))
3566 return FALSE;
3567
3568 const UINT32 captureFlags = settings->RemoteFxOnly ? 0 : CARDP_CAPS_CAPTURE_NON_CAC;
3569
3570 WINPR_ASSERT(settings->RemoteFxCodecMode <= UINT8_MAX);
3571 const UINT8 codecMode = (UINT8)settings->RemoteFxCodecMode;
3572 Stream_Write_UINT16(s, 49); /* codecPropertiesLength */
3573 /* TS_RFX_CLNT_CAPS_CONTAINER */
3574 Stream_Write_UINT32(s, 49); /* length */
3575 Stream_Write_UINT32(s, captureFlags); /* captureFlags */
3576 Stream_Write_UINT32(s, 37); /* capsLength */
3577 /* TS_RFX_CAPS */
3578 Stream_Write_UINT16(s, CBY_CAPS); /* blockType */
3579 Stream_Write_UINT32(s, 8); /* blockLen */
3580 Stream_Write_UINT16(s, 1); /* numCapsets */
3581 /* TS_RFX_CAPSET */
3582 Stream_Write_UINT16(s, CBY_CAPSET); /* blockType */
3583 Stream_Write_UINT32(s, 29); /* blockLen */
3584 Stream_Write_UINT8(s, 0x01); /* codecId (MUST be set to 0x01) */
3585 Stream_Write_UINT16(s, CLY_CAPSET); /* capsetType */
3586 Stream_Write_UINT16(s, 2); /* numIcaps */
3587 Stream_Write_UINT16(s, 8); /* icapLen */
3588 /* TS_RFX_ICAP (RLGR1) */
3589 Stream_Write_UINT16(s, CLW_VERSION_1_0); /* version */
3590 Stream_Write_UINT16(s, CT_TILE_64x64); /* tileSize */
3591 Stream_Write_UINT8(s, codecMode); /* flags */
3592 Stream_Write_UINT8(s, CLW_COL_CONV_ICT); /* colConvBits */
3593 Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3594 Stream_Write_UINT8(s, CLW_ENTROPY_RLGR1); /* entropyBits */
3595 /* TS_RFX_ICAP (RLGR3) */
3596 Stream_Write_UINT16(s, CLW_VERSION_1_0); /* version */
3597 Stream_Write_UINT16(s, CT_TILE_64x64); /* tileSize */
3598 Stream_Write_UINT8(s, codecMode); /* flags */
3599 Stream_Write_UINT8(s, CLW_COL_CONV_ICT); /* colConvBits */
3600 Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3601 Stream_Write_UINT8(s, CLW_ENTROPY_RLGR3); /* entropyBits */
3602 return TRUE;
3603}
3604
3605/*
3606 * Write NSCODEC Client Capability Container.
3607 */
3608static BOOL rdp_write_nsc_client_capability_container(wStream* s, const rdpSettings* settings)
3609{
3610 WINPR_ASSERT(settings);
3611
3612 const BOOL fAllowDynamicFidelity = settings->NSCodecAllowDynamicColorFidelity;
3613 const BOOL fAllowSubsampling = settings->NSCodecAllowSubsampling;
3614 UINT32 colorLossLevel = settings->NSCodecColorLossLevel;
3615
3616 if (colorLossLevel < 1)
3617 colorLossLevel = 1;
3618
3619 if (colorLossLevel > 7)
3620 colorLossLevel = 7;
3621
3622 if (!Stream_EnsureRemainingCapacity(s, 8))
3623 return FALSE;
3624
3625 Stream_Write_UINT16(s, 3); /* codecPropertiesLength */
3626 /* TS_NSCODEC_CAPABILITYSET */
3627 Stream_Write_UINT8(s, fAllowDynamicFidelity != 0); /* fAllowDynamicFidelity (1 byte) */
3628 Stream_Write_UINT8(s, fAllowSubsampling != 0); /* fAllowSubsampling (1 byte) */
3629 Stream_Write_UINT8(s, (UINT8)colorLossLevel); /* colorLossLevel (1 byte) */
3630 return TRUE;
3631}
3632
3633#if defined(WITH_JPEG)
3634static BOOL rdp_write_jpeg_client_capability_container(wStream* s, const rdpSettings* settings)
3635{
3636 WINPR_ASSERT(settings);
3637 if (!Stream_EnsureRemainingCapacity(s, 8))
3638 return FALSE;
3639
3640 Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3641
3642 const UINT32 q = freerdp_settings_get_uint32(settings, FreeRDP_JpegQuality);
3643 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, q));
3644 return TRUE;
3645}
3646#endif
3647
3648/*
3649 * Write RemoteFX Server Capability Container.
3650 */
3651static BOOL rdp_write_rfx_server_capability_container(wStream* s, const rdpSettings* settings)
3652{
3653 WINPR_UNUSED(settings);
3654 WINPR_ASSERT(settings);
3655
3656 if (!Stream_EnsureRemainingCapacity(s, 8))
3657 return FALSE;
3658
3659 Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3660 Stream_Write_UINT32(s, 0); /* reserved */
3661 return TRUE;
3662}
3663
3664#if defined(WITH_JPEG)
3665static BOOL rdp_write_jpeg_server_capability_container(wStream* s, const rdpSettings* settings)
3666{
3667 WINPR_UNUSED(settings);
3668 WINPR_ASSERT(settings);
3669
3670 if (!Stream_EnsureRemainingCapacity(s, 8))
3671 return FALSE;
3672
3673 Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3674 Stream_Write_UINT8(s, 75);
3675 return TRUE;
3676}
3677#endif
3678
3679/*
3680 * Write NSCODEC Server Capability Container.
3681 */
3682static BOOL rdp_write_nsc_server_capability_container(wStream* s, const rdpSettings* settings)
3683{
3684 WINPR_UNUSED(settings);
3685 WINPR_ASSERT(settings);
3686
3687 if (!Stream_EnsureRemainingCapacity(s, 8))
3688 return FALSE;
3689
3690 Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3691 Stream_Write_UINT32(s, 0); /* reserved */
3692 return TRUE;
3693}
3694
3695/*
3696 * Write bitmap codecs capability set.
3697 * msdn{dd891377}
3698 */
3699
3700static BOOL rdp_write_bitmap_codecs_capability_set(wLog* log, wStream* s,
3701 const rdpSettings* settings)
3702{
3703 WINPR_ASSERT(settings);
3704 if (!Stream_EnsureRemainingCapacity(s, 64))
3705 return FALSE;
3706
3707 const size_t header = rdp_capability_set_start(log, s);
3708 BYTE bitmapCodecCount = 0;
3709
3710 if (settings->RemoteFxCodec)
3711 bitmapCodecCount++;
3712
3713 if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3714 bitmapCodecCount++;
3715
3716#if defined(WITH_JPEG)
3717
3718 if (settings->JpegCodec)
3719 bitmapCodecCount++;
3720
3721#endif
3722
3723 if (settings->RemoteFxImageCodec)
3724 bitmapCodecCount++;
3725
3726 Stream_Write_UINT8(s, bitmapCodecCount);
3727
3728 if (settings->RemoteFxCodec)
3729 {
3730 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_REMOTEFX); /* codecGUID */
3731
3732 if (settings->ServerMode)
3733 {
3734 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3735
3736 if (!rdp_write_rfx_server_capability_container(s, settings))
3737 return FALSE;
3738 }
3739 else
3740 {
3741 Stream_Write_UINT8(s, RDP_CODEC_ID_REMOTEFX); /* codecID */
3742
3743 if (!rdp_write_rfx_client_capability_container(s, settings))
3744 return FALSE;
3745 }
3746 }
3747
3748 if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3749 {
3750 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_NSCODEC); /* codecGUID */
3751
3752 if (settings->ServerMode)
3753 {
3754 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3755
3756 if (!rdp_write_nsc_server_capability_container(s, settings))
3757 return FALSE;
3758 }
3759 else
3760 {
3761 Stream_Write_UINT8(s, RDP_CODEC_ID_NSCODEC); /* codecID */
3762
3763 if (!rdp_write_nsc_client_capability_container(s, settings))
3764 return FALSE;
3765 }
3766 }
3767
3768#if defined(WITH_JPEG)
3769
3770 if (settings->JpegCodec)
3771 {
3772 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_JPEG); /* codecGUID */
3773
3774 if (settings->ServerMode)
3775 {
3776 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3777
3778 if (!rdp_write_jpeg_server_capability_container(s, settings))
3779 return FALSE;
3780 }
3781 else
3782 {
3783 Stream_Write_UINT8(s, RDP_CODEC_ID_JPEG); /* codecID */
3784
3785 if (!rdp_write_jpeg_client_capability_container(s, settings))
3786 return FALSE;
3787 }
3788 }
3789
3790#endif
3791
3792 if (settings->RemoteFxImageCodec)
3793 {
3794 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_IMAGE_REMOTEFX); /* codecGUID */
3795
3796 if (settings->ServerMode)
3797 {
3798 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3799
3800 if (!rdp_write_rfx_server_capability_container(s, settings))
3801 return FALSE;
3802 }
3803 else
3804 {
3805 Stream_Write_UINT8(s, RDP_CODEC_ID_IMAGE_REMOTEFX); /* codecID */
3806
3807 if (!rdp_write_rfx_client_capability_container(s, settings))
3808 return FALSE;
3809 }
3810 }
3811
3812 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CODECS);
3813}
3814
3815#ifdef WITH_DEBUG_CAPABILITIES
3816static BOOL rdp_print_bitmap_codecs_capability_set(wLog* log, wStream* s)
3817{
3818 GUID codecGuid = WINPR_C_ARRAY_INIT;
3819 BYTE bitmapCodecCount = 0;
3820 BYTE codecId = 0;
3821 UINT16 codecPropertiesLength = 0;
3822
3823 WLog_Print(log, WLOG_TRACE,
3824 "BitmapCodecsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3825
3826 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3827 return FALSE;
3828
3829 Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3830 WLog_Print(log, WLOG_TRACE, "\tbitmapCodecCount: %" PRIu8 "", bitmapCodecCount);
3831
3832 while (bitmapCodecCount > 0)
3833 {
3834 if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3835 return FALSE;
3836 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3837 return FALSE;
3838 Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3839 WLog_Print(log, WLOG_TRACE, "\tcodecGuid: 0x");
3840 rdp_print_bitmap_codec_guid(log, &codecGuid);
3841 WLog_Print(log, WLOG_TRACE, " (%s)", rdp_get_bitmap_codec_guid_name(&codecGuid));
3842 WLog_Print(log, WLOG_TRACE, "\tcodecId: %" PRIu8 "", codecId);
3843 Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3844 WLog_Print(log, WLOG_TRACE, "\tcodecPropertiesLength: %" PRIu16 "", codecPropertiesLength);
3845
3846 if (!Stream_SafeSeek(s, codecPropertiesLength)) /* codecProperties */
3847 return FALSE;
3848 bitmapCodecCount--;
3849 }
3850
3851 return TRUE;
3852}
3853#endif
3854
3855static BOOL rdp_apply_frame_acknowledge_capability_set(rdpSettings* settings,
3856 const rdpSettings* src)
3857{
3858 WINPR_ASSERT(settings);
3859 WINPR_ASSERT(src);
3860
3861 if (settings->ServerMode)
3862 settings->FrameAcknowledge = src->FrameAcknowledge;
3863
3864 return TRUE;
3865}
3866
3867/*
3868 * Read frame acknowledge capability set.
3869 */
3870
3871static BOOL rdp_read_frame_acknowledge_capability_set(wLog* log, wStream* s, rdpSettings* settings)
3872{
3873 WINPR_ASSERT(settings);
3874 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3875 return FALSE;
3876
3877 Stream_Read_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3878
3879 return TRUE;
3880}
3881
3882/*
3883 * Write frame acknowledge capability set.
3884 */
3885
3886static BOOL rdp_write_frame_acknowledge_capability_set(wLog* log, wStream* s,
3887 const rdpSettings* settings)
3888{
3889 WINPR_ASSERT(settings);
3890 if (!Stream_EnsureRemainingCapacity(s, 32))
3891 return FALSE;
3892
3893 const size_t header = rdp_capability_set_start(log, s);
3894 Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3895 return rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE);
3896}
3897
3898#ifdef WITH_DEBUG_CAPABILITIES
3899static BOOL rdp_print_frame_acknowledge_capability_set(wLog* log, wStream* s)
3900{
3901 UINT32 frameAcknowledge = 0;
3902 WLog_Print(log, WLOG_TRACE,
3903 "FrameAcknowledgeCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3904
3905 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3906 return FALSE;
3907
3908 Stream_Read_UINT32(s, frameAcknowledge); /* frameAcknowledge (4 bytes) */
3909 WLog_Print(log, WLOG_TRACE, "\tframeAcknowledge: 0x%08" PRIX32 "", frameAcknowledge);
3910 return TRUE;
3911}
3912#endif
3913
3914static BOOL rdp_apply_bitmap_cache_v3_codec_id_capability_set(rdpSettings* settings,
3915 const rdpSettings* src)
3916{
3917 WINPR_ASSERT(settings);
3918 WINPR_ASSERT(src);
3919
3920 settings->BitmapCacheV3CodecId = src->BitmapCacheV3CodecId;
3921 return TRUE;
3922}
3923
3924static BOOL rdp_read_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3925 rdpSettings* settings)
3926{
3927 BYTE bitmapCacheV3CodecId = 0;
3928
3929 WINPR_ASSERT(settings);
3930 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3931 return FALSE;
3932
3933 Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3934 settings->BitmapCacheV3CodecId = bitmapCacheV3CodecId;
3935 return TRUE;
3936}
3937
3938static BOOL rdp_write_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3939 const rdpSettings* settings)
3940{
3941 WINPR_ASSERT(settings);
3942 if (!Stream_EnsureRemainingCapacity(s, 32))
3943 return FALSE;
3944
3945 const size_t header = rdp_capability_set_start(log, s);
3946 if (settings->BitmapCacheV3CodecId > UINT8_MAX)
3947 return FALSE;
3948 Stream_Write_UINT8(s, (UINT8)settings->BitmapCacheV3CodecId);
3949 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID);
3950}
3951
3952#ifdef WITH_DEBUG_CAPABILITIES
3953static BOOL rdp_print_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s)
3954{
3955 BYTE bitmapCacheV3CodecId = 0;
3956 WLog_Print(log, WLOG_TRACE, "BitmapCacheV3CodecIdCapabilitySet (length %" PRIuz "):",
3957 Stream_GetRemainingLength(s));
3958
3959 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3960 return FALSE;
3961
3962 Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3963 WLog_Print(log, WLOG_TRACE, "\tbitmapCacheV3CodecId: 0x%02" PRIX8 "", bitmapCacheV3CodecId);
3964 return TRUE;
3965}
3966
3967BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving)
3968{
3969 BOOL rc = FALSE;
3970 UINT16 type = 0;
3971 UINT16 length = 0;
3972 UINT16 numberCapabilities = 0;
3973
3974 size_t pos = Stream_GetPosition(s);
3975
3976 if (!Stream_SetPosition(s, start))
3977 goto fail;
3978
3979 if (receiving)
3980 {
3981 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3982 goto fail;
3983 }
3984 else
3985 {
3986 if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), 4))
3987 goto fail;
3988 }
3989
3990 Stream_Read_UINT16(s, numberCapabilities);
3991 Stream_Seek(s, 2);
3992
3993 while (numberCapabilities > 0)
3994 {
3995 size_t rest = 0;
3996 wStream subBuffer;
3997 wStream* sub = nullptr;
3998
3999 if (!rdp_read_capability_set_header(log, s, &length, &type))
4000 goto fail;
4001
4002 WLog_Print(log, WLOG_TRACE, "%s ", receiving ? "Receiving" : "Sending");
4003 sub = Stream_StaticInit(&subBuffer, Stream_Pointer(s), length - 4);
4004 if (!Stream_SafeSeek(s, length - 4))
4005 goto fail;
4006
4007 switch (type)
4008 {
4009 case CAPSET_TYPE_GENERAL:
4010 if (!rdp_print_general_capability_set(log, sub))
4011 goto fail;
4012
4013 break;
4014
4015 case CAPSET_TYPE_BITMAP:
4016 if (!rdp_print_bitmap_capability_set(log, sub))
4017 goto fail;
4018
4019 break;
4020
4021 case CAPSET_TYPE_ORDER:
4022 if (!rdp_print_order_capability_set(log, sub))
4023 goto fail;
4024
4025 break;
4026
4027 case CAPSET_TYPE_BITMAP_CACHE:
4028 if (!rdp_print_bitmap_cache_capability_set(log, sub))
4029 goto fail;
4030
4031 break;
4032
4033 case CAPSET_TYPE_CONTROL:
4034 if (!rdp_print_control_capability_set(log, sub))
4035 goto fail;
4036
4037 break;
4038
4039 case CAPSET_TYPE_ACTIVATION:
4040 if (!rdp_print_window_activation_capability_set(log, sub))
4041 goto fail;
4042
4043 break;
4044
4045 case CAPSET_TYPE_POINTER:
4046 if (!rdp_print_pointer_capability_set(log, sub))
4047 goto fail;
4048
4049 break;
4050
4051 case CAPSET_TYPE_SHARE:
4052 if (!rdp_print_share_capability_set(log, sub))
4053 goto fail;
4054
4055 break;
4056
4057 case CAPSET_TYPE_COLOR_CACHE:
4058 if (!rdp_print_color_cache_capability_set(log, sub))
4059 goto fail;
4060
4061 break;
4062
4063 case CAPSET_TYPE_SOUND:
4064 if (!rdp_print_sound_capability_set(log, sub))
4065 goto fail;
4066
4067 break;
4068
4069 case CAPSET_TYPE_INPUT:
4070 if (!rdp_print_input_capability_set(log, sub))
4071 goto fail;
4072
4073 break;
4074
4075 case CAPSET_TYPE_FONT:
4076 if (!rdp_print_font_capability_set(log, sub))
4077 goto fail;
4078
4079 break;
4080
4081 case CAPSET_TYPE_BRUSH:
4082 if (!rdp_print_brush_capability_set(log, sub))
4083 goto fail;
4084
4085 break;
4086
4087 case CAPSET_TYPE_GLYPH_CACHE:
4088 if (!rdp_print_glyph_cache_capability_set(log, sub))
4089 goto fail;
4090
4091 break;
4092
4093 case CAPSET_TYPE_OFFSCREEN_CACHE:
4094 if (!rdp_print_offscreen_bitmap_cache_capability_set(log, sub))
4095 goto fail;
4096
4097 break;
4098
4099 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4100 if (!rdp_print_bitmap_cache_host_support_capability_set(log, sub))
4101 goto fail;
4102
4103 break;
4104
4105 case CAPSET_TYPE_BITMAP_CACHE_V2:
4106 if (!rdp_print_bitmap_cache_v2_capability_set(log, sub))
4107 goto fail;
4108
4109 break;
4110
4111 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4112 if (!rdp_print_virtual_channel_capability_set(log, sub))
4113 goto fail;
4114
4115 break;
4116
4117 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4118 if (!rdp_print_draw_nine_grid_cache_capability_set(log, sub))
4119 goto fail;
4120
4121 break;
4122
4123 case CAPSET_TYPE_DRAW_GDI_PLUS:
4124 if (!rdp_print_draw_gdiplus_cache_capability_set(log, sub))
4125 goto fail;
4126
4127 break;
4128
4129 case CAPSET_TYPE_RAIL:
4130 if (!rdp_print_remote_programs_capability_set(log, sub))
4131 goto fail;
4132
4133 break;
4134
4135 case CAPSET_TYPE_WINDOW:
4136 if (!rdp_print_window_list_capability_set(log, sub))
4137 goto fail;
4138
4139 break;
4140
4141 case CAPSET_TYPE_COMP_DESK:
4142 if (!rdp_print_desktop_composition_capability_set(log, sub))
4143 goto fail;
4144
4145 break;
4146
4147 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4148 if (!rdp_print_multifragment_update_capability_set(log, sub))
4149 goto fail;
4150
4151 break;
4152
4153 case CAPSET_TYPE_LARGE_POINTER:
4154 if (!rdp_print_large_pointer_capability_set(log, sub))
4155 goto fail;
4156
4157 break;
4158
4159 case CAPSET_TYPE_SURFACE_COMMANDS:
4160 if (!rdp_print_surface_commands_capability_set(log, sub))
4161 goto fail;
4162
4163 break;
4164
4165 case CAPSET_TYPE_BITMAP_CODECS:
4166 if (!rdp_print_bitmap_codecs_capability_set(log, sub))
4167 goto fail;
4168
4169 break;
4170
4171 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4172 if (!rdp_print_frame_acknowledge_capability_set(log, sub))
4173 goto fail;
4174
4175 break;
4176
4177 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4178 if (!rdp_print_bitmap_cache_v3_codec_id_capability_set(log, sub))
4179 goto fail;
4180
4181 break;
4182
4183 default:
4184 WLog_Print(log, WLOG_ERROR, "unknown capability type %" PRIu16 "", type);
4185 break;
4186 }
4187
4188 rest = Stream_GetRemainingLength(sub);
4189 if (rest > 0)
4190 {
4191 WLog_Print(log, WLOG_WARN,
4192 "incorrect capability offset, type:0x%04" PRIX16 " %" PRIu16
4193 " bytes expected, %" PRIuz "bytes remaining",
4194 type, length, rest);
4195 }
4196
4197 numberCapabilities--;
4198 }
4199
4200 rc = TRUE;
4201fail:
4202 if (!Stream_SetPosition(s, pos))
4203 return FALSE;
4204
4205 return rc;
4206}
4207#endif
4208
4209static BOOL rdp_apply_from_received(UINT16 type, rdpSettings* dst, const rdpSettings* src)
4210{
4211 switch (type)
4212 {
4213 case CAPSET_TYPE_GENERAL:
4214 return rdp_apply_general_capability_set(dst, src);
4215 case CAPSET_TYPE_BITMAP:
4216 return rdp_apply_bitmap_capability_set(dst, src);
4217 case CAPSET_TYPE_ORDER:
4218 return rdp_apply_order_capability_set(dst, src);
4219 case CAPSET_TYPE_POINTER:
4220 return rdp_apply_pointer_capability_set(dst, src);
4221 case CAPSET_TYPE_INPUT:
4222 return rdp_apply_input_capability_set(dst, src);
4223 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4224 return rdp_apply_virtual_channel_capability_set(dst, src);
4225 case CAPSET_TYPE_SHARE:
4226 return rdp_apply_share_capability_set(dst, src);
4227 case CAPSET_TYPE_COLOR_CACHE:
4228 return rdp_apply_color_cache_capability_set(dst, src);
4229 case CAPSET_TYPE_FONT:
4230 return rdp_apply_font_capability_set(dst, src);
4231 case CAPSET_TYPE_DRAW_GDI_PLUS:
4232 return rdp_apply_draw_gdiplus_cache_capability_set(dst, src);
4233 case CAPSET_TYPE_RAIL:
4234 return rdp_apply_remote_programs_capability_set(dst, src);
4235 case CAPSET_TYPE_WINDOW:
4236 return rdp_apply_window_list_capability_set(dst, src);
4237 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4238 return rdp_apply_multifragment_update_capability_set(dst, src);
4239 case CAPSET_TYPE_LARGE_POINTER:
4240 return rdp_apply_large_pointer_capability_set(dst, src);
4241 case CAPSET_TYPE_COMP_DESK:
4242 return rdp_apply_desktop_composition_capability_set(dst, src);
4243 case CAPSET_TYPE_SURFACE_COMMANDS:
4244 return rdp_apply_surface_commands_capability_set(dst, src);
4245 case CAPSET_TYPE_BITMAP_CODECS:
4246 return rdp_apply_bitmap_codecs_capability_set(dst, src);
4247 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4248 return rdp_apply_frame_acknowledge_capability_set(dst, src);
4249 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4250 return rdp_apply_bitmap_cache_v3_codec_id_capability_set(dst, src);
4251 case CAPSET_TYPE_BITMAP_CACHE:
4252 return rdp_apply_bitmap_cache_capability_set(dst, src);
4253 case CAPSET_TYPE_BITMAP_CACHE_V2:
4254 return rdp_apply_bitmap_cache_v2_capability_set(dst, src);
4255 case CAPSET_TYPE_BRUSH:
4256 return rdp_apply_brush_capability_set(dst, src);
4257 case CAPSET_TYPE_GLYPH_CACHE:
4258 return rdp_apply_glyph_cache_capability_set(dst, src);
4259 case CAPSET_TYPE_OFFSCREEN_CACHE:
4260 return rdp_apply_offscreen_bitmap_cache_capability_set(dst, src);
4261 case CAPSET_TYPE_SOUND:
4262 return rdp_apply_sound_capability_set(dst, src);
4263 case CAPSET_TYPE_CONTROL:
4264 return rdp_apply_control_capability_set(dst, src);
4265 case CAPSET_TYPE_ACTIVATION:
4266 return rdp_apply_window_activation_capability_set(dst, src);
4267 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4268 return rdp_apply_draw_nine_grid_cache_capability_set(dst, src);
4269 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4270 return rdp_apply_bitmap_cache_host_support_capability_set(dst, src);
4271 default:
4272 return TRUE;
4273 }
4274}
4275
4276BOOL rdp_read_capability_set(wLog* log, wStream* sub, UINT16 type, rdpSettings* settings,
4277 BOOL isServer)
4278{
4279 WINPR_ASSERT(settings);
4280
4281 if (type <= CAPSET_TYPE_FRAME_ACKNOWLEDGE)
4282 {
4283 const size_t size = Stream_Length(sub);
4284 if (size > UINT32_MAX)
4285 return FALSE;
4286
4287 WINPR_ASSERT(settings->ReceivedCapabilities);
4288 settings->ReceivedCapabilities[type] = TRUE;
4289
4290 WINPR_ASSERT(settings->ReceivedCapabilityDataSizes);
4291 settings->ReceivedCapabilityDataSizes[type] = (UINT32)size;
4292
4293 WINPR_ASSERT(settings->ReceivedCapabilityData);
4294 void* tmp = realloc(settings->ReceivedCapabilityData[type], size);
4295 if (!tmp && (size > 0))
4296 return FALSE;
4297 memcpy(tmp, Stream_Buffer(sub), size);
4298 settings->ReceivedCapabilityData[type] = tmp;
4299 }
4300 else
4301 WLog_Print(log, WLOG_WARN, "not handling capability type %" PRIu16 " yet", type);
4302
4303 BOOL treated = TRUE;
4304
4305 switch (type)
4306 {
4307 case CAPSET_TYPE_GENERAL:
4308 if (!rdp_read_general_capability_set(log, sub, settings))
4309 return FALSE;
4310
4311 break;
4312
4313 case CAPSET_TYPE_BITMAP:
4314 if (!rdp_read_bitmap_capability_set(log, sub, settings))
4315 return FALSE;
4316
4317 break;
4318
4319 case CAPSET_TYPE_ORDER:
4320 if (!rdp_read_order_capability_set(log, sub, settings))
4321 return FALSE;
4322
4323 break;
4324
4325 case CAPSET_TYPE_POINTER:
4326 if (!rdp_read_pointer_capability_set(log, sub, settings))
4327 return FALSE;
4328
4329 break;
4330
4331 case CAPSET_TYPE_INPUT:
4332 if (!rdp_read_input_capability_set(log, sub, settings))
4333 return FALSE;
4334
4335 break;
4336
4337 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4338 if (!rdp_read_virtual_channel_capability_set(log, sub, settings))
4339 return FALSE;
4340
4341 break;
4342
4343 case CAPSET_TYPE_SHARE:
4344 if (!rdp_read_share_capability_set(log, sub, settings))
4345 return FALSE;
4346
4347 break;
4348
4349 case CAPSET_TYPE_COLOR_CACHE:
4350 if (!rdp_read_color_cache_capability_set(log, sub, settings))
4351 return FALSE;
4352
4353 break;
4354
4355 case CAPSET_TYPE_FONT:
4356 if (!rdp_read_font_capability_set(log, sub, settings))
4357 return FALSE;
4358
4359 break;
4360
4361 case CAPSET_TYPE_DRAW_GDI_PLUS:
4362 if (!rdp_read_draw_gdiplus_cache_capability_set(log, sub, settings))
4363 return FALSE;
4364
4365 break;
4366
4367 case CAPSET_TYPE_RAIL:
4368 if (!rdp_read_remote_programs_capability_set(log, sub, settings))
4369 return FALSE;
4370
4371 break;
4372
4373 case CAPSET_TYPE_WINDOW:
4374 if (!rdp_read_window_list_capability_set(log, sub, settings))
4375 return FALSE;
4376
4377 break;
4378
4379 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4380 if (!rdp_read_multifragment_update_capability_set(log, sub, settings))
4381 return FALSE;
4382
4383 break;
4384
4385 case CAPSET_TYPE_LARGE_POINTER:
4386 if (!rdp_read_large_pointer_capability_set(log, sub, settings))
4387 return FALSE;
4388
4389 break;
4390
4391 case CAPSET_TYPE_COMP_DESK:
4392 if (!rdp_read_desktop_composition_capability_set(log, sub, settings))
4393 return FALSE;
4394
4395 break;
4396
4397 case CAPSET_TYPE_SURFACE_COMMANDS:
4398 if (!rdp_read_surface_commands_capability_set(log, sub, settings))
4399 return FALSE;
4400
4401 break;
4402
4403 case CAPSET_TYPE_BITMAP_CODECS:
4404 if (!rdp_read_bitmap_codecs_capability_set(log, sub, settings, isServer))
4405 return FALSE;
4406
4407 break;
4408
4409 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4410 if (!rdp_read_frame_acknowledge_capability_set(log, sub, settings))
4411 return FALSE;
4412
4413 break;
4414
4415 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4416 if (!rdp_read_bitmap_cache_v3_codec_id_capability_set(log, sub, settings))
4417 return FALSE;
4418
4419 break;
4420
4421 default:
4422 treated = FALSE;
4423 break;
4424 }
4425
4426 if (!treated)
4427 {
4428 if (isServer)
4429 {
4430 /* treating capabilities that are supposed to be send only from the client */
4431 switch (type)
4432 {
4433 case CAPSET_TYPE_BITMAP_CACHE:
4434 if (!rdp_read_bitmap_cache_capability_set(log, sub, settings))
4435 return FALSE;
4436
4437 break;
4438
4439 case CAPSET_TYPE_BITMAP_CACHE_V2:
4440 if (!rdp_read_bitmap_cache_v2_capability_set(log, sub, settings))
4441 return FALSE;
4442
4443 break;
4444
4445 case CAPSET_TYPE_BRUSH:
4446 if (!rdp_read_brush_capability_set(log, sub, settings))
4447 return FALSE;
4448
4449 break;
4450
4451 case CAPSET_TYPE_GLYPH_CACHE:
4452 if (!rdp_read_glyph_cache_capability_set(log, sub, settings))
4453 return FALSE;
4454
4455 break;
4456
4457 case CAPSET_TYPE_OFFSCREEN_CACHE:
4458 if (!rdp_read_offscreen_bitmap_cache_capability_set(log, sub, settings))
4459 return FALSE;
4460
4461 break;
4462
4463 case CAPSET_TYPE_SOUND:
4464 if (!rdp_read_sound_capability_set(log, sub, settings))
4465 return FALSE;
4466
4467 break;
4468
4469 case CAPSET_TYPE_CONTROL:
4470 if (!rdp_read_control_capability_set(log, sub, settings))
4471 return FALSE;
4472
4473 break;
4474
4475 case CAPSET_TYPE_ACTIVATION:
4476 if (!rdp_read_window_activation_capability_set(log, sub, settings))
4477 return FALSE;
4478
4479 break;
4480
4481 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4482 if (!rdp_read_draw_nine_grid_cache_capability_set(log, sub, settings))
4483 return FALSE;
4484
4485 break;
4486
4487 default:
4488 WLog_Print(log, WLOG_ERROR,
4489 "capability %s(%" PRIu16 ") not expected from client",
4490 get_capability_name(type), type);
4491 return FALSE;
4492 }
4493 }
4494 else
4495 {
4496 /* treating capabilities that are supposed to be send only from the server */
4497 switch (type)
4498 {
4499 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4500 if (!rdp_read_bitmap_cache_host_support_capability_set(log, sub, settings))
4501 return FALSE;
4502
4503 break;
4504
4505 default:
4506 WLog_Print(log, WLOG_ERROR,
4507 "capability %s(%" PRIu16 ") not expected from server",
4508 get_capability_name(type), type);
4509 return FALSE;
4510 }
4511 }
4512 }
4513
4514 const size_t rest = Stream_GetRemainingLength(sub);
4515 if (rest > 0)
4516 {
4517 const size_t length = Stream_Capacity(sub);
4518 WLog_Print(log, WLOG_ERROR,
4519 "incorrect offset, type:0x%04" PRIx16 " actual:%" PRIuz " expected:%" PRIuz "",
4520 type, length - rest, length);
4521 }
4522 return TRUE;
4523}
4524
4525static BOOL rdp_read_capability_sets(wLog* log, wStream* s, rdpSettings* settings,
4526 rdpSettings* rcvSettings, UINT16 totalLength)
4527{
4528 BOOL rc = FALSE;
4529 size_t start = 0;
4530 size_t end = 0;
4531 size_t len = 0;
4532 UINT16 numberCapabilities = 0;
4533 UINT16 count = 0;
4534
4535#ifdef WITH_DEBUG_CAPABILITIES
4536 const size_t capstart = Stream_GetPosition(s);
4537#endif
4538
4539 WINPR_ASSERT(s);
4540 WINPR_ASSERT(settings);
4541
4542 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4543 return FALSE;
4544
4545 Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4546 Stream_Seek(s, 2); /* pad2Octets (2 bytes) */
4547 count = numberCapabilities;
4548
4549 start = Stream_GetPosition(s);
4550 while (numberCapabilities > 0 && Stream_GetRemainingLength(s) >= 4)
4551 {
4552 UINT16 type = 0;
4553 UINT16 length = 0;
4554 wStream subbuffer;
4555 wStream* sub = nullptr;
4556
4557 if (!rdp_read_capability_set_header(log, s, &length, &type))
4558 goto fail;
4559 sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), length - 4);
4560 if (!Stream_SafeSeek(s, length - 4))
4561 goto fail;
4562
4563 if (!rdp_read_capability_set(log, sub, type, rcvSettings, settings->ServerMode))
4564 goto fail;
4565
4566 if (!rdp_apply_from_received(type, settings, rcvSettings))
4567 goto fail;
4568 numberCapabilities--;
4569 }
4570
4571 end = Stream_GetPosition(s);
4572 len = end - start;
4573
4574 if (numberCapabilities)
4575 {
4576 WLog_Print(log, WLOG_ERROR,
4577 "strange we haven't read the number of announced capacity sets, read=%d "
4578 "expected=%" PRIu16 "",
4579 count - numberCapabilities, count);
4580 }
4581
4582#ifdef WITH_DEBUG_CAPABILITIES
4583 rdp_print_capability_sets(log, s, capstart, TRUE);
4584#endif
4585
4586 if (len > totalLength)
4587 {
4588 WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIuz,
4589 totalLength, len);
4590 goto fail;
4591 }
4592 rc = freerdp_capability_buffer_copy(settings, rcvSettings);
4593fail:
4594 return rc;
4595}
4596
4597BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId, UINT16* length)
4598{
4599 WINPR_ASSERT(rdp);
4600 WINPR_ASSERT(rdp->context);
4601
4602 if (!rdp_read_header(rdp, s, length, pChannelId))
4603 return FALSE;
4604
4605 if (freerdp_shall_disconnect_context(rdp->context))
4606 return TRUE;
4607
4608 if (*pChannelId != MCS_GLOBAL_CHANNEL_ID)
4609 {
4610 UINT16 mcsMessageChannelId = rdp->mcs->messageChannelId;
4611
4612 if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId))
4613 {
4614 WLog_Print(rdp->log, WLOG_ERROR, "unexpected MCS channel id %04" PRIx16 " received",
4615 *pChannelId);
4616 return FALSE;
4617 }
4618 }
4619
4620 return TRUE;
4621}
4622
4623BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s, UINT16 pduSource, UINT16 length)
4624{
4625 UINT16 lengthSourceDescriptor = 0;
4626 UINT16 lengthCombinedCapabilities = 0;
4627
4628 WINPR_ASSERT(rdp);
4629 WINPR_ASSERT(rdp->settings);
4630 WINPR_ASSERT(rdp->context);
4631 WINPR_ASSERT(s);
4632
4633 rdp->settings->PduSource = pduSource;
4634
4635 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 8))
4636 return FALSE;
4637
4638 Stream_Read_UINT32(s, rdp->settings->ShareId); /* shareId (4 bytes) */
4639 Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4640 Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4641
4642 if (!Stream_SafeSeek(s, lengthSourceDescriptor) ||
4643 !Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4)) /* sourceDescriptor */
4644 return FALSE;
4645
4646 /* capabilitySets */
4647 if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4648 lengthCombinedCapabilities))
4649 {
4650 WLog_Print(rdp->log, WLOG_ERROR, "rdp_read_capability_sets failed");
4651 return FALSE;
4652 }
4653
4654 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4))
4655 return FALSE;
4656
4657 /* [MS-RDPBCGR] 2.2.1.13.1.1 Demand Active PDU Data (TS_DEMAND_ACTIVE_PDU)::sessionId
4658 * is ignored by client */
4659 Stream_Seek_UINT32(s); /* SessionId */
4660
4661 {
4662 rdp_secondary_update_internal* secondary = secondary_update_cast(rdp->update->secondary);
4663 secondary->glyph_v2 = (rdp->settings->GlyphSupportLevel > GLYPH_SUPPORT_FULL);
4664 }
4665
4666 return tpkt_ensure_stream_consumed(rdp->log, s, length);
4667}
4668
4669static BOOL rdp_write_demand_active(wLog* log, wStream* s, rdpSettings* settings)
4670{
4671 size_t bm = 0;
4672 size_t em = 0;
4673 size_t lm = 0;
4674 UINT16 numberCapabilities = 0;
4675 size_t lengthCombinedCapabilities = 0;
4676
4677 if (!Stream_EnsureRemainingCapacity(s, 64))
4678 return FALSE;
4679
4680 Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4681 Stream_Write_UINT16(s, 4); /* lengthSourceDescriptor (2 bytes) */
4682 lm = Stream_GetPosition(s);
4683 Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4684 Stream_Write(s, "RDP", 4); /* sourceDescriptor */
4685 bm = Stream_GetPosition(s);
4686 Stream_Seek_UINT16(s); /* numberCapabilities (2 bytes) */
4687 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4688 numberCapabilities = 14;
4689
4690 if (!rdp_write_general_capability_set(log, s, settings) ||
4691 !rdp_write_bitmap_capability_set(log, s, settings) ||
4692 !rdp_write_order_capability_set(log, s, settings) ||
4693 !rdp_write_pointer_capability_set(log, s, settings) ||
4694 !rdp_write_input_capability_set(log, s, settings) ||
4695 !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4696 !rdp_write_share_capability_set(log, s, settings) ||
4697 !rdp_write_font_capability_set(log, s, settings) ||
4698 !rdp_write_multifragment_update_capability_set(log, s, settings) ||
4699 !rdp_write_large_pointer_capability_set(log, s, settings) ||
4700 !rdp_write_desktop_composition_capability_set(log, s, settings) ||
4701 !rdp_write_surface_commands_capability_set(log, s, settings) ||
4702 !rdp_write_bitmap_codecs_capability_set(log, s, settings) ||
4703 !rdp_write_frame_acknowledge_capability_set(log, s, settings))
4704 {
4705 return FALSE;
4706 }
4707
4708 if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
4709 {
4710 numberCapabilities++;
4711
4712 if (!rdp_write_bitmap_cache_host_support_capability_set(log, s, settings))
4713 return FALSE;
4714 }
4715
4716 if (settings->RemoteApplicationMode)
4717 {
4718 numberCapabilities += 2;
4719
4720 if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4721 !rdp_write_window_list_capability_set(log, s, settings))
4722 return FALSE;
4723 }
4724
4725 em = Stream_GetPosition(s);
4726 if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4727 return FALSE;
4728 lengthCombinedCapabilities = (em - bm);
4729 if (lengthCombinedCapabilities > UINT16_MAX)
4730 return FALSE;
4731 Stream_Write_UINT16(
4732 s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4733 if (!Stream_SetPosition(s, bm)) /* go back to numberCapabilities */
4734 return FALSE;
4735 Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4736#ifdef WITH_DEBUG_CAPABILITIES
4737 rdp_print_capability_sets(log, s, bm, FALSE);
4738#endif
4739 if (!Stream_SetPosition(s, em))
4740 return FALSE;
4741 Stream_Write_UINT32(s, 0); /* sessionId */
4742 return TRUE;
4743}
4744
4745BOOL rdp_send_demand_active(rdpRdp* rdp)
4746{
4747 UINT16 sec_flags = 0;
4748 wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4749 BOOL status = 0;
4750
4751 if (!s)
4752 return FALSE;
4753
4754 rdp->settings->ShareId = 0x10000 + rdp->mcs->userId;
4755 status = rdp_write_demand_active(rdp->log, s, rdp->settings) &&
4756 rdp_send_pdu(rdp, s, PDU_TYPE_DEMAND_ACTIVE, rdp->mcs->userId, sec_flags);
4757 Stream_Release(s);
4758 return status;
4759}
4760
4761BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength)
4762{
4763 rdpSettings* settings = nullptr;
4764 UINT16 lengthSourceDescriptor = 0;
4765 UINT16 lengthCombinedCapabilities = 0;
4766
4767 WINPR_ASSERT(rdp);
4768 WINPR_ASSERT(s);
4769 settings = rdp->settings;
4770 WINPR_ASSERT(settings);
4771
4772 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 10))
4773 return FALSE;
4774
4775 Stream_Seek_UINT32(s); /* shareId (4 bytes) */
4776 Stream_Seek_UINT16(s); /* originatorId (2 bytes) */
4777 Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4778 Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4779
4780 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, lengthSourceDescriptor + 4U))
4781 return FALSE;
4782
4783 Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor */
4784 if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4785 lengthCombinedCapabilities))
4786 return FALSE;
4787
4788 if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4789 {
4790 /* client does not support surface commands */
4791 settings->SurfaceCommandsEnabled = FALSE;
4792 settings->SurfaceFrameMarkerEnabled = FALSE;
4793 }
4794
4795 if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4796 {
4797 /* client does not support frame acks */
4798 settings->FrameAcknowledge = 0;
4799 }
4800
4801 if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4802 {
4803 /* client does not support bitmap cache v3 */
4804 settings->BitmapCacheV3Enabled = FALSE;
4805 }
4806
4807 if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4808 {
4809 /* client does not support bitmap codecs */
4810 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, FALSE))
4811 return FALSE;
4812 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, FALSE))
4813 return FALSE;
4814 if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
4815 return FALSE;
4816 }
4817
4818 if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4819 {
4820 /* client does not support multi fragment updates - make sure packages are not fragmented */
4821 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
4822 FASTPATH_FRAGMENT_SAFE_SIZE))
4823 return FALSE;
4824 }
4825
4826 if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4827 {
4828 /* client does not support large pointers */
4829 settings->LargePointerFlag = 0;
4830 }
4831
4832 return tpkt_ensure_stream_consumed(rdp->log, s, pduLength);
4833}
4834
4835static BOOL rdp_write_confirm_active(wLog* log, wStream* s, rdpSettings* settings)
4836{
4837 size_t bm = 0;
4838 size_t em = 0;
4839 size_t lm = 0;
4840 UINT16 numberCapabilities = 0;
4841 UINT16 lengthSourceDescriptor = 0;
4842 size_t lengthCombinedCapabilities = 0;
4843 BOOL ret = 0;
4844
4845 WINPR_ASSERT(settings);
4846
4847 lengthSourceDescriptor = sizeof(SOURCE_DESCRIPTOR);
4848 Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4849 Stream_Write_UINT16(s, 0x03EA); /* originatorId (2 bytes) */
4850 Stream_Write_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4851 lm = Stream_GetPosition(s);
4852 Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4853 Stream_Write(s, SOURCE_DESCRIPTOR, lengthSourceDescriptor); /* sourceDescriptor */
4854 bm = Stream_GetPosition(s);
4855 Stream_Seek_UINT16(s); /* numberCapabilities (2 bytes) */
4856 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4857 /* Capability Sets */
4858 numberCapabilities = 15;
4859
4860 if (!rdp_write_general_capability_set(log, s, settings) ||
4861 !rdp_write_bitmap_capability_set(log, s, settings) ||
4862 !rdp_write_order_capability_set(log, s, settings))
4863 return FALSE;
4864
4865 if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
4866 ret = rdp_write_bitmap_cache_v2_capability_set(log, s, settings);
4867 else
4868 ret = rdp_write_bitmap_cache_capability_set(log, s, settings);
4869
4870 if (!ret)
4871 return FALSE;
4872
4873 if (!rdp_write_pointer_capability_set(log, s, settings) ||
4874 !rdp_write_input_capability_set(log, s, settings) ||
4875 !rdp_write_brush_capability_set(log, s, settings) ||
4876 !rdp_write_glyph_cache_capability_set(log, s, settings) ||
4877 !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4878 !rdp_write_sound_capability_set(log, s, settings) ||
4879 !rdp_write_share_capability_set(log, s, settings) ||
4880 !rdp_write_font_capability_set(log, s, settings) ||
4881 !rdp_write_control_capability_set(log, s, settings) ||
4882 !rdp_write_color_cache_capability_set(log, s, settings) ||
4883 !rdp_write_window_activation_capability_set(log, s, settings))
4884 {
4885 return FALSE;
4886 }
4887
4888 {
4889 numberCapabilities++;
4890
4891 if (!rdp_write_offscreen_bitmap_cache_capability_set(log, s, settings))
4892 return FALSE;
4893 }
4894
4895 if (settings->DrawNineGridEnabled)
4896 {
4897 numberCapabilities++;
4898
4899 if (!rdp_write_draw_nine_grid_cache_capability_set(log, s, settings))
4900 return FALSE;
4901 }
4902
4903 if (settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4904 {
4905 if (settings->LargePointerFlag)
4906 {
4907 numberCapabilities++;
4908
4909 if (!rdp_write_large_pointer_capability_set(log, s, settings))
4910 return FALSE;
4911 }
4912 }
4913
4914 if (settings->RemoteApplicationMode)
4915 {
4916 numberCapabilities += 2;
4917
4918 if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4919 !rdp_write_window_list_capability_set(log, s, settings))
4920 return FALSE;
4921 }
4922
4923 if (settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4924 {
4925 numberCapabilities++;
4926
4927 if (!rdp_write_multifragment_update_capability_set(log, s, settings))
4928 return FALSE;
4929 }
4930
4931 if (settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4932 {
4933 numberCapabilities++;
4934
4935 if (!rdp_write_surface_commands_capability_set(log, s, settings))
4936 return FALSE;
4937 }
4938
4939 if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4940 {
4941 numberCapabilities++;
4942
4943 if (!rdp_write_bitmap_codecs_capability_set(log, s, settings))
4944 return FALSE;
4945 }
4946
4947 if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4948 settings->FrameAcknowledge = 0;
4949
4950 if (settings->FrameAcknowledge)
4951 {
4952 numberCapabilities++;
4953
4954 if (!rdp_write_frame_acknowledge_capability_set(log, s, settings))
4955 return FALSE;
4956 }
4957
4958 if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4959 {
4960 if (settings->BitmapCacheV3CodecId != 0)
4961 {
4962 numberCapabilities++;
4963
4964 if (!rdp_write_bitmap_cache_v3_codec_id_capability_set(log, s, settings))
4965 return FALSE;
4966 }
4967 }
4968
4969 em = Stream_GetPosition(s);
4970 if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4971 return FALSE;
4972 lengthCombinedCapabilities = (em - bm);
4973 if (lengthCombinedCapabilities > UINT16_MAX)
4974 return FALSE;
4975 Stream_Write_UINT16(
4976 s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4977 if (!Stream_SetPosition(s, bm)) /* go back to numberCapabilities */
4978 return FALSE;
4979 Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4980#ifdef WITH_DEBUG_CAPABILITIES
4981 rdp_print_capability_sets(log, s, bm, FALSE);
4982#endif
4983 return Stream_SetPosition(s, em);
4984}
4985
4986BOOL rdp_send_confirm_active(rdpRdp* rdp)
4987{
4988 UINT16 sec_flags = 0;
4989 wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4990 BOOL status = 0;
4991
4992 if (!s)
4993 return FALSE;
4994
4995 status = rdp_write_confirm_active(rdp->log, s, rdp->settings) &&
4996 rdp_send_pdu(rdp, s, PDU_TYPE_CONFIRM_ACTIVE, rdp->mcs->userId, sec_flags);
4997 Stream_Release(s);
4998 return status;
4999}
5000
5001const char* rdp_input_flag_string(UINT16 flags, char* buffer, size_t len)
5002{
5003 char prefix[16] = WINPR_C_ARRAY_INIT;
5004
5005 (void)_snprintf(prefix, sizeof(prefix), "[0x%04" PRIx16 "][", flags);
5006 winpr_str_append(prefix, buffer, len, "");
5007 if ((flags & INPUT_FLAG_SCANCODES) != 0)
5008 winpr_str_append("INPUT_FLAG_SCANCODES", buffer, len, "|");
5009 if ((flags & INPUT_FLAG_MOUSEX) != 0)
5010 winpr_str_append("INPUT_FLAG_MOUSEX", buffer, len, "|");
5011 if ((flags & INPUT_FLAG_FASTPATH_INPUT) != 0)
5012 winpr_str_append("INPUT_FLAG_FASTPATH_INPUT", buffer, len, "|");
5013 if ((flags & INPUT_FLAG_UNICODE) != 0)
5014 winpr_str_append("INPUT_FLAG_UNICODE", buffer, len, "|");
5015 if ((flags & INPUT_FLAG_FASTPATH_INPUT2) != 0)
5016 winpr_str_append("INPUT_FLAG_FASTPATH_INPUT2", buffer, len, "|");
5017 if ((flags & INPUT_FLAG_UNUSED1) != 0)
5018 winpr_str_append("INPUT_FLAG_UNUSED1", buffer, len, "|");
5019 if ((flags & INPUT_FLAG_MOUSE_RELATIVE) != 0)
5020 winpr_str_append("INPUT_FLAG_MOUSE_RELATIVE", buffer, len, "|");
5021 if ((flags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0)
5022 winpr_str_append("TS_INPUT_FLAG_MOUSE_HWHEEL", buffer, len, "|");
5023 if ((flags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0)
5024 winpr_str_append("TS_INPUT_FLAG_QOE_TIMESTAMPS", buffer, len, "|");
5025 winpr_str_append("]", buffer, len, "");
5026 return buffer;
5027}
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:263