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(src, 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(src, 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 BOOL isServer)
1435{
1436 UINT16 inputFlags = 0;
1437
1438 WINPR_ASSERT(settings);
1439 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1440 return FALSE;
1441
1442 Stream_Read_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1443 Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */
1444
1445 Stream_Read_UINT32(s, settings->KeyboardLayout); /* keyboardLayout (4 bytes) */
1446 Stream_Read_UINT32(s, settings->KeyboardType); /* keyboardType (4 bytes) */
1447 Stream_Read_UINT32(s, settings->KeyboardSubType); /* keyboardSubType (4 bytes) */
1448 Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1449
1450 /* Received after TS_UD_CS_CORE and copied over its (sanitized) value by
1451 * rdp_apply_input_capability_set(), so a client's out-of-spec KeyboardType (e.g. mstsc with
1452 * an MSKLC layout) must be checked here too. Servers send zeroed keyboard fields: skip. */
1453 if (isServer)
1454 freerdp_settings_sanitize_keyboard_type(log, settings, "TS_INPUT_CAPABILITYSET");
1455
1456 {
1457 WCHAR wstr[32] = WINPR_C_ARRAY_INIT;
1458 char str[65] = WINPR_C_ARRAY_INIT;
1459
1460 /* Older windows versions report invalid UTF16
1461 * [MS-RDPBCGR] <29> Section 2.2.7.1.6: Microsoft RDP 4.0, 5.0, 5.1, and 5.2 servers do not
1462 * explicitly fill the imeFileName field with zeros.
1463 */
1464 if (!Stream_Read_UTF16_String(s, wstr, ARRAYSIZE(wstr)))
1465 return FALSE;
1466
1467 if (ConvertWCharNToUtf8(wstr, ARRAYSIZE(wstr), str, ARRAYSIZE(str)) < 0)
1468 memset(str, 0, sizeof(str));
1469
1470 if (!freerdp_settings_set_string_len(settings, FreeRDP_ImeFileName, str, ARRAYSIZE(str)))
1471 return FALSE;
1472 }
1473
1474 if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathInput,
1475 inputFlags &
1476 (INPUT_FLAG_FASTPATH_INPUT | INPUT_FLAG_FASTPATH_INPUT2)))
1477 return FALSE;
1478 if (!freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel,
1479 (inputFlags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0))
1480 return FALSE;
1481 if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput,
1482 (inputFlags & INPUT_FLAG_UNICODE) != 0))
1483 return FALSE;
1484 if (!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent,
1485 (inputFlags & INPUT_FLAG_MOUSE_RELATIVE) != 0))
1486 return FALSE;
1487 if (!freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent,
1488 (inputFlags & INPUT_FLAG_MOUSEX) != 0))
1489 return FALSE;
1490 if (!freerdp_settings_set_bool(settings, FreeRDP_HasQoeEvent,
1491 (inputFlags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0))
1492 return FALSE;
1493
1494 return TRUE;
1495}
1496
1497/*
1498 * Write input capability set.
1499 * msdn{cc240563}
1500 */
1501
1502static BOOL rdp_write_input_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1503{
1504 WINPR_ASSERT(settings);
1505 if (!Stream_EnsureRemainingCapacity(s, 128))
1506 return FALSE;
1507
1508 const size_t header = rdp_capability_set_start(log, s);
1509 UINT16 inputFlags = INPUT_FLAG_SCANCODES;
1510
1511 if (settings->FastPathInput)
1512 {
1513 inputFlags |= INPUT_FLAG_FASTPATH_INPUT;
1514 inputFlags |= INPUT_FLAG_FASTPATH_INPUT2;
1515 }
1516
1517 if (freerdp_settings_get_bool(settings, FreeRDP_HasRelativeMouseEvent))
1518 inputFlags |= INPUT_FLAG_MOUSE_RELATIVE;
1519
1520 if (freerdp_settings_get_bool(settings, FreeRDP_HasHorizontalWheel))
1521 inputFlags |= TS_INPUT_FLAG_MOUSE_HWHEEL;
1522
1523 if (freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput))
1524 inputFlags |= INPUT_FLAG_UNICODE;
1525
1526 if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1527 inputFlags |= TS_INPUT_FLAG_QOE_TIMESTAMPS;
1528
1529 if (settings->HasExtendedMouseEvent)
1530 inputFlags |= INPUT_FLAG_MOUSEX;
1531
1532 Stream_Write_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1533 Stream_Write_UINT16(s, 0); /* pad2OctetsA (2 bytes) */
1534 Stream_Write_UINT32(s, settings->KeyboardLayout); /* keyboardLayout (4 bytes) */
1535 Stream_Write_UINT32(s, settings->KeyboardType); /* keyboardType (4 bytes) */
1536 Stream_Write_UINT32(s, settings->KeyboardSubType); /* keyboardSubType (4 bytes) */
1537 Stream_Write_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1538 Stream_Zero(s, 64); /* imeFileName (64 bytes) */
1539 return rdp_capability_set_finish(s, header, CAPSET_TYPE_INPUT);
1540}
1541
1542#ifdef WITH_DEBUG_CAPABILITIES
1543static BOOL rdp_print_input_capability_set(wLog* log, wStream* s)
1544{
1545 UINT16 inputFlags = 0;
1546 UINT16 pad2OctetsA = 0;
1547 UINT32 keyboardLayout = 0;
1548 UINT32 keyboardType = 0;
1549 UINT32 keyboardSubType = 0;
1550 UINT32 keyboardFunctionKey = 0;
1551 WLog_Print(log, WLOG_TRACE, "InputCapabilitySet (length %" PRIuz ")",
1552 Stream_GetRemainingLength(s));
1553
1554 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1555 return FALSE;
1556
1557 Stream_Read_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1558 Stream_Read_UINT16(s, pad2OctetsA); /* pad2OctetsA (2 bytes) */
1559 Stream_Read_UINT32(s, keyboardLayout); /* keyboardLayout (4 bytes) */
1560 Stream_Read_UINT32(s, keyboardType); /* keyboardType (4 bytes) */
1561 Stream_Read_UINT32(s, keyboardSubType); /* keyboardSubType (4 bytes) */
1562 Stream_Read_UINT32(s, keyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1563 Stream_Seek(s, 64); /* imeFileName (64 bytes) */
1564 WLog_Print(log, WLOG_TRACE, "\tinputFlags: 0x%04" PRIX16 "", inputFlags);
1565 WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
1566 WLog_Print(log, WLOG_TRACE, "\tkeyboardLayout: 0x%08" PRIX32 "", keyboardLayout);
1567 WLog_Print(log, WLOG_TRACE, "\tkeyboardType: 0x%08" PRIX32 "", keyboardType);
1568 WLog_Print(log, WLOG_TRACE, "\tkeyboardSubType: 0x%08" PRIX32 "", keyboardSubType);
1569 WLog_Print(log, WLOG_TRACE, "\tkeyboardFunctionKey: 0x%08" PRIX32 "", keyboardFunctionKey);
1570 return TRUE;
1571}
1572#endif
1573
1574static BOOL rdp_apply_font_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1575 WINPR_ATTR_UNUSED const rdpSettings* src)
1576{
1577 WINPR_ASSERT(settings);
1578 WINPR_ASSERT(src);
1579 return TRUE;
1580}
1581
1582/*
1583 * Read font capability set.
1584 * msdn{cc240571}
1585 */
1586
1587static BOOL rdp_read_font_capability_set(WINPR_ATTR_UNUSED wLog* log, wStream* s,
1588 rdpSettings* settings)
1589{
1590 WINPR_UNUSED(settings);
1591 if (Stream_GetRemainingLength(s) >= 2)
1592 Stream_Seek_UINT16(s); /* fontSupportFlags (2 bytes) */
1593
1594 if (Stream_GetRemainingLength(s) >= 2)
1595 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1596
1597 return TRUE;
1598}
1599
1600/*
1601 * Write font capability set.
1602 * msdn{cc240571}
1603 */
1604
1605static BOOL rdp_write_font_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1606{
1607 WINPR_UNUSED(settings);
1608 if (!Stream_EnsureRemainingCapacity(s, 32))
1609 return FALSE;
1610
1611 const size_t header = rdp_capability_set_start(log, s);
1612 Stream_Write_UINT16(s, FONTSUPPORT_FONTLIST); /* fontSupportFlags (2 bytes) */
1613 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1614 return rdp_capability_set_finish(s, header, CAPSET_TYPE_FONT);
1615}
1616
1617#ifdef WITH_DEBUG_CAPABILITIES
1618static BOOL rdp_print_font_capability_set(wLog* log, wStream* s)
1619{
1620 UINT16 fontSupportFlags = 0;
1621 UINT16 pad2Octets = 0;
1622 WLog_Print(log, WLOG_TRACE,
1623 "FontCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1624
1625 if (Stream_GetRemainingLength(s) >= 2)
1626 Stream_Read_UINT16(s, fontSupportFlags); /* fontSupportFlags (2 bytes) */
1627
1628 if (Stream_GetRemainingLength(s) >= 2)
1629 Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
1630
1631 WLog_Print(log, WLOG_TRACE, "\tfontSupportFlags: 0x%04" PRIX16 "", fontSupportFlags);
1632 WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1633 return TRUE;
1634}
1635#endif
1636
1637static BOOL rdp_apply_brush_capability_set(rdpSettings* settings, const rdpSettings* src)
1638{
1639 WINPR_ASSERT(settings);
1640 WINPR_ASSERT(src);
1641
1642 // TODO: Minimum of what?
1643 settings->BrushSupportLevel = src->BrushSupportLevel;
1644 return TRUE;
1645}
1646
1647/*
1648 * Read brush capability set.
1649 * msdn{cc240564}
1650 */
1651
1652static BOOL rdp_read_brush_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1653{
1654 WINPR_UNUSED(settings);
1655 WINPR_ASSERT(settings);
1656
1657 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1658 return FALSE;
1659 Stream_Read_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1660 return TRUE;
1661}
1662
1663/*
1664 * Write brush capability set.
1665 * msdn{cc240564}
1666 */
1667
1668static BOOL rdp_write_brush_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1669{
1670 WINPR_ASSERT(settings);
1671 if (!Stream_EnsureRemainingCapacity(s, 32))
1672 return FALSE;
1673
1674 const size_t header = rdp_capability_set_start(log, s);
1675 Stream_Write_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1676 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BRUSH);
1677}
1678
1679#ifdef WITH_DEBUG_CAPABILITIES
1680static BOOL rdp_print_brush_capability_set(wLog* log, wStream* s)
1681{
1682 UINT32 brushSupportLevel = 0;
1683 WLog_Print(log, WLOG_TRACE,
1684 "BrushCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1685
1686 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1687 return FALSE;
1688
1689 Stream_Read_UINT32(s, brushSupportLevel); /* brushSupportLevel (4 bytes) */
1690 WLog_Print(log, WLOG_TRACE, "\tbrushSupportLevel: 0x%08" PRIX32 "", brushSupportLevel);
1691 return TRUE;
1692}
1693#endif
1694
1695/*
1696 * Read cache definition (glyph).
1697 * msdn{cc240566}
1698 */
1699static void rdp_read_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_definition)
1700{
1701 WINPR_ASSERT(cache_definition);
1702 Stream_Read_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1703 Stream_Read_UINT16(s,
1704 cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1705}
1706
1707/*
1708 * Write cache definition (glyph).
1709 * msdn{cc240566}
1710 */
1711static void rdp_write_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_definition)
1712{
1713 WINPR_ASSERT(cache_definition);
1714 Stream_Write_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1715 Stream_Write_UINT16(
1716 s, cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1717}
1718
1719static BOOL rdp_apply_glyph_cache_capability_set(rdpSettings* settings, const rdpSettings* src)
1720{
1721 WINPR_ASSERT(settings);
1722 WINPR_ASSERT(src);
1723
1724 WINPR_ASSERT(src->GlyphCache);
1725 WINPR_ASSERT(settings->GlyphCache);
1726 for (size_t x = 0; x < 10; x++)
1727 settings->GlyphCache[x] = src->GlyphCache[x];
1728
1729 WINPR_ASSERT(src->FragCache);
1730 WINPR_ASSERT(settings->FragCache);
1731 settings->FragCache[0] = src->FragCache[0];
1732 settings->GlyphSupportLevel = src->GlyphSupportLevel;
1733
1734 return TRUE;
1735}
1736
1737/*
1738 * Read glyph cache capability set.
1739 * msdn{cc240565}
1740 */
1741
1742static BOOL rdp_read_glyph_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1743{
1744 WINPR_ASSERT(settings);
1745 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1746 return FALSE;
1747
1748 /* glyphCache (40 bytes) */
1749 for (size_t x = 0; x < 10; x++)
1750 rdp_read_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1751 rdp_read_cache_definition(s, settings->FragCache); /* fragCache (4 bytes) */
1752 Stream_Read_UINT16(s, settings->GlyphSupportLevel); /* glyphSupportLevel (2 bytes) */
1753 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1754 return TRUE;
1755}
1756
1757/*
1758 * Write glyph cache capability set.
1759 * msdn{cc240565}
1760 */
1761
1762static BOOL rdp_write_glyph_cache_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1763{
1764 WINPR_ASSERT(settings);
1765 if (!Stream_EnsureRemainingCapacity(s, 64))
1766 return FALSE;
1767
1768 const size_t header = rdp_capability_set_start(log, s);
1769 if (settings->GlyphSupportLevel > UINT16_MAX)
1770 return FALSE;
1771 /* glyphCache (40 bytes) */
1772 for (size_t x = 0; x < 10; x++)
1773 rdp_write_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1774 rdp_write_cache_definition(s, settings->FragCache); /* fragCache (4 bytes) */
1775 Stream_Write_UINT16(s, (UINT16)settings->GlyphSupportLevel); /* glyphSupportLevel (2 bytes) */
1776 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1777 return rdp_capability_set_finish(s, header, CAPSET_TYPE_GLYPH_CACHE);
1778}
1779
1780#ifdef WITH_DEBUG_CAPABILITIES
1781static BOOL rdp_print_glyph_cache_capability_set(wLog* log, wStream* s)
1782{
1783 GLYPH_CACHE_DEFINITION glyphCache[10] = WINPR_C_ARRAY_INIT;
1784 GLYPH_CACHE_DEFINITION fragCache = WINPR_C_ARRAY_INIT;
1785 UINT16 glyphSupportLevel = 0;
1786 UINT16 pad2Octets = 0;
1787 WLog_Print(log, WLOG_TRACE,
1788 "GlyphCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1789
1790 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1791 return FALSE;
1792
1793 /* glyphCache (40 bytes) */
1794 rdp_read_cache_definition(s, &glyphCache[0]); /* glyphCache0 (4 bytes) */
1795 rdp_read_cache_definition(s, &glyphCache[1]); /* glyphCache1 (4 bytes) */
1796 rdp_read_cache_definition(s, &glyphCache[2]); /* glyphCache2 (4 bytes) */
1797 rdp_read_cache_definition(s, &glyphCache[3]); /* glyphCache3 (4 bytes) */
1798 rdp_read_cache_definition(s, &glyphCache[4]); /* glyphCache4 (4 bytes) */
1799 rdp_read_cache_definition(s, &glyphCache[5]); /* glyphCache5 (4 bytes) */
1800 rdp_read_cache_definition(s, &glyphCache[6]); /* glyphCache6 (4 bytes) */
1801 rdp_read_cache_definition(s, &glyphCache[7]); /* glyphCache7 (4 bytes) */
1802 rdp_read_cache_definition(s, &glyphCache[8]); /* glyphCache8 (4 bytes) */
1803 rdp_read_cache_definition(s, &glyphCache[9]); /* glyphCache9 (4 bytes) */
1804 rdp_read_cache_definition(s, &fragCache); /* fragCache (4 bytes) */
1805 Stream_Read_UINT16(s, glyphSupportLevel); /* glyphSupportLevel (2 bytes) */
1806 Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
1807 WLog_Print(log, WLOG_TRACE, "\tglyphCache0: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1808 glyphCache[0].cacheEntries, glyphCache[0].cacheMaximumCellSize);
1809 WLog_Print(log, WLOG_TRACE, "\tglyphCache1: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1810 glyphCache[1].cacheEntries, glyphCache[1].cacheMaximumCellSize);
1811 WLog_Print(log, WLOG_TRACE, "\tglyphCache2: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1812 glyphCache[2].cacheEntries, glyphCache[2].cacheMaximumCellSize);
1813 WLog_Print(log, WLOG_TRACE, "\tglyphCache3: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1814 glyphCache[3].cacheEntries, glyphCache[3].cacheMaximumCellSize);
1815 WLog_Print(log, WLOG_TRACE, "\tglyphCache4: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1816 glyphCache[4].cacheEntries, glyphCache[4].cacheMaximumCellSize);
1817 WLog_Print(log, WLOG_TRACE, "\tglyphCache5: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1818 glyphCache[5].cacheEntries, glyphCache[5].cacheMaximumCellSize);
1819 WLog_Print(log, WLOG_TRACE, "\tglyphCache6: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1820 glyphCache[6].cacheEntries, glyphCache[6].cacheMaximumCellSize);
1821 WLog_Print(log, WLOG_TRACE, "\tglyphCache7: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1822 glyphCache[7].cacheEntries, glyphCache[7].cacheMaximumCellSize);
1823 WLog_Print(log, WLOG_TRACE, "\tglyphCache8: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1824 glyphCache[8].cacheEntries, glyphCache[8].cacheMaximumCellSize);
1825 WLog_Print(log, WLOG_TRACE, "\tglyphCache9: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1826 glyphCache[9].cacheEntries, glyphCache[9].cacheMaximumCellSize);
1827 WLog_Print(log, WLOG_TRACE, "\tfragCache: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1828 fragCache.cacheEntries, fragCache.cacheMaximumCellSize);
1829 WLog_Print(log, WLOG_TRACE, "\tglyphSupportLevel: 0x%04" PRIX16 "", glyphSupportLevel);
1830 WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1831 return TRUE;
1832}
1833#endif
1834
1835static BOOL rdp_apply_offscreen_bitmap_cache_capability_set(rdpSettings* settings,
1836 const rdpSettings* src)
1837{
1838 WINPR_ASSERT(settings);
1839 WINPR_ASSERT(src);
1840
1841 settings->OffscreenCacheSize = src->OffscreenCacheSize;
1842 settings->OffscreenCacheEntries = src->OffscreenCacheEntries;
1843 settings->OffscreenSupportLevel = src->OffscreenSupportLevel;
1844
1845 return TRUE;
1846}
1847
1848/*
1849 * Read offscreen bitmap cache capability set.
1850 * msdn{cc240550}
1851 */
1852
1853static BOOL rdp_read_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s,
1854 rdpSettings* settings)
1855{
1856 UINT32 offscreenSupportLevel = 0;
1857
1858 WINPR_ASSERT(settings);
1859 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1860 return FALSE;
1861
1862 Stream_Read_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */
1863 Stream_Read_UINT16(s, settings->OffscreenCacheSize); /* offscreenCacheSize (2 bytes) */
1864 Stream_Read_UINT16(s, settings->OffscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1865
1866 settings->OffscreenSupportLevel = offscreenSupportLevel & 0x01;
1867
1868 return TRUE;
1869}
1870
1871/*
1872 * Write offscreen bitmap cache capability set.
1873 * msdn{cc240550}
1874 */
1875
1876static BOOL rdp_write_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s,
1877 const rdpSettings* settings)
1878{
1879 UINT32 offscreenSupportLevel = 0x00;
1880
1881 WINPR_ASSERT(settings);
1882 if (!Stream_EnsureRemainingCapacity(s, 32))
1883 return FALSE;
1884
1885 const size_t header = rdp_capability_set_start(log, s);
1886 if (settings->OffscreenSupportLevel)
1887 {
1888 offscreenSupportLevel = 0x01;
1889 Stream_Write_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */
1890 Stream_Write_UINT16(
1891 s, WINPR_ASSERTING_INT_CAST(
1892 uint16_t, settings->OffscreenCacheSize)); /* offscreenCacheSize (2 bytes) */
1893 Stream_Write_UINT16(
1894 s,
1895 WINPR_ASSERTING_INT_CAST(
1896 uint16_t, settings->OffscreenCacheEntries)); /* offscreenCacheEntries (2 bytes) */
1897 }
1898 else
1899 Stream_Zero(s, 8);
1900
1901 return rdp_capability_set_finish(s, header, CAPSET_TYPE_OFFSCREEN_CACHE);
1902}
1903
1904#ifdef WITH_DEBUG_CAPABILITIES
1905static BOOL rdp_print_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s)
1906{
1907 UINT32 offscreenSupportLevel = 0;
1908 UINT16 offscreenCacheSize = 0;
1909 UINT16 offscreenCacheEntries = 0;
1910 WLog_Print(log, WLOG_TRACE, "OffscreenBitmapCacheCapabilitySet (length %" PRIuz "):",
1911 Stream_GetRemainingLength(s));
1912
1913 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1914 return FALSE;
1915
1916 Stream_Read_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */
1917 Stream_Read_UINT16(s, offscreenCacheSize); /* offscreenCacheSize (2 bytes) */
1918 Stream_Read_UINT16(s, offscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1919 WLog_Print(log, WLOG_TRACE, "\toffscreenSupportLevel: 0x%08" PRIX32 "", offscreenSupportLevel);
1920 WLog_Print(log, WLOG_TRACE, "\toffscreenCacheSize: 0x%04" PRIX16 "", offscreenCacheSize);
1921 WLog_Print(log, WLOG_TRACE, "\toffscreenCacheEntries: 0x%04" PRIX16 "", offscreenCacheEntries);
1922 return TRUE;
1923}
1924#endif
1925
1926static BOOL rdp_apply_bitmap_cache_host_support_capability_set(rdpSettings* settings,
1927 const rdpSettings* src)
1928{
1929 const BOOL val = (freerdp_settings_get_bool(src, FreeRDP_BitmapCachePersistEnabled) &&
1930 freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled));
1931 return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, val);
1932}
1933
1934/*
1935 * Read bitmap cache host support capability set.
1936 * msdn{cc240557}
1937 */
1938
1939static BOOL rdp_read_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
1940 rdpSettings* settings)
1941{
1942 BYTE cacheVersion = 0;
1943
1944 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1945 return FALSE;
1946
1947 Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1948 Stream_Seek_UINT8(s); /* pad1 (1 byte) */
1949 Stream_Seek_UINT16(s); /* pad2 (2 bytes) */
1950
1951 return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
1952 cacheVersion & BITMAP_CACHE_V2);
1953}
1954
1955/*
1956 * Write bitmap cache host support capability set.
1957 * msdn{cc240557}
1958 */
1959
1960static BOOL rdp_write_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
1961 const rdpSettings* settings)
1962{
1963 UINT8 cacheVersion = 0;
1964
1965 if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled))
1966 cacheVersion |= BITMAP_CACHE_V2;
1967
1968 if (!Stream_EnsureRemainingCapacity(s, 32))
1969 return FALSE;
1970
1971 const size_t header = rdp_capability_set_start(log, s);
1972 Stream_Write_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1973 Stream_Write_UINT8(s, 0); /* pad1 (1 byte) */
1974 Stream_Write_UINT16(s, 0); /* pad2 (2 bytes) */
1975 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT);
1976}
1977
1978#ifdef WITH_DEBUG_CAPABILITIES
1979static BOOL rdp_print_bitmap_cache_host_support_capability_set(wLog* log, wStream* s)
1980{
1981 BYTE cacheVersion = 0;
1982 BYTE pad1 = 0;
1983 UINT16 pad2 = 0;
1984 WLog_Print(log, WLOG_TRACE, "BitmapCacheHostSupportCapabilitySet (length %" PRIuz "):",
1985 Stream_GetRemainingLength(s));
1986
1987 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1988 return FALSE;
1989
1990 Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1991 Stream_Read_UINT8(s, pad1); /* pad1 (1 byte) */
1992 Stream_Read_UINT16(s, pad2); /* pad2 (2 bytes) */
1993 WLog_Print(log, WLOG_TRACE, "\tcacheVersion: 0x%02" PRIX8 "", cacheVersion);
1994 WLog_Print(log, WLOG_TRACE, "\tpad1: 0x%02" PRIX8 "", pad1);
1995 WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%04" PRIX16 "", pad2);
1996 return TRUE;
1997}
1998#endif
1999
2000static BOOL rdp_read_bitmap_cache_cell_info(wLog* log, wStream* s,
2001 BITMAP_CACHE_V2_CELL_INFO* cellInfo)
2002{
2003 UINT32 info = 0;
2004
2005 WINPR_ASSERT(cellInfo);
2006 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2007 return FALSE;
2008
2009 /*
2010 * numEntries is in the first 31 bits, while the last bit (k)
2011 * is used to indicate a persistent bitmap cache.
2012 */
2013 Stream_Read_UINT32(s, info);
2014 cellInfo->numEntries = (info & 0x7FFFFFFF);
2015 cellInfo->persistent = (info & 0x80000000) ? 1 : 0;
2016 return TRUE;
2017}
2018
2019static void rdp_write_bitmap_cache_cell_info(wStream* s, BITMAP_CACHE_V2_CELL_INFO* cellInfo)
2020{
2021 UINT32 info = 0;
2022 /*
2023 * numEntries is in the first 31 bits, while the last bit (k)
2024 * is used to indicate a persistent bitmap cache.
2025 */
2026 WINPR_ASSERT(cellInfo);
2027 info = (cellInfo->numEntries | (((UINT32)cellInfo->persistent << 31) & 0xFF000000));
2028 Stream_Write_UINT32(s, info);
2029}
2030
2031static BOOL rdp_apply_bitmap_cache_v2_capability_set(rdpSettings* settings, const rdpSettings* src)
2032{
2033 const FreeRDP_Settings_Keys_Bool keys[] = { FreeRDP_BitmapCacheEnabled,
2034 FreeRDP_BitmapCachePersistEnabled };
2035
2036 for (size_t x = 0; x < ARRAYSIZE(keys); x++)
2037 {
2038 const FreeRDP_Settings_Keys_Bool id = keys[x];
2039 const BOOL val = freerdp_settings_get_bool(src, id);
2040 if (!freerdp_settings_set_bool(settings, id, val))
2041 return FALSE;
2042 }
2043
2044 {
2045 const UINT32 BitmapCacheV2NumCells =
2046 freerdp_settings_get_uint32(src, FreeRDP_BitmapCacheV2NumCells);
2047 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_BitmapCacheV2CellInfo, nullptr,
2048 BitmapCacheV2NumCells))
2049 return FALSE;
2050
2051 for (size_t x = 0; x < BitmapCacheV2NumCells; x++)
2052 {
2053 const BITMAP_CACHE_V2_CELL_INFO* cdata =
2054 freerdp_settings_get_pointer_array(src, FreeRDP_BitmapCacheV2CellInfo, x);
2055 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, x,
2056 cdata))
2057 return FALSE;
2058 }
2059 }
2060
2061 return TRUE;
2062}
2063
2064/*
2065 * Read bitmap cache v2 capability set.
2066 * msdn{cc240560}
2067 */
2068
2069static BOOL rdp_read_bitmap_cache_v2_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2070{
2071 UINT16 cacheFlags = 0;
2072 WINPR_UNUSED(settings);
2073 WINPR_ASSERT(settings);
2074
2075 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2076 return FALSE;
2077
2078 Stream_Read_UINT16(s, cacheFlags); /* cacheFlags (2 bytes) */
2079
2080 if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE))
2081 return FALSE;
2082 if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
2083 cacheFlags & PERSISTENT_KEYS_EXPECTED_FLAG))
2084 return FALSE;
2085
2086 Stream_Seek_UINT8(s); /* pad2 (1 byte) */
2087 Stream_Read_UINT8(s, settings->BitmapCacheV2NumCells); /* numCellCaches (1 byte) */
2088 if (settings->BitmapCacheV2NumCells > 5)
2089 {
2090 WLog_Print(log, WLOG_ERROR,
2091 "Invalid TS_BITMAPCACHE_CAPABILITYSET_REV2::numCellCaches %" PRIu32 " > 5",
2092 settings->BitmapCacheV2NumCells);
2093 return FALSE;
2094 }
2095
2096 for (size_t x = 0; x < settings->BitmapCacheV2NumCells; x++)
2097 {
2099 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_BitmapCacheV2CellInfo, x);
2100 if (!rdp_read_bitmap_cache_cell_info(log, s, info))
2101 return FALSE;
2102 }
2103
2104 /* Input must always have 5 BitmapCacheV2CellInfo values */
2105 for (size_t x = settings->BitmapCacheV2NumCells; x < 5; x++)
2106 {
2107 if (!Stream_SafeSeek(s, 4))
2108 return FALSE;
2109 }
2110 Stream_Seek(s, 12); /* pad3 (12 bytes) */
2111 return TRUE;
2112}
2113
2114/*
2115 * Write bitmap cache v2 capability set.
2116 * msdn{cc240560}
2117 */
2118
2119static BOOL rdp_write_bitmap_cache_v2_capability_set(wLog* log, wStream* s,
2120 const rdpSettings* settings)
2121{
2122 WINPR_ASSERT(settings);
2123 if (!Stream_EnsureRemainingCapacity(s, 64))
2124 return FALSE;
2125
2126 const size_t header = rdp_capability_set_start(log, s);
2127 UINT16 cacheFlags = ALLOW_CACHE_WAITING_LIST_FLAG;
2128
2129 if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
2130 {
2131 cacheFlags |= PERSISTENT_KEYS_EXPECTED_FLAG;
2132 settings->BitmapCacheV2CellInfo[0].persistent = 1;
2133 settings->BitmapCacheV2CellInfo[1].persistent = 1;
2134 settings->BitmapCacheV2CellInfo[2].persistent = 1;
2135 settings->BitmapCacheV2CellInfo[3].persistent = 1;
2136 settings->BitmapCacheV2CellInfo[4].persistent = 1;
2137 }
2138
2139 Stream_Write_UINT16(s, cacheFlags); /* cacheFlags (2 bytes) */
2140 Stream_Write_UINT8(s, 0); /* pad2 (1 byte) */
2141 Stream_Write_UINT8(
2142 s, WINPR_ASSERTING_INT_CAST(uint8_t,
2143 settings->BitmapCacheV2NumCells)); /* numCellCaches (1 byte) */
2144 rdp_write_bitmap_cache_cell_info(
2145 s, &settings->BitmapCacheV2CellInfo[0]); /* bitmapCache0CellInfo (4 bytes) */
2146 rdp_write_bitmap_cache_cell_info(
2147 s, &settings->BitmapCacheV2CellInfo[1]); /* bitmapCache1CellInfo (4 bytes) */
2148 rdp_write_bitmap_cache_cell_info(
2149 s, &settings->BitmapCacheV2CellInfo[2]); /* bitmapCache2CellInfo (4 bytes) */
2150 rdp_write_bitmap_cache_cell_info(
2151 s, &settings->BitmapCacheV2CellInfo[3]); /* bitmapCache3CellInfo (4 bytes) */
2152 rdp_write_bitmap_cache_cell_info(
2153 s, &settings->BitmapCacheV2CellInfo[4]); /* bitmapCache4CellInfo (4 bytes) */
2154 Stream_Zero(s, 12); /* pad3 (12 bytes) */
2155 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V2);
2156}
2157
2158#ifdef WITH_DEBUG_CAPABILITIES
2159static BOOL rdp_print_bitmap_cache_v2_capability_set(wLog* log, wStream* s)
2160{
2161 BITMAP_CACHE_V2_CELL_INFO bitmapCacheV2CellInfo[5] = WINPR_C_ARRAY_INIT;
2162 WLog_Print(log, WLOG_TRACE,
2163 "BitmapCacheV2CapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2164
2165 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2166 return FALSE;
2167
2168 const UINT16 cacheFlags = Stream_Get_UINT16(s); /* cacheFlags (2 bytes) */
2169 const UINT8 pad2 = Stream_Get_UINT8(s); /* pad2 (1 byte) */
2170 const UINT8 numCellCaches = Stream_Get_UINT8(s); /* numCellCaches (1 byte) */
2171
2172 for (size_t x = 0; x < ARRAYSIZE(bitmapCacheV2CellInfo); x++)
2173 {
2174 if (!rdp_read_bitmap_cache_cell_info(
2175 log, s, &bitmapCacheV2CellInfo[x])) /* bitmapCache0CellInfo (4 bytes) */
2176 return FALSE;
2177 }
2178
2179 if (!Stream_SafeSeek(s, 12)) /* pad3 (12 bytes) */
2180 return FALSE;
2181
2182 WLog_Print(log, WLOG_TRACE, "\tcacheFlags: 0x%04" PRIX16 "", cacheFlags);
2183 WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%02" PRIX8 "", pad2);
2184 WLog_Print(log, WLOG_TRACE, "\tnumCellCaches: 0x%02" PRIX8 "", numCellCaches);
2185 for (size_t x = 0; x < ARRAYSIZE(bitmapCacheV2CellInfo); x++)
2186 {
2187 const BITMAP_CACHE_V2_CELL_INFO* info = &bitmapCacheV2CellInfo[x];
2188 WLog_Print(log, WLOG_TRACE,
2189 "\tbitmapCache%" PRIuz "CellInfo: numEntries: %" PRIu32 " persistent: %" PRId32
2190 "",
2191 x, info->numEntries, info->persistent);
2192 }
2193 return TRUE;
2194}
2195#endif
2196
2197static BOOL rdp_apply_virtual_channel_capability_set(rdpSettings* settings, const rdpSettings* src)
2198{
2199 WINPR_ASSERT(settings);
2200 WINPR_ASSERT(src);
2201
2202 /* MS servers and clients disregard in advertising what is relevant for their own side */
2203 if (settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_SC) &&
2204 (src->VCFlags & VCCAPS_COMPR_SC))
2205 settings->VCFlags |= VCCAPS_COMPR_SC;
2206 else
2207 settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_SC;
2208
2209 if (!settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_CS_8K) &&
2210 (src->VCFlags & VCCAPS_COMPR_CS_8K))
2211 settings->VCFlags |= VCCAPS_COMPR_CS_8K;
2212 else
2213 settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_CS_8K;
2214
2215 /*
2216 * When one peer does not write the VCChunkSize, the VCChunkSize must not be
2217 * larger than CHANNEL_CHUNK_LENGTH (1600) bytes.
2218 * Also prevent an invalid 0 size.
2219 */
2220 if (!settings->ServerMode)
2221 {
2222 if ((src->VCChunkSize > CHANNEL_CHUNK_MAX_LENGTH) || (src->VCChunkSize == 0))
2223 settings->VCChunkSize = CHANNEL_CHUNK_LENGTH;
2224 else
2225 {
2226 settings->VCChunkSize = src->VCChunkSize;
2227 }
2228 }
2229
2230 return TRUE;
2231}
2232
2233/*
2234 * Read virtual channel capability set.
2235 * msdn{cc240551}
2236 */
2237
2238static BOOL rdp_read_virtual_channel_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2239{
2240 UINT32 flags = 0;
2241 UINT32 VCChunkSize = 0;
2242
2243 WINPR_ASSERT(settings);
2244 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2245 return FALSE;
2246
2247 Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2248
2249 if (Stream_GetRemainingLength(s) >= 4)
2250 Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2251 else
2252 VCChunkSize = UINT32_MAX; /* Use an invalid value to determine that value is not present */
2253
2254 settings->VCFlags = flags;
2255 settings->VCChunkSize = VCChunkSize;
2256
2257 return TRUE;
2258}
2259
2260/*
2261 * Write virtual channel capability set.
2262 * msdn{cc240551}
2263 */
2264
2265static BOOL rdp_write_virtual_channel_capability_set(wLog* log, wStream* s,
2266 const rdpSettings* settings)
2267{
2268 WINPR_ASSERT(settings);
2269 if (!Stream_EnsureRemainingCapacity(s, 32))
2270 return FALSE;
2271
2272 const size_t header = rdp_capability_set_start(log, s);
2273 Stream_Write_UINT32(s, settings->VCFlags); /* flags (4 bytes) */
2274 Stream_Write_UINT32(s, settings->VCChunkSize); /* VCChunkSize (4 bytes) */
2275 return rdp_capability_set_finish(s, header, CAPSET_TYPE_VIRTUAL_CHANNEL);
2276}
2277
2278#ifdef WITH_DEBUG_CAPABILITIES
2279static BOOL rdp_print_virtual_channel_capability_set(wLog* log, wStream* s)
2280{
2281 UINT32 flags = 0;
2282 UINT32 VCChunkSize = 0;
2283 WLog_Print(log, WLOG_TRACE,
2284 "VirtualChannelCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2285
2286 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2287 return FALSE;
2288
2289 Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2290
2291 if (Stream_GetRemainingLength(s) >= 4)
2292 Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2293 else
2294 VCChunkSize = 1600;
2295
2296 WLog_Print(log, WLOG_TRACE, "\tflags: 0x%08" PRIX32 "", flags);
2297 WLog_Print(log, WLOG_TRACE, "\tVCChunkSize: 0x%08" PRIX32 "", VCChunkSize);
2298 return TRUE;
2299}
2300#endif
2301
2302static BOOL rdp_apply_draw_nine_grid_cache_capability_set(rdpSettings* settings,
2303 const rdpSettings* src)
2304{
2305 WINPR_ASSERT(settings);
2306 WINPR_ASSERT(src);
2307
2308 settings->DrawNineGridCacheSize = src->DrawNineGridCacheSize;
2309 settings->DrawNineGridCacheEntries = src->DrawNineGridCacheEntries;
2310 settings->DrawNineGridEnabled = src->DrawNineGridEnabled;
2311
2312 return TRUE;
2313}
2314
2315/*
2316 * Read drawn nine grid cache capability set.
2317 * msdn{cc241565}
2318 */
2319
2320static BOOL rdp_read_draw_nine_grid_cache_capability_set(wLog* log, wStream* s,
2321 rdpSettings* settings)
2322{
2323 UINT32 drawNineGridSupportLevel = 0;
2324
2325 WINPR_ASSERT(settings);
2326 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2327 return FALSE;
2328
2329 Stream_Read_UINT32(s, drawNineGridSupportLevel); /* drawNineGridSupportLevel (4 bytes) */
2330 Stream_Read_UINT16(s, settings->DrawNineGridCacheSize); /* drawNineGridCacheSize (2 bytes) */
2331 Stream_Read_UINT16(s,
2332 settings->DrawNineGridCacheEntries); /* drawNineGridCacheEntries (2 bytes) */
2333
2334 settings->DrawNineGridEnabled =
2335 (drawNineGridSupportLevel & (DRAW_NINEGRID_SUPPORTED | DRAW_NINEGRID_SUPPORTED_V2)) != 0;
2336
2337 return TRUE;
2338}
2339
2340/*
2341 * Write drawn nine grid cache capability set.
2342 * msdn{cc241565}
2343 */
2344
2345static BOOL rdp_write_draw_nine_grid_cache_capability_set(wLog* log, wStream* s,
2346 const rdpSettings* settings)
2347{
2348 WINPR_ASSERT(settings);
2349 if (!Stream_EnsureRemainingCapacity(s, 32))
2350 return FALSE;
2351
2352 const size_t header = rdp_capability_set_start(log, s);
2353 const UINT32 drawNineGridSupportLevel =
2354 (settings->DrawNineGridEnabled) ? DRAW_NINEGRID_SUPPORTED_V2 : DRAW_NINEGRID_NO_SUPPORT;
2355 Stream_Write_UINT32(s, drawNineGridSupportLevel); /* drawNineGridSupportLevel (4 bytes) */
2356 Stream_Write_UINT16(
2357 s, WINPR_ASSERTING_INT_CAST(
2358 uint16_t, settings->DrawNineGridCacheSize)); /* drawNineGridCacheSize (2 bytes) */
2359 Stream_Write_UINT16(
2360 s,
2361 WINPR_ASSERTING_INT_CAST(
2362 uint16_t, settings->DrawNineGridCacheEntries)); /* drawNineGridCacheEntries (2 bytes) */
2363 return rdp_capability_set_finish(s, header, CAPSET_TYPE_DRAW_NINE_GRID_CACHE);
2364}
2365
2366#ifdef WITH_DEBUG_CAPABILITIES
2367static BOOL rdp_print_draw_nine_grid_cache_capability_set(wLog* log, wStream* s)
2368{
2369 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2370 return FALSE;
2371
2372 const uint32_t drawNineGridSupportLevel =
2373 Stream_Get_UINT32(s); /* drawNineGridSupportLevel (4 bytes) */
2374 const uint32_t DrawNineGridCacheSize =
2375 Stream_Get_UINT16(s); /* drawNineGridCacheSize (2 bytes) */
2376 const uint32_t DrawNineGridCacheEntries =
2377 Stream_Get_UINT16(s); /* drawNineGridCacheEntries (2 bytes) */
2378
2379 WLog_Print(log, WLOG_TRACE,
2380 "DrawNineGridCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2381 WLog_Print(log, WLOG_TRACE, "drawNineGridSupportLevel=0x%08" PRIx32, drawNineGridSupportLevel);
2382 WLog_Print(log, WLOG_TRACE, "DrawNineGridCacheSize=0x%08" PRIx32, DrawNineGridCacheSize);
2383 WLog_Print(log, WLOG_TRACE, "DrawNineGridCacheEntries=0x%08" PRIx32, DrawNineGridCacheEntries);
2384 return TRUE;
2385}
2386#endif
2387
2388static BOOL rdp_apply_draw_gdiplus_cache_capability_set(rdpSettings* settings,
2389 const rdpSettings* src)
2390{
2391 WINPR_ASSERT(settings);
2392 WINPR_ASSERT(src);
2393
2394 if (src->DrawGdiPlusEnabled)
2395 settings->DrawGdiPlusEnabled = TRUE;
2396
2397 if (src->DrawGdiPlusCacheEnabled)
2398 settings->DrawGdiPlusCacheEnabled = TRUE;
2399
2400 return TRUE;
2401}
2402
2403/*
2404 * Read GDI+ cache capability set.
2405 * msdn{cc241566}
2406 */
2407
2408static BOOL rdp_read_draw_gdiplus_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2409{
2410 UINT32 drawGDIPlusSupportLevel = 0;
2411 UINT32 drawGdiplusCacheLevel = 0;
2412
2413 WINPR_ASSERT(settings);
2414 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2415 return FALSE;
2416
2417 Stream_Read_UINT32(s, drawGDIPlusSupportLevel); /* drawGDIPlusSupportLevel (4 bytes) */
2418 Stream_Seek_UINT32(s); /* GdipVersion (4 bytes) */
2419 Stream_Read_UINT32(s, drawGdiplusCacheLevel); /* drawGdiplusCacheLevel (4 bytes) */
2420 Stream_Seek(s, 10); /* GdipCacheEntries (10 bytes) */
2421 Stream_Seek(s, 8); /* GdipCacheChunkSize (8 bytes) */
2422 Stream_Seek(s, 6); /* GdipImageCacheProperties (6 bytes) */
2423
2424 settings->DrawGdiPlusEnabled = (drawGDIPlusSupportLevel & DRAW_GDIPLUS_SUPPORTED) != 0;
2425 settings->DrawGdiPlusCacheEnabled = (drawGdiplusCacheLevel & DRAW_GDIPLUS_CACHE_LEVEL_ONE) != 0;
2426
2427 return TRUE;
2428}
2429
2430#ifdef WITH_DEBUG_CAPABILITIES
2431static BOOL rdp_print_draw_gdiplus_cache_capability_set(wLog* log, wStream* s)
2432{
2433 WLog_Print(log, WLOG_TRACE,
2434 "DrawGdiPlusCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2435
2436 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2437 return FALSE;
2438
2439 const uint32_t drawGdiPlusSupportLevel =
2440 Stream_Get_UINT32(s); /* drawGdiPlusSupportLevel (4 bytes) */
2441 const uint32_t GdipVersion = Stream_Get_UINT32(s); /* GdipVersion (4 bytes) */
2442 const uint32_t drawGdiplusCacheLevel =
2443 Stream_Get_UINT32(s); /* drawGdiPlusCacheLevel (4 bytes) */
2444 WLog_Print(log, WLOG_TRACE,
2445 "drawGdiPlusSupportLevel=0x%08" PRIx32 ", GdipVersion=0x%08" PRIx32
2446 ", drawGdiplusdrawGdiplusCacheLevelCacheLevel=0x%08" PRIx32,
2447 drawGdiPlusSupportLevel, GdipVersion, drawGdiplusCacheLevel);
2448 /* GdipCacheEntries (10 bytes) */
2449 const uint16_t GdipGraphicsCacheEntries = Stream_Get_UINT16(s);
2450 const uint16_t GdipBrushCacheEntries = Stream_Get_UINT16(s);
2451 const uint16_t GdipPenCacheEntries = Stream_Get_UINT16(s);
2452 const uint16_t GdipImageCacheEntries = Stream_Get_UINT16(s);
2453 const uint16_t GdipImageAttributesCacheEntries = Stream_Get_UINT16(s);
2454 WLog_Print(log, WLOG_TRACE,
2455 "GdipGraphicsCacheEntries=0x%04" PRIx16 ", GdipBrushCacheEntries=0x%04" PRIx16
2456 ", GdipPenCacheEntries=0x%04" PRIx16 ", GdipImageCacheEntries=0x%04" PRIx16
2457 ", GdipImageAttributesCacheEntries=0x%04" PRIx16,
2458 GdipGraphicsCacheEntries, GdipBrushCacheEntries, GdipPenCacheEntries,
2459 GdipImageCacheEntries, GdipImageAttributesCacheEntries);
2460 /* GdipCacheChunkSize (8 bytes) */
2461 const uint16_t GdipGraphicsCacheChunkSize = Stream_Get_UINT16(s);
2462 const uint16_t GdipObjectBrushCacheChunkSize = Stream_Get_UINT16(s);
2463 const uint16_t GdipObjectPenCacheChunkSize = Stream_Get_UINT16(s);
2464 const uint16_t GdipObjectImageAttributesCacheChunkSize = Stream_Get_UINT16(s);
2465 WLog_Print(log, WLOG_TRACE,
2466 "GdipGraphicsCacheChunkSize=0x%04" PRIx16
2467 ", GdipObjectBrushCacheChunkSize=0x%04" PRIx16
2468 ", GdipObjectPenCacheChunkSize=0x%04" PRIx16
2469 ",GdipObjectImageAttributesCacheChunkSize=0x%04" PRIx16,
2470 GdipGraphicsCacheChunkSize, GdipObjectBrushCacheChunkSize,
2471 GdipObjectPenCacheChunkSize, GdipObjectImageAttributesCacheChunkSize);
2472 /* GdipImageCacheProperties (6 bytes) */
2473 const uint16_t GdipObjectImageCacheChunkSize = Stream_Get_UINT16(s);
2474 const uint16_t GdipObjectImageCacheTotalSize = Stream_Get_UINT16(s);
2475 const uint16_t GdipObjectImageCacheMaxSize = Stream_Get_UINT16(s);
2476 WLog_Print(
2477 log, WLOG_TRACE,
2478 "GdipObjectImageCacheChunkSize=0x%04" PRIx16 ", GdipObjectImageCacheTotalSize=0x%04" PRIx16
2479 ", GdipObjectImageCacheMaxSize=0x%04" PRIx16,
2480 GdipObjectImageCacheChunkSize, GdipObjectImageCacheTotalSize, GdipObjectImageCacheMaxSize);
2481 return TRUE;
2482}
2483#endif
2484
2485static BOOL rdp_apply_remote_programs_capability_set(rdpSettings* settings, const rdpSettings* src)
2486{
2487 WINPR_ASSERT(settings);
2488 WINPR_ASSERT(src);
2489
2490 if (settings->RemoteApplicationMode)
2491 settings->RemoteApplicationMode = src->RemoteApplicationMode;
2492
2493 /* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX)
2494 * the handshake ex pdu is supported when both, client and server announce
2495 * it OR if we are ready to begin enhanced remoteAPP mode. */
2496 UINT32 supportLevel = src->RemoteApplicationSupportLevel;
2497 if (settings->RemoteApplicationMode)
2498 supportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2499
2500 settings->RemoteApplicationSupportLevel = supportLevel & settings->RemoteApplicationSupportMask;
2501
2502 return TRUE;
2503}
2504
2505/*
2506 * Read remote programs capability set.
2507 * msdn{cc242518}
2508 */
2509
2510static BOOL rdp_read_remote_programs_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2511{
2512 UINT32 railSupportLevel = 0;
2513
2514 WINPR_ASSERT(settings);
2515 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2516 return FALSE;
2517
2518 Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2519
2520 settings->RemoteApplicationMode = (railSupportLevel & RAIL_LEVEL_SUPPORTED) != 0;
2521 settings->RemoteApplicationSupportLevel = railSupportLevel;
2522 return TRUE;
2523}
2524
2525/*
2526 * Write remote programs capability set.
2527 * msdn{cc242518}
2528 */
2529
2530static BOOL rdp_write_remote_programs_capability_set(wLog* log, wStream* s,
2531 const rdpSettings* settings)
2532{
2533 WINPR_ASSERT(settings);
2534 if (!Stream_EnsureRemainingCapacity(s, 64))
2535 return FALSE;
2536
2537 const size_t header = rdp_capability_set_start(log, s);
2538 UINT32 railSupportLevel = RAIL_LEVEL_SUPPORTED;
2539
2540 if (settings->RemoteApplicationSupportLevel & RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED)
2541 {
2542 if (settings->RemoteAppLanguageBarSupported)
2543 railSupportLevel |= RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED;
2544 }
2545
2546 railSupportLevel |= RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED;
2547 railSupportLevel |= RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED;
2548 railSupportLevel |= RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED;
2549 railSupportLevel |= RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED;
2550 railSupportLevel |= RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED;
2551 railSupportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2552 /* Mask out everything the server does not support. */
2553 railSupportLevel &= settings->RemoteApplicationSupportLevel;
2554 Stream_Write_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2555 return rdp_capability_set_finish(s, header, CAPSET_TYPE_RAIL);
2556}
2557
2558#ifdef WITH_DEBUG_CAPABILITIES
2559static BOOL rdp_print_remote_programs_capability_set(wLog* log, wStream* s)
2560{
2561 UINT32 railSupportLevel = 0;
2562 WLog_Print(log, WLOG_TRACE,
2563 "RemoteProgramsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2564
2565 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2566 return FALSE;
2567
2568 Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2569 WLog_Print(log, WLOG_TRACE, "\trailSupportLevel: 0x%08" PRIX32 "", railSupportLevel);
2570 return TRUE;
2571}
2572#endif
2573
2574static BOOL rdp_apply_window_list_capability_set(rdpSettings* settings, const rdpSettings* src)
2575{
2576 WINPR_ASSERT(settings);
2577 WINPR_ASSERT(src);
2578
2579 settings->RemoteWndSupportLevel = src->RemoteWndSupportLevel;
2580 settings->RemoteAppNumIconCaches = src->RemoteAppNumIconCaches;
2581 settings->RemoteAppNumIconCacheEntries = src->RemoteAppNumIconCacheEntries;
2582
2583 return TRUE;
2584}
2585
2586/*
2587 * Read window list capability set.
2588 * msdn{cc242564}
2589 */
2590
2591static BOOL rdp_read_window_list_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2592{
2593 WINPR_ASSERT(settings);
2594 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2595 return FALSE;
2596
2597 Stream_Read_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2598 Stream_Read_UINT8(s, settings->RemoteAppNumIconCaches); /* numIconCaches (1 byte) */
2599 Stream_Read_UINT16(s,
2600 settings->RemoteAppNumIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2601 return TRUE;
2602}
2603
2604/*
2605 * Write window list capability set.
2606 * msdn{cc242564}
2607 */
2608
2609static BOOL rdp_write_window_list_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
2610{
2611 WINPR_ASSERT(settings);
2612 if (!Stream_EnsureRemainingCapacity(s, 32))
2613 return FALSE;
2614
2615 const size_t header = rdp_capability_set_start(log, s);
2616 Stream_Write_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2617 Stream_Write_UINT8(
2618 s, WINPR_ASSERTING_INT_CAST(uint8_t,
2619 settings->RemoteAppNumIconCaches)); /* numIconCaches (1 byte) */
2620 Stream_Write_UINT16(
2621 s,
2622 WINPR_ASSERTING_INT_CAST(
2623 uint16_t, settings->RemoteAppNumIconCacheEntries)); /* numIconCacheEntries (2 bytes) */
2624 return rdp_capability_set_finish(s, header, CAPSET_TYPE_WINDOW);
2625}
2626
2627#ifdef WITH_DEBUG_CAPABILITIES
2628static BOOL rdp_print_window_list_capability_set(wLog* log, wStream* s)
2629{
2630 UINT32 wndSupportLevel = 0;
2631 BYTE numIconCaches = 0;
2632 UINT16 numIconCacheEntries = 0;
2633 WLog_Print(log, WLOG_TRACE,
2634 "WindowListCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2635
2636 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2637 return FALSE;
2638
2639 Stream_Read_UINT32(s, wndSupportLevel); /* wndSupportLevel (4 bytes) */
2640 Stream_Read_UINT8(s, numIconCaches); /* numIconCaches (1 byte) */
2641 Stream_Read_UINT16(s, numIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2642 WLog_Print(log, WLOG_TRACE, "\twndSupportLevel: 0x%08" PRIX32 "", wndSupportLevel);
2643 WLog_Print(log, WLOG_TRACE, "\tnumIconCaches: 0x%02" PRIX8 "", numIconCaches);
2644 WLog_Print(log, WLOG_TRACE, "\tnumIconCacheEntries: 0x%04" PRIX16 "", numIconCacheEntries);
2645 return TRUE;
2646}
2647#endif
2648
2649static BOOL rdp_apply_desktop_composition_capability_set(rdpSettings* settings,
2650 const rdpSettings* src)
2651{
2652 WINPR_ASSERT(settings);
2653 WINPR_ASSERT(src);
2654
2655 settings->CompDeskSupportLevel = src->CompDeskSupportLevel;
2656 return TRUE;
2657}
2658
2659/*
2660 * Read desktop composition capability set.
2661 * msdn{cc240855}
2662 */
2663
2664static BOOL rdp_read_desktop_composition_capability_set(wLog* log, wStream* s,
2665 rdpSettings* settings)
2666{
2667 WINPR_UNUSED(settings);
2668 WINPR_ASSERT(settings);
2669
2670 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2671 return FALSE;
2672
2673 Stream_Read_UINT16(s, settings->CompDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2674 return TRUE;
2675}
2676
2677/*
2678 * Write desktop composition capability set.
2679 * msdn{cc240855}
2680 */
2681
2682static BOOL rdp_write_desktop_composition_capability_set(wLog* log, wStream* s,
2683 const rdpSettings* settings)
2684{
2685 WINPR_ASSERT(settings);
2686
2687 if (!Stream_EnsureRemainingCapacity(s, 32))
2688 return FALSE;
2689
2690 const size_t header = rdp_capability_set_start(log, s);
2691 const UINT16 compDeskSupportLevel =
2692 (settings->AllowDesktopComposition) ? COMPDESK_SUPPORTED : COMPDESK_NOT_SUPPORTED;
2693 Stream_Write_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2694 return rdp_capability_set_finish(s, header, CAPSET_TYPE_COMP_DESK);
2695}
2696
2697#ifdef WITH_DEBUG_CAPABILITIES
2698static BOOL rdp_print_desktop_composition_capability_set(wLog* log, wStream* s)
2699{
2700 UINT16 compDeskSupportLevel = 0;
2701 WLog_Print(log, WLOG_TRACE, "DesktopCompositionCapabilitySet (length %" PRIuz "):",
2702 Stream_GetRemainingLength(s));
2703
2704 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2705 return FALSE;
2706
2707 Stream_Read_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2708 WLog_Print(log, WLOG_TRACE, "\tcompDeskSupportLevel: 0x%04" PRIX16 "", compDeskSupportLevel);
2709 return TRUE;
2710}
2711#endif
2712
2713static BOOL rdp_apply_multifragment_update_capability_set(rdpSettings* settings,
2714 const rdpSettings* src)
2715{
2716 WINPR_ASSERT(settings);
2717 WINPR_ASSERT(src);
2718
2719 UINT32 multifragMaxRequestSize =
2720 freerdp_settings_get_uint32(src, FreeRDP_MultifragMaxRequestSize);
2721
2722 if (settings->ServerMode)
2723 {
2724 /*
2725 * Special case: The client announces multifragment update support but sets the maximum
2726 * request size to something smaller than maximum size for *one* fast-path PDU. In this case
2727 * behave like no multifragment updates were supported and make sure no fragmentation
2728 * happens by setting FASTPATH_FRAGMENT_SAFE_SIZE.
2729 *
2730 * This behaviour was observed with some windows ce rdp clients.
2731 */
2732 if (multifragMaxRequestSize < FASTPATH_MAX_PACKET_SIZE)
2733 multifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE;
2734
2735 if (settings->RemoteFxCodec)
2736 {
2737 /*
2738 * If we are using RemoteFX the client MUST use a value greater
2739 * than or equal to the value we've previously sent in the server to
2740 * client multi-fragment update capability set (MS-RDPRFX 1.5)
2741 */
2742 if (multifragMaxRequestSize <
2743 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize))
2744 {
2745 /*
2746 * If it happens to be smaller we honor the client's value but
2747 * have to disable RemoteFX
2748 */
2749 settings->RemoteFxCodec = FALSE;
2750 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2751 multifragMaxRequestSize))
2752 return FALSE;
2753 }
2754 else
2755 {
2756 /* no need to increase server's max request size setting here */
2757 }
2758 }
2759 else
2760 {
2761 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2762 multifragMaxRequestSize))
2763 return FALSE;
2764 }
2765 }
2766 else
2767 {
2768 /*
2769 * In client mode we keep up with the server's capabilities.
2770 * In RemoteFX mode we MUST do this but it might also be useful to
2771 * receive larger related bitmap updates.
2772 */
2773 if (multifragMaxRequestSize >
2774 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize))
2775 {
2776 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2777 multifragMaxRequestSize))
2778 return FALSE;
2779 }
2780 }
2781 return TRUE;
2782}
2783
2784/*
2785 * Read multifragment update capability set.
2786 * msdn{cc240649}
2787 */
2788
2789static BOOL rdp_read_multifragment_update_capability_set(wLog* log, wStream* s,
2790 rdpSettings* settings)
2791{
2792 WINPR_ASSERT(settings);
2793 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2794 return FALSE;
2795
2796 const UINT32 multifragMaxRequestSize = Stream_Get_UINT32(s); /* MaxRequestSize (4 bytes) */
2797 return freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2798 multifragMaxRequestSize);
2799}
2800
2801/*
2802 * Write multifragment update capability set.
2803 * msdn{cc240649}
2804 */
2805
2806static BOOL rdp_write_multifragment_update_capability_set(wLog* log, wStream* s,
2807 rdpSettings* settings)
2808{
2809 WINPR_ASSERT(settings);
2810 if (settings->ServerMode &&
2811 (freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize) == 0))
2812 {
2813 /*
2814 * In server mode we prefer to use the highest useful request size that
2815 * will allow us to pack a complete screen update into a single fast
2816 * path PDU using any of the supported codecs.
2817 * However, the client is completely free to accept our proposed
2818 * max request size or send a different value in the client-to-server
2819 * multi-fragment update capability set and we have to accept that,
2820 * unless we are using RemoteFX where the client MUST announce a value
2821 * greater than or equal to the value we're sending here.
2822 * See [MS-RDPRFX 1.5 capability #2]
2823 */
2824 const UINT32 tileNumX = (settings->DesktopWidth + 63) / 64;
2825 const UINT32 tileNumY = (settings->DesktopHeight + 63) / 64;
2826 const UINT32 limit = UINT32_MAX / 16384u;
2827
2828 if (tileNumX >= limit / tileNumY)
2829 {
2830 WLog_Print(log, WLOG_ERROR,
2831 "(DesktopWidth * DesktopHeigth) / 64 exceed limit of %" PRIu32, limit);
2832 return FALSE;
2833 }
2834 if (tileNumY >= limit / tileNumX)
2835 {
2836 WLog_Print(log, WLOG_ERROR,
2837 "(DesktopWidth * DesktopHeigth) / 64 exceed limit of %" PRIu32, limit);
2838 return FALSE;
2839 }
2840
2841 /* and add room for headers, regions, frame markers, etc. */
2842 const UINT32 MultifragMaxRequestSize = (tileNumX * tileNumY + 1u) * 16384u;
2843
2844 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2845 MultifragMaxRequestSize))
2846 return FALSE;
2847 }
2848
2849 if (!Stream_EnsureRemainingCapacity(s, 32))
2850 return FALSE;
2851 const size_t header = rdp_capability_set_start(log, s);
2852 Stream_Write_UINT32(s, settings->MultifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
2853 return rdp_capability_set_finish(s, header, CAPSET_TYPE_MULTI_FRAGMENT_UPDATE);
2854}
2855
2856#ifdef WITH_DEBUG_CAPABILITIES
2857static BOOL rdp_print_multifragment_update_capability_set(wLog* log, wStream* s)
2858{
2859 UINT32 maxRequestSize = 0;
2860 WLog_Print(log, WLOG_TRACE, "MultifragmentUpdateCapabilitySet (length %" PRIuz "):",
2861 Stream_GetRemainingLength(s));
2862
2863 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2864 return FALSE;
2865
2866 Stream_Read_UINT32(s, maxRequestSize); /* maxRequestSize (4 bytes) */
2867 WLog_Print(log, WLOG_TRACE, "\tmaxRequestSize: 0x%08" PRIX32 "", maxRequestSize);
2868 return TRUE;
2869}
2870#endif
2871
2872static BOOL rdp_apply_large_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
2873{
2874 WINPR_ASSERT(settings);
2875 WINPR_ASSERT(src);
2876
2877 settings->LargePointerFlag = src->LargePointerFlag;
2878 return TRUE;
2879}
2880
2881/*
2882 * Read large pointer capability set.
2883 * msdn{cc240650}
2884 */
2885
2886static BOOL rdp_read_large_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2887{
2888 UINT16 largePointerSupportFlags = 0;
2889
2890 WINPR_ASSERT(settings);
2891 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2892 return FALSE;
2893
2894 Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2895 settings->LargePointerFlag &= largePointerSupportFlags;
2896 if ((largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) != 0)
2897 {
2898 WLog_Print(
2899 log, WLOG_WARN,
2900 "TS_LARGE_POINTER_CAPABILITYSET with unsupported flags %04X (all flags %04X) received",
2901 WINPR_CXX_COMPAT_CAST(UINT32, largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 |
2902 LARGE_POINTER_FLAG_384x384)),
2903 largePointerSupportFlags);
2904 }
2905 return TRUE;
2906}
2907
2908/*
2909 * Write large pointer capability set.
2910 * msdn{cc240650}
2911 */
2912
2913static BOOL rdp_write_large_pointer_capability_set(wLog* log, wStream* s,
2914 const rdpSettings* settings)
2915{
2916 WINPR_ASSERT(settings);
2917 if (!Stream_EnsureRemainingCapacity(s, 32))
2918 return FALSE;
2919
2920 const size_t header = rdp_capability_set_start(log, s);
2921 const UINT16 largePointerSupportFlags =
2922 settings->LargePointerFlag & (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
2923 Stream_Write_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2924 return rdp_capability_set_finish(s, header, CAPSET_TYPE_LARGE_POINTER);
2925}
2926
2927#ifdef WITH_DEBUG_CAPABILITIES
2928static BOOL rdp_print_large_pointer_capability_set(wLog* log, wStream* s)
2929{
2930 UINT16 largePointerSupportFlags = 0;
2931 WLog_Print(log, WLOG_TRACE,
2932 "LargePointerCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2933
2934 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2935 return FALSE;
2936
2937 Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2938 WLog_Print(log, WLOG_TRACE, "\tlargePointerSupportFlags: 0x%04" PRIX16 "",
2939 largePointerSupportFlags);
2940 return TRUE;
2941}
2942#endif
2943
2944static BOOL rdp_apply_surface_commands_capability_set(rdpSettings* settings, const rdpSettings* src)
2945{
2946 WINPR_ASSERT(settings);
2947 WINPR_ASSERT(src);
2948
2949 /* [MS-RDPBCGR] 2.2.7.2.9 Surface Commands Capability Set (TS_SURFCMDS_CAPABILITYSET)
2950 *
2951 * disable surface commands if the remote does not support fastpath
2952 */
2953 if (src->FastPathOutput)
2954 {
2955 settings->SurfaceCommandsSupported &= src->SurfaceCommandsSupported;
2956 settings->SurfaceCommandsEnabled = src->SurfaceCommandsEnabled;
2957 settings->SurfaceFrameMarkerEnabled = src->SurfaceFrameMarkerEnabled;
2958 }
2959 else
2960 {
2961 settings->SurfaceCommandsSupported = 0;
2962 settings->SurfaceCommandsEnabled = FALSE;
2963 settings->SurfaceFrameMarkerEnabled = FALSE;
2964 }
2965
2966 return TRUE;
2967}
2968
2969/*
2970 * Read surface commands capability set.
2971 * msdn{dd871563}
2972 */
2973
2974static BOOL rdp_read_surface_commands_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2975{
2976 UINT32 cmdFlags = 0;
2977
2978 WINPR_ASSERT(settings);
2979 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2980 return FALSE;
2981
2982 Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
2983 Stream_Seek_UINT32(s); /* reserved (4 bytes) */
2984 settings->SurfaceCommandsSupported = cmdFlags;
2985 settings->SurfaceCommandsEnabled =
2986 (cmdFlags & (SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS)) != 0;
2987 settings->SurfaceFrameMarkerEnabled = (cmdFlags & SURFCMDS_FRAME_MARKER) != 0;
2988 return TRUE;
2989}
2990
2991/*
2992 * Write surface commands capability set.
2993 * msdn{dd871563}
2994 */
2995
2996static BOOL rdp_write_surface_commands_capability_set(wLog* log, wStream* s,
2997 const rdpSettings* settings)
2998{
2999 WINPR_ASSERT(settings);
3000 if (!Stream_EnsureRemainingCapacity(s, 32))
3001 return FALSE;
3002
3003 const size_t header = rdp_capability_set_start(log, s);
3004 // TODO: Make these configurable too
3005 UINT32 cmdFlags = freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
3006
3007 if (settings->SurfaceFrameMarkerEnabled)
3008 cmdFlags |= SURFCMDS_FRAME_MARKER;
3009
3010 Stream_Write_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3011 Stream_Write_UINT32(s, 0); /* reserved (4 bytes) */
3012 return rdp_capability_set_finish(s, header, CAPSET_TYPE_SURFACE_COMMANDS);
3013}
3014
3015static bool sUuidEqual(const UUID* Uuid1, const UUID* Uuid2)
3016{
3017 if (!Uuid1 && !Uuid2)
3018 return false;
3019
3020 if (Uuid1 && !Uuid2)
3021 return false;
3022
3023 if (!Uuid1 && Uuid2)
3024 return false;
3025
3026 if (Uuid1->Data1 != Uuid2->Data1)
3027 return false;
3028
3029 if (Uuid1->Data2 != Uuid2->Data2)
3030 return false;
3031
3032 if (Uuid1->Data3 != Uuid2->Data3)
3033 return false;
3034
3035 for (int index = 0; index < 8; index++)
3036 {
3037 if (Uuid1->Data4[index] != Uuid2->Data4[index])
3038 return false;
3039 }
3040
3041 return true;
3042}
3043
3044#ifdef WITH_DEBUG_CAPABILITIES
3045static BOOL rdp_print_surface_commands_capability_set(wLog* log, wStream* s)
3046{
3047 UINT32 cmdFlags = 0;
3048 UINT32 reserved = 0;
3049
3050 WLog_Print(log, WLOG_TRACE,
3051 "SurfaceCommandsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3052
3053 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
3054 return FALSE;
3055
3056 Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3057 Stream_Read_UINT32(s, reserved); /* reserved (4 bytes) */
3058 WLog_Print(log, WLOG_TRACE, "\tcmdFlags: 0x%08" PRIX32 "", cmdFlags);
3059 WLog_Print(log, WLOG_TRACE, "\treserved: 0x%08" PRIX32 "", reserved);
3060 return TRUE;
3061}
3062
3063static void rdp_print_bitmap_codec_guid(wLog* log, const GUID* guid)
3064{
3065 WINPR_ASSERT(guid);
3066 WLog_Print(log, WLOG_TRACE,
3067 "%08" PRIX32 "%04" PRIX16 "%04" PRIX16 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8
3068 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "",
3069 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
3070 guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6],
3071 guid->Data4[7]);
3072}
3073
3074static char* rdp_get_bitmap_codec_guid_name(const GUID* guid)
3075{
3076 WINPR_ASSERT(guid);
3077 if (sUuidEqual(guid, &CODEC_GUID_REMOTEFX))
3078 return "CODEC_GUID_REMOTEFX";
3079 else if (sUuidEqual(guid, &CODEC_GUID_NSCODEC))
3080 return "CODEC_GUID_NSCODEC";
3081 else if (sUuidEqual(guid, &CODEC_GUID_IGNORE))
3082 return "CODEC_GUID_IGNORE";
3083 else if (sUuidEqual(guid, &CODEC_GUID_IMAGE_REMOTEFX))
3084 return "CODEC_GUID_IMAGE_REMOTEFX";
3085
3086#if defined(WITH_JPEG)
3087 else if (sUuidEqual(guid, &CODEC_GUID_JPEG))
3088 return "CODEC_GUID_JPEG";
3089
3090#endif
3091 return "CODEC_GUID_UNKNOWN";
3092}
3093#endif
3094
3095static BOOL rdp_read_bitmap_codec_guid(wLog* log, wStream* s, GUID* guid)
3096{
3097 BYTE g[16] = WINPR_C_ARRAY_INIT;
3098
3099 WINPR_ASSERT(guid);
3100 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16))
3101 return FALSE;
3102 Stream_Read(s, g, 16);
3103 guid->Data1 = ((UINT32)g[3] << 24U) | ((UINT32)g[2] << 16U) | (UINT32)(g[1] << 8U) | g[0];
3104 guid->Data2 = ((g[5] << 8U) | g[4]) & 0xFFFF;
3105 guid->Data3 = ((g[7] << 8U) | g[6]) & 0xFFFF;
3106 guid->Data4[0] = g[8];
3107 guid->Data4[1] = g[9];
3108 guid->Data4[2] = g[10];
3109 guid->Data4[3] = g[11];
3110 guid->Data4[4] = g[12];
3111 guid->Data4[5] = g[13];
3112 guid->Data4[6] = g[14];
3113 guid->Data4[7] = g[15];
3114 return TRUE;
3115}
3116
3117static void rdp_write_bitmap_codec_guid(wStream* s, const GUID* guid)
3118{
3119 BYTE g[16] = WINPR_C_ARRAY_INIT;
3120 WINPR_ASSERT(guid);
3121 g[0] = guid->Data1 & 0xFF;
3122 g[1] = (guid->Data1 >> 8) & 0xFF;
3123 g[2] = (guid->Data1 >> 16) & 0xFF;
3124 g[3] = (guid->Data1 >> 24) & 0xFF;
3125 g[4] = (guid->Data2) & 0xFF;
3126 g[5] = (guid->Data2 >> 8) & 0xFF;
3127 g[6] = (guid->Data3) & 0xFF;
3128 g[7] = (guid->Data3 >> 8) & 0xFF;
3129 g[8] = guid->Data4[0];
3130 g[9] = guid->Data4[1];
3131 g[10] = guid->Data4[2];
3132 g[11] = guid->Data4[3];
3133 g[12] = guid->Data4[4];
3134 g[13] = guid->Data4[5];
3135 g[14] = guid->Data4[6];
3136 g[15] = guid->Data4[7];
3137 Stream_Write(s, g, 16);
3138}
3139
3140static BOOL rdp_apply_bitmap_codecs_capability_set(rdpSettings* settings, const rdpSettings* src)
3141{
3142 WINPR_ASSERT(settings);
3143 WINPR_ASSERT(src);
3144
3145 if (settings->ServerMode)
3146 {
3147
3148 settings->RemoteFxCodecId = src->RemoteFxCodecId;
3149 settings->RemoteFxCaptureFlags = src->RemoteFxCaptureFlags;
3150 settings->RemoteFxOnly = src->RemoteFxOnly;
3151 settings->RemoteFxRlgrMode = src->RemoteFxRlgrMode;
3152 settings->RemoteFxCodecMode = src->RemoteFxCodecMode;
3153 settings->NSCodecId = src->NSCodecId;
3154 settings->NSCodecAllowDynamicColorFidelity = src->NSCodecAllowDynamicColorFidelity;
3155 settings->NSCodecAllowSubsampling = src->NSCodecAllowSubsampling;
3156 settings->NSCodecColorLossLevel = src->NSCodecColorLossLevel;
3157
3158 /* only enable a codec if we've announced/enabled it before */
3159 settings->RemoteFxCodec = settings->RemoteFxCodec && src->RemoteFxCodecId;
3160 settings->RemoteFxImageCodec = settings->RemoteFxImageCodec && src->RemoteFxImageCodec;
3161 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec,
3162 settings->NSCodec && src->NSCodec))
3163 return FALSE;
3164 settings->JpegCodec = src->JpegCodec;
3165 }
3166 return TRUE;
3167}
3168
3169static BOOL rdp_read_codec_ts_rfx_icap(wLog* log, wStream* sub, rdpSettings* settings,
3170 UINT16 icapLen)
3171{
3172 UINT16 version = 0;
3173 UINT16 tileSize = 0;
3174 BYTE codecFlags = 0;
3175 BYTE colConvBits = 0;
3176 BYTE transformBits = 0;
3177 BYTE entropyBits = 0;
3178 /* TS_RFX_ICAP */
3179 if (icapLen != 8)
3180 {
3181 WLog_Print(log, WLOG_ERROR,
3182 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP size %" PRIu16
3183 " unsupported, expecting size %" PRIu16 " not supported",
3184 icapLen, 8u);
3185 return FALSE;
3186 }
3187
3188 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3189 return FALSE;
3190
3191 Stream_Read_UINT16(sub, version); /* version (2 bytes) */
3192 Stream_Read_UINT16(sub, tileSize); /* tileSize (2 bytes) */
3193 Stream_Read_UINT8(sub, codecFlags); /* flags (1 byte) */
3194 Stream_Read_UINT8(sub, colConvBits); /* colConvBits (1 byte) */
3195 Stream_Read_UINT8(sub, transformBits); /* transformBits (1 byte) */
3196 Stream_Read_UINT8(sub, entropyBits); /* entropyBits (1 byte) */
3197
3198 if (version == 0x0009)
3199 {
3200 /* Version 0.9 */
3201 if (tileSize != 0x0080)
3202 {
3203 WLog_Print(log, WLOG_ERROR,
3204 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3205 " tile size %" PRIu16 " not supported",
3206 version, tileSize);
3207 return FALSE;
3208 }
3209 }
3210 else if (version == 0x0100)
3211 {
3212 /* Version 1.0 */
3213 if (tileSize != 0x0040)
3214 {
3215 WLog_Print(log, WLOG_ERROR,
3216 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3217 " tile size %" PRIu16 " not supported",
3218 version, tileSize);
3219 return FALSE;
3220 }
3221 }
3222 else
3223 {
3224 WLog_Print(log, WLOG_ERROR,
3225 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16 " not supported",
3226 version);
3227 return FALSE;
3228 }
3229
3230 /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_COL_CONV_ICT (0x1) */
3231 if (colConvBits != 1)
3232 {
3233 WLog_Print(log, WLOG_ERROR,
3234 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::colConvBits %" PRIu8
3235 " not supported, must be CLW_COL_CONV_ICT (0x1)",
3236 colConvBits);
3237 return FALSE;
3238 }
3239
3240 /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_XFORM_DWT_53_A (0x1) */
3241 if (transformBits != 1)
3242 {
3243 WLog_Print(log, WLOG_ERROR,
3244 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::transformBits %" PRIu8
3245 " not supported, must be CLW_XFORM_DWT_53_A (0x1)",
3246 colConvBits);
3247 return FALSE;
3248 }
3249
3250 const UINT8 CODEC_MODE = 0x02; /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP */
3251 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x00))
3252 return FALSE;
3253
3254 if ((codecFlags & CODEC_MODE) != 0)
3255 {
3256 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x02))
3257 return FALSE;
3258 }
3259 else if ((codecFlags & ~CODEC_MODE) != 0)
3260 WLog_Print(log, WLOG_WARN,
3261 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::flags unknown value "
3262 "0x%02" PRIx32,
3263 WINPR_CXX_COMPAT_CAST(UINT32, (codecFlags & ~CODEC_MODE)));
3264
3265 switch (entropyBits)
3266 {
3267 case CLW_ENTROPY_RLGR1:
3268 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR1))
3269 return FALSE;
3270 break;
3271 case CLW_ENTROPY_RLGR3:
3272 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3))
3273 return FALSE;
3274 break;
3275 default:
3276 WLog_Print(log, WLOG_ERROR,
3277 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::entropyBits "
3278 "unsupported value 0x%02" PRIx8
3279 ", must be CLW_ENTROPY_RLGR1 (0x01) or CLW_ENTROPY_RLGR3 "
3280 "(0x04)",
3281 entropyBits);
3282 return FALSE;
3283 }
3284 return TRUE;
3285}
3286
3287static BOOL rdp_read_codec_ts_rfx_capset(wLog* log, wStream* s, rdpSettings* settings)
3288{
3289 UINT16 blockType = 0;
3290 UINT32 blockLen = 0;
3291 BYTE rfxCodecId = 0;
3292 UINT16 capsetType = 0;
3293 UINT16 numIcaps = 0;
3294 UINT16 icapLen = 0;
3295
3296 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
3297 return FALSE;
3298
3299 /* TS_RFX_CAPSET */
3300 Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
3301 Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */
3302 if (blockType != 0xCBC1)
3303 {
3304 WLog_Print(log, WLOG_ERROR,
3305 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockType[0x%04" PRIx16
3306 "] != CBY_CAPSET (0xCBC1)",
3307 blockType);
3308 return FALSE;
3309 }
3310 if (blockLen < 6ull)
3311 {
3312 WLog_Print(log, WLOG_ERROR,
3313 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockLen[%" PRIu32 "] < 6", blockLen);
3314 return FALSE;
3315 }
3316 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, blockLen - 6ull))
3317 return FALSE;
3318
3319 wStream sbuffer = WINPR_C_ARRAY_INIT;
3320 wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), blockLen - 6ull);
3321 WINPR_ASSERT(sub);
3322
3323 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 7))
3324 return FALSE;
3325
3326 Stream_Read_UINT8(sub, rfxCodecId); /* codecId (1 byte) */
3327 Stream_Read_UINT16(sub, capsetType); /* capsetType (2 bytes) */
3328 Stream_Read_UINT16(sub, numIcaps); /* numIcaps (2 bytes) */
3329 Stream_Read_UINT16(sub, icapLen); /* icapLen (2 bytes) */
3330
3331 if (rfxCodecId != 1)
3332 {
3333 WLog_Print(log, WLOG_ERROR,
3334 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::codecId[%" PRIu16 "] != 1", rfxCodecId);
3335 return FALSE;
3336 }
3337
3338 if (capsetType != 0xCFC0)
3339 {
3340 WLog_Print(log, WLOG_ERROR,
3341 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::capsetType[0x%04" PRIx16
3342 "] != CLY_CAPSET (0xCFC0)",
3343 capsetType);
3344 return FALSE;
3345 }
3346
3347 while (numIcaps--)
3348 {
3349 if (!rdp_read_codec_ts_rfx_icap(log, sub, settings, icapLen))
3350 return FALSE;
3351 }
3352 return TRUE;
3353}
3354
3355static BOOL rdp_read_codec_ts_rfx_caps(wLog* log, wStream* sub, rdpSettings* settings)
3356{
3357 if (Stream_GetRemainingLength(sub) == 0)
3358 return TRUE;
3359
3360 UINT16 blockType = 0;
3361 UINT32 blockLen = 0;
3362 UINT16 numCapsets = 0;
3363
3364 /* TS_RFX_CAPS */
3365 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3366 return FALSE;
3367 Stream_Read_UINT16(sub, blockType); /* blockType (2 bytes) */
3368 Stream_Read_UINT32(sub, blockLen); /* blockLen (4 bytes) */
3369 Stream_Read_UINT16(sub, numCapsets); /* numCapsets (2 bytes) */
3370
3371 if (blockType != 0xCBC0)
3372 {
3373 WLog_Print(log, WLOG_ERROR,
3374 "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockType[0x%04" PRIx16
3375 "] != CBY_CAPS (0xCBC0)",
3376 blockType);
3377 return FALSE;
3378 }
3379
3380 if (blockLen != 8)
3381 {
3382 WLog_Print(log, WLOG_ERROR, "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockLen[%" PRIu16 "] != 8",
3383 blockLen);
3384 return FALSE;
3385 }
3386
3387 if (numCapsets != 1)
3388 {
3389 WLog_Print(log, WLOG_ERROR,
3390 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::numIcaps[%" PRIu16 "] != 1", numCapsets);
3391 return FALSE;
3392 }
3393
3394 for (UINT16 x = 0; x < numCapsets; x++)
3395 {
3396 if (!rdp_read_codec_ts_rfx_capset(log, sub, settings))
3397 return FALSE;
3398 }
3399
3400 return TRUE;
3401}
3402
3403static BOOL rdp_read_codec_ts_rfx_clnt_caps_container(wLog* log, wStream* s, rdpSettings* settings)
3404{
3405 UINT32 rfxCapsLength = 0;
3406 UINT32 rfxPropsLength = 0;
3407 UINT32 captureFlags = 0;
3408
3409 /* [MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER */
3410 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3411 return FALSE;
3412 Stream_Read_UINT32(s, rfxPropsLength); /* length (4 bytes) */
3413 if (rfxPropsLength < 4)
3414 {
3415 WLog_Print(log, WLOG_ERROR,
3416 "[MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER::length %" PRIu32
3417 " too short, require at least 4 bytes",
3418 rfxPropsLength);
3419 return FALSE;
3420 }
3421 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, rfxPropsLength - 4ull))
3422 return FALSE;
3423
3424 wStream sbuffer = WINPR_C_ARRAY_INIT;
3425 wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), rfxPropsLength - 4ull);
3426 WINPR_ASSERT(sub);
3427
3428 Stream_Seek(s, rfxPropsLength - 4ull);
3429
3430 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3431 return FALSE;
3432
3433 Stream_Read_UINT32(sub, captureFlags); /* captureFlags (4 bytes) */
3434 Stream_Read_UINT32(sub, rfxCapsLength); /* capsLength (4 bytes) */
3435 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, rfxCapsLength))
3436 return FALSE;
3437
3438 settings->RemoteFxCaptureFlags = captureFlags;
3439 settings->RemoteFxOnly = !(captureFlags & CARDP_CAPS_CAPTURE_NON_CAC);
3440
3441 /* [MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS */
3442 wStream tsbuffer = WINPR_C_ARRAY_INIT;
3443 wStream* ts_sub = Stream_StaticConstInit(&tsbuffer, Stream_Pointer(sub), rfxCapsLength);
3444 WINPR_ASSERT(ts_sub);
3445 return rdp_read_codec_ts_rfx_caps(log, ts_sub, settings);
3446}
3447
3448/*
3449 * Read bitmap codecs capability set.
3450 * msdn{dd891377}
3451 */
3452
3453static BOOL rdp_read_bitmap_codecs_capability_set(wLog* log, wStream* s, rdpSettings* settings,
3454 BOOL isServer)
3455{
3456 BYTE codecId = 0;
3457 GUID codecGuid = WINPR_C_ARRAY_INIT;
3458 BYTE bitmapCodecCount = 0;
3459 UINT16 codecPropertiesLength = 0;
3460
3461 BOOL guidNSCodec = FALSE;
3462 BOOL guidRemoteFx = FALSE;
3463 BOOL guidRemoteFxImage = FALSE;
3464
3465 WINPR_ASSERT(settings);
3466 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3467 return FALSE;
3468
3469 Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3470
3471 while (bitmapCodecCount > 0)
3472 {
3473 wStream subbuffer = WINPR_C_ARRAY_INIT;
3474
3475 if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3476 return FALSE;
3477 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3478 return FALSE;
3479 Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3480 Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3481
3482 wStream* sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), codecPropertiesLength);
3483 if (!Stream_SafeSeek(s, codecPropertiesLength))
3484 return FALSE;
3485
3486 if (isServer)
3487 {
3488 if (sUuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX))
3489 {
3490 guidRemoteFx = TRUE;
3491 settings->RemoteFxCodecId = codecId;
3492 if (!rdp_read_codec_ts_rfx_clnt_caps_container(log, sub, settings))
3493 return FALSE;
3494 }
3495 else if (sUuidEqual(&codecGuid, &CODEC_GUID_IMAGE_REMOTEFX))
3496 {
3497 /* Microsoft RDP servers ignore CODEC_GUID_IMAGE_REMOTEFX codec properties */
3498 guidRemoteFxImage = TRUE;
3499 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3500 return FALSE;
3501 }
3502 else if (sUuidEqual(&codecGuid, &CODEC_GUID_NSCODEC))
3503 {
3504 BYTE colorLossLevel = 0;
3505 BYTE fAllowSubsampling = 0;
3506 BYTE fAllowDynamicFidelity = 0;
3507 guidNSCodec = TRUE;
3508 settings->NSCodecId = codecId;
3509 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 3))
3510 return FALSE;
3511 Stream_Read_UINT8(sub, fAllowDynamicFidelity); /* fAllowDynamicFidelity (1 byte) */
3512 Stream_Read_UINT8(sub, fAllowSubsampling); /* fAllowSubsampling (1 byte) */
3513 Stream_Read_UINT8(sub, colorLossLevel); /* colorLossLevel (1 byte) */
3514
3515 if (colorLossLevel < 1)
3516 colorLossLevel = 1;
3517
3518 if (colorLossLevel > 7)
3519 colorLossLevel = 7;
3520
3521 settings->NSCodecAllowDynamicColorFidelity = fAllowDynamicFidelity;
3522 settings->NSCodecAllowSubsampling = fAllowSubsampling;
3523 settings->NSCodecColorLossLevel = colorLossLevel;
3524 }
3525 else if (sUuidEqual(&codecGuid, &CODEC_GUID_IGNORE))
3526 {
3527 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3528 return FALSE;
3529 }
3530 else
3531 {
3532 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3533 return FALSE;
3534 }
3535 }
3536 else
3537 {
3538 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3539 return FALSE;
3540 }
3541
3542 const size_t rest = Stream_GetRemainingLength(sub);
3543 if (rest > 0)
3544 {
3545 WLog_Print(log, WLOG_ERROR,
3546 "error while reading codec properties: actual size: %" PRIuz
3547 " expected size: %" PRIu32 "",
3548 rest + codecPropertiesLength, codecPropertiesLength);
3549 }
3550 bitmapCodecCount--;
3551
3552 /* only enable a codec if we've announced/enabled it before */
3553 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, guidRemoteFx))
3554 return FALSE;
3555 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, guidRemoteFxImage))
3556 return FALSE;
3557 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, guidNSCodec))
3558 return FALSE;
3559 if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
3560 return FALSE;
3561 }
3562
3563 return TRUE;
3564}
3565
3566/*
3567 * Write RemoteFX Client Capability Container.
3568 */
3569static BOOL rdp_write_rfx_client_capability_container(wStream* s, const rdpSettings* settings)
3570{
3571 WINPR_ASSERT(settings);
3572 if (!Stream_EnsureRemainingCapacity(s, 64))
3573 return FALSE;
3574
3575 const UINT32 captureFlags = settings->RemoteFxOnly ? 0 : CARDP_CAPS_CAPTURE_NON_CAC;
3576
3577 WINPR_ASSERT(settings->RemoteFxCodecMode <= UINT8_MAX);
3578 const UINT8 codecMode = (UINT8)settings->RemoteFxCodecMode;
3579 Stream_Write_UINT16(s, 49); /* codecPropertiesLength */
3580 /* TS_RFX_CLNT_CAPS_CONTAINER */
3581 Stream_Write_UINT32(s, 49); /* length */
3582 Stream_Write_UINT32(s, captureFlags); /* captureFlags */
3583 Stream_Write_UINT32(s, 37); /* capsLength */
3584 /* TS_RFX_CAPS */
3585 Stream_Write_UINT16(s, CBY_CAPS); /* blockType */
3586 Stream_Write_UINT32(s, 8); /* blockLen */
3587 Stream_Write_UINT16(s, 1); /* numCapsets */
3588 /* TS_RFX_CAPSET */
3589 Stream_Write_UINT16(s, CBY_CAPSET); /* blockType */
3590 Stream_Write_UINT32(s, 29); /* blockLen */
3591 Stream_Write_UINT8(s, 0x01); /* codecId (MUST be set to 0x01) */
3592 Stream_Write_UINT16(s, CLY_CAPSET); /* capsetType */
3593 Stream_Write_UINT16(s, 2); /* numIcaps */
3594 Stream_Write_UINT16(s, 8); /* icapLen */
3595 /* TS_RFX_ICAP (RLGR1) */
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_RLGR1); /* entropyBits */
3602 /* TS_RFX_ICAP (RLGR3) */
3603 Stream_Write_UINT16(s, CLW_VERSION_1_0); /* version */
3604 Stream_Write_UINT16(s, CT_TILE_64x64); /* tileSize */
3605 Stream_Write_UINT8(s, codecMode); /* flags */
3606 Stream_Write_UINT8(s, CLW_COL_CONV_ICT); /* colConvBits */
3607 Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3608 Stream_Write_UINT8(s, CLW_ENTROPY_RLGR3); /* entropyBits */
3609 return TRUE;
3610}
3611
3612/*
3613 * Write NSCODEC Client Capability Container.
3614 */
3615static BOOL rdp_write_nsc_client_capability_container(wStream* s, const rdpSettings* settings)
3616{
3617 WINPR_ASSERT(settings);
3618
3619 const BOOL fAllowDynamicFidelity = settings->NSCodecAllowDynamicColorFidelity;
3620 const BOOL fAllowSubsampling = settings->NSCodecAllowSubsampling;
3621 UINT32 colorLossLevel = settings->NSCodecColorLossLevel;
3622
3623 if (colorLossLevel < 1)
3624 colorLossLevel = 1;
3625
3626 if (colorLossLevel > 7)
3627 colorLossLevel = 7;
3628
3629 if (!Stream_EnsureRemainingCapacity(s, 8))
3630 return FALSE;
3631
3632 Stream_Write_UINT16(s, 3); /* codecPropertiesLength */
3633 /* TS_NSCODEC_CAPABILITYSET */
3634 Stream_Write_UINT8(s, fAllowDynamicFidelity != 0); /* fAllowDynamicFidelity (1 byte) */
3635 Stream_Write_UINT8(s, fAllowSubsampling != 0); /* fAllowSubsampling (1 byte) */
3636 Stream_Write_UINT8(s, (UINT8)colorLossLevel); /* colorLossLevel (1 byte) */
3637 return TRUE;
3638}
3639
3640#if defined(WITH_JPEG)
3641static BOOL rdp_write_jpeg_client_capability_container(wStream* s, const rdpSettings* settings)
3642{
3643 WINPR_ASSERT(settings);
3644 if (!Stream_EnsureRemainingCapacity(s, 8))
3645 return FALSE;
3646
3647 Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3648
3649 const UINT32 q = freerdp_settings_get_uint32(settings, FreeRDP_JpegQuality);
3650 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, q));
3651 return TRUE;
3652}
3653#endif
3654
3655/*
3656 * Write RemoteFX Server Capability Container.
3657 */
3658static BOOL rdp_write_rfx_server_capability_container(wStream* s, const rdpSettings* settings)
3659{
3660 WINPR_UNUSED(settings);
3661 WINPR_ASSERT(settings);
3662
3663 if (!Stream_EnsureRemainingCapacity(s, 8))
3664 return FALSE;
3665
3666 Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3667 Stream_Write_UINT32(s, 0); /* reserved */
3668 return TRUE;
3669}
3670
3671#if defined(WITH_JPEG)
3672static BOOL rdp_write_jpeg_server_capability_container(wStream* s, const rdpSettings* settings)
3673{
3674 WINPR_UNUSED(settings);
3675 WINPR_ASSERT(settings);
3676
3677 if (!Stream_EnsureRemainingCapacity(s, 8))
3678 return FALSE;
3679
3680 Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3681 Stream_Write_UINT8(s, 75);
3682 return TRUE;
3683}
3684#endif
3685
3686/*
3687 * Write NSCODEC Server Capability Container.
3688 */
3689static BOOL rdp_write_nsc_server_capability_container(wStream* s, const rdpSettings* settings)
3690{
3691 WINPR_UNUSED(settings);
3692 WINPR_ASSERT(settings);
3693
3694 if (!Stream_EnsureRemainingCapacity(s, 8))
3695 return FALSE;
3696
3697 Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3698 Stream_Write_UINT32(s, 0); /* reserved */
3699 return TRUE;
3700}
3701
3702/*
3703 * Write bitmap codecs capability set.
3704 * msdn{dd891377}
3705 */
3706
3707static BOOL rdp_write_bitmap_codecs_capability_set(wLog* log, wStream* s,
3708 const rdpSettings* settings)
3709{
3710 WINPR_ASSERT(settings);
3711 if (!Stream_EnsureRemainingCapacity(s, 64))
3712 return FALSE;
3713
3714 const size_t header = rdp_capability_set_start(log, s);
3715 BYTE bitmapCodecCount = 0;
3716
3717 if (settings->RemoteFxCodec)
3718 bitmapCodecCount++;
3719
3720 if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3721 bitmapCodecCount++;
3722
3723#if defined(WITH_JPEG)
3724
3725 if (settings->JpegCodec)
3726 bitmapCodecCount++;
3727
3728#endif
3729
3730 if (settings->RemoteFxImageCodec)
3731 bitmapCodecCount++;
3732
3733 Stream_Write_UINT8(s, bitmapCodecCount);
3734
3735 if (settings->RemoteFxCodec)
3736 {
3737 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_REMOTEFX); /* codecGUID */
3738
3739 if (settings->ServerMode)
3740 {
3741 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3742
3743 if (!rdp_write_rfx_server_capability_container(s, settings))
3744 return FALSE;
3745 }
3746 else
3747 {
3748 Stream_Write_UINT8(s, RDP_CODEC_ID_REMOTEFX); /* codecID */
3749
3750 if (!rdp_write_rfx_client_capability_container(s, settings))
3751 return FALSE;
3752 }
3753 }
3754
3755 if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3756 {
3757 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_NSCODEC); /* codecGUID */
3758
3759 if (settings->ServerMode)
3760 {
3761 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3762
3763 if (!rdp_write_nsc_server_capability_container(s, settings))
3764 return FALSE;
3765 }
3766 else
3767 {
3768 Stream_Write_UINT8(s, RDP_CODEC_ID_NSCODEC); /* codecID */
3769
3770 if (!rdp_write_nsc_client_capability_container(s, settings))
3771 return FALSE;
3772 }
3773 }
3774
3775#if defined(WITH_JPEG)
3776
3777 if (settings->JpegCodec)
3778 {
3779 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_JPEG); /* codecGUID */
3780
3781 if (settings->ServerMode)
3782 {
3783 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3784
3785 if (!rdp_write_jpeg_server_capability_container(s, settings))
3786 return FALSE;
3787 }
3788 else
3789 {
3790 Stream_Write_UINT8(s, RDP_CODEC_ID_JPEG); /* codecID */
3791
3792 if (!rdp_write_jpeg_client_capability_container(s, settings))
3793 return FALSE;
3794 }
3795 }
3796
3797#endif
3798
3799 if (settings->RemoteFxImageCodec)
3800 {
3801 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_IMAGE_REMOTEFX); /* codecGUID */
3802
3803 if (settings->ServerMode)
3804 {
3805 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3806
3807 if (!rdp_write_rfx_server_capability_container(s, settings))
3808 return FALSE;
3809 }
3810 else
3811 {
3812 Stream_Write_UINT8(s, RDP_CODEC_ID_IMAGE_REMOTEFX); /* codecID */
3813
3814 if (!rdp_write_rfx_client_capability_container(s, settings))
3815 return FALSE;
3816 }
3817 }
3818
3819 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CODECS);
3820}
3821
3822#ifdef WITH_DEBUG_CAPABILITIES
3823static BOOL rdp_print_bitmap_codecs_capability_set(wLog* log, wStream* s)
3824{
3825 GUID codecGuid = WINPR_C_ARRAY_INIT;
3826 BYTE bitmapCodecCount = 0;
3827 BYTE codecId = 0;
3828 UINT16 codecPropertiesLength = 0;
3829
3830 WLog_Print(log, WLOG_TRACE,
3831 "BitmapCodecsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3832
3833 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3834 return FALSE;
3835
3836 Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3837 WLog_Print(log, WLOG_TRACE, "\tbitmapCodecCount: %" PRIu8 "", bitmapCodecCount);
3838
3839 while (bitmapCodecCount > 0)
3840 {
3841 if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3842 return FALSE;
3843 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3844 return FALSE;
3845 Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3846 WLog_Print(log, WLOG_TRACE, "\tcodecGuid: 0x");
3847 rdp_print_bitmap_codec_guid(log, &codecGuid);
3848 WLog_Print(log, WLOG_TRACE, " (%s)", rdp_get_bitmap_codec_guid_name(&codecGuid));
3849 WLog_Print(log, WLOG_TRACE, "\tcodecId: %" PRIu8 "", codecId);
3850 Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3851 WLog_Print(log, WLOG_TRACE, "\tcodecPropertiesLength: %" PRIu16 "", codecPropertiesLength);
3852
3853 if (!Stream_SafeSeek(s, codecPropertiesLength)) /* codecProperties */
3854 return FALSE;
3855 bitmapCodecCount--;
3856 }
3857
3858 return TRUE;
3859}
3860#endif
3861
3862static BOOL rdp_apply_frame_acknowledge_capability_set(rdpSettings* settings,
3863 const rdpSettings* src)
3864{
3865 WINPR_ASSERT(settings);
3866 WINPR_ASSERT(src);
3867
3868 if (settings->ServerMode)
3869 settings->FrameAcknowledge = src->FrameAcknowledge;
3870
3871 return TRUE;
3872}
3873
3874/*
3875 * Read frame acknowledge capability set.
3876 */
3877
3878static BOOL rdp_read_frame_acknowledge_capability_set(wLog* log, wStream* s, rdpSettings* settings)
3879{
3880 WINPR_ASSERT(settings);
3881 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3882 return FALSE;
3883
3884 Stream_Read_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3885
3886 return TRUE;
3887}
3888
3889/*
3890 * Write frame acknowledge capability set.
3891 */
3892
3893static BOOL rdp_write_frame_acknowledge_capability_set(wLog* log, wStream* s,
3894 const rdpSettings* settings)
3895{
3896 WINPR_ASSERT(settings);
3897 if (!Stream_EnsureRemainingCapacity(s, 32))
3898 return FALSE;
3899
3900 const size_t header = rdp_capability_set_start(log, s);
3901 Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3902 return rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE);
3903}
3904
3905#ifdef WITH_DEBUG_CAPABILITIES
3906static BOOL rdp_print_frame_acknowledge_capability_set(wLog* log, wStream* s)
3907{
3908 UINT32 frameAcknowledge = 0;
3909 WLog_Print(log, WLOG_TRACE,
3910 "FrameAcknowledgeCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3911
3912 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3913 return FALSE;
3914
3915 Stream_Read_UINT32(s, frameAcknowledge); /* frameAcknowledge (4 bytes) */
3916 WLog_Print(log, WLOG_TRACE, "\tframeAcknowledge: 0x%08" PRIX32 "", frameAcknowledge);
3917 return TRUE;
3918}
3919#endif
3920
3921static BOOL rdp_apply_bitmap_cache_v3_codec_id_capability_set(rdpSettings* settings,
3922 const rdpSettings* src)
3923{
3924 WINPR_ASSERT(settings);
3925 WINPR_ASSERT(src);
3926
3927 settings->BitmapCacheV3CodecId = src->BitmapCacheV3CodecId;
3928 return TRUE;
3929}
3930
3931static BOOL rdp_read_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3932 rdpSettings* settings)
3933{
3934 BYTE bitmapCacheV3CodecId = 0;
3935
3936 WINPR_ASSERT(settings);
3937 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3938 return FALSE;
3939
3940 Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3941 settings->BitmapCacheV3CodecId = bitmapCacheV3CodecId;
3942 return TRUE;
3943}
3944
3945static BOOL rdp_write_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
3946 const rdpSettings* settings)
3947{
3948 WINPR_ASSERT(settings);
3949 if (!Stream_EnsureRemainingCapacity(s, 32))
3950 return FALSE;
3951
3952 const size_t header = rdp_capability_set_start(log, s);
3953 if (settings->BitmapCacheV3CodecId > UINT8_MAX)
3954 return FALSE;
3955 Stream_Write_UINT8(s, (UINT8)settings->BitmapCacheV3CodecId);
3956 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID);
3957}
3958
3959#ifdef WITH_DEBUG_CAPABILITIES
3960static BOOL rdp_print_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s)
3961{
3962 BYTE bitmapCacheV3CodecId = 0;
3963 WLog_Print(log, WLOG_TRACE, "BitmapCacheV3CodecIdCapabilitySet (length %" PRIuz "):",
3964 Stream_GetRemainingLength(s));
3965
3966 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3967 return FALSE;
3968
3969 Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
3970 WLog_Print(log, WLOG_TRACE, "\tbitmapCacheV3CodecId: 0x%02" PRIX8 "", bitmapCacheV3CodecId);
3971 return TRUE;
3972}
3973
3974BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving)
3975{
3976 BOOL rc = FALSE;
3977 UINT16 type = 0;
3978 UINT16 length = 0;
3979 UINT16 numberCapabilities = 0;
3980
3981 size_t pos = Stream_GetPosition(s);
3982
3983 if (!Stream_SetPosition(s, start))
3984 goto fail;
3985
3986 if (receiving)
3987 {
3988 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3989 goto fail;
3990 }
3991 else
3992 {
3993 if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), 4))
3994 goto fail;
3995 }
3996
3997 Stream_Read_UINT16(s, numberCapabilities);
3998 Stream_Seek(s, 2);
3999
4000 while (numberCapabilities > 0)
4001 {
4002 size_t rest = 0;
4003 wStream subBuffer;
4004 wStream* sub = nullptr;
4005
4006 if (!rdp_read_capability_set_header(log, s, &length, &type))
4007 goto fail;
4008
4009 WLog_Print(log, WLOG_TRACE, "%s ", receiving ? "Receiving" : "Sending");
4010 sub = Stream_StaticInit(&subBuffer, Stream_Pointer(s), length - 4);
4011 if (!Stream_SafeSeek(s, length - 4))
4012 goto fail;
4013
4014 switch (type)
4015 {
4016 case CAPSET_TYPE_GENERAL:
4017 if (!rdp_print_general_capability_set(log, sub))
4018 goto fail;
4019
4020 break;
4021
4022 case CAPSET_TYPE_BITMAP:
4023 if (!rdp_print_bitmap_capability_set(log, sub))
4024 goto fail;
4025
4026 break;
4027
4028 case CAPSET_TYPE_ORDER:
4029 if (!rdp_print_order_capability_set(log, sub))
4030 goto fail;
4031
4032 break;
4033
4034 case CAPSET_TYPE_BITMAP_CACHE:
4035 if (!rdp_print_bitmap_cache_capability_set(log, sub))
4036 goto fail;
4037
4038 break;
4039
4040 case CAPSET_TYPE_CONTROL:
4041 if (!rdp_print_control_capability_set(log, sub))
4042 goto fail;
4043
4044 break;
4045
4046 case CAPSET_TYPE_ACTIVATION:
4047 if (!rdp_print_window_activation_capability_set(log, sub))
4048 goto fail;
4049
4050 break;
4051
4052 case CAPSET_TYPE_POINTER:
4053 if (!rdp_print_pointer_capability_set(log, sub))
4054 goto fail;
4055
4056 break;
4057
4058 case CAPSET_TYPE_SHARE:
4059 if (!rdp_print_share_capability_set(log, sub))
4060 goto fail;
4061
4062 break;
4063
4064 case CAPSET_TYPE_COLOR_CACHE:
4065 if (!rdp_print_color_cache_capability_set(log, sub))
4066 goto fail;
4067
4068 break;
4069
4070 case CAPSET_TYPE_SOUND:
4071 if (!rdp_print_sound_capability_set(log, sub))
4072 goto fail;
4073
4074 break;
4075
4076 case CAPSET_TYPE_INPUT:
4077 if (!rdp_print_input_capability_set(log, sub))
4078 goto fail;
4079
4080 break;
4081
4082 case CAPSET_TYPE_FONT:
4083 if (!rdp_print_font_capability_set(log, sub))
4084 goto fail;
4085
4086 break;
4087
4088 case CAPSET_TYPE_BRUSH:
4089 if (!rdp_print_brush_capability_set(log, sub))
4090 goto fail;
4091
4092 break;
4093
4094 case CAPSET_TYPE_GLYPH_CACHE:
4095 if (!rdp_print_glyph_cache_capability_set(log, sub))
4096 goto fail;
4097
4098 break;
4099
4100 case CAPSET_TYPE_OFFSCREEN_CACHE:
4101 if (!rdp_print_offscreen_bitmap_cache_capability_set(log, sub))
4102 goto fail;
4103
4104 break;
4105
4106 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4107 if (!rdp_print_bitmap_cache_host_support_capability_set(log, sub))
4108 goto fail;
4109
4110 break;
4111
4112 case CAPSET_TYPE_BITMAP_CACHE_V2:
4113 if (!rdp_print_bitmap_cache_v2_capability_set(log, sub))
4114 goto fail;
4115
4116 break;
4117
4118 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4119 if (!rdp_print_virtual_channel_capability_set(log, sub))
4120 goto fail;
4121
4122 break;
4123
4124 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4125 if (!rdp_print_draw_nine_grid_cache_capability_set(log, sub))
4126 goto fail;
4127
4128 break;
4129
4130 case CAPSET_TYPE_DRAW_GDI_PLUS:
4131 if (!rdp_print_draw_gdiplus_cache_capability_set(log, sub))
4132 goto fail;
4133
4134 break;
4135
4136 case CAPSET_TYPE_RAIL:
4137 if (!rdp_print_remote_programs_capability_set(log, sub))
4138 goto fail;
4139
4140 break;
4141
4142 case CAPSET_TYPE_WINDOW:
4143 if (!rdp_print_window_list_capability_set(log, sub))
4144 goto fail;
4145
4146 break;
4147
4148 case CAPSET_TYPE_COMP_DESK:
4149 if (!rdp_print_desktop_composition_capability_set(log, sub))
4150 goto fail;
4151
4152 break;
4153
4154 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4155 if (!rdp_print_multifragment_update_capability_set(log, sub))
4156 goto fail;
4157
4158 break;
4159
4160 case CAPSET_TYPE_LARGE_POINTER:
4161 if (!rdp_print_large_pointer_capability_set(log, sub))
4162 goto fail;
4163
4164 break;
4165
4166 case CAPSET_TYPE_SURFACE_COMMANDS:
4167 if (!rdp_print_surface_commands_capability_set(log, sub))
4168 goto fail;
4169
4170 break;
4171
4172 case CAPSET_TYPE_BITMAP_CODECS:
4173 if (!rdp_print_bitmap_codecs_capability_set(log, sub))
4174 goto fail;
4175
4176 break;
4177
4178 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4179 if (!rdp_print_frame_acknowledge_capability_set(log, sub))
4180 goto fail;
4181
4182 break;
4183
4184 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4185 if (!rdp_print_bitmap_cache_v3_codec_id_capability_set(log, sub))
4186 goto fail;
4187
4188 break;
4189
4190 default:
4191 WLog_Print(log, WLOG_ERROR, "unknown capability type %" PRIu16 "", type);
4192 break;
4193 }
4194
4195 rest = Stream_GetRemainingLength(sub);
4196 if (rest > 0)
4197 {
4198 WLog_Print(log, WLOG_WARN,
4199 "incorrect capability offset, type:0x%04" PRIX16 " %" PRIu16
4200 " bytes expected, %" PRIuz "bytes remaining",
4201 type, length, rest);
4202 }
4203
4204 numberCapabilities--;
4205 }
4206
4207 rc = TRUE;
4208fail:
4209 if (!Stream_SetPosition(s, pos))
4210 return FALSE;
4211
4212 return rc;
4213}
4214#endif
4215
4216static BOOL rdp_apply_from_received(UINT16 type, rdpSettings* dst, const rdpSettings* src)
4217{
4218 switch (type)
4219 {
4220 case CAPSET_TYPE_GENERAL:
4221 return rdp_apply_general_capability_set(dst, src);
4222 case CAPSET_TYPE_BITMAP:
4223 return rdp_apply_bitmap_capability_set(dst, src);
4224 case CAPSET_TYPE_ORDER:
4225 return rdp_apply_order_capability_set(dst, src);
4226 case CAPSET_TYPE_POINTER:
4227 return rdp_apply_pointer_capability_set(dst, src);
4228 case CAPSET_TYPE_INPUT:
4229 return rdp_apply_input_capability_set(dst, src);
4230 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4231 return rdp_apply_virtual_channel_capability_set(dst, src);
4232 case CAPSET_TYPE_SHARE:
4233 return rdp_apply_share_capability_set(dst, src);
4234 case CAPSET_TYPE_COLOR_CACHE:
4235 return rdp_apply_color_cache_capability_set(dst, src);
4236 case CAPSET_TYPE_FONT:
4237 return rdp_apply_font_capability_set(dst, src);
4238 case CAPSET_TYPE_DRAW_GDI_PLUS:
4239 return rdp_apply_draw_gdiplus_cache_capability_set(dst, src);
4240 case CAPSET_TYPE_RAIL:
4241 return rdp_apply_remote_programs_capability_set(dst, src);
4242 case CAPSET_TYPE_WINDOW:
4243 return rdp_apply_window_list_capability_set(dst, src);
4244 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4245 return rdp_apply_multifragment_update_capability_set(dst, src);
4246 case CAPSET_TYPE_LARGE_POINTER:
4247 return rdp_apply_large_pointer_capability_set(dst, src);
4248 case CAPSET_TYPE_COMP_DESK:
4249 return rdp_apply_desktop_composition_capability_set(dst, src);
4250 case CAPSET_TYPE_SURFACE_COMMANDS:
4251 return rdp_apply_surface_commands_capability_set(dst, src);
4252 case CAPSET_TYPE_BITMAP_CODECS:
4253 return rdp_apply_bitmap_codecs_capability_set(dst, src);
4254 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4255 return rdp_apply_frame_acknowledge_capability_set(dst, src);
4256 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4257 return rdp_apply_bitmap_cache_v3_codec_id_capability_set(dst, src);
4258 case CAPSET_TYPE_BITMAP_CACHE:
4259 return rdp_apply_bitmap_cache_capability_set(dst, src);
4260 case CAPSET_TYPE_BITMAP_CACHE_V2:
4261 return rdp_apply_bitmap_cache_v2_capability_set(dst, src);
4262 case CAPSET_TYPE_BRUSH:
4263 return rdp_apply_brush_capability_set(dst, src);
4264 case CAPSET_TYPE_GLYPH_CACHE:
4265 return rdp_apply_glyph_cache_capability_set(dst, src);
4266 case CAPSET_TYPE_OFFSCREEN_CACHE:
4267 return rdp_apply_offscreen_bitmap_cache_capability_set(dst, src);
4268 case CAPSET_TYPE_SOUND:
4269 return rdp_apply_sound_capability_set(dst, src);
4270 case CAPSET_TYPE_CONTROL:
4271 return rdp_apply_control_capability_set(dst, src);
4272 case CAPSET_TYPE_ACTIVATION:
4273 return rdp_apply_window_activation_capability_set(dst, src);
4274 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4275 return rdp_apply_draw_nine_grid_cache_capability_set(dst, src);
4276 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4277 return rdp_apply_bitmap_cache_host_support_capability_set(dst, src);
4278 default:
4279 return TRUE;
4280 }
4281}
4282
4283BOOL rdp_read_capability_set(wLog* log, wStream* sub, UINT16 type, rdpSettings* settings,
4284 BOOL isServer)
4285{
4286 WINPR_ASSERT(settings);
4287
4288 if (type <= CAPSET_TYPE_FRAME_ACKNOWLEDGE)
4289 {
4290 const size_t size = Stream_Length(sub);
4291 if (size > UINT32_MAX)
4292 return FALSE;
4293
4294 WINPR_ASSERT(settings->ReceivedCapabilities);
4295 settings->ReceivedCapabilities[type] = TRUE;
4296
4297 WINPR_ASSERT(settings->ReceivedCapabilityDataSizes);
4298 settings->ReceivedCapabilityDataSizes[type] = (UINT32)size;
4299
4300 WINPR_ASSERT(settings->ReceivedCapabilityData);
4301 void* tmp = realloc(settings->ReceivedCapabilityData[type], size);
4302 if (!tmp && (size > 0))
4303 return FALSE;
4304 if (tmp)
4305 memcpy(tmp, Stream_Buffer(sub), size);
4306 settings->ReceivedCapabilityData[type] = tmp;
4307 }
4308 else
4309 WLog_Print(log, WLOG_WARN, "not handling capability type %" PRIu16 " yet", type);
4310
4311 BOOL treated = TRUE;
4312
4313 switch (type)
4314 {
4315 case CAPSET_TYPE_GENERAL:
4316 if (!rdp_read_general_capability_set(log, sub, settings))
4317 return FALSE;
4318
4319 break;
4320
4321 case CAPSET_TYPE_BITMAP:
4322 if (!rdp_read_bitmap_capability_set(log, sub, settings))
4323 return FALSE;
4324
4325 break;
4326
4327 case CAPSET_TYPE_ORDER:
4328 if (!rdp_read_order_capability_set(log, sub, settings))
4329 return FALSE;
4330
4331 break;
4332
4333 case CAPSET_TYPE_POINTER:
4334 if (!rdp_read_pointer_capability_set(log, sub, settings))
4335 return FALSE;
4336
4337 break;
4338
4339 case CAPSET_TYPE_INPUT:
4340 if (!rdp_read_input_capability_set(log, sub, settings, isServer))
4341 return FALSE;
4342
4343 break;
4344
4345 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4346 if (!rdp_read_virtual_channel_capability_set(log, sub, settings))
4347 return FALSE;
4348
4349 break;
4350
4351 case CAPSET_TYPE_SHARE:
4352 if (!rdp_read_share_capability_set(log, sub, settings))
4353 return FALSE;
4354
4355 break;
4356
4357 case CAPSET_TYPE_COLOR_CACHE:
4358 if (!rdp_read_color_cache_capability_set(log, sub, settings))
4359 return FALSE;
4360
4361 break;
4362
4363 case CAPSET_TYPE_FONT:
4364 if (!rdp_read_font_capability_set(log, sub, settings))
4365 return FALSE;
4366
4367 break;
4368
4369 case CAPSET_TYPE_DRAW_GDI_PLUS:
4370 if (!rdp_read_draw_gdiplus_cache_capability_set(log, sub, settings))
4371 return FALSE;
4372
4373 break;
4374
4375 case CAPSET_TYPE_RAIL:
4376 if (!rdp_read_remote_programs_capability_set(log, sub, settings))
4377 return FALSE;
4378
4379 break;
4380
4381 case CAPSET_TYPE_WINDOW:
4382 if (!rdp_read_window_list_capability_set(log, sub, settings))
4383 return FALSE;
4384
4385 break;
4386
4387 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4388 if (!rdp_read_multifragment_update_capability_set(log, sub, settings))
4389 return FALSE;
4390
4391 break;
4392
4393 case CAPSET_TYPE_LARGE_POINTER:
4394 if (!rdp_read_large_pointer_capability_set(log, sub, settings))
4395 return FALSE;
4396
4397 break;
4398
4399 case CAPSET_TYPE_COMP_DESK:
4400 if (!rdp_read_desktop_composition_capability_set(log, sub, settings))
4401 return FALSE;
4402
4403 break;
4404
4405 case CAPSET_TYPE_SURFACE_COMMANDS:
4406 if (!rdp_read_surface_commands_capability_set(log, sub, settings))
4407 return FALSE;
4408
4409 break;
4410
4411 case CAPSET_TYPE_BITMAP_CODECS:
4412 if (!rdp_read_bitmap_codecs_capability_set(log, sub, settings, isServer))
4413 return FALSE;
4414
4415 break;
4416
4417 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4418 if (!rdp_read_frame_acknowledge_capability_set(log, sub, settings))
4419 return FALSE;
4420
4421 break;
4422
4423 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4424 if (!rdp_read_bitmap_cache_v3_codec_id_capability_set(log, sub, settings))
4425 return FALSE;
4426
4427 break;
4428
4429 default:
4430 treated = FALSE;
4431 break;
4432 }
4433
4434 if (!treated)
4435 {
4436 if (isServer)
4437 {
4438 /* treating capabilities that are supposed to be send only from the client */
4439 switch (type)
4440 {
4441 case CAPSET_TYPE_BITMAP_CACHE:
4442 if (!rdp_read_bitmap_cache_capability_set(log, sub, settings))
4443 return FALSE;
4444
4445 break;
4446
4447 case CAPSET_TYPE_BITMAP_CACHE_V2:
4448 if (!rdp_read_bitmap_cache_v2_capability_set(log, sub, settings))
4449 return FALSE;
4450
4451 break;
4452
4453 case CAPSET_TYPE_BRUSH:
4454 if (!rdp_read_brush_capability_set(log, sub, settings))
4455 return FALSE;
4456
4457 break;
4458
4459 case CAPSET_TYPE_GLYPH_CACHE:
4460 if (!rdp_read_glyph_cache_capability_set(log, sub, settings))
4461 return FALSE;
4462
4463 break;
4464
4465 case CAPSET_TYPE_OFFSCREEN_CACHE:
4466 if (!rdp_read_offscreen_bitmap_cache_capability_set(log, sub, settings))
4467 return FALSE;
4468
4469 break;
4470
4471 case CAPSET_TYPE_SOUND:
4472 if (!rdp_read_sound_capability_set(log, sub, settings))
4473 return FALSE;
4474
4475 break;
4476
4477 case CAPSET_TYPE_CONTROL:
4478 if (!rdp_read_control_capability_set(log, sub, settings))
4479 return FALSE;
4480
4481 break;
4482
4483 case CAPSET_TYPE_ACTIVATION:
4484 if (!rdp_read_window_activation_capability_set(log, sub, settings))
4485 return FALSE;
4486
4487 break;
4488
4489 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4490 if (!rdp_read_draw_nine_grid_cache_capability_set(log, sub, settings))
4491 return FALSE;
4492
4493 break;
4494
4495 default:
4496 WLog_Print(log, WLOG_ERROR,
4497 "capability %s(%" PRIu16 ") not expected from client",
4498 get_capability_name(type), type);
4499 return FALSE;
4500 }
4501 }
4502 else
4503 {
4504 /* treating capabilities that are supposed to be send only from the server */
4505 switch (type)
4506 {
4507 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4508 if (!rdp_read_bitmap_cache_host_support_capability_set(log, sub, settings))
4509 return FALSE;
4510
4511 break;
4512
4513 default:
4514 WLog_Print(log, WLOG_ERROR,
4515 "capability %s(%" PRIu16 ") not expected from server",
4516 get_capability_name(type), type);
4517 return FALSE;
4518 }
4519 }
4520 }
4521
4522 const size_t rest = Stream_GetRemainingLength(sub);
4523 if (rest > 0)
4524 {
4525 const size_t length = Stream_Capacity(sub);
4526 WLog_Print(log, WLOG_ERROR,
4527 "incorrect offset, type:0x%04" PRIx16 " actual:%" PRIuz " expected:%" PRIuz "",
4528 type, length - rest, length);
4529 }
4530 return TRUE;
4531}
4532
4533static BOOL rdp_read_capability_sets(wLog* log, wStream* s, rdpSettings* settings,
4534 rdpSettings* rcvSettings, UINT16 totalLength)
4535{
4536 BOOL rc = FALSE;
4537 size_t start = 0;
4538 size_t end = 0;
4539 size_t len = 0;
4540 UINT16 numberCapabilities = 0;
4541 UINT16 count = 0;
4542
4543#ifdef WITH_DEBUG_CAPABILITIES
4544 const size_t capstart = Stream_GetPosition(s);
4545#endif
4546
4547 WINPR_ASSERT(s);
4548 WINPR_ASSERT(settings);
4549
4550 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4551 return FALSE;
4552
4553 Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4554 Stream_Seek(s, 2); /* pad2Octets (2 bytes) */
4555 count = numberCapabilities;
4556
4557 start = Stream_GetPosition(s);
4558 while (numberCapabilities > 0 && Stream_GetRemainingLength(s) >= 4)
4559 {
4560 UINT16 type = 0;
4561 UINT16 length = 0;
4562 wStream subbuffer;
4563 wStream* sub = nullptr;
4564
4565 if (!rdp_read_capability_set_header(log, s, &length, &type))
4566 goto fail;
4567 sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), length - 4);
4568 if (!Stream_SafeSeek(s, length - 4))
4569 goto fail;
4570
4571 if (!rdp_read_capability_set(log, sub, type, rcvSettings, settings->ServerMode))
4572 goto fail;
4573
4574 if (!rdp_apply_from_received(type, settings, rcvSettings))
4575 goto fail;
4576 numberCapabilities--;
4577 }
4578
4579 end = Stream_GetPosition(s);
4580 len = end - start;
4581
4582 if (numberCapabilities)
4583 {
4584 WLog_Print(log, WLOG_ERROR,
4585 "strange we haven't read the number of announced capacity sets, read=%d "
4586 "expected=%" PRIu16 "",
4587 count - numberCapabilities, count);
4588 }
4589
4590#ifdef WITH_DEBUG_CAPABILITIES
4591 rdp_print_capability_sets(log, s, capstart, TRUE);
4592#endif
4593
4594 if (len > totalLength)
4595 {
4596 WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIuz,
4597 totalLength, len);
4598 goto fail;
4599 }
4600 rc = freerdp_capability_buffer_copy(settings, rcvSettings);
4601fail:
4602 return rc;
4603}
4604
4605BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId, UINT16* length)
4606{
4607 WINPR_ASSERT(rdp);
4608 WINPR_ASSERT(rdp->context);
4609
4610 if (!rdp_read_header(rdp, s, length, pChannelId))
4611 return FALSE;
4612
4613 if (freerdp_shall_disconnect_context(rdp->context))
4614 return TRUE;
4615
4616 if (*pChannelId != MCS_GLOBAL_CHANNEL_ID)
4617 {
4618 UINT16 mcsMessageChannelId = rdp->mcs->messageChannelId;
4619
4620 if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId))
4621 {
4622 WLog_Print(rdp->log, WLOG_ERROR, "unexpected MCS channel id %04" PRIx16 " received",
4623 *pChannelId);
4624 return FALSE;
4625 }
4626 }
4627
4628 return TRUE;
4629}
4630
4631BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s, UINT16 pduSource, UINT16 length)
4632{
4633 UINT16 lengthSourceDescriptor = 0;
4634 UINT16 lengthCombinedCapabilities = 0;
4635
4636 WINPR_ASSERT(rdp);
4637 WINPR_ASSERT(rdp->settings);
4638 WINPR_ASSERT(rdp->context);
4639 WINPR_ASSERT(s);
4640
4641 rdp->settings->PduSource = pduSource;
4642
4643 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 8))
4644 return FALSE;
4645
4646 Stream_Read_UINT32(s, rdp->settings->ShareId); /* shareId (4 bytes) */
4647 Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4648 Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4649
4650 if (!Stream_SafeSeek(s, lengthSourceDescriptor) ||
4651 !Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4)) /* sourceDescriptor */
4652 return FALSE;
4653
4654 /* capabilitySets */
4655 if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4656 lengthCombinedCapabilities))
4657 {
4658 WLog_Print(rdp->log, WLOG_ERROR, "rdp_read_capability_sets failed");
4659 return FALSE;
4660 }
4661
4662 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4))
4663 return FALSE;
4664
4665 /* [MS-RDPBCGR] 2.2.1.13.1.1 Demand Active PDU Data (TS_DEMAND_ACTIVE_PDU)::sessionId
4666 * is ignored by client */
4667 Stream_Seek_UINT32(s); /* SessionId */
4668
4669 {
4670 rdp_secondary_update_internal* secondary = secondary_update_cast(rdp->update->secondary);
4671 secondary->glyph_v2 = (rdp->settings->GlyphSupportLevel > GLYPH_SUPPORT_FULL);
4672 }
4673
4674 return tpkt_ensure_stream_consumed(rdp->log, s, length);
4675}
4676
4677static BOOL rdp_write_demand_active(wLog* log, wStream* s, rdpSettings* settings)
4678{
4679 size_t bm = 0;
4680 size_t em = 0;
4681 size_t lm = 0;
4682 UINT16 numberCapabilities = 0;
4683 size_t lengthCombinedCapabilities = 0;
4684
4685 if (!Stream_EnsureRemainingCapacity(s, 64))
4686 return FALSE;
4687
4688 Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4689 Stream_Write_UINT16(s, 4); /* lengthSourceDescriptor (2 bytes) */
4690 lm = Stream_GetPosition(s);
4691 Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4692 Stream_Write(s, "RDP", 4); /* sourceDescriptor */
4693 bm = Stream_GetPosition(s);
4694 Stream_Seek_UINT16(s); /* numberCapabilities (2 bytes) */
4695 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4696 numberCapabilities = 14;
4697
4698 if (!rdp_write_general_capability_set(log, s, settings) ||
4699 !rdp_write_bitmap_capability_set(log, s, settings) ||
4700 !rdp_write_order_capability_set(log, s, settings) ||
4701 !rdp_write_pointer_capability_set(log, s, settings) ||
4702 !rdp_write_input_capability_set(log, s, settings) ||
4703 !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4704 !rdp_write_share_capability_set(log, s, settings) ||
4705 !rdp_write_font_capability_set(log, s, settings) ||
4706 !rdp_write_multifragment_update_capability_set(log, s, settings) ||
4707 !rdp_write_large_pointer_capability_set(log, s, settings) ||
4708 !rdp_write_desktop_composition_capability_set(log, s, settings) ||
4709 !rdp_write_surface_commands_capability_set(log, s, settings) ||
4710 !rdp_write_bitmap_codecs_capability_set(log, s, settings) ||
4711 !rdp_write_frame_acknowledge_capability_set(log, s, settings))
4712 {
4713 return FALSE;
4714 }
4715
4716 if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
4717 {
4718 numberCapabilities++;
4719
4720 if (!rdp_write_bitmap_cache_host_support_capability_set(log, s, settings))
4721 return FALSE;
4722 }
4723
4724 if (settings->RemoteApplicationMode)
4725 {
4726 numberCapabilities += 2;
4727
4728 if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4729 !rdp_write_window_list_capability_set(log, s, settings))
4730 return FALSE;
4731 }
4732
4733 em = Stream_GetPosition(s);
4734 if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4735 return FALSE;
4736 lengthCombinedCapabilities = (em - bm);
4737 if (lengthCombinedCapabilities > UINT16_MAX)
4738 return FALSE;
4739 Stream_Write_UINT16(
4740 s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4741 if (!Stream_SetPosition(s, bm)) /* go back to numberCapabilities */
4742 return FALSE;
4743 Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4744#ifdef WITH_DEBUG_CAPABILITIES
4745 rdp_print_capability_sets(log, s, bm, FALSE);
4746#endif
4747 if (!Stream_SetPosition(s, em))
4748 return FALSE;
4749 Stream_Write_UINT32(s, 0); /* sessionId */
4750 return TRUE;
4751}
4752
4753BOOL rdp_send_demand_active(rdpRdp* rdp)
4754{
4755 UINT16 sec_flags = 0;
4756 wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4757 BOOL status = 0;
4758
4759 if (!s)
4760 return FALSE;
4761
4762 rdp->settings->ShareId = 0x10000 + rdp->mcs->userId;
4763 status = rdp_write_demand_active(rdp->log, s, rdp->settings) &&
4764 rdp_send_pdu(rdp, s, PDU_TYPE_DEMAND_ACTIVE, rdp->mcs->userId, sec_flags);
4765 Stream_Release(s);
4766 return status;
4767}
4768
4769BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength)
4770{
4771 rdpSettings* settings = nullptr;
4772 UINT16 lengthSourceDescriptor = 0;
4773 UINT16 lengthCombinedCapabilities = 0;
4774
4775 WINPR_ASSERT(rdp);
4776 WINPR_ASSERT(s);
4777 settings = rdp->settings;
4778 WINPR_ASSERT(settings);
4779
4780 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 10))
4781 return FALSE;
4782
4783 Stream_Seek_UINT32(s); /* shareId (4 bytes) */
4784 Stream_Seek_UINT16(s); /* originatorId (2 bytes) */
4785 Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4786 Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4787
4788 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, lengthSourceDescriptor + 4U))
4789 return FALSE;
4790
4791 Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor */
4792 if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4793 lengthCombinedCapabilities))
4794 return FALSE;
4795
4796 if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4797 {
4798 /* client does not support surface commands */
4799 settings->SurfaceCommandsEnabled = FALSE;
4800 settings->SurfaceFrameMarkerEnabled = FALSE;
4801 }
4802
4803 if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4804 {
4805 /* client does not support frame acks */
4806 settings->FrameAcknowledge = 0;
4807 }
4808
4809 if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4810 {
4811 /* client does not support bitmap cache v3 */
4812 settings->BitmapCacheV3Enabled = FALSE;
4813 }
4814
4815 if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4816 {
4817 /* client does not support bitmap codecs */
4818 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, FALSE))
4819 return FALSE;
4820 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, FALSE))
4821 return FALSE;
4822 if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
4823 return FALSE;
4824 }
4825
4826 if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4827 {
4828 /* client does not support multi fragment updates - make sure packages are not fragmented */
4829 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
4830 FASTPATH_FRAGMENT_SAFE_SIZE))
4831 return FALSE;
4832 }
4833
4834 if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4835 {
4836 /* client does not support large pointers */
4837 settings->LargePointerFlag = 0;
4838 }
4839
4840 return tpkt_ensure_stream_consumed(rdp->log, s, pduLength);
4841}
4842
4843static BOOL rdp_write_confirm_active(wLog* log, wStream* s, rdpSettings* settings)
4844{
4845 size_t bm = 0;
4846 size_t em = 0;
4847 size_t lm = 0;
4848 UINT16 numberCapabilities = 0;
4849 UINT16 lengthSourceDescriptor = 0;
4850 size_t lengthCombinedCapabilities = 0;
4851 BOOL ret = 0;
4852
4853 WINPR_ASSERT(settings);
4854
4855 lengthSourceDescriptor = sizeof(SOURCE_DESCRIPTOR);
4856 Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4857 Stream_Write_UINT16(s, 0x03EA); /* originatorId (2 bytes) */
4858 Stream_Write_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4859 lm = Stream_GetPosition(s);
4860 Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4861 Stream_Write(s, SOURCE_DESCRIPTOR, lengthSourceDescriptor); /* sourceDescriptor */
4862 bm = Stream_GetPosition(s);
4863 Stream_Seek_UINT16(s); /* numberCapabilities (2 bytes) */
4864 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4865 /* Capability Sets */
4866 numberCapabilities = 15;
4867
4868 if (!rdp_write_general_capability_set(log, s, settings) ||
4869 !rdp_write_bitmap_capability_set(log, s, settings) ||
4870 !rdp_write_order_capability_set(log, s, settings))
4871 return FALSE;
4872
4873 if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
4874 ret = rdp_write_bitmap_cache_v2_capability_set(log, s, settings);
4875 else
4876 ret = rdp_write_bitmap_cache_capability_set(log, s, settings);
4877
4878 if (!ret)
4879 return FALSE;
4880
4881 if (!rdp_write_pointer_capability_set(log, s, settings) ||
4882 !rdp_write_input_capability_set(log, s, settings) ||
4883 !rdp_write_brush_capability_set(log, s, settings) ||
4884 !rdp_write_glyph_cache_capability_set(log, s, settings) ||
4885 !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4886 !rdp_write_sound_capability_set(log, s, settings) ||
4887 !rdp_write_share_capability_set(log, s, settings) ||
4888 !rdp_write_font_capability_set(log, s, settings) ||
4889 !rdp_write_control_capability_set(log, s, settings) ||
4890 !rdp_write_color_cache_capability_set(log, s, settings) ||
4891 !rdp_write_window_activation_capability_set(log, s, settings))
4892 {
4893 return FALSE;
4894 }
4895
4896 {
4897 numberCapabilities++;
4898
4899 if (!rdp_write_offscreen_bitmap_cache_capability_set(log, s, settings))
4900 return FALSE;
4901 }
4902
4903 if (settings->DrawNineGridEnabled)
4904 {
4905 numberCapabilities++;
4906
4907 if (!rdp_write_draw_nine_grid_cache_capability_set(log, s, settings))
4908 return FALSE;
4909 }
4910
4911 if (settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4912 {
4913 if (settings->LargePointerFlag)
4914 {
4915 numberCapabilities++;
4916
4917 if (!rdp_write_large_pointer_capability_set(log, s, settings))
4918 return FALSE;
4919 }
4920 }
4921
4922 if (settings->RemoteApplicationMode)
4923 {
4924 numberCapabilities += 2;
4925
4926 if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4927 !rdp_write_window_list_capability_set(log, s, settings))
4928 return FALSE;
4929 }
4930
4931 if (settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4932 {
4933 numberCapabilities++;
4934
4935 if (!rdp_write_multifragment_update_capability_set(log, s, settings))
4936 return FALSE;
4937 }
4938
4939 if (settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4940 {
4941 numberCapabilities++;
4942
4943 if (!rdp_write_surface_commands_capability_set(log, s, settings))
4944 return FALSE;
4945 }
4946
4947 if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4948 {
4949 numberCapabilities++;
4950
4951 if (!rdp_write_bitmap_codecs_capability_set(log, s, settings))
4952 return FALSE;
4953 }
4954
4955 if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4956 settings->FrameAcknowledge = 0;
4957
4958 if (settings->FrameAcknowledge)
4959 {
4960 numberCapabilities++;
4961
4962 if (!rdp_write_frame_acknowledge_capability_set(log, s, settings))
4963 return FALSE;
4964 }
4965
4966 if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4967 {
4968 if (settings->BitmapCacheV3CodecId != 0)
4969 {
4970 numberCapabilities++;
4971
4972 if (!rdp_write_bitmap_cache_v3_codec_id_capability_set(log, s, settings))
4973 return FALSE;
4974 }
4975 }
4976
4977 em = Stream_GetPosition(s);
4978 if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4979 return FALSE;
4980 lengthCombinedCapabilities = (em - bm);
4981 if (lengthCombinedCapabilities > UINT16_MAX)
4982 return FALSE;
4983 Stream_Write_UINT16(
4984 s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4985 if (!Stream_SetPosition(s, bm)) /* go back to numberCapabilities */
4986 return FALSE;
4987 Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4988#ifdef WITH_DEBUG_CAPABILITIES
4989 rdp_print_capability_sets(log, s, bm, FALSE);
4990#endif
4991 return Stream_SetPosition(s, em);
4992}
4993
4994BOOL rdp_send_confirm_active(rdpRdp* rdp)
4995{
4996 UINT16 sec_flags = 0;
4997 wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4998 BOOL status = 0;
4999
5000 if (!s)
5001 return FALSE;
5002
5003 status = rdp_write_confirm_active(rdp->log, s, rdp->settings) &&
5004 rdp_send_pdu(rdp, s, PDU_TYPE_CONFIRM_ACTIVE, rdp->mcs->userId, sec_flags);
5005 Stream_Release(s);
5006 return status;
5007}
5008
5009const char* rdp_input_flag_string(UINT16 flags, char* buffer, size_t len)
5010{
5011 char prefix[16] = WINPR_C_ARRAY_INIT;
5012
5013 (void)_snprintf(prefix, sizeof(prefix), "[0x%04" PRIx16 "][", flags);
5014 winpr_str_append(prefix, buffer, len, "");
5015 if ((flags & INPUT_FLAG_SCANCODES) != 0)
5016 winpr_str_append("INPUT_FLAG_SCANCODES", buffer, len, "|");
5017 if ((flags & INPUT_FLAG_MOUSEX) != 0)
5018 winpr_str_append("INPUT_FLAG_MOUSEX", buffer, len, "|");
5019 if ((flags & INPUT_FLAG_FASTPATH_INPUT) != 0)
5020 winpr_str_append("INPUT_FLAG_FASTPATH_INPUT", buffer, len, "|");
5021 if ((flags & INPUT_FLAG_UNICODE) != 0)
5022 winpr_str_append("INPUT_FLAG_UNICODE", buffer, len, "|");
5023 if ((flags & INPUT_FLAG_FASTPATH_INPUT2) != 0)
5024 winpr_str_append("INPUT_FLAG_FASTPATH_INPUT2", buffer, len, "|");
5025 if ((flags & INPUT_FLAG_UNUSED1) != 0)
5026 winpr_str_append("INPUT_FLAG_UNUSED1", buffer, len, "|");
5027 if ((flags & INPUT_FLAG_MOUSE_RELATIVE) != 0)
5028 winpr_str_append("INPUT_FLAG_MOUSE_RELATIVE", buffer, len, "|");
5029 if ((flags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0)
5030 winpr_str_append("TS_INPUT_FLAG_MOUSE_HWHEEL", buffer, len, "|");
5031 if ((flags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0)
5032 winpr_str_append("TS_INPUT_FLAG_QOE_TIMESTAMPS", buffer, len, "|");
5033 winpr_str_append("]", buffer, len, "");
5034 return buffer;
5035}
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