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
34/* [MS-RDPBCGR] 2.2.7.1.4.2
35Revision 2 (TS_BITMAPCACHE_CAPABILITYSET_REV2)
36*/
37static const size_t bitmapCacheV2CellInfoLimits[] = { 600, 600, 65536, 4096, 2048 };
38
39static const char* const CAPSET_TYPE_STRINGS[] = { "Unknown",
40 "General",
41 "Bitmap",
42 "Order",
43 "Bitmap Cache",
44 "Control",
45 "Unknown",
46 "Window Activation",
47 "Pointer",
48 "Share",
49 "Color Cache",
50 "Unknown",
51 "Sound",
52 "Input",
53 "Font",
54 "Brush",
55 "Glyph Cache",
56 "Offscreen Bitmap Cache",
57 "Bitmap Cache Host Support",
58 "Bitmap Cache v2",
59 "Virtual Channel",
60 "DrawNineGrid Cache",
61 "Draw GDI+ Cache",
62 "Remote Programs",
63 "Window List",
64 "Desktop Composition",
65 "Multifragment Update",
66 "Large Pointer",
67 "Surface Commands",
68 "Bitmap Codecs",
69 "Frame Acknowledge" };
70
71WINPR_ATTR_NODISCARD
72static const char* get_capability_name(UINT16 type)
73{
74 if (type > CAPSET_TYPE_FRAME_ACKNOWLEDGE)
75 return "<unknown>";
76
77 return CAPSET_TYPE_STRINGS[type];
78}
79
80#ifdef WITH_DEBUG_CAPABILITIES
81static BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving);
82#endif
83
84/* CODEC_GUID_REMOTEFX: 0x76772F12BD724463AFB3B73C9C6F7886 */
85
86static const GUID CODEC_GUID_REMOTEFX = {
87 0x76772F12, 0xBD72, 0x4463, { 0xAF, 0xB3, 0xB7, 0x3C, 0x9C, 0x6F, 0x78, 0x86 }
88};
89
90/* CODEC_GUID_NSCODEC 0xCA8D1BB9000F154F589FAE2D1A87E2D6 */
91
92static const GUID CODEC_GUID_NSCODEC = {
93 0xCA8D1BB9, 0x000F, 0x154F, { 0x58, 0x9F, 0xAE, 0x2D, 0x1A, 0x87, 0xE2, 0xD6 }
94};
95
96/* CODEC_GUID_IGNORE 0x9C4351A6353542AE910CCDFCE5760B58 */
97
98static const GUID CODEC_GUID_IGNORE = {
99 0x9C4351A6, 0x3535, 0x42AE, { 0x91, 0x0C, 0xCD, 0xFC, 0xE5, 0x76, 0x0B, 0x58 }
100};
101
102/* CODEC_GUID_IMAGE_REMOTEFX 0x2744CCD49D8A4E74803C0ECBEEA19C54 */
103
104static const GUID CODEC_GUID_IMAGE_REMOTEFX = {
105 0x2744CCD4, 0x9D8A, 0x4E74, { 0x80, 0x3C, 0x0E, 0xCB, 0xEE, 0xA1, 0x9C, 0x54 }
106};
107
108#if defined(WITH_JPEG)
109/* CODEC_GUID_JPEG 0x430C9EED1BAF4CE6869ACB8B37B66237 */
110
111static const GUID CODEC_GUID_JPEG = {
112 0x430C9EED, 0x1BAF, 0x4CE6, { 0x86, 0x9A, 0xCB, 0x8B, 0x37, 0xB6, 0x62, 0x37 }
113};
114#endif
115
116WINPR_ATTR_NODISCARD
117static BOOL rdp_read_capability_set_header(wLog* log, wStream* s, UINT16* length, UINT16* type)
118{
119 WINPR_ASSERT(s);
120 WINPR_ASSERT(length);
121 WINPR_ASSERT(type);
122
123 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
124 return FALSE;
125 Stream_Read_UINT16(s, *type); /* capabilitySetType */
126 Stream_Read_UINT16(s, *length); /* lengthCapability */
127 return (*length >= 4);
128}
129
130static void rdp_write_capability_set_header(wStream* s, UINT16 length, UINT16 type)
131{
132 WINPR_ASSERT(s);
133 WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 4);
134 Stream_Write_UINT16(s, type); /* capabilitySetType */
135 Stream_Write_UINT16(s, length); /* lengthCapability */
136}
137
138WINPR_ATTR_NODISCARD
139static size_t rdp_capability_set_start(wLog* log, wStream* s)
140{
141 size_t header = Stream_GetPosition(s);
142 if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), CAPSET_HEADER_LENGTH))
143 return SIZE_MAX;
144 Stream_Zero(s, CAPSET_HEADER_LENGTH);
145 return header;
146}
147
148WINPR_ATTR_NODISCARD
149static BOOL rdp_capability_set_finish(wStream* s, size_t header, UINT16 type)
150{
151 const size_t footer = Stream_GetPosition(s);
152 if (header > footer)
153 return FALSE;
154 if (header > UINT16_MAX)
155 return FALSE;
156 const size_t length = footer - header;
157 if ((Stream_Capacity(s) < header + 4ULL) || (length > UINT16_MAX))
158 return FALSE;
159 if (!Stream_SetPosition(s, header))
160 return FALSE;
161 rdp_write_capability_set_header(s, (UINT16)length, type);
162 return Stream_SetPosition(s, footer);
163}
164
165WINPR_ATTR_NODISCARD
166static BOOL rdp_apply_general_capability_set(rdpSettings* settings, const rdpSettings* src)
167{
168 WINPR_ASSERT(settings);
169 WINPR_ASSERT(src);
170
171 if (settings->ServerMode)
172 {
173 settings->OsMajorType = src->OsMajorType;
174 settings->OsMinorType = src->OsMinorType;
175 }
176
177 settings->CapsProtocolVersion = src->CapsProtocolVersion;
178 settings->NoBitmapCompressionHeader = src->NoBitmapCompressionHeader;
179 settings->LongCredentialsSupported = src->LongCredentialsSupported;
180 settings->AutoReconnectionPacketSupported = src->AutoReconnectionPacketSupported;
181 if (!src->FastPathOutput)
182 settings->FastPathOutput = FALSE;
183
184 if (!src->SaltedChecksum)
185 settings->SaltedChecksum = FALSE;
186
187 if (!settings->ServerMode)
188 {
189 /*
190 * Note: refreshRectSupport and suppressOutputSupport are
191 * server-only flags indicating to the client weather the
192 * respective PDUs are supported. See MS-RDPBCGR 2.2.7.1.1
193 */
194 if (!src->RefreshRect)
195 settings->RefreshRect = FALSE;
196
197 if (!src->SuppressOutput)
198 settings->SuppressOutput = FALSE;
199 }
200 return TRUE;
201}
202
203/*
204 * Read general capability set.
205 * msdn{cc240549}
206 */
207WINPR_ATTR_NODISCARD
208static BOOL rdp_read_general_capability_set(wLog* log, wStream* s, rdpSettings* settings)
209{
210 UINT16 extraFlags = 0;
211 BYTE refreshRectSupport = 0;
212 BYTE suppressOutputSupport = 0;
213
214 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
215 return FALSE;
216
217 WINPR_ASSERT(settings);
218 Stream_Read_UINT16(s, settings->OsMajorType); /* osMajorType (2 bytes) */
219 Stream_Read_UINT16(s, settings->OsMinorType); /* osMinorType (2 bytes) */
220
221 Stream_Read_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
222 if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
223 {
224 WLog_Print(log, WLOG_ERROR,
225 "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
226 ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
227 settings->CapsProtocolVersion,
228 WINPR_CXX_COMPAT_CAST(UINT32, TS_CAPS_PROTOCOLVERSION));
229 if (settings->CapsProtocolVersion == 0x0000)
230 {
231 WLog_Print(log, WLOG_WARN,
232 "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
233 " assuming old FreeRDP, ignoring protocol violation, correcting value.",
234 settings->CapsProtocolVersion);
235 settings->CapsProtocolVersion = TS_CAPS_PROTOCOLVERSION;
236 }
237 else
238 return FALSE;
239 }
240 Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */
241 Stream_Read_UINT16(
242 s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
243 Stream_Read_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
244 Stream_Read_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
245 Stream_Read_UINT16(s, settings->CapsRemoteUnshareFlag); /* remoteUnshareFlag (2 bytes) */
246 Stream_Read_UINT16(
247 s, settings->CapsGeneralCompressionLevel); /* generalCompressionLevel (2 bytes) */
248 Stream_Read_UINT8(s, refreshRectSupport); /* refreshRectSupport (1 byte) */
249 Stream_Read_UINT8(s, suppressOutputSupport); /* suppressOutputSupport (1 byte) */
250 settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) != 0;
251 settings->LongCredentialsSupported = (extraFlags & LONG_CREDENTIALS_SUPPORTED) != 0;
252
253 settings->AutoReconnectionPacketSupported = (extraFlags & AUTORECONNECT_SUPPORTED) != 0;
254 settings->FastPathOutput = (extraFlags & FASTPATH_OUTPUT_SUPPORTED) != 0;
255 settings->SaltedChecksum = (extraFlags & ENC_SALTED_CHECKSUM) != 0;
256 settings->RefreshRect = refreshRectSupport;
257 settings->SuppressOutput = suppressOutputSupport;
258
259 return TRUE;
260}
261
262/*
263 * Write general capability set.
264 * msdn{cc240549}
265 */
266WINPR_ATTR_NODISCARD
267static BOOL rdp_write_general_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
268{
269 if (!Stream_EnsureRemainingCapacity(s, 64))
270 return FALSE;
271
272 const size_t header = rdp_capability_set_start(log, s);
273 UINT16 extraFlags = 0;
274
275 WINPR_ASSERT(settings);
276 if (settings->LongCredentialsSupported)
277 extraFlags |= LONG_CREDENTIALS_SUPPORTED;
278
279 if (settings->NoBitmapCompressionHeader)
280 extraFlags |= NO_BITMAP_COMPRESSION_HDR;
281
282 if (settings->AutoReconnectionPacketSupported)
283 extraFlags |= AUTORECONNECT_SUPPORTED;
284
285 if (settings->FastPathOutput)
286 extraFlags |= FASTPATH_OUTPUT_SUPPORTED;
287
288 if (settings->SaltedChecksum)
289 extraFlags |= ENC_SALTED_CHECKSUM;
290
291 if ((settings->OsMajorType > UINT16_MAX) || (settings->OsMinorType > UINT16_MAX))
292 {
293 WLog_Print(log, WLOG_ERROR,
294 "OsMajorType=%08" PRIx32 ", OsMinorType=%08" PRIx32
295 " they need to be smaller %04" PRIx32,
296 settings->OsMajorType, settings->OsMinorType,
297 WINPR_CXX_COMPAT_CAST(UINT32, UINT16_MAX));
298 return FALSE;
299 }
300 if (settings->CapsProtocolVersion != TS_CAPS_PROTOCOLVERSION)
301 {
302 WLog_Print(log, WLOG_ERROR,
303 "TS_GENERAL_CAPABILITYSET::protocolVersion(0x%04" PRIx16
304 ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")",
305 settings->CapsProtocolVersion,
306 WINPR_CXX_COMPAT_CAST(UINT32, TS_CAPS_PROTOCOLVERSION));
307 return FALSE;
308 }
309 Stream_Write_UINT16(s, (UINT16)settings->OsMajorType); /* osMajorType (2 bytes) */
310 Stream_Write_UINT16(s, (UINT16)settings->OsMinorType); /* osMinorType (2 bytes) */
311 Stream_Write_UINT16(s, settings->CapsProtocolVersion); /* protocolVersion (2 bytes) */
312 Stream_Write_UINT16(s, 0); /* pad2OctetsA (2 bytes) */
313 Stream_Write_UINT16(
314 s, settings->CapsGeneralCompressionTypes); /* generalCompressionTypes (2 bytes) */
315 Stream_Write_UINT16(s, extraFlags); /* extraFlags (2 bytes) */
316 Stream_Write_UINT16(s, settings->CapsUpdateCapabilityFlag); /* updateCapabilityFlag (2 bytes) */
317 Stream_Write_UINT16(s, settings->CapsRemoteUnshareFlag); /* remoteUnshareFlag (2 bytes) */
318 Stream_Write_UINT16(
319 s, settings->CapsGeneralCompressionLevel); /* generalCompressionLevel (2 bytes) */
320 Stream_Write_UINT8(s, settings->RefreshRect ? 1 : 0); /* refreshRectSupport (1 byte) */
321 Stream_Write_UINT8(s, settings->SuppressOutput ? 1 : 0); /* suppressOutputSupport (1 byte) */
322 return rdp_capability_set_finish(s, header, CAPSET_TYPE_GENERAL);
323}
324
325#ifdef WITH_DEBUG_CAPABILITIES
326WINPR_ATTR_NODISCARD
327static BOOL rdp_print_general_capability_set(wLog* log, wStream* s)
328{
329 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20))
330 return FALSE;
331
332 WLog_Print(log, WLOG_TRACE,
333 "GeneralCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
334 const uint16_t osMinorType = Stream_Get_UINT16(s); /* osMajorType (2 bytes) */
335 const uint16_t osMajorType = Stream_Get_UINT16(s); /* osMinorType (2 bytes) */
336 const uint16_t protocolVersion = Stream_Get_UINT16(s); /* protocolVersion (2 bytes) */
337 const uint16_t pad2OctetsA = Stream_Get_UINT16(s); /* pad2OctetsA (2 bytes) */
338 const uint16_t generalCompressionTypes =
339 Stream_Get_UINT16(s); /* generalCompressionTypes (2 bytes) */
340 const uint16_t extraFlags = Stream_Get_UINT16(s); /* extraFlags (2 bytes) */
341 const uint16_t updateCapabilityFlag = Stream_Get_UINT16(s); /* updateCapabilityFlag (2 bytes) */
342 const uint16_t remoteUnshareFlag = Stream_Get_UINT16(s); /* remoteUnshareFlag (2 bytes) */
343 const uint16_t generalCompressionLevel =
344 Stream_Get_UINT16(s); /* generalCompressionLevel (2 bytes) */
345 const uint8_t refreshRectSupport = Stream_Get_UINT8(s); /* refreshRectSupport (1 byte) */
346 const uint8_t suppressOutputSupport = Stream_Get_UINT8(s); /* suppressOutputSupport (1 byte) */
347 WLog_Print(log, WLOG_TRACE, "\tosMajorType: 0x%04" PRIX16 "", osMajorType);
348 WLog_Print(log, WLOG_TRACE, "\tosMinorType: 0x%04" PRIX16 "", osMinorType);
349 WLog_Print(log, WLOG_TRACE, "\tprotocolVersion: 0x%04" PRIX16 "", protocolVersion);
350 WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
351 WLog_Print(log, WLOG_TRACE, "\tgeneralCompressionTypes: 0x%04" PRIX16 "",
352 generalCompressionTypes);
353 WLog_Print(log, WLOG_TRACE, "\textraFlags: 0x%04" PRIX16 "", extraFlags);
354 WLog_Print(log, WLOG_TRACE, "\tupdateCapabilityFlag: 0x%04" PRIX16 "", updateCapabilityFlag);
355 WLog_Print(log, WLOG_TRACE, "\tremoteUnshareFlag: 0x%04" PRIX16 "", remoteUnshareFlag);
356 WLog_Print(log, WLOG_TRACE, "\tgeneralCompressionLevel: 0x%04" PRIX16 "",
357 generalCompressionLevel);
358 WLog_Print(log, WLOG_TRACE, "\trefreshRectSupport: 0x%02" PRIX8 "", refreshRectSupport);
359 WLog_Print(log, WLOG_TRACE, "\tsuppressOutputSupport: 0x%02" PRIX8 "", suppressOutputSupport);
360 return TRUE;
361}
362#endif
363
364WINPR_ATTR_NODISCARD
365static BOOL rdp_apply_bitmap_capability_set(rdpSettings* settings, const rdpSettings* src)
366{
367 WINPR_ASSERT(settings);
368 WINPR_ASSERT(src);
369
370 if (!settings->ServerMode)
371 {
372 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
373 freerdp_settings_get_uint32(src, FreeRDP_ColorDepth)))
374 return FALSE;
375 }
376
377 if (!src->DesktopResize)
378 settings->DesktopResize = FALSE;
379
380 if (!settings->ServerMode && settings->DesktopResize)
381 {
382 /* The server may request a different desktop size during Deactivation-Reactivation sequence
383 */
384 settings->DesktopWidth = src->DesktopWidth;
385 settings->DesktopHeight = src->DesktopHeight;
386 }
387
388 if (settings->DrawAllowSkipAlpha)
389 settings->DrawAllowSkipAlpha = src->DrawAllowSkipAlpha;
390
391 if (settings->DrawAllowDynamicColorFidelity)
392 settings->DrawAllowDynamicColorFidelity = src->DrawAllowDynamicColorFidelity;
393
394 if (settings->DrawAllowColorSubsampling)
395 settings->DrawAllowColorSubsampling = src->DrawAllowColorSubsampling;
396
397 return TRUE;
398}
399
400/*
401 * Read bitmap capability set.
402 * msdn{cc240554}
403 */
404WINPR_ATTR_NODISCARD
405static BOOL rdp_read_bitmap_capability_set(wLog* log, wStream* s, rdpSettings* settings)
406{
407 BYTE drawingFlags = 0;
408 UINT16 desktopWidth = 0;
409 UINT16 desktopHeight = 0;
410 UINT16 desktopResizeFlag = 0;
411 UINT16 preferredBitsPerPixel = 0;
412
413 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 24))
414 return FALSE;
415
416 Stream_Read_UINT16(s, preferredBitsPerPixel); /* preferredBitsPerPixel (2 bytes) */
417 Stream_Seek_UINT16(s); /* receive1BitPerPixel (2 bytes) */
418 Stream_Seek_UINT16(s); /* receive4BitsPerPixel (2 bytes) */
419 Stream_Seek_UINT16(s); /* receive8BitsPerPixel (2 bytes) */
420 Stream_Read_UINT16(s, desktopWidth); /* desktopWidth (2 bytes) */
421 Stream_Read_UINT16(s, desktopHeight); /* desktopHeight (2 bytes) */
422 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
423 Stream_Read_UINT16(s, desktopResizeFlag); /* desktopResizeFlag (2 bytes) */
424 Stream_Seek_UINT16(s); /* bitmapCompressionFlag (2 bytes) */
425 Stream_Seek_UINT8(s); /* highColorFlags (1 byte) */
426 Stream_Read_UINT8(s, drawingFlags); /* drawingFlags (1 byte) */
427 Stream_Seek_UINT16(s); /* multipleRectangleSupport (2 bytes) */
428 Stream_Seek_UINT16(s); /* pad2OctetsB (2 bytes) */
429
430 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, preferredBitsPerPixel))
431 return FALSE;
432 settings->DesktopResize = desktopResizeFlag;
433 settings->DesktopWidth = desktopWidth;
434 settings->DesktopHeight = desktopHeight;
435 settings->DrawAllowSkipAlpha = (drawingFlags & DRAW_ALLOW_SKIP_ALPHA) != 0;
436 settings->DrawAllowDynamicColorFidelity =
437 (drawingFlags & DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY) != 0;
438 settings->DrawAllowColorSubsampling = (drawingFlags & DRAW_ALLOW_COLOR_SUBSAMPLING) != 0;
439
440 return TRUE;
441}
442
443/*
444 * Write bitmap capability set.
445 * msdn{cc240554}
446 */
447WINPR_ATTR_NODISCARD
448static BOOL rdp_write_bitmap_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
449{
450 BYTE drawingFlags = 0;
451 UINT16 preferredBitsPerPixel = 0;
452
453 if (!Stream_EnsureRemainingCapacity(s, 64))
454 return FALSE;
455
456 const size_t header = rdp_capability_set_start(log, s);
457
458 WINPR_ASSERT(settings);
459 if (settings->DrawAllowSkipAlpha)
460 drawingFlags |= DRAW_ALLOW_SKIP_ALPHA;
461
462 if (settings->DrawAllowDynamicColorFidelity)
463 drawingFlags |= DRAW_ALLOW_DYNAMIC_COLOR_FIDELITY;
464
465 if (settings->DrawAllowColorSubsampling)
466 drawingFlags |= DRAW_ALLOW_COLOR_SUBSAMPLING; /* currently unimplemented */
467
468 /* While bitmap_decode.c now implements YCoCg, in turning it
469 * on we have found Microsoft is inconsistent on whether to invert R & B.
470 * And it's not only from one server to another; on Win7/2008R2, it appears
471 * to send the main content with a different inversion than the Windows
472 * button! So... don't advertise that we support YCoCg and the server
473 * will not send it. YCoCg is still needed for EGFX, but it at least
474 * appears consistent in its use.
475 */
476
477 if ((freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) > UINT16_MAX) ||
478 (settings->DesktopWidth > UINT16_MAX) || (settings->DesktopHeight > UINT16_MAX))
479 return FALSE;
480
481 if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
482 preferredBitsPerPixel = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
483 else
484 preferredBitsPerPixel = 8;
485
486 Stream_Write_UINT16(s, preferredBitsPerPixel); /* preferredBitsPerPixel (2 bytes) */
487 Stream_Write_UINT16(s, 1); /* receive1BitPerPixel (2 bytes) */
488 Stream_Write_UINT16(s, 1); /* receive4BitsPerPixel (2 bytes) */
489 Stream_Write_UINT16(s, 1); /* receive8BitsPerPixel (2 bytes) */
490 Stream_Write_UINT16(s, (UINT16)settings->DesktopWidth); /* desktopWidth (2 bytes) */
491 Stream_Write_UINT16(s, (UINT16)settings->DesktopHeight); /* desktopHeight (2 bytes) */
492 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
493 Stream_Write_UINT16(s, (UINT16)settings->DesktopResize); /* desktopResizeFlag (2 bytes) */
494 Stream_Write_UINT16(s, 1); /* bitmapCompressionFlag (2 bytes) */
495 Stream_Write_UINT8(s, 0); /* highColorFlags (1 byte) */
496 Stream_Write_UINT8(s, drawingFlags); /* drawingFlags (1 byte) */
497 Stream_Write_UINT16(s, 1); /* multipleRectangleSupport (2 bytes) */
498 Stream_Write_UINT16(s, 0); /* pad2OctetsB (2 bytes) */
499 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP);
500}
501
502#ifdef WITH_DEBUG_CAPABILITIES
503WINPR_ATTR_NODISCARD
504static BOOL rdp_print_bitmap_capability_set(wLog* log, wStream* s)
505{
506 UINT16 preferredBitsPerPixel = 0;
507 UINT16 receive1BitPerPixel = 0;
508 UINT16 receive4BitsPerPixel = 0;
509 UINT16 receive8BitsPerPixel = 0;
510 UINT16 desktopWidth = 0;
511 UINT16 desktopHeight = 0;
512 UINT16 pad2Octets = 0;
513 UINT16 desktopResizeFlag = 0;
514 UINT16 bitmapCompressionFlag = 0;
515 BYTE highColorFlags = 0;
516 BYTE drawingFlags = 0;
517 UINT16 multipleRectangleSupport = 0;
518 UINT16 pad2OctetsB = 0;
519 WLog_Print(log, WLOG_TRACE,
520 "BitmapCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
521
522 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 24))
523 return FALSE;
524
525 Stream_Read_UINT16(s, preferredBitsPerPixel); /* preferredBitsPerPixel (2 bytes) */
526 Stream_Read_UINT16(s, receive1BitPerPixel); /* receive1BitPerPixel (2 bytes) */
527 Stream_Read_UINT16(s, receive4BitsPerPixel); /* receive4BitsPerPixel (2 bytes) */
528 Stream_Read_UINT16(s, receive8BitsPerPixel); /* receive8BitsPerPixel (2 bytes) */
529 Stream_Read_UINT16(s, desktopWidth); /* desktopWidth (2 bytes) */
530 Stream_Read_UINT16(s, desktopHeight); /* desktopHeight (2 bytes) */
531 Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
532 Stream_Read_UINT16(s, desktopResizeFlag); /* desktopResizeFlag (2 bytes) */
533 Stream_Read_UINT16(s, bitmapCompressionFlag); /* bitmapCompressionFlag (2 bytes) */
534 Stream_Read_UINT8(s, highColorFlags); /* highColorFlags (1 byte) */
535 Stream_Read_UINT8(s, drawingFlags); /* drawingFlags (1 byte) */
536 Stream_Read_UINT16(s, multipleRectangleSupport); /* multipleRectangleSupport (2 bytes) */
537 Stream_Read_UINT16(s, pad2OctetsB); /* pad2OctetsB (2 bytes) */
538 WLog_Print(log, WLOG_TRACE, "\tpreferredBitsPerPixel: 0x%04" PRIX16 "", preferredBitsPerPixel);
539 WLog_Print(log, WLOG_TRACE, "\treceive1BitPerPixel: 0x%04" PRIX16 "", receive1BitPerPixel);
540 WLog_Print(log, WLOG_TRACE, "\treceive4BitsPerPixel: 0x%04" PRIX16 "", receive4BitsPerPixel);
541 WLog_Print(log, WLOG_TRACE, "\treceive8BitsPerPixel: 0x%04" PRIX16 "", receive8BitsPerPixel);
542 WLog_Print(log, WLOG_TRACE, "\tdesktopWidth: 0x%04" PRIX16 "", desktopWidth);
543 WLog_Print(log, WLOG_TRACE, "\tdesktopHeight: 0x%04" PRIX16 "", desktopHeight);
544 WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
545 WLog_Print(log, WLOG_TRACE, "\tdesktopResizeFlag: 0x%04" PRIX16 "", desktopResizeFlag);
546 WLog_Print(log, WLOG_TRACE, "\tbitmapCompressionFlag: 0x%04" PRIX16 "", bitmapCompressionFlag);
547 WLog_Print(log, WLOG_TRACE, "\thighColorFlags: 0x%02" PRIX8 "", highColorFlags);
548 WLog_Print(log, WLOG_TRACE, "\tdrawingFlags: 0x%02" PRIX8 "", drawingFlags);
549 WLog_Print(log, WLOG_TRACE, "\tmultipleRectangleSupport: 0x%04" PRIX16 "",
550 multipleRectangleSupport);
551 WLog_Print(log, WLOG_TRACE, "\tpad2OctetsB: 0x%04" PRIX16 "", pad2OctetsB);
552 return TRUE;
553}
554#endif
555
556WINPR_ATTR_NODISCARD
557static BOOL rdp_apply_order_capability_set(rdpSettings* settings, const rdpSettings* src)
558{
559 WINPR_ASSERT(settings);
560 WINPR_ASSERT(src);
561
562 BOOL BitmapCacheV3Enabled = FALSE;
563 BOOL FrameMarkerCommandEnabled = FALSE;
564
565 for (size_t i = 0; i < 32; i++)
566 {
567 if (!src->OrderSupport[i])
568 settings->OrderSupport[i] = FALSE;
569 }
570
571 if (src->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
572 {
573 if (src->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT)
574 BitmapCacheV3Enabled = TRUE;
575
576 if (src->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT)
577 FrameMarkerCommandEnabled = TRUE;
578 }
579
580 if (BitmapCacheV3Enabled && settings->BitmapCacheV3Enabled)
581 {
582 settings->BitmapCacheV3Enabled = src->BitmapCacheV3Enabled;
583 settings->BitmapCacheVersion = src->BitmapCacheVersion;
584 }
585 else
586 settings->BitmapCacheV3Enabled = FALSE;
587
588 settings->FrameMarkerCommandEnabled =
589 (FrameMarkerCommandEnabled && src->FrameMarkerCommandEnabled);
590
591 return TRUE;
592}
593
594/*
595 * Read order capability set.
596 * msdn{cc240556}
597 */
598WINPR_ATTR_NODISCARD
599static BOOL rdp_read_order_capability_set(wLog* log, wStream* s, rdpSettings* settings)
600{
601 char terminalDescriptor[17] = WINPR_C_ARRAY_INIT;
602 BYTE orderSupport[32] = WINPR_C_ARRAY_INIT;
603 BOOL BitmapCacheV3Enabled = FALSE;
604 BOOL FrameMarkerCommandEnabled = FALSE;
605
606 WINPR_ASSERT(settings);
607 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
608 return FALSE;
609
610 Stream_Read(s, terminalDescriptor, 16); /* terminalDescriptor (16 bytes) */
611 Stream_Seek_UINT32(s); /* pad4OctetsA (4 bytes) */
612 Stream_Seek_UINT16(s); /* desktopSaveXGranularity (2 bytes) */
613 Stream_Seek_UINT16(s); /* desktopSaveYGranularity (2 bytes) */
614 Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */
615 Stream_Seek_UINT16(s); /* maximumOrderLevel (2 bytes) */
616 Stream_Seek_UINT16(s); /* numberFonts (2 bytes) */
617 Stream_Read_UINT16(s, settings->OrderSupportFlags); /* orderFlags (2 bytes) */
618 Stream_Read(s, orderSupport, 32); /* orderSupport (32 bytes) */
619 Stream_Seek_UINT16(s); /* textFlags (2 bytes) */
620 Stream_Read_UINT16(s, settings->OrderSupportFlagsEx); /* orderSupportExFlags (2 bytes) */
621 Stream_Seek_UINT32(s); /* pad4OctetsB (4 bytes) */
622 Stream_Seek_UINT32(s); /* desktopSaveSize (4 bytes) */
623 Stream_Seek_UINT16(s); /* pad2OctetsC (2 bytes) */
624 Stream_Seek_UINT16(s); /* pad2OctetsD (2 bytes) */
625 Stream_Read_UINT16(s, settings->TextANSICodePage); /* textANSICodePage (2 bytes) */
626 Stream_Seek_UINT16(s); /* pad2OctetsE (2 bytes) */
627
628 if (!freerdp_settings_set_string(settings, FreeRDP_TerminalDescriptor, terminalDescriptor))
629 return FALSE;
630
631 for (size_t i = 0; i < ARRAYSIZE(orderSupport); i++)
632 settings->OrderSupport[i] = orderSupport[i];
633
634 if (settings->OrderSupportFlags & ORDER_FLAGS_EXTRA_SUPPORT)
635 {
636 BitmapCacheV3Enabled = (settings->OrderSupportFlagsEx & CACHE_BITMAP_V3_SUPPORT) != 0;
637 FrameMarkerCommandEnabled =
638 (settings->OrderSupportFlagsEx & ALTSEC_FRAME_MARKER_SUPPORT) != 0;
639 }
640
641 settings->BitmapCacheV3Enabled = BitmapCacheV3Enabled;
642 if (BitmapCacheV3Enabled)
643 settings->BitmapCacheVersion = 3;
644
645 settings->FrameMarkerCommandEnabled = FrameMarkerCommandEnabled;
646
647 return TRUE;
648}
649
650/*
651 * Write order capability set.
652 * msdn{cc240556}
653 */
654WINPR_ATTR_NODISCARD
655static BOOL rdp_write_order_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
656{
657 char terminalDescriptor[16] = WINPR_C_ARRAY_INIT;
658
659 WINPR_ASSERT(settings);
660 if (!Stream_EnsureRemainingCapacity(s, 64))
661 return FALSE;
662
663 const size_t header = rdp_capability_set_start(log, s);
664
665 UINT16 orderSupportExFlags = settings->OrderSupportFlagsEx;
666 UINT16 orderFlags = settings->OrderSupportFlags;
667
668 if (settings->BitmapCacheV3Enabled)
669 {
670 if ((orderSupportExFlags & CACHE_BITMAP_V3_SUPPORT) == 0)
671 {
672 WLog_Print(log, WLOG_WARN,
673 "rdpSettings::BitmapCacheV3Enabled=TRUE, but CACHE_BITMAP_V3_SUPPORT not "
674 "set in rdpSettings::OrderSupportEx, aborting.");
675 }
676 if ((orderFlags & ORDER_FLAGS_EXTRA_SUPPORT) == 0)
677 {
678 WLog_Print(log, WLOG_WARN,
679 "rdpSettings::BitmapCacheV3Enabled=TRUE, but ORDER_FLAGS_EXTRA_SUPPORT not "
680 "set in rdpSettings::OrderSupport, aborting.");
681 }
682 }
683
684 if (settings->FrameMarkerCommandEnabled)
685 {
686 if ((orderSupportExFlags & ALTSEC_FRAME_MARKER_SUPPORT) == 0)
687 {
688 WLog_Print(
689 log, WLOG_WARN,
690 "rdpSettings::FrameMarkerCommandEnabled=TRUE, but "
691 "ALTSEC_FRAME_MARKER_SUPPORT not set in rdpSettings::OrderSupportEx, aborting.");
692 }
693 if ((orderFlags & ORDER_FLAGS_EXTRA_SUPPORT) == 0)
694 {
695 WLog_Print(log, WLOG_WARN,
696 "rdpSettings::FrameMarkerCommandEnabled=TRUE, but ORDER_FLAGS_EXTRA_SUPPORT "
697 "not set in rdpSettings::OrderSupport, aborting.");
698 }
699 }
700
701 const char* dsc = freerdp_settings_get_string(settings, FreeRDP_TerminalDescriptor);
702 if (dsc)
703 {
704 const size_t len = strnlen(dsc, ARRAYSIZE(terminalDescriptor));
705 strncpy(terminalDescriptor, dsc, len);
706 }
707 Stream_Write(s, terminalDescriptor,
708 sizeof(terminalDescriptor)); /* terminalDescriptor (16 bytes) */
709 Stream_Write_UINT32(s, 0); /* pad4OctetsA (4 bytes) */
710 Stream_Write_UINT16(s, 1); /* desktopSaveXGranularity (2 bytes) */
711 Stream_Write_UINT16(s, 20); /* desktopSaveYGranularity (2 bytes) */
712 Stream_Write_UINT16(s, 0); /* pad2OctetsA (2 bytes) */
713 Stream_Write_UINT16(s, 1); /* maximumOrderLevel (2 bytes) */
714 Stream_Write_UINT16(s, 0); /* numberFonts (2 bytes) */
715 Stream_Write_UINT16(s, orderFlags); /* orderFlags (2 bytes) */
716 Stream_Write(s, settings->OrderSupport, 32); /* orderSupport (32 bytes) */
717 Stream_Write_UINT16(s, 0); /* textFlags (2 bytes) */
718 Stream_Write_UINT16(s, orderSupportExFlags); /* orderSupportExFlags (2 bytes) */
719 Stream_Write_UINT32(s, 0); /* pad4OctetsB (4 bytes) */
720 Stream_Write_UINT32(s, 230400); /* desktopSaveSize (4 bytes) */
721 Stream_Write_UINT16(s, 0); /* pad2OctetsC (2 bytes) */
722 Stream_Write_UINT16(s, 0); /* pad2OctetsD (2 bytes) */
723 Stream_Write_UINT16(s, settings->TextANSICodePage); /* textANSICodePage (2 bytes) */
724 Stream_Write_UINT16(s, 0); /* pad2OctetsE (2 bytes) */
725 return rdp_capability_set_finish(s, header, CAPSET_TYPE_ORDER);
726}
727
728#ifdef WITH_DEBUG_CAPABILITIES
729WINPR_ATTR_NODISCARD
730static BOOL rdp_print_order_capability_set(wLog* log, wStream* s)
731{
732 BYTE terminalDescriptor[16];
733 UINT32 pad4OctetsA = 0;
734 UINT16 desktopSaveXGranularity = 0;
735 UINT16 desktopSaveYGranularity = 0;
736 UINT16 pad2OctetsA = 0;
737 UINT16 maximumOrderLevel = 0;
738 UINT16 numberFonts = 0;
739 UINT16 orderFlags = 0;
740 BYTE orderSupport[32];
741 UINT16 textFlags = 0;
742 UINT16 orderSupportExFlags = 0;
743 UINT32 pad4OctetsB = 0;
744 UINT32 desktopSaveSize = 0;
745 UINT16 pad2OctetsC = 0;
746 UINT16 pad2OctetsD = 0;
747 UINT16 textANSICodePage = 0;
748 UINT16 pad2OctetsE = 0;
749 WLog_Print(log, WLOG_TRACE,
750 "OrderCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
751
752 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
753 return FALSE;
754
755 Stream_Read(s, terminalDescriptor, 16); /* terminalDescriptor (16 bytes) */
756 Stream_Read_UINT32(s, pad4OctetsA); /* pad4OctetsA (4 bytes) */
757 Stream_Read_UINT16(s, desktopSaveXGranularity); /* desktopSaveXGranularity (2 bytes) */
758 Stream_Read_UINT16(s, desktopSaveYGranularity); /* desktopSaveYGranularity (2 bytes) */
759 Stream_Read_UINT16(s, pad2OctetsA); /* pad2OctetsA (2 bytes) */
760 Stream_Read_UINT16(s, maximumOrderLevel); /* maximumOrderLevel (2 bytes) */
761 Stream_Read_UINT16(s, numberFonts); /* numberFonts (2 bytes) */
762 Stream_Read_UINT16(s, orderFlags); /* orderFlags (2 bytes) */
763 Stream_Read(s, orderSupport, 32); /* orderSupport (32 bytes) */
764 Stream_Read_UINT16(s, textFlags); /* textFlags (2 bytes) */
765 Stream_Read_UINT16(s, orderSupportExFlags); /* orderSupportExFlags (2 bytes) */
766 Stream_Read_UINT32(s, pad4OctetsB); /* pad4OctetsB (4 bytes) */
767 Stream_Read_UINT32(s, desktopSaveSize); /* desktopSaveSize (4 bytes) */
768 Stream_Read_UINT16(s, pad2OctetsC); /* pad2OctetsC (2 bytes) */
769 Stream_Read_UINT16(s, pad2OctetsD); /* pad2OctetsD (2 bytes) */
770 Stream_Read_UINT16(s, textANSICodePage); /* textANSICodePage (2 bytes) */
771 Stream_Read_UINT16(s, pad2OctetsE); /* pad2OctetsE (2 bytes) */
772 WLog_Print(log, WLOG_TRACE, "\tpad4OctetsA: 0x%08" PRIX32 "", pad4OctetsA);
773 WLog_Print(log, WLOG_TRACE, "\tdesktopSaveXGranularity: 0x%04" PRIX16 "",
774 desktopSaveXGranularity);
775 WLog_Print(log, WLOG_TRACE, "\tdesktopSaveYGranularity: 0x%04" PRIX16 "",
776 desktopSaveYGranularity);
777 WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
778 WLog_Print(log, WLOG_TRACE, "\tmaximumOrderLevel: 0x%04" PRIX16 "", maximumOrderLevel);
779 WLog_Print(log, WLOG_TRACE, "\tnumberFonts: 0x%04" PRIX16 "", numberFonts);
780 WLog_Print(log, WLOG_TRACE, "\torderFlags: 0x%04" PRIX16 "", orderFlags);
781 WLog_Print(log, WLOG_TRACE, "\torderSupport:");
782 WLog_Print(log, WLOG_TRACE, "\t\tDSTBLT: %" PRIu8 "", orderSupport[NEG_DSTBLT_INDEX]);
783 WLog_Print(log, WLOG_TRACE, "\t\tPATBLT: %" PRIu8 "", orderSupport[NEG_PATBLT_INDEX]);
784 WLog_Print(log, WLOG_TRACE, "\t\tSCRBLT: %" PRIu8 "", orderSupport[NEG_SCRBLT_INDEX]);
785 WLog_Print(log, WLOG_TRACE, "\t\tMEMBLT: %" PRIu8 "", orderSupport[NEG_MEMBLT_INDEX]);
786 WLog_Print(log, WLOG_TRACE, "\t\tMEM3BLT: %" PRIu8 "", orderSupport[NEG_MEM3BLT_INDEX]);
787 WLog_Print(log, WLOG_TRACE, "\t\tATEXTOUT: %" PRIu8 "", orderSupport[NEG_ATEXTOUT_INDEX]);
788 WLog_Print(log, WLOG_TRACE, "\t\tAEXTTEXTOUT: %" PRIu8 "", orderSupport[NEG_AEXTTEXTOUT_INDEX]);
789 WLog_Print(log, WLOG_TRACE, "\t\tDRAWNINEGRID: %" PRIu8 "",
790 orderSupport[NEG_DRAWNINEGRID_INDEX]);
791 WLog_Print(log, WLOG_TRACE, "\t\tLINETO: %" PRIu8 "", orderSupport[NEG_LINETO_INDEX]);
792 WLog_Print(log, WLOG_TRACE, "\t\tMULTI_DRAWNINEGRID: %" PRIu8 "",
793 orderSupport[NEG_MULTI_DRAWNINEGRID_INDEX]);
794 WLog_Print(log, WLOG_TRACE, "\t\tOPAQUE_RECT: %" PRIu8 "", orderSupport[NEG_OPAQUE_RECT_INDEX]);
795 WLog_Print(log, WLOG_TRACE, "\t\tSAVEBITMAP: %" PRIu8 "", orderSupport[NEG_SAVEBITMAP_INDEX]);
796 WLog_Print(log, WLOG_TRACE, "\t\tWTEXTOUT: %" PRIu8 "", orderSupport[NEG_WTEXTOUT_INDEX]);
797 WLog_Print(log, WLOG_TRACE, "\t\tMEMBLT_V2: %" PRIu8 "", orderSupport[NEG_MEMBLT_V2_INDEX]);
798 WLog_Print(log, WLOG_TRACE, "\t\tMEM3BLT_V2: %" PRIu8 "", orderSupport[NEG_MEM3BLT_V2_INDEX]);
799 WLog_Print(log, WLOG_TRACE, "\t\tMULTIDSTBLT: %" PRIu8 "", orderSupport[NEG_MULTIDSTBLT_INDEX]);
800 WLog_Print(log, WLOG_TRACE, "\t\tMULTIPATBLT: %" PRIu8 "", orderSupport[NEG_MULTIPATBLT_INDEX]);
801 WLog_Print(log, WLOG_TRACE, "\t\tMULTISCRBLT: %" PRIu8 "", orderSupport[NEG_MULTISCRBLT_INDEX]);
802 WLog_Print(log, WLOG_TRACE, "\t\tMULTIOPAQUERECT: %" PRIu8 "",
803 orderSupport[NEG_MULTIOPAQUERECT_INDEX]);
804 WLog_Print(log, WLOG_TRACE, "\t\tFAST_INDEX: %" PRIu8 "", orderSupport[NEG_FAST_INDEX_INDEX]);
805 WLog_Print(log, WLOG_TRACE, "\t\tPOLYGON_SC: %" PRIu8 "", orderSupport[NEG_POLYGON_SC_INDEX]);
806 WLog_Print(log, WLOG_TRACE, "\t\tPOLYGON_CB: %" PRIu8 "", orderSupport[NEG_POLYGON_CB_INDEX]);
807 WLog_Print(log, WLOG_TRACE, "\t\tPOLYLINE: %" PRIu8 "", orderSupport[NEG_POLYLINE_INDEX]);
808 WLog_Print(log, WLOG_TRACE, "\t\tUNUSED23: %" PRIu8 "", orderSupport[NEG_UNUSED23_INDEX]);
809 WLog_Print(log, WLOG_TRACE, "\t\tFAST_GLYPH: %" PRIu8 "", orderSupport[NEG_FAST_GLYPH_INDEX]);
810 WLog_Print(log, WLOG_TRACE, "\t\tELLIPSE_SC: %" PRIu8 "", orderSupport[NEG_ELLIPSE_SC_INDEX]);
811 WLog_Print(log, WLOG_TRACE, "\t\tELLIPSE_CB: %" PRIu8 "", orderSupport[NEG_ELLIPSE_CB_INDEX]);
812 WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_INDEX: %" PRIu8 "", orderSupport[NEG_GLYPH_INDEX_INDEX]);
813 WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_WEXTTEXTOUT: %" PRIu8 "",
814 orderSupport[NEG_GLYPH_WEXTTEXTOUT_INDEX]);
815 WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_WLONGTEXTOUT: %" PRIu8 "",
816 orderSupport[NEG_GLYPH_WLONGTEXTOUT_INDEX]);
817 WLog_Print(log, WLOG_TRACE, "\t\tGLYPH_WLONGEXTTEXTOUT: %" PRIu8 "",
818 orderSupport[NEG_GLYPH_WLONGEXTTEXTOUT_INDEX]);
819 WLog_Print(log, WLOG_TRACE, "\t\tUNUSED31: %" PRIu8 "", orderSupport[NEG_UNUSED31_INDEX]);
820 WLog_Print(log, WLOG_TRACE, "\ttextFlags: 0x%04" PRIX16 "", textFlags);
821 WLog_Print(log, WLOG_TRACE, "\torderSupportExFlags: 0x%04" PRIX16 "", orderSupportExFlags);
822 WLog_Print(log, WLOG_TRACE, "\tpad4OctetsB: 0x%08" PRIX32 "", pad4OctetsB);
823 WLog_Print(log, WLOG_TRACE, "\tdesktopSaveSize: 0x%08" PRIX32 "", desktopSaveSize);
824 WLog_Print(log, WLOG_TRACE, "\tpad2OctetsC: 0x%04" PRIX16 "", pad2OctetsC);
825 WLog_Print(log, WLOG_TRACE, "\tpad2OctetsD: 0x%04" PRIX16 "", pad2OctetsD);
826 WLog_Print(log, WLOG_TRACE, "\ttextANSICodePage: 0x%04" PRIX16 "", textANSICodePage);
827 WLog_Print(log, WLOG_TRACE, "\tpad2OctetsE: 0x%04" PRIX16 "", pad2OctetsE);
828 return TRUE;
829}
830#endif
831
832WINPR_ATTR_NODISCARD
833static BOOL rdp_apply_bitmap_cache_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
834 WINPR_ATTR_UNUSED const rdpSettings* src)
835{
836 WINPR_ASSERT(settings);
837 WINPR_ASSERT(src);
838 return TRUE;
839}
840
841/*
842 * Read bitmap cache capability set.
843 * msdn{cc240559}
844 */
845WINPR_ATTR_NODISCARD
846static BOOL rdp_read_bitmap_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
847{
848 WINPR_UNUSED(settings);
849 WINPR_ASSERT(settings);
850
851 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
852 return FALSE;
853
854 Stream_Seek_UINT32(s); /* pad1 (4 bytes) */
855 Stream_Seek_UINT32(s); /* pad2 (4 bytes) */
856 Stream_Seek_UINT32(s); /* pad3 (4 bytes) */
857 Stream_Seek_UINT32(s); /* pad4 (4 bytes) */
858 Stream_Seek_UINT32(s); /* pad5 (4 bytes) */
859 Stream_Seek_UINT32(s); /* pad6 (4 bytes) */
860 Stream_Seek_UINT16(s); /* Cache0Entries (2 bytes) */
861 Stream_Seek_UINT16(s); /* Cache0MaximumCellSize (2 bytes) */
862 Stream_Seek_UINT16(s); /* Cache1Entries (2 bytes) */
863 Stream_Seek_UINT16(s); /* Cache1MaximumCellSize (2 bytes) */
864 Stream_Seek_UINT16(s); /* Cache2Entries (2 bytes) */
865 Stream_Seek_UINT16(s); /* Cache2MaximumCellSize (2 bytes) */
866 return TRUE;
867}
868
869/*
870 * Write bitmap cache capability set.
871 * msdn{cc240559}
872 */
873WINPR_ATTR_NODISCARD
874static BOOL rdp_write_bitmap_cache_capability_set(wLog* log, wStream* s,
875 const rdpSettings* settings)
876{
877 if (!Stream_EnsureRemainingCapacity(s, 64))
878 return FALSE;
879
880 const size_t header = rdp_capability_set_start(log, s);
881 const UINT32 bpp = (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) + 7) / 8;
882 if (bpp > UINT16_MAX)
883 return FALSE;
884 Stream_Write_UINT32(s, 0); /* pad1 (4 bytes) */
885 Stream_Write_UINT32(s, 0); /* pad2 (4 bytes) */
886 Stream_Write_UINT32(s, 0); /* pad3 (4 bytes) */
887 Stream_Write_UINT32(s, 0); /* pad4 (4 bytes) */
888 Stream_Write_UINT32(s, 0); /* pad5 (4 bytes) */
889 Stream_Write_UINT32(s, 0); /* pad6 (4 bytes) */
890 UINT32 size = bpp * 256;
891 if (size > UINT16_MAX)
892 return FALSE;
893 Stream_Write_UINT16(s, 200); /* Cache0Entries (2 bytes) */
894 Stream_Write_UINT16(s, (UINT16)size); /* Cache0MaximumCellSize (2 bytes) */
895 size = bpp * 1024;
896 if (size > UINT16_MAX)
897 return FALSE;
898 Stream_Write_UINT16(s, 600); /* Cache1Entries (2 bytes) */
899 Stream_Write_UINT16(s, (UINT16)size); /* Cache1MaximumCellSize (2 bytes) */
900 size = bpp * 4096;
901 if (size > UINT16_MAX)
902 return FALSE;
903 Stream_Write_UINT16(s, 1000); /* Cache2Entries (2 bytes) */
904 Stream_Write_UINT16(s, (UINT16)size); /* Cache2MaximumCellSize (2 bytes) */
905 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE);
906}
907
908#ifdef WITH_DEBUG_CAPABILITIES
909WINPR_ATTR_NODISCARD
910static BOOL rdp_print_bitmap_cache_capability_set(wLog* log, wStream* s)
911{
912 UINT32 pad1 = 0;
913 UINT32 pad2 = 0;
914 UINT32 pad3 = 0;
915 UINT32 pad4 = 0;
916 UINT32 pad5 = 0;
917 UINT32 pad6 = 0;
918 UINT16 Cache0Entries = 0;
919 UINT16 Cache0MaximumCellSize = 0;
920 UINT16 Cache1Entries = 0;
921 UINT16 Cache1MaximumCellSize = 0;
922 UINT16 Cache2Entries = 0;
923 UINT16 Cache2MaximumCellSize = 0;
924 WLog_Print(log, WLOG_TRACE,
925 "BitmapCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
926
927 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
928 return FALSE;
929
930 Stream_Read_UINT32(s, pad1); /* pad1 (4 bytes) */
931 Stream_Read_UINT32(s, pad2); /* pad2 (4 bytes) */
932 Stream_Read_UINT32(s, pad3); /* pad3 (4 bytes) */
933 Stream_Read_UINT32(s, pad4); /* pad4 (4 bytes) */
934 Stream_Read_UINT32(s, pad5); /* pad5 (4 bytes) */
935 Stream_Read_UINT32(s, pad6); /* pad6 (4 bytes) */
936 Stream_Read_UINT16(s, Cache0Entries); /* Cache0Entries (2 bytes) */
937 Stream_Read_UINT16(s, Cache0MaximumCellSize); /* Cache0MaximumCellSize (2 bytes) */
938 Stream_Read_UINT16(s, Cache1Entries); /* Cache1Entries (2 bytes) */
939 Stream_Read_UINT16(s, Cache1MaximumCellSize); /* Cache1MaximumCellSize (2 bytes) */
940 Stream_Read_UINT16(s, Cache2Entries); /* Cache2Entries (2 bytes) */
941 Stream_Read_UINT16(s, Cache2MaximumCellSize); /* Cache2MaximumCellSize (2 bytes) */
942 WLog_Print(log, WLOG_TRACE, "\tpad1: 0x%08" PRIX32 "", pad1);
943 WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%08" PRIX32 "", pad2);
944 WLog_Print(log, WLOG_TRACE, "\tpad3: 0x%08" PRIX32 "", pad3);
945 WLog_Print(log, WLOG_TRACE, "\tpad4: 0x%08" PRIX32 "", pad4);
946 WLog_Print(log, WLOG_TRACE, "\tpad5: 0x%08" PRIX32 "", pad5);
947 WLog_Print(log, WLOG_TRACE, "\tpad6: 0x%08" PRIX32 "", pad6);
948 WLog_Print(log, WLOG_TRACE, "\tCache0Entries: 0x%04" PRIX16 "", Cache0Entries);
949 WLog_Print(log, WLOG_TRACE, "\tCache0MaximumCellSize: 0x%04" PRIX16 "", Cache0MaximumCellSize);
950 WLog_Print(log, WLOG_TRACE, "\tCache1Entries: 0x%04" PRIX16 "", Cache1Entries);
951 WLog_Print(log, WLOG_TRACE, "\tCache1MaximumCellSize: 0x%04" PRIX16 "", Cache1MaximumCellSize);
952 WLog_Print(log, WLOG_TRACE, "\tCache2Entries: 0x%04" PRIX16 "", Cache2Entries);
953 WLog_Print(log, WLOG_TRACE, "\tCache2MaximumCellSize: 0x%04" PRIX16 "", Cache2MaximumCellSize);
954 return TRUE;
955}
956#endif
957
958WINPR_ATTR_NODISCARD
959static BOOL rdp_apply_control_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
960 WINPR_ATTR_UNUSED const rdpSettings* src)
961{
962 WINPR_ASSERT(settings);
963 WINPR_ASSERT(src);
964
965 return TRUE;
966}
967
968/*
969 * Read control capability set.
970 * msdn{cc240568}
971 */
972WINPR_ATTR_NODISCARD
973static BOOL rdp_read_control_capability_set(wLog* log, wStream* s, rdpSettings* settings)
974{
975 WINPR_UNUSED(settings);
976 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
977 return FALSE;
978
979 Stream_Seek_UINT16(s); /* controlFlags (2 bytes) */
980 Stream_Seek_UINT16(s); /* remoteDetachFlag (2 bytes) */
981 Stream_Seek_UINT16(s); /* controlInterest (2 bytes) */
982 Stream_Seek_UINT16(s); /* detachInterest (2 bytes) */
983 return TRUE;
984}
985
986/*
987 * Write control capability set.
988 * msdn{cc240568}
989 */
990WINPR_ATTR_NODISCARD
991static BOOL rdp_write_control_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
992{
993 WINPR_UNUSED(settings);
994 if (!Stream_EnsureRemainingCapacity(s, 32))
995 return FALSE;
996
997 const size_t header = rdp_capability_set_start(log, s);
998 Stream_Write_UINT16(s, 0); /* controlFlags (2 bytes) */
999 Stream_Write_UINT16(s, 0); /* remoteDetachFlag (2 bytes) */
1000 Stream_Write_UINT16(s, 2); /* controlInterest (2 bytes) */
1001 Stream_Write_UINT16(s, 2); /* detachInterest (2 bytes) */
1002 return rdp_capability_set_finish(s, header, CAPSET_TYPE_CONTROL);
1003}
1004
1005#ifdef WITH_DEBUG_CAPABILITIES
1006WINPR_ATTR_NODISCARD
1007static BOOL rdp_print_control_capability_set(wLog* log, wStream* s)
1008{
1009 UINT16 controlFlags = 0;
1010 UINT16 remoteDetachFlag = 0;
1011 UINT16 controlInterest = 0;
1012 UINT16 detachInterest = 0;
1013 WLog_Print(log, WLOG_TRACE,
1014 "ControlCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1015
1016 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1017 return FALSE;
1018
1019 Stream_Read_UINT16(s, controlFlags); /* controlFlags (2 bytes) */
1020 Stream_Read_UINT16(s, remoteDetachFlag); /* remoteDetachFlag (2 bytes) */
1021 Stream_Read_UINT16(s, controlInterest); /* controlInterest (2 bytes) */
1022 Stream_Read_UINT16(s, detachInterest); /* detachInterest (2 bytes) */
1023 WLog_Print(log, WLOG_TRACE, "\tcontrolFlags: 0x%04" PRIX16 "", controlFlags);
1024 WLog_Print(log, WLOG_TRACE, "\tremoteDetachFlag: 0x%04" PRIX16 "", remoteDetachFlag);
1025 WLog_Print(log, WLOG_TRACE, "\tcontrolInterest: 0x%04" PRIX16 "", controlInterest);
1026 WLog_Print(log, WLOG_TRACE, "\tdetachInterest: 0x%04" PRIX16 "", detachInterest);
1027 return TRUE;
1028}
1029#endif
1030
1031WINPR_ATTR_NODISCARD
1032static BOOL rdp_apply_window_activation_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1033 WINPR_ATTR_UNUSED const rdpSettings* src)
1034{
1035 WINPR_ASSERT(settings);
1036 WINPR_ASSERT(src);
1037
1038 return TRUE;
1039}
1040
1041/*
1042 * Read window activation capability set.
1043 * msdn{cc240569}
1044 */
1045WINPR_ATTR_NODISCARD
1046static BOOL rdp_read_window_activation_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1047{
1048 WINPR_UNUSED(settings);
1049 WINPR_ASSERT(settings);
1050 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1051 return FALSE;
1052
1053 Stream_Seek_UINT16(s); /* helpKeyFlag (2 bytes) */
1054 Stream_Seek_UINT16(s); /* helpKeyIndexFlag (2 bytes) */
1055 Stream_Seek_UINT16(s); /* helpExtendedKeyFlag (2 bytes) */
1056 Stream_Seek_UINT16(s); /* windowManagerKeyFlag (2 bytes) */
1057 return TRUE;
1058}
1059
1060/*
1061 * Write window activation capability set.
1062 * msdn{cc240569}
1063 */
1064WINPR_ATTR_NODISCARD
1065static BOOL rdp_write_window_activation_capability_set(wLog* log, wStream* s,
1066 const rdpSettings* settings)
1067{
1068 WINPR_UNUSED(settings);
1069 WINPR_ASSERT(settings);
1070 if (!Stream_EnsureRemainingCapacity(s, 32))
1071 return FALSE;
1072
1073 const size_t header = rdp_capability_set_start(log, s);
1074 Stream_Write_UINT16(s, 0); /* helpKeyFlag (2 bytes) */
1075 Stream_Write_UINT16(s, 0); /* helpKeyIndexFlag (2 bytes) */
1076 Stream_Write_UINT16(s, 0); /* helpExtendedKeyFlag (2 bytes) */
1077 Stream_Write_UINT16(s, 0); /* windowManagerKeyFlag (2 bytes) */
1078 return rdp_capability_set_finish(s, header, CAPSET_TYPE_ACTIVATION);
1079}
1080
1081#ifdef WITH_DEBUG_CAPABILITIES
1082WINPR_ATTR_NODISCARD
1083static BOOL rdp_print_window_activation_capability_set(wLog* log, wStream* s)
1084{
1085 UINT16 helpKeyFlag = 0;
1086 UINT16 helpKeyIndexFlag = 0;
1087 UINT16 helpExtendedKeyFlag = 0;
1088 UINT16 windowManagerKeyFlag = 0;
1089 WLog_Print(log, WLOG_TRACE,
1090 "WindowActivationCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1091
1092 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1093 return FALSE;
1094
1095 Stream_Read_UINT16(s, helpKeyFlag); /* helpKeyFlag (2 bytes) */
1096 Stream_Read_UINT16(s, helpKeyIndexFlag); /* helpKeyIndexFlag (2 bytes) */
1097 Stream_Read_UINT16(s, helpExtendedKeyFlag); /* helpExtendedKeyFlag (2 bytes) */
1098 Stream_Read_UINT16(s, windowManagerKeyFlag); /* windowManagerKeyFlag (2 bytes) */
1099 WLog_Print(log, WLOG_TRACE, "\thelpKeyFlag: 0x%04" PRIX16 "", helpKeyFlag);
1100 WLog_Print(log, WLOG_TRACE, "\thelpKeyIndexFlag: 0x%04" PRIX16 "", helpKeyIndexFlag);
1101 WLog_Print(log, WLOG_TRACE, "\thelpExtendedKeyFlag: 0x%04" PRIX16 "", helpExtendedKeyFlag);
1102 WLog_Print(log, WLOG_TRACE, "\twindowManagerKeyFlag: 0x%04" PRIX16 "", windowManagerKeyFlag);
1103 return TRUE;
1104}
1105#endif
1106WINPR_ATTR_NODISCARD
1107static BOOL rdp_apply_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
1108{
1109 WINPR_ASSERT(settings);
1110 WINPR_ASSERT(src);
1111
1112 const UINT32 pointerCacheSize = freerdp_settings_get_uint32(src, FreeRDP_PointerCacheSize);
1113 const UINT32 colorPointerCacheSize =
1114 freerdp_settings_get_uint32(src, FreeRDP_ColorPointerCacheSize);
1115 const UINT32 dstPointerCacheSize =
1116 freerdp_settings_get_uint32(settings, FreeRDP_PointerCacheSize);
1117 const UINT32 dstColorPointerCacheSize =
1118 freerdp_settings_get_uint32(settings, FreeRDP_ColorPointerCacheSize);
1119
1120 /* We want the minimum of our setting and the remote announced value. */
1121 const UINT32 actualPointerCacheSize = MIN(pointerCacheSize, dstPointerCacheSize);
1122 const UINT32 actualColorPointerCacheSize = MIN(colorPointerCacheSize, dstColorPointerCacheSize);
1123
1124 return !(
1125 !freerdp_settings_set_uint32(settings, FreeRDP_PointerCacheSize, actualPointerCacheSize) ||
1126 !freerdp_settings_set_uint32(settings, FreeRDP_ColorPointerCacheSize,
1127 actualColorPointerCacheSize));
1128}
1129
1130/*
1131 * Read pointer capability set.
1132 * msdn{cc240562}
1133 */
1134WINPR_ATTR_NODISCARD
1135static BOOL rdp_read_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1136{
1137 UINT16 colorPointerFlag = 0;
1138 UINT16 colorPointerCacheSize = 0;
1139 UINT16 pointerCacheSize = 0;
1140
1141 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1142 return FALSE;
1143
1144 Stream_Read_UINT16(s, colorPointerFlag); /* colorPointerFlag (2 bytes) */
1145 Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1146
1147 if (colorPointerFlag == 0)
1148 {
1149 WLog_Print(log, WLOG_WARN,
1150 "[MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set "
1151 "(TS_POINTER_CAPABILITYSET)::colorPointerFlag received is %" PRIu16
1152 ". Value is ignored and always assumed to be TRUE",
1153 colorPointerFlag);
1154 }
1155
1156 /* pointerCacheSize is optional */
1157 if (Stream_GetRemainingLength(s) >= 2)
1158 Stream_Read_UINT16(s, pointerCacheSize); /* pointerCacheSize (2 bytes) */
1159
1160 WINPR_ASSERT(settings);
1161 settings->PointerCacheSize = pointerCacheSize;
1162 settings->ColorPointerCacheSize = colorPointerCacheSize;
1163
1164 return TRUE;
1165}
1166
1167/*
1168 * Write pointer capability set.
1169 * msdn{cc240562}
1170 */
1171WINPR_ATTR_NODISCARD
1172static BOOL rdp_write_pointer_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1173{
1174 if (!Stream_EnsureRemainingCapacity(s, 32))
1175 return FALSE;
1176
1177 const size_t header = rdp_capability_set_start(log, s);
1178 if (settings->PointerCacheSize > UINT16_MAX)
1179 return FALSE;
1180 if (settings->ColorPointerCacheSize > UINT16_MAX)
1181 return FALSE;
1182
1183 WINPR_ASSERT(settings);
1184 const UINT32 colorPointerFlag =
1185 1; /* [MS-RDPBCGR] 2.2.7.1.5 Pointer Capability Set (TS_POINTER_CAPABILITYSET)
1186 * colorPointerFlag is ignored and always assumed to be TRUE */
1187 Stream_Write_UINT16(s, colorPointerFlag); /* colorPointerFlag (2 bytes) */
1188 Stream_Write_UINT16(
1189 s, (UINT16)settings->ColorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1190 Stream_Write_UINT16(s, (UINT16)settings->PointerCacheSize); /* pointerCacheSize (2 bytes) */
1191
1192 return rdp_capability_set_finish(s, header, CAPSET_TYPE_POINTER);
1193}
1194
1195#ifdef WITH_DEBUG_CAPABILITIES
1196WINPR_ATTR_NODISCARD
1197static BOOL rdp_print_pointer_capability_set(wLog* log, wStream* s)
1198{
1199 UINT16 colorPointerFlag = 0;
1200 UINT16 colorPointerCacheSize = 0;
1201 UINT16 pointerCacheSize = 0;
1202
1203 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
1204 return FALSE;
1205
1206 WLog_Print(log, WLOG_TRACE,
1207 "PointerCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1208 Stream_Read_UINT16(s, colorPointerFlag); /* colorPointerFlag (2 bytes) */
1209 Stream_Read_UINT16(s, colorPointerCacheSize); /* colorPointerCacheSize (2 bytes) */
1210 Stream_Read_UINT16(s, pointerCacheSize); /* pointerCacheSize (2 bytes) */
1211 WLog_Print(log, WLOG_TRACE, "\tcolorPointerFlag: 0x%04" PRIX16 "", colorPointerFlag);
1212 WLog_Print(log, WLOG_TRACE, "\tcolorPointerCacheSize: 0x%04" PRIX16 "", colorPointerCacheSize);
1213 WLog_Print(log, WLOG_TRACE, "\tpointerCacheSize: 0x%04" PRIX16 "", pointerCacheSize);
1214 return TRUE;
1215}
1216#endif
1217
1218WINPR_ATTR_NODISCARD
1219static BOOL rdp_apply_share_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1220 WINPR_ATTR_UNUSED const rdpSettings* src)
1221{
1222 WINPR_ASSERT(settings);
1223 WINPR_ASSERT(src);
1224
1225 return TRUE;
1226}
1227
1228/*
1229 * Read share capability set.
1230 * msdn{cc240570}
1231 */
1232WINPR_ATTR_NODISCARD
1233static BOOL rdp_read_share_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1234{
1235 WINPR_UNUSED(settings);
1236 WINPR_ASSERT(settings);
1237
1238 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1239 return FALSE;
1240
1241 Stream_Seek_UINT16(s); /* nodeId (2 bytes) */
1242 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1243 return TRUE;
1244}
1245
1246/*
1247 * Write share capability set.
1248 * msdn{cc240570}
1249 */
1250WINPR_ATTR_NODISCARD
1251static BOOL rdp_write_share_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1252{
1253 if (!Stream_EnsureRemainingCapacity(s, 32))
1254 return FALSE;
1255
1256 const size_t header = rdp_capability_set_start(log, s);
1257
1258 WINPR_ASSERT(settings);
1259 const UINT16 nodeId = (settings->ServerMode) ? 0x03EA : 0;
1260 Stream_Write_UINT16(s, nodeId); /* nodeId (2 bytes) */
1261 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1262 return rdp_capability_set_finish(s, header, CAPSET_TYPE_SHARE);
1263}
1264
1265#ifdef WITH_DEBUG_CAPABILITIES
1266WINPR_ATTR_NODISCARD
1267static BOOL rdp_print_share_capability_set(wLog* log, wStream* s)
1268{
1269 UINT16 nodeId = 0;
1270 UINT16 pad2Octets = 0;
1271 WLog_Print(log, WLOG_TRACE,
1272 "ShareCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1273
1274 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1275 return FALSE;
1276
1277 Stream_Read_UINT16(s, nodeId); /* nodeId (2 bytes) */
1278 Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
1279 WLog_Print(log, WLOG_TRACE, "\tnodeId: 0x%04" PRIX16 "", nodeId);
1280 WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1281 return TRUE;
1282}
1283#endif
1284
1285WINPR_ATTR_NODISCARD
1286static BOOL rdp_apply_color_cache_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1287 WINPR_ATTR_UNUSED const rdpSettings* src)
1288{
1289 WINPR_ASSERT(settings);
1290 WINPR_ASSERT(src);
1291 return TRUE;
1292}
1293
1294/*
1295 * Read color cache capability set.
1296 * msdn{cc241564}
1297 */
1298WINPR_ATTR_NODISCARD
1299static BOOL rdp_read_color_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1300{
1301 WINPR_UNUSED(settings);
1302 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1303 return FALSE;
1304
1305 Stream_Seek_UINT16(s); /* colorTableCacheSize (2 bytes) */
1306 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1307 return TRUE;
1308}
1309
1310/*
1311 * Write color cache capability set.
1312 * msdn{cc241564}
1313 */
1314WINPR_ATTR_NODISCARD
1315static BOOL rdp_write_color_cache_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1316{
1317 WINPR_UNUSED(settings);
1318 if (!Stream_EnsureRemainingCapacity(s, 32))
1319 return FALSE;
1320
1321 const size_t header = rdp_capability_set_start(log, s);
1322 Stream_Write_UINT16(s, 6); /* colorTableCacheSize (2 bytes) */
1323 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1324 return rdp_capability_set_finish(s, header, CAPSET_TYPE_COLOR_CACHE);
1325}
1326
1327#ifdef WITH_DEBUG_CAPABILITIES
1328WINPR_ATTR_NODISCARD
1329static BOOL rdp_print_color_cache_capability_set(wLog* log, wStream* s)
1330{
1331 UINT16 colorTableCacheSize = 0;
1332 UINT16 pad2Octets = 0;
1333 WLog_Print(log, WLOG_TRACE,
1334 "ColorCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1335
1336 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1337 return FALSE;
1338
1339 Stream_Read_UINT16(s, colorTableCacheSize); /* colorTableCacheSize (2 bytes) */
1340 Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
1341 WLog_Print(log, WLOG_TRACE, "\tcolorTableCacheSize: 0x%04" PRIX16 "", colorTableCacheSize);
1342 WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1343 return TRUE;
1344}
1345#endif
1346
1347WINPR_ATTR_NODISCARD
1348static BOOL rdp_apply_sound_capability_set(rdpSettings* settings, const rdpSettings* src)
1349{
1350 WINPR_ASSERT(settings);
1351 WINPR_ASSERT(src);
1352
1353 settings->SoundBeepsEnabled = src->SoundBeepsEnabled;
1354
1355 return TRUE;
1356}
1357
1358/*
1359 * Read sound capability set.
1360 * msdn{cc240552}
1361 */
1362WINPR_ATTR_NODISCARD
1363static BOOL rdp_read_sound_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1364{
1365 UINT16 soundFlags = 0;
1366
1367 WINPR_ASSERT(settings);
1368 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1369 return FALSE;
1370
1371 Stream_Read_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1372 Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */
1373 settings->SoundBeepsEnabled = (soundFlags & SOUND_BEEPS_FLAG) != 0;
1374 return TRUE;
1375}
1376
1377/*
1378 * Write sound capability set.
1379 * msdn{cc240552}
1380 */
1381WINPR_ATTR_NODISCARD
1382static BOOL rdp_write_sound_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1383{
1384 WINPR_ASSERT(settings);
1385 if (!Stream_EnsureRemainingCapacity(s, 32))
1386 return FALSE;
1387
1388 const size_t header = rdp_capability_set_start(log, s);
1389 const UINT16 soundFlags = (settings->SoundBeepsEnabled) ? SOUND_BEEPS_FLAG : 0;
1390 Stream_Write_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1391 Stream_Write_UINT16(s, 0); /* pad2OctetsA (2 bytes) */
1392 return rdp_capability_set_finish(s, header, CAPSET_TYPE_SOUND);
1393}
1394
1395#ifdef WITH_DEBUG_CAPABILITIES
1396WINPR_ATTR_NODISCARD
1397static BOOL rdp_print_sound_capability_set(wLog* log, wStream* s)
1398{
1399 UINT16 soundFlags = 0;
1400 UINT16 pad2OctetsA = 0;
1401 WLog_Print(log, WLOG_TRACE,
1402 "SoundCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1403
1404 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1405 return FALSE;
1406
1407 Stream_Read_UINT16(s, soundFlags); /* soundFlags (2 bytes) */
1408 Stream_Read_UINT16(s, pad2OctetsA); /* pad2OctetsA (2 bytes) */
1409 WLog_Print(log, WLOG_TRACE, "\tsoundFlags: 0x%04" PRIX16 "", soundFlags);
1410 WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
1411 return TRUE;
1412}
1413#endif
1414
1415WINPR_ATTR_NODISCARD
1416static BOOL rdp_apply_input_capability_set(rdpSettings* settings, const rdpSettings* src)
1417{
1418 WINPR_ASSERT(settings);
1419 WINPR_ASSERT(src);
1420
1421 if (settings->ServerMode)
1422 {
1423 settings->KeyboardLayout = src->KeyboardLayout;
1424 settings->KeyboardType = src->KeyboardType;
1425 settings->KeyboardSubType = src->KeyboardSubType;
1426 settings->KeyboardFunctionKey = src->KeyboardFunctionKey;
1427 }
1428
1429 if (!freerdp_settings_set_string(settings, FreeRDP_ImeFileName, src->ImeFileName))
1430 return FALSE;
1431
1432 if (!settings->ServerMode)
1433 {
1434 settings->FastPathInput = src->FastPathInput;
1435
1436 /* Note: These settings have split functionality:
1437 * 1. If disabled in client pre_connect, it can disable announcing the feature
1438 * 2. If enabled in client pre_connect, override it with the server announced support flag.
1439 */
1440 if (settings->HasHorizontalWheel)
1441 settings->HasHorizontalWheel = src->HasHorizontalWheel;
1442 const BOOL UnicodeInput = freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput);
1443 if (UnicodeInput)
1444 {
1445 const BOOL srcVal = freerdp_settings_get_bool(src, FreeRDP_UnicodeInput);
1446 if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, srcVal))
1447 return FALSE;
1448 }
1449 if (settings->HasExtendedMouseEvent)
1450 settings->HasExtendedMouseEvent = src->HasExtendedMouseEvent;
1451 if (settings->HasRelativeMouseEvent)
1452 settings->HasRelativeMouseEvent = src->HasRelativeMouseEvent;
1453 if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1454 settings->HasQoeEvent = freerdp_settings_get_bool(src, FreeRDP_HasQoeEvent);
1455 }
1456 return TRUE;
1457}
1458
1459/*
1460 * Read input capability set.
1461 * msdn{cc240563}
1462 */
1463WINPR_ATTR_NODISCARD
1464static BOOL rdp_read_input_capability_set(wLog* log, wStream* s, rdpSettings* settings,
1465 BOOL isServer)
1466{
1467 UINT16 inputFlags = 0;
1468
1469 WINPR_ASSERT(settings);
1470 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1471 return FALSE;
1472
1473 Stream_Read_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1474 Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */
1475
1476 Stream_Read_UINT32(s, settings->KeyboardLayout); /* keyboardLayout (4 bytes) */
1477 Stream_Read_UINT32(s, settings->KeyboardType); /* keyboardType (4 bytes) */
1478 Stream_Read_UINT32(s, settings->KeyboardSubType); /* keyboardSubType (4 bytes) */
1479 Stream_Read_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1480
1481 /* Received after TS_UD_CS_CORE and copied over its (sanitized) value by
1482 * rdp_apply_input_capability_set(), so a client's out-of-spec KeyboardType (e.g. mstsc with
1483 * an MSKLC layout) must be checked here too. Servers send zeroed keyboard fields: skip. */
1484 if (isServer)
1485 freerdp_settings_sanitize_keyboard_type(log, settings, "TS_INPUT_CAPABILITYSET");
1486
1487 {
1488 WCHAR wstr[32] = WINPR_C_ARRAY_INIT;
1489 char str[65] = WINPR_C_ARRAY_INIT;
1490
1491 /* Older windows versions report invalid UTF16
1492 * [MS-RDPBCGR] <29> Section 2.2.7.1.6: Microsoft RDP 4.0, 5.0, 5.1, and 5.2 servers do not
1493 * explicitly fill the imeFileName field with zeros.
1494 */
1495 if (!Stream_Read_UTF16_String(s, wstr, ARRAYSIZE(wstr)))
1496 return FALSE;
1497
1498 if (ConvertWCharNToUtf8(wstr, ARRAYSIZE(wstr), str, ARRAYSIZE(str)) < 0)
1499 memset(str, 0, sizeof(str));
1500
1501 if (!freerdp_settings_set_string_len(settings, FreeRDP_ImeFileName, str, ARRAYSIZE(str)))
1502 return FALSE;
1503 }
1504
1505 if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathInput,
1506 inputFlags &
1507 (INPUT_FLAG_FASTPATH_INPUT | INPUT_FLAG_FASTPATH_INPUT2)))
1508 return FALSE;
1509 if (!freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel,
1510 (inputFlags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0))
1511 return FALSE;
1512 if (!freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput,
1513 (inputFlags & INPUT_FLAG_UNICODE) != 0))
1514 return FALSE;
1515 if (!freerdp_settings_set_bool(settings, FreeRDP_HasRelativeMouseEvent,
1516 (inputFlags & INPUT_FLAG_MOUSE_RELATIVE) != 0))
1517 return FALSE;
1518 if (!freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent,
1519 (inputFlags & INPUT_FLAG_MOUSEX) != 0))
1520 return FALSE;
1521 if (!freerdp_settings_set_bool(settings, FreeRDP_HasQoeEvent,
1522 (inputFlags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0))
1523 return FALSE;
1524
1525 return TRUE;
1526}
1527
1528/*
1529 * Write input capability set.
1530 * msdn{cc240563}
1531 */
1532WINPR_ATTR_NODISCARD
1533static BOOL rdp_write_input_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1534{
1535 WINPR_ASSERT(settings);
1536 if (!Stream_EnsureRemainingCapacity(s, 128))
1537 return FALSE;
1538
1539 const size_t header = rdp_capability_set_start(log, s);
1540 UINT16 inputFlags = INPUT_FLAG_SCANCODES;
1541
1542 if (settings->FastPathInput)
1543 {
1544 inputFlags |= INPUT_FLAG_FASTPATH_INPUT;
1545 inputFlags |= INPUT_FLAG_FASTPATH_INPUT2;
1546 }
1547
1548 if (freerdp_settings_get_bool(settings, FreeRDP_HasRelativeMouseEvent))
1549 inputFlags |= INPUT_FLAG_MOUSE_RELATIVE;
1550
1551 if (freerdp_settings_get_bool(settings, FreeRDP_HasHorizontalWheel))
1552 inputFlags |= TS_INPUT_FLAG_MOUSE_HWHEEL;
1553
1554 if (freerdp_settings_get_bool(settings, FreeRDP_UnicodeInput))
1555 inputFlags |= INPUT_FLAG_UNICODE;
1556
1557 if (freerdp_settings_get_bool(settings, FreeRDP_HasQoeEvent))
1558 inputFlags |= TS_INPUT_FLAG_QOE_TIMESTAMPS;
1559
1560 if (settings->HasExtendedMouseEvent)
1561 inputFlags |= INPUT_FLAG_MOUSEX;
1562
1563 Stream_Write_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1564 Stream_Write_UINT16(s, 0); /* pad2OctetsA (2 bytes) */
1565 Stream_Write_UINT32(s, settings->KeyboardLayout); /* keyboardLayout (4 bytes) */
1566 Stream_Write_UINT32(s, settings->KeyboardType); /* keyboardType (4 bytes) */
1567 Stream_Write_UINT32(s, settings->KeyboardSubType); /* keyboardSubType (4 bytes) */
1568 Stream_Write_UINT32(s, settings->KeyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1569 Stream_Zero(s, 64); /* imeFileName (64 bytes) */
1570 return rdp_capability_set_finish(s, header, CAPSET_TYPE_INPUT);
1571}
1572
1573#ifdef WITH_DEBUG_CAPABILITIES
1574WINPR_ATTR_NODISCARD
1575static BOOL rdp_print_input_capability_set(wLog* log, wStream* s)
1576{
1577 UINT16 inputFlags = 0;
1578 UINT16 pad2OctetsA = 0;
1579 UINT32 keyboardLayout = 0;
1580 UINT32 keyboardType = 0;
1581 UINT32 keyboardSubType = 0;
1582 UINT32 keyboardFunctionKey = 0;
1583 WLog_Print(log, WLOG_TRACE, "InputCapabilitySet (length %" PRIuz ")",
1584 Stream_GetRemainingLength(s));
1585
1586 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 84))
1587 return FALSE;
1588
1589 Stream_Read_UINT16(s, inputFlags); /* inputFlags (2 bytes) */
1590 Stream_Read_UINT16(s, pad2OctetsA); /* pad2OctetsA (2 bytes) */
1591 Stream_Read_UINT32(s, keyboardLayout); /* keyboardLayout (4 bytes) */
1592 Stream_Read_UINT32(s, keyboardType); /* keyboardType (4 bytes) */
1593 Stream_Read_UINT32(s, keyboardSubType); /* keyboardSubType (4 bytes) */
1594 Stream_Read_UINT32(s, keyboardFunctionKey); /* keyboardFunctionKeys (4 bytes) */
1595 Stream_Seek(s, 64); /* imeFileName (64 bytes) */
1596 WLog_Print(log, WLOG_TRACE, "\tinputFlags: 0x%04" PRIX16 "", inputFlags);
1597 WLog_Print(log, WLOG_TRACE, "\tpad2OctetsA: 0x%04" PRIX16 "", pad2OctetsA);
1598 WLog_Print(log, WLOG_TRACE, "\tkeyboardLayout: 0x%08" PRIX32 "", keyboardLayout);
1599 WLog_Print(log, WLOG_TRACE, "\tkeyboardType: 0x%08" PRIX32 "", keyboardType);
1600 WLog_Print(log, WLOG_TRACE, "\tkeyboardSubType: 0x%08" PRIX32 "", keyboardSubType);
1601 WLog_Print(log, WLOG_TRACE, "\tkeyboardFunctionKey: 0x%08" PRIX32 "", keyboardFunctionKey);
1602 return TRUE;
1603}
1604#endif
1605
1606WINPR_ATTR_NODISCARD
1607static BOOL rdp_apply_font_capability_set(WINPR_ATTR_UNUSED rdpSettings* settings,
1608 WINPR_ATTR_UNUSED const rdpSettings* src)
1609{
1610 WINPR_ASSERT(settings);
1611 WINPR_ASSERT(src);
1612 return TRUE;
1613}
1614
1615/*
1616 * Read font capability set.
1617 * msdn{cc240571}
1618 */
1619WINPR_ATTR_NODISCARD
1620static BOOL rdp_read_font_capability_set(WINPR_ATTR_UNUSED wLog* log, wStream* s,
1621 rdpSettings* settings)
1622{
1623 WINPR_UNUSED(settings);
1624 if (Stream_GetRemainingLength(s) >= 2)
1625 Stream_Seek_UINT16(s); /* fontSupportFlags (2 bytes) */
1626
1627 if (Stream_GetRemainingLength(s) >= 2)
1628 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1629
1630 return TRUE;
1631}
1632
1633/*
1634 * Write font capability set.
1635 * msdn{cc240571}
1636 */
1637WINPR_ATTR_NODISCARD
1638static BOOL rdp_write_font_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1639{
1640 WINPR_UNUSED(settings);
1641 if (!Stream_EnsureRemainingCapacity(s, 32))
1642 return FALSE;
1643
1644 const size_t header = rdp_capability_set_start(log, s);
1645 Stream_Write_UINT16(s, FONTSUPPORT_FONTLIST); /* fontSupportFlags (2 bytes) */
1646 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1647 return rdp_capability_set_finish(s, header, CAPSET_TYPE_FONT);
1648}
1649
1650#ifdef WITH_DEBUG_CAPABILITIES
1651WINPR_ATTR_NODISCARD
1652static BOOL rdp_print_font_capability_set(wLog* log, wStream* s)
1653{
1654 UINT16 fontSupportFlags = 0;
1655 UINT16 pad2Octets = 0;
1656 WLog_Print(log, WLOG_TRACE,
1657 "FontCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1658
1659 if (Stream_GetRemainingLength(s) >= 2)
1660 Stream_Read_UINT16(s, fontSupportFlags); /* fontSupportFlags (2 bytes) */
1661
1662 if (Stream_GetRemainingLength(s) >= 2)
1663 Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
1664
1665 WLog_Print(log, WLOG_TRACE, "\tfontSupportFlags: 0x%04" PRIX16 "", fontSupportFlags);
1666 WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1667 return TRUE;
1668}
1669#endif
1670
1671WINPR_ATTR_NODISCARD
1672static BOOL rdp_apply_brush_capability_set(rdpSettings* settings, const rdpSettings* src)
1673{
1674 WINPR_ASSERT(settings);
1675 WINPR_ASSERT(src);
1676
1677 // TODO: Minimum of what?
1678 settings->BrushSupportLevel = src->BrushSupportLevel;
1679 return TRUE;
1680}
1681
1682/*
1683 * Read brush capability set.
1684 * msdn{cc240564}
1685 */
1686WINPR_ATTR_NODISCARD
1687static BOOL rdp_read_brush_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1688{
1689 WINPR_UNUSED(settings);
1690 WINPR_ASSERT(settings);
1691
1692 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1693 return FALSE;
1694 Stream_Read_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1695 return TRUE;
1696}
1697
1698/*
1699 * Write brush capability set.
1700 * msdn{cc240564}
1701 */
1702WINPR_ATTR_NODISCARD
1703static BOOL rdp_write_brush_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1704{
1705 WINPR_ASSERT(settings);
1706 if (!Stream_EnsureRemainingCapacity(s, 32))
1707 return FALSE;
1708
1709 const size_t header = rdp_capability_set_start(log, s);
1710 Stream_Write_UINT32(s, settings->BrushSupportLevel); /* brushSupportLevel (4 bytes) */
1711 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BRUSH);
1712}
1713
1714#ifdef WITH_DEBUG_CAPABILITIES
1715WINPR_ATTR_NODISCARD
1716static BOOL rdp_print_brush_capability_set(wLog* log, wStream* s)
1717{
1718 UINT32 brushSupportLevel = 0;
1719 WLog_Print(log, WLOG_TRACE,
1720 "BrushCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1721
1722 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1723 return FALSE;
1724
1725 Stream_Read_UINT32(s, brushSupportLevel); /* brushSupportLevel (4 bytes) */
1726 WLog_Print(log, WLOG_TRACE, "\tbrushSupportLevel: 0x%08" PRIX32 "", brushSupportLevel);
1727 return TRUE;
1728}
1729#endif
1730
1731/*
1732 * Read cache definition (glyph).
1733 * msdn{cc240566}
1734 */
1735static void rdp_read_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_definition)
1736{
1737 WINPR_ASSERT(cache_definition);
1738 Stream_Read_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1739 Stream_Read_UINT16(s,
1740 cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1741}
1742
1743/*
1744 * Write cache definition (glyph).
1745 * msdn{cc240566}
1746 */
1747static void rdp_write_cache_definition(wStream* s, GLYPH_CACHE_DEFINITION* cache_definition)
1748{
1749 WINPR_ASSERT(cache_definition);
1750 Stream_Write_UINT16(s, cache_definition->cacheEntries); /* cacheEntries (2 bytes) */
1751 Stream_Write_UINT16(
1752 s, cache_definition->cacheMaximumCellSize); /* cacheMaximumCellSize (2 bytes) */
1753}
1754
1755WINPR_ATTR_NODISCARD
1756static BOOL rdp_apply_glyph_cache_capability_set(rdpSettings* settings, const rdpSettings* src)
1757{
1758 WINPR_ASSERT(settings);
1759 WINPR_ASSERT(src);
1760
1761 WINPR_ASSERT(src->GlyphCache);
1762 WINPR_ASSERT(settings->GlyphCache);
1763 for (size_t x = 0; x < 10; x++)
1764 settings->GlyphCache[x] = src->GlyphCache[x];
1765
1766 WINPR_ASSERT(src->FragCache);
1767 WINPR_ASSERT(settings->FragCache);
1768 settings->FragCache[0] = src->FragCache[0];
1769 settings->GlyphSupportLevel = src->GlyphSupportLevel;
1770
1771 return TRUE;
1772}
1773
1774/*
1775 * Read glyph cache capability set.
1776 * msdn{cc240565}
1777 */
1778WINPR_ATTR_NODISCARD
1779static BOOL rdp_read_glyph_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
1780{
1781 WINPR_ASSERT(settings);
1782 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1783 return FALSE;
1784
1785 /* glyphCache (40 bytes) */
1786 for (size_t x = 0; x < 10; x++)
1787 rdp_read_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1788 rdp_read_cache_definition(s, settings->FragCache); /* fragCache (4 bytes) */
1789 Stream_Read_UINT16(s, settings->GlyphSupportLevel); /* glyphSupportLevel (2 bytes) */
1790 Stream_Seek_UINT16(s); /* pad2Octets (2 bytes) */
1791 return TRUE;
1792}
1793
1794/*
1795 * Write glyph cache capability set.
1796 * msdn{cc240565}
1797 */
1798WINPR_ATTR_NODISCARD
1799static BOOL rdp_write_glyph_cache_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
1800{
1801 WINPR_ASSERT(settings);
1802 if (!Stream_EnsureRemainingCapacity(s, 64))
1803 return FALSE;
1804
1805 const size_t header = rdp_capability_set_start(log, s);
1806 if (settings->GlyphSupportLevel > UINT16_MAX)
1807 return FALSE;
1808 /* glyphCache (40 bytes) */
1809 for (size_t x = 0; x < 10; x++)
1810 rdp_write_cache_definition(s, &(settings->GlyphCache[x])); /* glyphCache0 (4 bytes) */
1811 rdp_write_cache_definition(s, settings->FragCache); /* fragCache (4 bytes) */
1812 Stream_Write_UINT16(s, (UINT16)settings->GlyphSupportLevel); /* glyphSupportLevel (2 bytes) */
1813 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
1814 return rdp_capability_set_finish(s, header, CAPSET_TYPE_GLYPH_CACHE);
1815}
1816
1817#ifdef WITH_DEBUG_CAPABILITIES
1818WINPR_ATTR_NODISCARD
1819static BOOL rdp_print_glyph_cache_capability_set(wLog* log, wStream* s)
1820{
1821 GLYPH_CACHE_DEFINITION glyphCache[10] = WINPR_C_ARRAY_INIT;
1822 GLYPH_CACHE_DEFINITION fragCache = WINPR_C_ARRAY_INIT;
1823 UINT16 glyphSupportLevel = 0;
1824 UINT16 pad2Octets = 0;
1825 WLog_Print(log, WLOG_TRACE,
1826 "GlyphCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
1827
1828 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 48))
1829 return FALSE;
1830
1831 /* glyphCache (40 bytes) */
1832 rdp_read_cache_definition(s, &glyphCache[0]); /* glyphCache0 (4 bytes) */
1833 rdp_read_cache_definition(s, &glyphCache[1]); /* glyphCache1 (4 bytes) */
1834 rdp_read_cache_definition(s, &glyphCache[2]); /* glyphCache2 (4 bytes) */
1835 rdp_read_cache_definition(s, &glyphCache[3]); /* glyphCache3 (4 bytes) */
1836 rdp_read_cache_definition(s, &glyphCache[4]); /* glyphCache4 (4 bytes) */
1837 rdp_read_cache_definition(s, &glyphCache[5]); /* glyphCache5 (4 bytes) */
1838 rdp_read_cache_definition(s, &glyphCache[6]); /* glyphCache6 (4 bytes) */
1839 rdp_read_cache_definition(s, &glyphCache[7]); /* glyphCache7 (4 bytes) */
1840 rdp_read_cache_definition(s, &glyphCache[8]); /* glyphCache8 (4 bytes) */
1841 rdp_read_cache_definition(s, &glyphCache[9]); /* glyphCache9 (4 bytes) */
1842 rdp_read_cache_definition(s, &fragCache); /* fragCache (4 bytes) */
1843 Stream_Read_UINT16(s, glyphSupportLevel); /* glyphSupportLevel (2 bytes) */
1844 Stream_Read_UINT16(s, pad2Octets); /* pad2Octets (2 bytes) */
1845 WLog_Print(log, WLOG_TRACE, "\tglyphCache0: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1846 glyphCache[0].cacheEntries, glyphCache[0].cacheMaximumCellSize);
1847 WLog_Print(log, WLOG_TRACE, "\tglyphCache1: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1848 glyphCache[1].cacheEntries, glyphCache[1].cacheMaximumCellSize);
1849 WLog_Print(log, WLOG_TRACE, "\tglyphCache2: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1850 glyphCache[2].cacheEntries, glyphCache[2].cacheMaximumCellSize);
1851 WLog_Print(log, WLOG_TRACE, "\tglyphCache3: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1852 glyphCache[3].cacheEntries, glyphCache[3].cacheMaximumCellSize);
1853 WLog_Print(log, WLOG_TRACE, "\tglyphCache4: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1854 glyphCache[4].cacheEntries, glyphCache[4].cacheMaximumCellSize);
1855 WLog_Print(log, WLOG_TRACE, "\tglyphCache5: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1856 glyphCache[5].cacheEntries, glyphCache[5].cacheMaximumCellSize);
1857 WLog_Print(log, WLOG_TRACE, "\tglyphCache6: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1858 glyphCache[6].cacheEntries, glyphCache[6].cacheMaximumCellSize);
1859 WLog_Print(log, WLOG_TRACE, "\tglyphCache7: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1860 glyphCache[7].cacheEntries, glyphCache[7].cacheMaximumCellSize);
1861 WLog_Print(log, WLOG_TRACE, "\tglyphCache8: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1862 glyphCache[8].cacheEntries, glyphCache[8].cacheMaximumCellSize);
1863 WLog_Print(log, WLOG_TRACE, "\tglyphCache9: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1864 glyphCache[9].cacheEntries, glyphCache[9].cacheMaximumCellSize);
1865 WLog_Print(log, WLOG_TRACE, "\tfragCache: Entries: %" PRIu16 " MaximumCellSize: %" PRIu16 "",
1866 fragCache.cacheEntries, fragCache.cacheMaximumCellSize);
1867 WLog_Print(log, WLOG_TRACE, "\tglyphSupportLevel: 0x%04" PRIX16 "", glyphSupportLevel);
1868 WLog_Print(log, WLOG_TRACE, "\tpad2Octets: 0x%04" PRIX16 "", pad2Octets);
1869 return TRUE;
1870}
1871#endif
1872WINPR_ATTR_NODISCARD
1873static BOOL rdp_apply_offscreen_bitmap_cache_capability_set(rdpSettings* settings,
1874 const rdpSettings* src)
1875{
1876 WINPR_ASSERT(settings);
1877 WINPR_ASSERT(src);
1878
1879 settings->OffscreenCacheSize = src->OffscreenCacheSize;
1880 settings->OffscreenCacheEntries = src->OffscreenCacheEntries;
1881 settings->OffscreenSupportLevel = src->OffscreenSupportLevel;
1882
1883 return TRUE;
1884}
1885
1886/*
1887 * Read offscreen bitmap cache capability set.
1888 * msdn{cc240550}
1889 */
1890WINPR_ATTR_NODISCARD
1891static BOOL rdp_read_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s,
1892 rdpSettings* settings)
1893{
1894 UINT32 offscreenSupportLevel = 0;
1895
1896 WINPR_ASSERT(settings);
1897 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1898 return FALSE;
1899
1900 Stream_Read_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */
1901 Stream_Read_UINT16(s, settings->OffscreenCacheSize); /* offscreenCacheSize (2 bytes) */
1902 Stream_Read_UINT16(s, settings->OffscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1903
1904 settings->OffscreenSupportLevel = offscreenSupportLevel & 0x01;
1905
1906 return TRUE;
1907}
1908
1909/*
1910 * Write offscreen bitmap cache capability set.
1911 * msdn{cc240550}
1912 */
1913WINPR_ATTR_NODISCARD
1914static BOOL rdp_write_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s,
1915 const rdpSettings* settings)
1916{
1917 UINT32 offscreenSupportLevel = 0x00;
1918
1919 WINPR_ASSERT(settings);
1920 if (!Stream_EnsureRemainingCapacity(s, 32))
1921 return FALSE;
1922
1923 const size_t header = rdp_capability_set_start(log, s);
1924 if (settings->OffscreenSupportLevel)
1925 {
1926 offscreenSupportLevel = 0x01;
1927 Stream_Write_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */
1928 Stream_Write_UINT16(
1929 s, WINPR_ASSERTING_INT_CAST(
1930 uint16_t, settings->OffscreenCacheSize)); /* offscreenCacheSize (2 bytes) */
1931 Stream_Write_UINT16(
1932 s,
1933 WINPR_ASSERTING_INT_CAST(
1934 uint16_t, settings->OffscreenCacheEntries)); /* offscreenCacheEntries (2 bytes) */
1935 }
1936 else
1937 Stream_Zero(s, 8);
1938
1939 return rdp_capability_set_finish(s, header, CAPSET_TYPE_OFFSCREEN_CACHE);
1940}
1941
1942#ifdef WITH_DEBUG_CAPABILITIES
1943WINPR_ATTR_NODISCARD
1944static BOOL rdp_print_offscreen_bitmap_cache_capability_set(wLog* log, wStream* s)
1945{
1946 UINT32 offscreenSupportLevel = 0;
1947 UINT16 offscreenCacheSize = 0;
1948 UINT16 offscreenCacheEntries = 0;
1949 WLog_Print(log, WLOG_TRACE, "OffscreenBitmapCacheCapabilitySet (length %" PRIuz "):",
1950 Stream_GetRemainingLength(s));
1951
1952 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
1953 return FALSE;
1954
1955 Stream_Read_UINT32(s, offscreenSupportLevel); /* offscreenSupportLevel (4 bytes) */
1956 Stream_Read_UINT16(s, offscreenCacheSize); /* offscreenCacheSize (2 bytes) */
1957 Stream_Read_UINT16(s, offscreenCacheEntries); /* offscreenCacheEntries (2 bytes) */
1958 WLog_Print(log, WLOG_TRACE, "\toffscreenSupportLevel: 0x%08" PRIX32 "", offscreenSupportLevel);
1959 WLog_Print(log, WLOG_TRACE, "\toffscreenCacheSize: 0x%04" PRIX16 "", offscreenCacheSize);
1960 WLog_Print(log, WLOG_TRACE, "\toffscreenCacheEntries: 0x%04" PRIX16 "", offscreenCacheEntries);
1961 return TRUE;
1962}
1963#endif
1964
1965WINPR_ATTR_NODISCARD
1966static BOOL rdp_apply_bitmap_cache_host_support_capability_set(rdpSettings* settings,
1967 const rdpSettings* src)
1968{
1969 const BOOL val = (freerdp_settings_get_bool(src, FreeRDP_BitmapCachePersistEnabled) &&
1970 freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled));
1971 return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled, val);
1972}
1973
1974/*
1975 * Read bitmap cache host support capability set.
1976 * msdn{cc240557}
1977 */
1978WINPR_ATTR_NODISCARD
1979static BOOL rdp_read_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
1980 rdpSettings* settings)
1981{
1982 BYTE cacheVersion = 0;
1983
1984 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
1985 return FALSE;
1986
1987 Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
1988 Stream_Seek_UINT8(s); /* pad1 (1 byte) */
1989 Stream_Seek_UINT16(s); /* pad2 (2 bytes) */
1990
1991 return freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
1992 cacheVersion & BITMAP_CACHE_V2);
1993}
1994
1995/*
1996 * Write bitmap cache host support capability set.
1997 * msdn{cc240557}
1998 */
1999WINPR_ATTR_NODISCARD
2000static BOOL rdp_write_bitmap_cache_host_support_capability_set(wLog* log, wStream* s,
2001 const rdpSettings* settings)
2002{
2003 UINT8 cacheVersion = 0;
2004
2005 if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCacheEnabled))
2006 cacheVersion |= BITMAP_CACHE_V2;
2007
2008 if (!Stream_EnsureRemainingCapacity(s, 32))
2009 return FALSE;
2010
2011 const size_t header = rdp_capability_set_start(log, s);
2012 Stream_Write_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
2013 Stream_Write_UINT8(s, 0); /* pad1 (1 byte) */
2014 Stream_Write_UINT16(s, 0); /* pad2 (2 bytes) */
2015 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT);
2016}
2017
2018#ifdef WITH_DEBUG_CAPABILITIES
2019WINPR_ATTR_NODISCARD
2020static BOOL rdp_print_bitmap_cache_host_support_capability_set(wLog* log, wStream* s)
2021{
2022 BYTE cacheVersion = 0;
2023 BYTE pad1 = 0;
2024 UINT16 pad2 = 0;
2025 WLog_Print(log, WLOG_TRACE, "BitmapCacheHostSupportCapabilitySet (length %" PRIuz "):",
2026 Stream_GetRemainingLength(s));
2027
2028 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2029 return FALSE;
2030
2031 Stream_Read_UINT8(s, cacheVersion); /* cacheVersion (1 byte) */
2032 Stream_Read_UINT8(s, pad1); /* pad1 (1 byte) */
2033 Stream_Read_UINT16(s, pad2); /* pad2 (2 bytes) */
2034 WLog_Print(log, WLOG_TRACE, "\tcacheVersion: 0x%02" PRIX8 "", cacheVersion);
2035 WLog_Print(log, WLOG_TRACE, "\tpad1: 0x%02" PRIX8 "", pad1);
2036 WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%04" PRIX16 "", pad2);
2037 return TRUE;
2038}
2039#endif
2040
2041WINPR_ATTR_NODISCARD
2042static BOOL rdp_read_bitmap_cache_cell_info(wLog* log, wStream* s,
2043 BITMAP_CACHE_V2_CELL_INFO* cellInfo, size_t limit)
2044{
2045 UINT32 info = 0;
2046
2047 WINPR_ASSERT(cellInfo);
2048 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2049 return FALSE;
2050
2051 /*
2052 * numEntries is in the first 31 bits, while the last bit (k)
2053 * is used to indicate a persistent bitmap cache.
2054 */
2055 Stream_Read_UINT32(s, info);
2056
2057 cellInfo->numEntries = (info & 0x7FFFFFFF);
2058 if (cellInfo->numEntries > limit)
2059 {
2060 WLog_Print(log, WLOG_ERROR,
2061 "BITMAP_CACHE_V2_CELL_INFO::numEntries (%" PRIu32 ") > limit(%" PRIuz ")",
2062 cellInfo->numEntries, limit);
2063 }
2064 cellInfo->persistent = (info & 0x80000000) ? 1 : 0;
2065 return TRUE;
2066}
2067
2068WINPR_ATTR_NODISCARD
2069static BOOL rdp_write_bitmap_cache_cell_info(wStream* s, BITMAP_CACHE_V2_CELL_INFO* cellInfo)
2070{
2071 /*
2072 * numEntries is in the first 31 bits, while the last bit (k)
2073 * is used to indicate a persistent bitmap cache.
2074 */
2075 WINPR_ASSERT(cellInfo);
2076 const UINT32 info =
2077 (cellInfo->numEntries | (((UINT32)cellInfo->persistent << 31) & 0xFF000000));
2078 if (!Stream_EnsureRemainingCapacity(s, 4))
2079 return FALSE;
2080 Stream_Write_UINT32(s, info);
2081 return TRUE;
2082}
2083
2084WINPR_ATTR_NODISCARD
2085static BOOL rdp_apply_bitmap_cache_v2_capability_set(rdpSettings* settings, const rdpSettings* src)
2086{
2087 const FreeRDP_Settings_Keys_Bool keys[] = { FreeRDP_BitmapCacheEnabled,
2088 FreeRDP_BitmapCachePersistEnabled };
2089
2090 for (size_t x = 0; x < ARRAYSIZE(keys); x++)
2091 {
2092 const FreeRDP_Settings_Keys_Bool id = keys[x];
2093 const BOOL val = freerdp_settings_get_bool(src, id);
2094 if (!freerdp_settings_set_bool(settings, id, val))
2095 return FALSE;
2096 }
2097
2098 {
2099 const UINT32 BitmapCacheV2NumCells =
2100 freerdp_settings_get_uint32(src, FreeRDP_BitmapCacheV2NumCells);
2101 if (!freerdp_settings_set_pointer_len(settings, FreeRDP_BitmapCacheV2CellInfo, nullptr,
2102 BitmapCacheV2NumCells))
2103 return FALSE;
2104
2105 for (size_t x = 0; x < BitmapCacheV2NumCells; x++)
2106 {
2107 const BITMAP_CACHE_V2_CELL_INFO* cdata =
2108 freerdp_settings_get_pointer_array(src, FreeRDP_BitmapCacheV2CellInfo, x);
2109 if (!freerdp_settings_set_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, x,
2110 cdata))
2111 return FALSE;
2112 }
2113 }
2114
2115 return TRUE;
2116}
2117
2118/*
2119 * Read bitmap cache v2 capability set.
2120 * msdn{cc240560}
2121 */
2122WINPR_ATTR_NODISCARD
2123static BOOL rdp_read_bitmap_cache_v2_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2124{
2125 UINT16 cacheFlags = 0;
2126 WINPR_UNUSED(settings);
2127 WINPR_ASSERT(settings);
2128
2129 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2130 return FALSE;
2131
2132 Stream_Read_UINT16(s, cacheFlags); /* cacheFlags (2 bytes) */
2133
2134 if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, TRUE))
2135 return FALSE;
2136 if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCachePersistEnabled,
2137 cacheFlags & PERSISTENT_KEYS_EXPECTED_FLAG))
2138 return FALSE;
2139
2140 Stream_Seek_UINT8(s); /* pad2 (1 byte) */
2141 Stream_Read_UINT8(s, settings->BitmapCacheV2NumCells); /* numCellCaches (1 byte) */
2142 if (settings->BitmapCacheV2NumCells > 5)
2143 {
2144 WLog_Print(log, WLOG_ERROR,
2145 "Invalid TS_BITMAPCACHE_CAPABILITYSET_REV2::numCellCaches %" PRIu32 " > 5",
2146 settings->BitmapCacheV2NumCells);
2147 return FALSE;
2148 }
2149
2150 for (size_t x = 0; x < settings->BitmapCacheV2NumCells; x++)
2151 {
2153 freerdp_settings_get_pointer_array_writable(settings, FreeRDP_BitmapCacheV2CellInfo, x);
2154 if (!rdp_read_bitmap_cache_cell_info(log, s, info, bitmapCacheV2CellInfoLimits[x]))
2155 return FALSE;
2156 }
2157
2158 /* Input must always have 5 BitmapCacheV2CellInfo values */
2159 for (size_t x = settings->BitmapCacheV2NumCells; x < 5; x++)
2160 {
2161 if (!Stream_SafeSeek(s, 4))
2162 return FALSE;
2163 }
2164 Stream_Seek(s, 12); /* pad3 (12 bytes) */
2165 return TRUE;
2166}
2167
2168/*
2169 * Write bitmap cache v2 capability set.
2170 * msdn{cc240560}
2171 */
2172WINPR_ATTR_NODISCARD
2173static BOOL rdp_write_bitmap_cache_v2_capability_set(wLog* log, wStream* s,
2174 const rdpSettings* settings)
2175{
2176 WINPR_ASSERT(settings);
2177 if (!Stream_EnsureRemainingCapacity(s, 64))
2178 return FALSE;
2179
2180 const UINT32 BitmapCacheV2NumCells =
2181 freerdp_settings_get_uint32(settings, FreeRDP_BitmapCacheV2NumCells);
2182 BITMAP_CACHE_V2_CELL_INFO CellInfo[5] = WINPR_C_ARRAY_INIT;
2183
2184 const size_t header = rdp_capability_set_start(log, s);
2185 UINT16 cacheFlags = ALLOW_CACHE_WAITING_LIST_FLAG;
2186
2187 const BOOL persist = freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled);
2188 if (persist)
2189 cacheFlags |= PERSISTENT_KEYS_EXPECTED_FLAG;
2190
2191 for (UINT32 x = 0; x < BitmapCacheV2NumCells; x++)
2192 {
2193 BITMAP_CACHE_V2_CELL_INFO* cur = &settings->BitmapCacheV2CellInfo[x];
2194 if (persist)
2195 cur->persistent = 1;
2196 CellInfo[x] = *cur;
2197 }
2198
2199 Stream_Write_UINT16(s, cacheFlags); /* cacheFlags (2 bytes) */
2200 Stream_Write_UINT8(s, 0); /* pad2 (1 byte) */
2201 Stream_Write_UINT8(
2202 s, WINPR_ASSERTING_INT_CAST(uint8_t,
2203 settings->BitmapCacheV2NumCells)); /* numCellCaches (1 byte) */
2204
2205 for (UINT32 x = 0; x < ARRAYSIZE(CellInfo); x++)
2206 {
2207 if (!rdp_write_bitmap_cache_cell_info(s, &CellInfo[x])) /* bitmapCache0CellInfo (4 bytes) */
2208 return FALSE;
2209 }
2210 Stream_Zero(s, 12); /* pad3 (12 bytes) */
2211 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V2);
2212}
2213
2214#ifdef WITH_DEBUG_CAPABILITIES
2215WINPR_ATTR_NODISCARD
2216static BOOL rdp_print_bitmap_cache_v2_capability_set(wLog* log, wStream* s)
2217{
2218 BITMAP_CACHE_V2_CELL_INFO bitmapCacheV2CellInfo[5] = WINPR_C_ARRAY_INIT;
2219 WLog_Print(log, WLOG_TRACE,
2220 "BitmapCacheV2CapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2221
2222 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2223 return FALSE;
2224
2225 const UINT16 cacheFlags = Stream_Get_UINT16(s); /* cacheFlags (2 bytes) */
2226 const UINT8 pad2 = Stream_Get_UINT8(s); /* pad2 (1 byte) */
2227 const UINT8 numCellCaches = Stream_Get_UINT8(s); /* numCellCaches (1 byte) */
2228
2229 for (size_t x = 0; x < ARRAYSIZE(bitmapCacheV2CellInfo); x++)
2230 {
2231 if (!rdp_read_bitmap_cache_cell_info(
2232 log, s, &bitmapCacheV2CellInfo[x],
2233 bitmapCacheV2CellInfoLimits[x])) /* bitmapCache0CellInfo (4 bytes) */
2234 return FALSE;
2235 }
2236
2237 if (!Stream_SafeSeek(s, 12)) /* pad3 (12 bytes) */
2238 return FALSE;
2239
2240 WLog_Print(log, WLOG_TRACE, "\tcacheFlags: 0x%04" PRIX16 "", cacheFlags);
2241 WLog_Print(log, WLOG_TRACE, "\tpad2: 0x%02" PRIX8 "", pad2);
2242 WLog_Print(log, WLOG_TRACE, "\tnumCellCaches: 0x%02" PRIX8 "", numCellCaches);
2243 for (size_t x = 0; x < ARRAYSIZE(bitmapCacheV2CellInfo); x++)
2244 {
2245 const BITMAP_CACHE_V2_CELL_INFO* info = &bitmapCacheV2CellInfo[x];
2246 WLog_Print(log, WLOG_TRACE,
2247 "\tbitmapCache%" PRIuz "CellInfo: numEntries: %" PRIu32 " persistent: %" PRId32
2248 "",
2249 x, info->numEntries, info->persistent);
2250 }
2251 return TRUE;
2252}
2253#endif
2254
2255WINPR_ATTR_NODISCARD
2256static BOOL rdp_apply_virtual_channel_capability_set(rdpSettings* settings, const rdpSettings* src)
2257{
2258 WINPR_ASSERT(settings);
2259 WINPR_ASSERT(src);
2260
2261 /* MS servers and clients disregard in advertising what is relevant for their own side */
2262 if (settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_SC) &&
2263 (src->VCFlags & VCCAPS_COMPR_SC))
2264 settings->VCFlags |= VCCAPS_COMPR_SC;
2265 else
2266 settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_SC;
2267
2268 if (!settings->ServerMode && (settings->VCFlags & VCCAPS_COMPR_CS_8K) &&
2269 (src->VCFlags & VCCAPS_COMPR_CS_8K))
2270 settings->VCFlags |= VCCAPS_COMPR_CS_8K;
2271 else
2272 settings->VCFlags &= (uint32_t)~VCCAPS_COMPR_CS_8K;
2273
2274 /*
2275 * When one peer does not write the VCChunkSize, the VCChunkSize must not be
2276 * larger than CHANNEL_CHUNK_LENGTH (1600) bytes.
2277 * Also prevent an invalid 0 size.
2278 */
2279 if (!settings->ServerMode)
2280 {
2281 if ((src->VCChunkSize > CHANNEL_CHUNK_MAX_LENGTH) || (src->VCChunkSize == 0))
2282 settings->VCChunkSize = CHANNEL_CHUNK_LENGTH;
2283 else
2284 {
2285 settings->VCChunkSize = src->VCChunkSize;
2286 }
2287 }
2288
2289 return TRUE;
2290}
2291
2292/*
2293 * Read virtual channel capability set.
2294 * msdn{cc240551}
2295 */
2296WINPR_ATTR_NODISCARD
2297static BOOL rdp_read_virtual_channel_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2298{
2299 UINT32 flags = 0;
2300 UINT32 VCChunkSize = 0;
2301
2302 WINPR_ASSERT(settings);
2303 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2304 return FALSE;
2305
2306 Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2307
2308 if (Stream_GetRemainingLength(s) >= 4)
2309 Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2310 else
2311 VCChunkSize = UINT32_MAX; /* Use an invalid value to determine that value is not present */
2312
2313 settings->VCFlags = flags;
2314 settings->VCChunkSize = VCChunkSize;
2315
2316 return TRUE;
2317}
2318
2319/*
2320 * Write virtual channel capability set.
2321 * msdn{cc240551}
2322 */
2323WINPR_ATTR_NODISCARD
2324static BOOL rdp_write_virtual_channel_capability_set(wLog* log, wStream* s,
2325 const rdpSettings* settings)
2326{
2327 WINPR_ASSERT(settings);
2328 if (!Stream_EnsureRemainingCapacity(s, 32))
2329 return FALSE;
2330
2331 const size_t header = rdp_capability_set_start(log, s);
2332 Stream_Write_UINT32(s, settings->VCFlags); /* flags (4 bytes) */
2333 Stream_Write_UINT32(s, settings->VCChunkSize); /* VCChunkSize (4 bytes) */
2334 return rdp_capability_set_finish(s, header, CAPSET_TYPE_VIRTUAL_CHANNEL);
2335}
2336
2337#ifdef WITH_DEBUG_CAPABILITIES
2338WINPR_ATTR_NODISCARD
2339static BOOL rdp_print_virtual_channel_capability_set(wLog* log, wStream* s)
2340{
2341 UINT32 flags = 0;
2342 UINT32 VCChunkSize = 0;
2343 WLog_Print(log, WLOG_TRACE,
2344 "VirtualChannelCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2345
2346 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2347 return FALSE;
2348
2349 Stream_Read_UINT32(s, flags); /* flags (4 bytes) */
2350
2351 if (Stream_GetRemainingLength(s) >= 4)
2352 Stream_Read_UINT32(s, VCChunkSize); /* VCChunkSize (4 bytes) */
2353 else
2354 VCChunkSize = 1600;
2355
2356 WLog_Print(log, WLOG_TRACE, "\tflags: 0x%08" PRIX32 "", flags);
2357 WLog_Print(log, WLOG_TRACE, "\tVCChunkSize: 0x%08" PRIX32 "", VCChunkSize);
2358 return TRUE;
2359}
2360#endif
2361
2362WINPR_ATTR_NODISCARD
2363static BOOL rdp_apply_draw_nine_grid_cache_capability_set(rdpSettings* settings,
2364 const rdpSettings* src)
2365{
2366 WINPR_ASSERT(settings);
2367 WINPR_ASSERT(src);
2368
2369 settings->DrawNineGridCacheSize = src->DrawNineGridCacheSize;
2370 settings->DrawNineGridCacheEntries = src->DrawNineGridCacheEntries;
2371 settings->DrawNineGridEnabled = src->DrawNineGridEnabled;
2372
2373 return TRUE;
2374}
2375
2376/*
2377 * Read drawn nine grid cache capability set.
2378 * msdn{cc241565}
2379 */
2380WINPR_ATTR_NODISCARD
2381static BOOL rdp_read_draw_nine_grid_cache_capability_set(wLog* log, wStream* s,
2382 rdpSettings* settings)
2383{
2384 UINT32 drawNineGridSupportLevel = 0;
2385
2386 WINPR_ASSERT(settings);
2387 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2388 return FALSE;
2389
2390 Stream_Read_UINT32(s, drawNineGridSupportLevel); /* drawNineGridSupportLevel (4 bytes) */
2391 Stream_Read_UINT16(s, settings->DrawNineGridCacheSize); /* drawNineGridCacheSize (2 bytes) */
2392 Stream_Read_UINT16(s,
2393 settings->DrawNineGridCacheEntries); /* drawNineGridCacheEntries (2 bytes) */
2394
2395 settings->DrawNineGridEnabled =
2396 (drawNineGridSupportLevel & (DRAW_NINEGRID_SUPPORTED | DRAW_NINEGRID_SUPPORTED_V2)) != 0;
2397
2398 return TRUE;
2399}
2400
2401/*
2402 * Write drawn nine grid cache capability set.
2403 * msdn{cc241565}
2404 */
2405WINPR_ATTR_NODISCARD
2406static BOOL rdp_write_draw_nine_grid_cache_capability_set(wLog* log, wStream* s,
2407 const rdpSettings* settings)
2408{
2409 WINPR_ASSERT(settings);
2410 if (!Stream_EnsureRemainingCapacity(s, 32))
2411 return FALSE;
2412
2413 const size_t header = rdp_capability_set_start(log, s);
2414 const UINT32 drawNineGridSupportLevel =
2415 (settings->DrawNineGridEnabled) ? DRAW_NINEGRID_SUPPORTED_V2 : DRAW_NINEGRID_NO_SUPPORT;
2416 Stream_Write_UINT32(s, drawNineGridSupportLevel); /* drawNineGridSupportLevel (4 bytes) */
2417 Stream_Write_UINT16(
2418 s, WINPR_ASSERTING_INT_CAST(
2419 uint16_t, settings->DrawNineGridCacheSize)); /* drawNineGridCacheSize (2 bytes) */
2420 Stream_Write_UINT16(
2421 s,
2422 WINPR_ASSERTING_INT_CAST(
2423 uint16_t, settings->DrawNineGridCacheEntries)); /* drawNineGridCacheEntries (2 bytes) */
2424 return rdp_capability_set_finish(s, header, CAPSET_TYPE_DRAW_NINE_GRID_CACHE);
2425}
2426
2427#ifdef WITH_DEBUG_CAPABILITIES
2428WINPR_ATTR_NODISCARD
2429static BOOL rdp_print_draw_nine_grid_cache_capability_set(wLog* log, wStream* s)
2430{
2431 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
2432 return FALSE;
2433
2434 const uint32_t drawNineGridSupportLevel =
2435 Stream_Get_UINT32(s); /* drawNineGridSupportLevel (4 bytes) */
2436 const uint32_t DrawNineGridCacheSize =
2437 Stream_Get_UINT16(s); /* drawNineGridCacheSize (2 bytes) */
2438 const uint32_t DrawNineGridCacheEntries =
2439 Stream_Get_UINT16(s); /* drawNineGridCacheEntries (2 bytes) */
2440
2441 WLog_Print(log, WLOG_TRACE,
2442 "DrawNineGridCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2443 WLog_Print(log, WLOG_TRACE, "drawNineGridSupportLevel=0x%08" PRIx32, drawNineGridSupportLevel);
2444 WLog_Print(log, WLOG_TRACE, "DrawNineGridCacheSize=0x%08" PRIx32, DrawNineGridCacheSize);
2445 WLog_Print(log, WLOG_TRACE, "DrawNineGridCacheEntries=0x%08" PRIx32, DrawNineGridCacheEntries);
2446 return TRUE;
2447}
2448#endif
2449
2450WINPR_ATTR_NODISCARD
2451static BOOL rdp_apply_draw_gdiplus_cache_capability_set(rdpSettings* settings,
2452 const rdpSettings* src)
2453{
2454 WINPR_ASSERT(settings);
2455 WINPR_ASSERT(src);
2456
2457 if (src->DrawGdiPlusEnabled)
2458 settings->DrawGdiPlusEnabled = TRUE;
2459
2460 if (src->DrawGdiPlusCacheEnabled)
2461 settings->DrawGdiPlusCacheEnabled = TRUE;
2462
2463 return TRUE;
2464}
2465
2466/*
2467 * Read GDI+ cache capability set.
2468 * msdn{cc241566}
2469 */
2470WINPR_ATTR_NODISCARD
2471static BOOL rdp_read_draw_gdiplus_cache_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2472{
2473 UINT32 drawGDIPlusSupportLevel = 0;
2474 UINT32 drawGdiplusCacheLevel = 0;
2475
2476 WINPR_ASSERT(settings);
2477 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2478 return FALSE;
2479
2480 Stream_Read_UINT32(s, drawGDIPlusSupportLevel); /* drawGDIPlusSupportLevel (4 bytes) */
2481 Stream_Seek_UINT32(s); /* GdipVersion (4 bytes) */
2482 Stream_Read_UINT32(s, drawGdiplusCacheLevel); /* drawGdiplusCacheLevel (4 bytes) */
2483 Stream_Seek(s, 10); /* GdipCacheEntries (10 bytes) */
2484 Stream_Seek(s, 8); /* GdipCacheChunkSize (8 bytes) */
2485 Stream_Seek(s, 6); /* GdipImageCacheProperties (6 bytes) */
2486
2487 settings->DrawGdiPlusEnabled = (drawGDIPlusSupportLevel & DRAW_GDIPLUS_SUPPORTED) != 0;
2488 settings->DrawGdiPlusCacheEnabled = (drawGdiplusCacheLevel & DRAW_GDIPLUS_CACHE_LEVEL_ONE) != 0;
2489
2490 return TRUE;
2491}
2492
2493#ifdef WITH_DEBUG_CAPABILITIES
2494WINPR_ATTR_NODISCARD
2495static BOOL rdp_print_draw_gdiplus_cache_capability_set(wLog* log, wStream* s)
2496{
2497 WLog_Print(log, WLOG_TRACE,
2498 "DrawGdiPlusCacheCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2499
2500 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 36))
2501 return FALSE;
2502
2503 const uint32_t drawGdiPlusSupportLevel =
2504 Stream_Get_UINT32(s); /* drawGdiPlusSupportLevel (4 bytes) */
2505 const uint32_t GdipVersion = Stream_Get_UINT32(s); /* GdipVersion (4 bytes) */
2506 const uint32_t drawGdiplusCacheLevel =
2507 Stream_Get_UINT32(s); /* drawGdiPlusCacheLevel (4 bytes) */
2508 WLog_Print(log, WLOG_TRACE,
2509 "drawGdiPlusSupportLevel=0x%08" PRIx32 ", GdipVersion=0x%08" PRIx32
2510 ", drawGdiplusdrawGdiplusCacheLevelCacheLevel=0x%08" PRIx32,
2511 drawGdiPlusSupportLevel, GdipVersion, drawGdiplusCacheLevel);
2512 /* GdipCacheEntries (10 bytes) */
2513 const uint16_t GdipGraphicsCacheEntries = Stream_Get_UINT16(s);
2514 const uint16_t GdipBrushCacheEntries = Stream_Get_UINT16(s);
2515 const uint16_t GdipPenCacheEntries = Stream_Get_UINT16(s);
2516 const uint16_t GdipImageCacheEntries = Stream_Get_UINT16(s);
2517 const uint16_t GdipImageAttributesCacheEntries = Stream_Get_UINT16(s);
2518 WLog_Print(log, WLOG_TRACE,
2519 "GdipGraphicsCacheEntries=0x%04" PRIx16 ", GdipBrushCacheEntries=0x%04" PRIx16
2520 ", GdipPenCacheEntries=0x%04" PRIx16 ", GdipImageCacheEntries=0x%04" PRIx16
2521 ", GdipImageAttributesCacheEntries=0x%04" PRIx16,
2522 GdipGraphicsCacheEntries, GdipBrushCacheEntries, GdipPenCacheEntries,
2523 GdipImageCacheEntries, GdipImageAttributesCacheEntries);
2524 /* GdipCacheChunkSize (8 bytes) */
2525 const uint16_t GdipGraphicsCacheChunkSize = Stream_Get_UINT16(s);
2526 const uint16_t GdipObjectBrushCacheChunkSize = Stream_Get_UINT16(s);
2527 const uint16_t GdipObjectPenCacheChunkSize = Stream_Get_UINT16(s);
2528 const uint16_t GdipObjectImageAttributesCacheChunkSize = Stream_Get_UINT16(s);
2529 WLog_Print(log, WLOG_TRACE,
2530 "GdipGraphicsCacheChunkSize=0x%04" PRIx16
2531 ", GdipObjectBrushCacheChunkSize=0x%04" PRIx16
2532 ", GdipObjectPenCacheChunkSize=0x%04" PRIx16
2533 ",GdipObjectImageAttributesCacheChunkSize=0x%04" PRIx16,
2534 GdipGraphicsCacheChunkSize, GdipObjectBrushCacheChunkSize,
2535 GdipObjectPenCacheChunkSize, GdipObjectImageAttributesCacheChunkSize);
2536 /* GdipImageCacheProperties (6 bytes) */
2537 const uint16_t GdipObjectImageCacheChunkSize = Stream_Get_UINT16(s);
2538 const uint16_t GdipObjectImageCacheTotalSize = Stream_Get_UINT16(s);
2539 const uint16_t GdipObjectImageCacheMaxSize = Stream_Get_UINT16(s);
2540 WLog_Print(
2541 log, WLOG_TRACE,
2542 "GdipObjectImageCacheChunkSize=0x%04" PRIx16 ", GdipObjectImageCacheTotalSize=0x%04" PRIx16
2543 ", GdipObjectImageCacheMaxSize=0x%04" PRIx16,
2544 GdipObjectImageCacheChunkSize, GdipObjectImageCacheTotalSize, GdipObjectImageCacheMaxSize);
2545 return TRUE;
2546}
2547#endif
2548
2549WINPR_ATTR_NODISCARD
2550static BOOL rdp_apply_remote_programs_capability_set(rdpSettings* settings, const rdpSettings* src)
2551{
2552 WINPR_ASSERT(settings);
2553 WINPR_ASSERT(src);
2554
2555 if (settings->RemoteApplicationMode)
2556 settings->RemoteApplicationMode = src->RemoteApplicationMode;
2557
2558 /* 2.2.2.2.3 HandshakeEx PDU (TS_RAIL_ORDER_HANDSHAKE_EX)
2559 * the handshake ex pdu is supported when both, client and server announce
2560 * it OR if we are ready to begin enhanced remoteAPP mode. */
2561 UINT32 supportLevel = src->RemoteApplicationSupportLevel;
2562 if (settings->RemoteApplicationMode)
2563 supportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2564
2565 settings->RemoteApplicationSupportLevel = supportLevel & settings->RemoteApplicationSupportMask;
2566
2567 return TRUE;
2568}
2569
2570/*
2571 * Read remote programs capability set.
2572 * msdn{cc242518}
2573 */
2574WINPR_ATTR_NODISCARD
2575static BOOL rdp_read_remote_programs_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2576{
2577 UINT32 railSupportLevel = 0;
2578
2579 WINPR_ASSERT(settings);
2580 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2581 return FALSE;
2582
2583 Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2584
2585 settings->RemoteApplicationMode = (railSupportLevel & RAIL_LEVEL_SUPPORTED) != 0;
2586 settings->RemoteApplicationSupportLevel = railSupportLevel;
2587 return TRUE;
2588}
2589
2590/*
2591 * Write remote programs capability set.
2592 * msdn{cc242518}
2593 */
2594WINPR_ATTR_NODISCARD
2595static BOOL rdp_write_remote_programs_capability_set(wLog* log, wStream* s,
2596 const rdpSettings* settings)
2597{
2598 WINPR_ASSERT(settings);
2599 if (!Stream_EnsureRemainingCapacity(s, 64))
2600 return FALSE;
2601
2602 const size_t header = rdp_capability_set_start(log, s);
2603 UINT32 railSupportLevel = RAIL_LEVEL_SUPPORTED;
2604
2605 if (settings->RemoteApplicationSupportLevel & RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED)
2606 {
2607 if (settings->RemoteAppLanguageBarSupported)
2608 railSupportLevel |= RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED;
2609 }
2610
2611 railSupportLevel |= RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED;
2612 railSupportLevel |= RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED;
2613 railSupportLevel |= RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED;
2614 railSupportLevel |= RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED;
2615 railSupportLevel |= RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED;
2616 railSupportLevel |= RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED;
2617 /* Mask out everything the server does not support. */
2618 railSupportLevel &= settings->RemoteApplicationSupportLevel;
2619 Stream_Write_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2620 return rdp_capability_set_finish(s, header, CAPSET_TYPE_RAIL);
2621}
2622
2623#ifdef WITH_DEBUG_CAPABILITIES
2624WINPR_ATTR_NODISCARD
2625static BOOL rdp_print_remote_programs_capability_set(wLog* log, wStream* s)
2626{
2627 UINT32 railSupportLevel = 0;
2628 WLog_Print(log, WLOG_TRACE,
2629 "RemoteProgramsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2630
2631 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2632 return FALSE;
2633
2634 Stream_Read_UINT32(s, railSupportLevel); /* railSupportLevel (4 bytes) */
2635 WLog_Print(log, WLOG_TRACE, "\trailSupportLevel: 0x%08" PRIX32 "", railSupportLevel);
2636 return TRUE;
2637}
2638#endif
2639
2640WINPR_ATTR_NODISCARD
2641static BOOL rdp_apply_window_list_capability_set(rdpSettings* settings, const rdpSettings* src)
2642{
2643 WINPR_ASSERT(settings);
2644 WINPR_ASSERT(src);
2645
2646 settings->RemoteWndSupportLevel = src->RemoteWndSupportLevel;
2647 settings->RemoteAppNumIconCaches = src->RemoteAppNumIconCaches;
2648 settings->RemoteAppNumIconCacheEntries = src->RemoteAppNumIconCacheEntries;
2649
2650 return TRUE;
2651}
2652
2653/*
2654 * Read window list capability set.
2655 * msdn{cc242564}
2656 */
2657WINPR_ATTR_NODISCARD
2658static BOOL rdp_read_window_list_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2659{
2660 WINPR_ASSERT(settings);
2661 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2662 return FALSE;
2663
2664 Stream_Read_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2665 Stream_Read_UINT8(s, settings->RemoteAppNumIconCaches); /* numIconCaches (1 byte) */
2666 Stream_Read_UINT16(s,
2667 settings->RemoteAppNumIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2668 return TRUE;
2669}
2670
2671/*
2672 * Write window list capability set.
2673 * msdn{cc242564}
2674 */
2675WINPR_ATTR_NODISCARD
2676static BOOL rdp_write_window_list_capability_set(wLog* log, wStream* s, const rdpSettings* settings)
2677{
2678 WINPR_ASSERT(settings);
2679 if (!Stream_EnsureRemainingCapacity(s, 32))
2680 return FALSE;
2681
2682 const size_t header = rdp_capability_set_start(log, s);
2683 Stream_Write_UINT32(s, settings->RemoteWndSupportLevel); /* wndSupportLevel (4 bytes) */
2684 Stream_Write_UINT8(
2685 s, WINPR_ASSERTING_INT_CAST(uint8_t,
2686 settings->RemoteAppNumIconCaches)); /* numIconCaches (1 byte) */
2687 Stream_Write_UINT16(
2688 s,
2689 WINPR_ASSERTING_INT_CAST(
2690 uint16_t, settings->RemoteAppNumIconCacheEntries)); /* numIconCacheEntries (2 bytes) */
2691 return rdp_capability_set_finish(s, header, CAPSET_TYPE_WINDOW);
2692}
2693
2694#ifdef WITH_DEBUG_CAPABILITIES
2695WINPR_ATTR_NODISCARD
2696static BOOL rdp_print_window_list_capability_set(wLog* log, wStream* s)
2697{
2698 UINT32 wndSupportLevel = 0;
2699 BYTE numIconCaches = 0;
2700 UINT16 numIconCacheEntries = 0;
2701 WLog_Print(log, WLOG_TRACE,
2702 "WindowListCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
2703
2704 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 7))
2705 return FALSE;
2706
2707 Stream_Read_UINT32(s, wndSupportLevel); /* wndSupportLevel (4 bytes) */
2708 Stream_Read_UINT8(s, numIconCaches); /* numIconCaches (1 byte) */
2709 Stream_Read_UINT16(s, numIconCacheEntries); /* numIconCacheEntries (2 bytes) */
2710 WLog_Print(log, WLOG_TRACE, "\twndSupportLevel: 0x%08" PRIX32 "", wndSupportLevel);
2711 WLog_Print(log, WLOG_TRACE, "\tnumIconCaches: 0x%02" PRIX8 "", numIconCaches);
2712 WLog_Print(log, WLOG_TRACE, "\tnumIconCacheEntries: 0x%04" PRIX16 "", numIconCacheEntries);
2713 return TRUE;
2714}
2715#endif
2716
2717WINPR_ATTR_NODISCARD
2718static BOOL rdp_apply_desktop_composition_capability_set(rdpSettings* settings,
2719 const rdpSettings* src)
2720{
2721 WINPR_ASSERT(settings);
2722 WINPR_ASSERT(src);
2723
2724 settings->CompDeskSupportLevel = src->CompDeskSupportLevel;
2725 return TRUE;
2726}
2727
2728/*
2729 * Read desktop composition capability set.
2730 * msdn{cc240855}
2731 */
2732WINPR_ATTR_NODISCARD
2733static BOOL rdp_read_desktop_composition_capability_set(wLog* log, wStream* s,
2734 rdpSettings* settings)
2735{
2736 WINPR_UNUSED(settings);
2737 WINPR_ASSERT(settings);
2738
2739 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2740 return FALSE;
2741
2742 Stream_Read_UINT16(s, settings->CompDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2743 return TRUE;
2744}
2745
2746/*
2747 * Write desktop composition capability set.
2748 * msdn{cc240855}
2749 */
2750WINPR_ATTR_NODISCARD
2751static BOOL rdp_write_desktop_composition_capability_set(wLog* log, wStream* s,
2752 const rdpSettings* settings)
2753{
2754 WINPR_ASSERT(settings);
2755
2756 if (!Stream_EnsureRemainingCapacity(s, 32))
2757 return FALSE;
2758
2759 const size_t header = rdp_capability_set_start(log, s);
2760 const UINT16 compDeskSupportLevel =
2761 (settings->AllowDesktopComposition) ? COMPDESK_SUPPORTED : COMPDESK_NOT_SUPPORTED;
2762 Stream_Write_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2763 return rdp_capability_set_finish(s, header, CAPSET_TYPE_COMP_DESK);
2764}
2765
2766#ifdef WITH_DEBUG_CAPABILITIES
2767WINPR_ATTR_NODISCARD
2768static BOOL rdp_print_desktop_composition_capability_set(wLog* log, wStream* s)
2769{
2770 UINT16 compDeskSupportLevel = 0;
2771 WLog_Print(log, WLOG_TRACE, "DesktopCompositionCapabilitySet (length %" PRIuz "):",
2772 Stream_GetRemainingLength(s));
2773
2774 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2775 return FALSE;
2776
2777 Stream_Read_UINT16(s, compDeskSupportLevel); /* compDeskSupportLevel (2 bytes) */
2778 WLog_Print(log, WLOG_TRACE, "\tcompDeskSupportLevel: 0x%04" PRIX16 "", compDeskSupportLevel);
2779 return TRUE;
2780}
2781#endif
2782
2783WINPR_ATTR_NODISCARD
2784static BOOL rdp_apply_multifragment_update_capability_set(rdpSettings* settings,
2785 const rdpSettings* src)
2786{
2787 WINPR_ASSERT(settings);
2788 WINPR_ASSERT(src);
2789
2790 UINT32 multifragMaxRequestSize =
2791 freerdp_settings_get_uint32(src, FreeRDP_MultifragMaxRequestSize);
2792
2793 if (settings->ServerMode)
2794 {
2795 /*
2796 * Special case: The client announces multifragment update support but sets the maximum
2797 * request size to something smaller than maximum size for *one* fast-path PDU. In this case
2798 * behave like no multifragment updates were supported and make sure no fragmentation
2799 * happens by setting FASTPATH_FRAGMENT_SAFE_SIZE.
2800 *
2801 * This behaviour was observed with some windows ce rdp clients.
2802 */
2803 if (multifragMaxRequestSize < FASTPATH_MAX_PACKET_SIZE)
2804 multifragMaxRequestSize = FASTPATH_FRAGMENT_SAFE_SIZE;
2805
2806 if (settings->RemoteFxCodec)
2807 {
2808 /*
2809 * If we are using RemoteFX the client MUST use a value greater
2810 * than or equal to the value we've previously sent in the server to
2811 * client multi-fragment update capability set (MS-RDPRFX 1.5)
2812 */
2813 if (multifragMaxRequestSize <
2814 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize))
2815 {
2816 /*
2817 * If it happens to be smaller we honor the client's value but
2818 * have to disable RemoteFX
2819 */
2820 settings->RemoteFxCodec = FALSE;
2821 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2822 multifragMaxRequestSize))
2823 return FALSE;
2824 }
2825 else
2826 {
2827 /* no need to increase server's max request size setting here */
2828 }
2829 }
2830 else
2831 {
2832 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2833 multifragMaxRequestSize))
2834 return FALSE;
2835 }
2836 }
2837 else
2838 {
2839 /*
2840 * In client mode we keep up with the server's capabilities.
2841 * In RemoteFX mode we MUST do this but it might also be useful to
2842 * receive larger related bitmap updates.
2843 */
2844 if (multifragMaxRequestSize >
2845 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize))
2846 {
2847 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2848 multifragMaxRequestSize))
2849 return FALSE;
2850 }
2851 }
2852 return TRUE;
2853}
2854
2855/*
2856 * Read multifragment update capability set.
2857 * msdn{cc240649}
2858 */
2859WINPR_ATTR_NODISCARD
2860static BOOL rdp_read_multifragment_update_capability_set(wLog* log, wStream* s,
2861 rdpSettings* settings)
2862{
2863 WINPR_ASSERT(settings);
2864 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2865 return FALSE;
2866
2867 const UINT32 multifragMaxRequestSize = Stream_Get_UINT32(s); /* MaxRequestSize (4 bytes) */
2868 return freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2869 multifragMaxRequestSize);
2870}
2871
2872/*
2873 * Write multifragment update capability set.
2874 * msdn{cc240649}
2875 */
2876WINPR_ATTR_NODISCARD
2877static BOOL rdp_write_multifragment_update_capability_set(wLog* log, wStream* s,
2878 rdpSettings* settings)
2879{
2880 WINPR_ASSERT(settings);
2881 if (settings->ServerMode &&
2882 (freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize) == 0))
2883 {
2884 /*
2885 * In server mode we prefer to use the highest useful request size that
2886 * will allow us to pack a complete screen update into a single fast
2887 * path PDU using any of the supported codecs.
2888 * However, the client is completely free to accept our proposed
2889 * max request size or send a different value in the client-to-server
2890 * multi-fragment update capability set and we have to accept that,
2891 * unless we are using RemoteFX where the client MUST announce a value
2892 * greater than or equal to the value we're sending here.
2893 * See [MS-RDPRFX 1.5 capability #2]
2894 */
2895 const UINT32 tileNumX = (settings->DesktopWidth + 63) / 64;
2896 const UINT32 tileNumY = (settings->DesktopHeight + 63) / 64;
2897 const UINT32 limit = UINT32_MAX / 16384u;
2898
2899 if (tileNumX >= limit / tileNumY)
2900 {
2901 WLog_Print(log, WLOG_ERROR,
2902 "(DesktopWidth * DesktopHeigth) / 64 exceed limit of %" PRIu32, limit);
2903 return FALSE;
2904 }
2905 if (tileNumY >= limit / tileNumX)
2906 {
2907 WLog_Print(log, WLOG_ERROR,
2908 "(DesktopWidth * DesktopHeigth) / 64 exceed limit of %" PRIu32, limit);
2909 return FALSE;
2910 }
2911
2912 /* and add room for headers, regions, frame markers, etc. */
2913 const UINT32 MultifragMaxRequestSize = (tileNumX * tileNumY + 1u) * 16384u;
2914
2915 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
2916 MultifragMaxRequestSize))
2917 return FALSE;
2918 }
2919
2920 if (!Stream_EnsureRemainingCapacity(s, 32))
2921 return FALSE;
2922 const size_t header = rdp_capability_set_start(log, s);
2923 Stream_Write_UINT32(s, settings->MultifragMaxRequestSize); /* MaxRequestSize (4 bytes) */
2924 return rdp_capability_set_finish(s, header, CAPSET_TYPE_MULTI_FRAGMENT_UPDATE);
2925}
2926
2927#ifdef WITH_DEBUG_CAPABILITIES
2928WINPR_ATTR_NODISCARD
2929static BOOL rdp_print_multifragment_update_capability_set(wLog* log, wStream* s)
2930{
2931 UINT32 maxRequestSize = 0;
2932 WLog_Print(log, WLOG_TRACE, "MultifragmentUpdateCapabilitySet (length %" PRIuz "):",
2933 Stream_GetRemainingLength(s));
2934
2935 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
2936 return FALSE;
2937
2938 Stream_Read_UINT32(s, maxRequestSize); /* maxRequestSize (4 bytes) */
2939 WLog_Print(log, WLOG_TRACE, "\tmaxRequestSize: 0x%08" PRIX32 "", maxRequestSize);
2940 return TRUE;
2941}
2942#endif
2943
2944WINPR_ATTR_NODISCARD
2945static BOOL rdp_apply_large_pointer_capability_set(rdpSettings* settings, const rdpSettings* src)
2946{
2947 WINPR_ASSERT(settings);
2948 WINPR_ASSERT(src);
2949
2950 settings->LargePointerFlag = src->LargePointerFlag;
2951 return TRUE;
2952}
2953
2954/*
2955 * Read large pointer capability set.
2956 * msdn{cc240650}
2957 */
2958WINPR_ATTR_NODISCARD
2959static BOOL rdp_read_large_pointer_capability_set(wLog* log, wStream* s, rdpSettings* settings)
2960{
2961 UINT16 largePointerSupportFlags = 0;
2962
2963 WINPR_ASSERT(settings);
2964 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
2965 return FALSE;
2966
2967 Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2968 settings->LargePointerFlag &= largePointerSupportFlags;
2969 if ((largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384)) != 0)
2970 {
2971 WLog_Print(
2972 log, WLOG_WARN,
2973 "TS_LARGE_POINTER_CAPABILITYSET with unsupported flags %04X (all flags %04X) received",
2974 WINPR_CXX_COMPAT_CAST(UINT32, largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 |
2975 LARGE_POINTER_FLAG_384x384)),
2976 largePointerSupportFlags);
2977 }
2978 return TRUE;
2979}
2980
2981/*
2982 * Write large pointer capability set.
2983 * msdn{cc240650}
2984 */
2985WINPR_ATTR_NODISCARD
2986static BOOL rdp_write_large_pointer_capability_set(wLog* log, wStream* s,
2987 const rdpSettings* settings)
2988{
2989 WINPR_ASSERT(settings);
2990 if (!Stream_EnsureRemainingCapacity(s, 32))
2991 return FALSE;
2992
2993 const size_t header = rdp_capability_set_start(log, s);
2994 const UINT16 largePointerSupportFlags =
2995 settings->LargePointerFlag & (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384);
2996 Stream_Write_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
2997 return rdp_capability_set_finish(s, header, CAPSET_TYPE_LARGE_POINTER);
2998}
2999
3000#ifdef WITH_DEBUG_CAPABILITIES
3001WINPR_ATTR_NODISCARD
3002static BOOL rdp_print_large_pointer_capability_set(wLog* log, wStream* s)
3003{
3004 UINT16 largePointerSupportFlags = 0;
3005 WLog_Print(log, WLOG_TRACE,
3006 "LargePointerCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3007
3008 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
3009 return FALSE;
3010
3011 Stream_Read_UINT16(s, largePointerSupportFlags); /* largePointerSupportFlags (2 bytes) */
3012 WLog_Print(log, WLOG_TRACE, "\tlargePointerSupportFlags: 0x%04" PRIX16 "",
3013 largePointerSupportFlags);
3014 return TRUE;
3015}
3016#endif
3017
3018WINPR_ATTR_NODISCARD
3019static BOOL rdp_apply_surface_commands_capability_set(rdpSettings* settings, const rdpSettings* src)
3020{
3021 WINPR_ASSERT(settings);
3022 WINPR_ASSERT(src);
3023
3024 /* [MS-RDPBCGR] 2.2.7.2.9 Surface Commands Capability Set (TS_SURFCMDS_CAPABILITYSET)
3025 *
3026 * disable surface commands if the remote does not support fastpath
3027 */
3028 if (src->FastPathOutput)
3029 {
3030 settings->SurfaceCommandsSupported &= src->SurfaceCommandsSupported;
3031 settings->SurfaceCommandsEnabled = src->SurfaceCommandsEnabled;
3032 settings->SurfaceFrameMarkerEnabled = src->SurfaceFrameMarkerEnabled;
3033 }
3034 else
3035 {
3036 settings->SurfaceCommandsSupported = 0;
3037 settings->SurfaceCommandsEnabled = FALSE;
3038 settings->SurfaceFrameMarkerEnabled = FALSE;
3039 }
3040
3041 return TRUE;
3042}
3043
3044/*
3045 * Read surface commands capability set.
3046 * msdn{dd871563}
3047 */
3048WINPR_ATTR_NODISCARD
3049static BOOL rdp_read_surface_commands_capability_set(wLog* log, wStream* s, rdpSettings* settings)
3050{
3051 UINT32 cmdFlags = 0;
3052
3053 WINPR_ASSERT(settings);
3054 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
3055 return FALSE;
3056
3057 Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3058 Stream_Seek_UINT32(s); /* reserved (4 bytes) */
3059 settings->SurfaceCommandsSupported = cmdFlags;
3060 settings->SurfaceCommandsEnabled =
3061 (cmdFlags & (SURFCMDS_SET_SURFACE_BITS | SURFCMDS_STREAM_SURFACE_BITS)) != 0;
3062 settings->SurfaceFrameMarkerEnabled = (cmdFlags & SURFCMDS_FRAME_MARKER) != 0;
3063 return TRUE;
3064}
3065
3066/*
3067 * Write surface commands capability set.
3068 * msdn{dd871563}
3069 */
3070WINPR_ATTR_NODISCARD
3071static BOOL rdp_write_surface_commands_capability_set(wLog* log, wStream* s,
3072 const rdpSettings* settings)
3073{
3074 WINPR_ASSERT(settings);
3075 if (!Stream_EnsureRemainingCapacity(s, 32))
3076 return FALSE;
3077
3078 const size_t header = rdp_capability_set_start(log, s);
3079 // TODO: Make these configurable too
3080 UINT32 cmdFlags = freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
3081
3082 if (settings->SurfaceFrameMarkerEnabled)
3083 cmdFlags |= SURFCMDS_FRAME_MARKER;
3084
3085 Stream_Write_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3086 Stream_Write_UINT32(s, 0); /* reserved (4 bytes) */
3087 return rdp_capability_set_finish(s, header, CAPSET_TYPE_SURFACE_COMMANDS);
3088}
3089
3090WINPR_ATTR_NODISCARD
3091static bool sUuidEqual(const UUID* Uuid1, const UUID* Uuid2)
3092{
3093 if (!Uuid1 && !Uuid2)
3094 return false;
3095
3096 if (Uuid1 && !Uuid2)
3097 return false;
3098
3099 if (!Uuid1 && Uuid2)
3100 return false;
3101
3102 if (Uuid1->Data1 != Uuid2->Data1)
3103 return false;
3104
3105 if (Uuid1->Data2 != Uuid2->Data2)
3106 return false;
3107
3108 if (Uuid1->Data3 != Uuid2->Data3)
3109 return false;
3110
3111 for (int index = 0; index < 8; index++)
3112 {
3113 if (Uuid1->Data4[index] != Uuid2->Data4[index])
3114 return false;
3115 }
3116
3117 return true;
3118}
3119
3120#ifdef WITH_DEBUG_CAPABILITIES
3121WINPR_ATTR_NODISCARD
3122static BOOL rdp_print_surface_commands_capability_set(wLog* log, wStream* s)
3123{
3124 UINT32 cmdFlags = 0;
3125 UINT32 reserved = 0;
3126
3127 WLog_Print(log, WLOG_TRACE,
3128 "SurfaceCommandsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3129
3130 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8))
3131 return FALSE;
3132
3133 Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
3134 Stream_Read_UINT32(s, reserved); /* reserved (4 bytes) */
3135 WLog_Print(log, WLOG_TRACE, "\tcmdFlags: 0x%08" PRIX32 "", cmdFlags);
3136 WLog_Print(log, WLOG_TRACE, "\treserved: 0x%08" PRIX32 "", reserved);
3137 return TRUE;
3138}
3139
3140static void rdp_print_bitmap_codec_guid(wLog* log, const GUID* guid)
3141{
3142 WINPR_ASSERT(guid);
3143 WLog_Print(log, WLOG_TRACE,
3144 "%08" PRIX32 "%04" PRIX16 "%04" PRIX16 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8
3145 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "",
3146 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
3147 guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6],
3148 guid->Data4[7]);
3149}
3150
3151WINPR_ATTR_NODISCARD
3152static char* rdp_get_bitmap_codec_guid_name(const GUID* guid)
3153{
3154 WINPR_ASSERT(guid);
3155 if (sUuidEqual(guid, &CODEC_GUID_REMOTEFX))
3156 return "CODEC_GUID_REMOTEFX";
3157 else if (sUuidEqual(guid, &CODEC_GUID_NSCODEC))
3158 return "CODEC_GUID_NSCODEC";
3159 else if (sUuidEqual(guid, &CODEC_GUID_IGNORE))
3160 return "CODEC_GUID_IGNORE";
3161 else if (sUuidEqual(guid, &CODEC_GUID_IMAGE_REMOTEFX))
3162 return "CODEC_GUID_IMAGE_REMOTEFX";
3163
3164#if defined(WITH_JPEG)
3165 else if (sUuidEqual(guid, &CODEC_GUID_JPEG))
3166 return "CODEC_GUID_JPEG";
3167
3168#endif
3169 return "CODEC_GUID_UNKNOWN";
3170}
3171#endif
3172
3173WINPR_ATTR_NODISCARD
3174static BOOL rdp_read_bitmap_codec_guid(wLog* log, wStream* s, GUID* guid)
3175{
3176 BYTE g[16] = WINPR_C_ARRAY_INIT;
3177
3178 WINPR_ASSERT(guid);
3179 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16))
3180 return FALSE;
3181 Stream_Read(s, g, 16);
3182 guid->Data1 = ((UINT32)g[3] << 24U) | ((UINT32)g[2] << 16U) | (UINT32)(g[1] << 8U) | g[0];
3183 guid->Data2 = ((g[5] << 8U) | g[4]) & 0xFFFF;
3184 guid->Data3 = ((g[7] << 8U) | g[6]) & 0xFFFF;
3185 guid->Data4[0] = g[8];
3186 guid->Data4[1] = g[9];
3187 guid->Data4[2] = g[10];
3188 guid->Data4[3] = g[11];
3189 guid->Data4[4] = g[12];
3190 guid->Data4[5] = g[13];
3191 guid->Data4[6] = g[14];
3192 guid->Data4[7] = g[15];
3193 return TRUE;
3194}
3195
3196static void rdp_write_bitmap_codec_guid(wStream* s, const GUID* guid)
3197{
3198 BYTE g[16] = WINPR_C_ARRAY_INIT;
3199 WINPR_ASSERT(guid);
3200 g[0] = guid->Data1 & 0xFF;
3201 g[1] = (guid->Data1 >> 8) & 0xFF;
3202 g[2] = (guid->Data1 >> 16) & 0xFF;
3203 g[3] = (guid->Data1 >> 24) & 0xFF;
3204 g[4] = (guid->Data2) & 0xFF;
3205 g[5] = (guid->Data2 >> 8) & 0xFF;
3206 g[6] = (guid->Data3) & 0xFF;
3207 g[7] = (guid->Data3 >> 8) & 0xFF;
3208 g[8] = guid->Data4[0];
3209 g[9] = guid->Data4[1];
3210 g[10] = guid->Data4[2];
3211 g[11] = guid->Data4[3];
3212 g[12] = guid->Data4[4];
3213 g[13] = guid->Data4[5];
3214 g[14] = guid->Data4[6];
3215 g[15] = guid->Data4[7];
3216 Stream_Write(s, g, 16);
3217}
3218
3219WINPR_ATTR_NODISCARD
3220static BOOL rdp_apply_bitmap_codecs_capability_set(rdpSettings* settings, const rdpSettings* src)
3221{
3222 WINPR_ASSERT(settings);
3223 WINPR_ASSERT(src);
3224
3225 if (settings->ServerMode)
3226 {
3227
3228 settings->RemoteFxCodecId = src->RemoteFxCodecId;
3229 settings->RemoteFxCaptureFlags = src->RemoteFxCaptureFlags;
3230 settings->RemoteFxOnly = src->RemoteFxOnly;
3231 settings->RemoteFxRlgrMode = src->RemoteFxRlgrMode;
3232 settings->RemoteFxCodecMode = src->RemoteFxCodecMode;
3233 settings->NSCodecId = src->NSCodecId;
3234 settings->NSCodecAllowDynamicColorFidelity = src->NSCodecAllowDynamicColorFidelity;
3235 settings->NSCodecAllowSubsampling = src->NSCodecAllowSubsampling;
3236 settings->NSCodecColorLossLevel = src->NSCodecColorLossLevel;
3237
3238 /* only enable a codec if we've announced/enabled it before */
3239 settings->RemoteFxCodec = settings->RemoteFxCodec && src->RemoteFxCodecId;
3240 settings->RemoteFxImageCodec = settings->RemoteFxImageCodec && src->RemoteFxImageCodec;
3241 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec,
3242 settings->NSCodec && src->NSCodec))
3243 return FALSE;
3244 settings->JpegCodec = src->JpegCodec;
3245 }
3246 return TRUE;
3247}
3248
3249WINPR_ATTR_NODISCARD
3250static BOOL rdp_read_codec_ts_rfx_icap(wLog* log, wStream* sub, rdpSettings* settings,
3251 UINT16 icapLen)
3252{
3253 UINT16 version = 0;
3254 UINT16 tileSize = 0;
3255 BYTE codecFlags = 0;
3256 BYTE colConvBits = 0;
3257 BYTE transformBits = 0;
3258 BYTE entropyBits = 0;
3259 /* TS_RFX_ICAP */
3260 if (icapLen != 8)
3261 {
3262 WLog_Print(log, WLOG_ERROR,
3263 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP size %" PRIu16
3264 " unsupported, expecting size %" PRIu16 " not supported",
3265 icapLen, 8u);
3266 return FALSE;
3267 }
3268
3269 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3270 return FALSE;
3271
3272 Stream_Read_UINT16(sub, version); /* version (2 bytes) */
3273 Stream_Read_UINT16(sub, tileSize); /* tileSize (2 bytes) */
3274 Stream_Read_UINT8(sub, codecFlags); /* flags (1 byte) */
3275 Stream_Read_UINT8(sub, colConvBits); /* colConvBits (1 byte) */
3276 Stream_Read_UINT8(sub, transformBits); /* transformBits (1 byte) */
3277 Stream_Read_UINT8(sub, entropyBits); /* entropyBits (1 byte) */
3278
3279 if (version == 0x0009)
3280 {
3281 /* Version 0.9 */
3282 if (tileSize != 0x0080)
3283 {
3284 WLog_Print(log, WLOG_ERROR,
3285 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3286 " tile size %" PRIu16 " not supported",
3287 version, tileSize);
3288 return FALSE;
3289 }
3290 }
3291 else if (version == 0x0100)
3292 {
3293 /* Version 1.0 */
3294 if (tileSize != 0x0040)
3295 {
3296 WLog_Print(log, WLOG_ERROR,
3297 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16
3298 " tile size %" PRIu16 " not supported",
3299 version, tileSize);
3300 return FALSE;
3301 }
3302 }
3303 else
3304 {
3305 WLog_Print(log, WLOG_ERROR,
3306 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16 " not supported",
3307 version);
3308 return FALSE;
3309 }
3310
3311 /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_COL_CONV_ICT (0x1) */
3312 if (colConvBits != 1)
3313 {
3314 WLog_Print(log, WLOG_ERROR,
3315 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::colConvBits %" PRIu8
3316 " not supported, must be CLW_COL_CONV_ICT (0x1)",
3317 colConvBits);
3318 return FALSE;
3319 }
3320
3321 /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_XFORM_DWT_53_A (0x1) */
3322 if (transformBits != 1)
3323 {
3324 WLog_Print(log, WLOG_ERROR,
3325 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::transformBits %" PRIu8
3326 " not supported, must be CLW_XFORM_DWT_53_A (0x1)",
3327 colConvBits);
3328 return FALSE;
3329 }
3330
3331 const UINT8 CODEC_MODE = 0x02; /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP */
3332 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x00))
3333 return FALSE;
3334
3335 if ((codecFlags & CODEC_MODE) != 0)
3336 {
3337 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x02))
3338 return FALSE;
3339 }
3340 else if ((codecFlags & ~CODEC_MODE) != 0)
3341 WLog_Print(log, WLOG_WARN,
3342 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::flags unknown value "
3343 "0x%02" PRIx32,
3344 WINPR_CXX_COMPAT_CAST(UINT32, (codecFlags & ~CODEC_MODE)));
3345
3346 switch (entropyBits)
3347 {
3348 case CLW_ENTROPY_RLGR1:
3349 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR1))
3350 return FALSE;
3351 break;
3352 case CLW_ENTROPY_RLGR3:
3353 if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3))
3354 return FALSE;
3355 break;
3356 default:
3357 WLog_Print(log, WLOG_ERROR,
3358 "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::entropyBits "
3359 "unsupported value 0x%02" PRIx8
3360 ", must be CLW_ENTROPY_RLGR1 (0x01) or CLW_ENTROPY_RLGR3 "
3361 "(0x04)",
3362 entropyBits);
3363 return FALSE;
3364 }
3365 return TRUE;
3366}
3367
3368WINPR_ATTR_NODISCARD
3369static BOOL rdp_read_codec_ts_rfx_capset(wLog* log, wStream* s, rdpSettings* settings)
3370{
3371 UINT16 blockType = 0;
3372 UINT32 blockLen = 0;
3373 BYTE rfxCodecId = 0;
3374 UINT16 capsetType = 0;
3375 UINT16 numIcaps = 0;
3376 UINT16 icapLen = 0;
3377
3378 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 6))
3379 return FALSE;
3380
3381 /* TS_RFX_CAPSET */
3382 Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
3383 Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */
3384 if (blockType != 0xCBC1)
3385 {
3386 WLog_Print(log, WLOG_ERROR,
3387 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockType[0x%04" PRIx16
3388 "] != CBY_CAPSET (0xCBC1)",
3389 blockType);
3390 return FALSE;
3391 }
3392 if (blockLen < 6ull)
3393 {
3394 WLog_Print(log, WLOG_ERROR,
3395 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockLen[%" PRIu32 "] < 6", blockLen);
3396 return FALSE;
3397 }
3398 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, blockLen - 6ull))
3399 return FALSE;
3400
3401 wStream sbuffer = WINPR_C_ARRAY_INIT;
3402 wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), blockLen - 6ull);
3403 WINPR_ASSERT(sub);
3404
3405 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 7))
3406 return FALSE;
3407
3408 Stream_Read_UINT8(sub, rfxCodecId); /* codecId (1 byte) */
3409 Stream_Read_UINT16(sub, capsetType); /* capsetType (2 bytes) */
3410 Stream_Read_UINT16(sub, numIcaps); /* numIcaps (2 bytes) */
3411 Stream_Read_UINT16(sub, icapLen); /* icapLen (2 bytes) */
3412
3413 if (rfxCodecId != 1)
3414 {
3415 WLog_Print(log, WLOG_ERROR,
3416 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::codecId[%" PRIu16 "] != 1", rfxCodecId);
3417 return FALSE;
3418 }
3419
3420 if (capsetType != 0xCFC0)
3421 {
3422 WLog_Print(log, WLOG_ERROR,
3423 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::capsetType[0x%04" PRIx16
3424 "] != CLY_CAPSET (0xCFC0)",
3425 capsetType);
3426 return FALSE;
3427 }
3428
3429 while (numIcaps--)
3430 {
3431 if (!rdp_read_codec_ts_rfx_icap(log, sub, settings, icapLen))
3432 return FALSE;
3433 }
3434 return TRUE;
3435}
3436
3437WINPR_ATTR_NODISCARD
3438static BOOL rdp_read_codec_ts_rfx_caps(wLog* log, wStream* sub, rdpSettings* settings)
3439{
3440 if (Stream_GetRemainingLength(sub) == 0)
3441 return TRUE;
3442
3443 UINT16 blockType = 0;
3444 UINT32 blockLen = 0;
3445 UINT16 numCapsets = 0;
3446
3447 /* TS_RFX_CAPS */
3448 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3449 return FALSE;
3450 Stream_Read_UINT16(sub, blockType); /* blockType (2 bytes) */
3451 Stream_Read_UINT32(sub, blockLen); /* blockLen (4 bytes) */
3452 Stream_Read_UINT16(sub, numCapsets); /* numCapsets (2 bytes) */
3453
3454 if (blockType != 0xCBC0)
3455 {
3456 WLog_Print(log, WLOG_ERROR,
3457 "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockType[0x%04" PRIx16
3458 "] != CBY_CAPS (0xCBC0)",
3459 blockType);
3460 return FALSE;
3461 }
3462
3463 if (blockLen != 8)
3464 {
3465 WLog_Print(log, WLOG_ERROR, "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockLen[%" PRIu16 "] != 8",
3466 blockLen);
3467 return FALSE;
3468 }
3469
3470 if (numCapsets != 1)
3471 {
3472 WLog_Print(log, WLOG_ERROR,
3473 "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::numIcaps[%" PRIu16 "] != 1", numCapsets);
3474 return FALSE;
3475 }
3476
3477 for (UINT16 x = 0; x < numCapsets; x++)
3478 {
3479 if (!rdp_read_codec_ts_rfx_capset(log, sub, settings))
3480 return FALSE;
3481 }
3482
3483 return TRUE;
3484}
3485
3486WINPR_ATTR_NODISCARD
3487static BOOL rdp_read_codec_ts_rfx_clnt_caps_container(wLog* log, wStream* s, rdpSettings* settings)
3488{
3489 UINT32 rfxCapsLength = 0;
3490 UINT32 rfxPropsLength = 0;
3491 UINT32 captureFlags = 0;
3492
3493 /* [MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER */
3494 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3495 return FALSE;
3496 Stream_Read_UINT32(s, rfxPropsLength); /* length (4 bytes) */
3497 if (rfxPropsLength < 4)
3498 {
3499 WLog_Print(log, WLOG_ERROR,
3500 "[MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER::length %" PRIu32
3501 " too short, require at least 4 bytes",
3502 rfxPropsLength);
3503 return FALSE;
3504 }
3505 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, rfxPropsLength - 4ull))
3506 return FALSE;
3507
3508 wStream sbuffer = WINPR_C_ARRAY_INIT;
3509 wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), rfxPropsLength - 4ull);
3510 WINPR_ASSERT(sub);
3511
3512 Stream_Seek(s, rfxPropsLength - 4ull);
3513
3514 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 8))
3515 return FALSE;
3516
3517 Stream_Read_UINT32(sub, captureFlags); /* captureFlags (4 bytes) */
3518 Stream_Read_UINT32(sub, rfxCapsLength); /* capsLength (4 bytes) */
3519 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, rfxCapsLength))
3520 return FALSE;
3521
3522 settings->RemoteFxCaptureFlags = captureFlags;
3523 settings->RemoteFxOnly = !(captureFlags & CARDP_CAPS_CAPTURE_NON_CAC);
3524
3525 /* [MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS */
3526 wStream tsbuffer = WINPR_C_ARRAY_INIT;
3527 wStream* ts_sub = Stream_StaticConstInit(&tsbuffer, Stream_Pointer(sub), rfxCapsLength);
3528 WINPR_ASSERT(ts_sub);
3529 return rdp_read_codec_ts_rfx_caps(log, ts_sub, settings);
3530}
3531
3532/*
3533 * Read bitmap codecs capability set.
3534 * msdn{dd891377}
3535 */
3536WINPR_ATTR_NODISCARD
3537static BOOL rdp_read_bitmap_codecs_capability_set(wLog* log, wStream* s, rdpSettings* settings,
3538 BOOL isServer)
3539{
3540 BYTE codecId = 0;
3541 GUID codecGuid = WINPR_C_ARRAY_INIT;
3542 BYTE bitmapCodecCount = 0;
3543 UINT16 codecPropertiesLength = 0;
3544
3545 BOOL guidNSCodec = FALSE;
3546 BOOL guidRemoteFx = FALSE;
3547 BOOL guidRemoteFxImage = FALSE;
3548
3549 WINPR_ASSERT(settings);
3550 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3551 return FALSE;
3552
3553 Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3554
3555 while (bitmapCodecCount > 0)
3556 {
3557 wStream subbuffer = WINPR_C_ARRAY_INIT;
3558
3559 if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3560 return FALSE;
3561 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3562 return FALSE;
3563 Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3564 Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3565
3566 wStream* sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), codecPropertiesLength);
3567 if (!Stream_SafeSeek(s, codecPropertiesLength))
3568 return FALSE;
3569
3570 if (isServer)
3571 {
3572 if (sUuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX))
3573 {
3574 guidRemoteFx = TRUE;
3575 settings->RemoteFxCodecId = codecId;
3576 if (!rdp_read_codec_ts_rfx_clnt_caps_container(log, sub, settings))
3577 return FALSE;
3578 }
3579 else if (sUuidEqual(&codecGuid, &CODEC_GUID_IMAGE_REMOTEFX))
3580 {
3581 /* Microsoft RDP servers ignore CODEC_GUID_IMAGE_REMOTEFX codec properties */
3582 guidRemoteFxImage = TRUE;
3583 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3584 return FALSE;
3585 }
3586 else if (sUuidEqual(&codecGuid, &CODEC_GUID_NSCODEC))
3587 {
3588 BYTE colorLossLevel = 0;
3589 BYTE fAllowSubsampling = 0;
3590 BYTE fAllowDynamicFidelity = 0;
3591 guidNSCodec = TRUE;
3592 settings->NSCodecId = codecId;
3593 if (!Stream_CheckAndLogRequiredLengthWLog(log, sub, 3))
3594 return FALSE;
3595 Stream_Read_UINT8(sub, fAllowDynamicFidelity); /* fAllowDynamicFidelity (1 byte) */
3596 Stream_Read_UINT8(sub, fAllowSubsampling); /* fAllowSubsampling (1 byte) */
3597 Stream_Read_UINT8(sub, colorLossLevel); /* colorLossLevel (1 byte) */
3598
3599 if (colorLossLevel < 1)
3600 colorLossLevel = 1;
3601
3602 if (colorLossLevel > 7)
3603 colorLossLevel = 7;
3604
3605 settings->NSCodecAllowDynamicColorFidelity = fAllowDynamicFidelity;
3606 settings->NSCodecAllowSubsampling = fAllowSubsampling;
3607 settings->NSCodecColorLossLevel = colorLossLevel;
3608 }
3609 else if (sUuidEqual(&codecGuid, &CODEC_GUID_IGNORE))
3610 {
3611 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3612 return FALSE;
3613 }
3614 else
3615 {
3616 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3617 return FALSE;
3618 }
3619 }
3620 else
3621 {
3622 if (!Stream_SafeSeek(sub, codecPropertiesLength)) /* codecProperties */
3623 return FALSE;
3624 }
3625
3626 const size_t rest = Stream_GetRemainingLength(sub);
3627 if (rest > 0)
3628 {
3629 WLog_Print(log, WLOG_ERROR,
3630 "error while reading codec properties: actual size: %" PRIuz
3631 " expected size: %" PRIu32 "",
3632 rest + codecPropertiesLength, codecPropertiesLength);
3633 }
3634 bitmapCodecCount--;
3635
3636 /* only enable a codec if we've announced/enabled it before */
3637 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, guidRemoteFx))
3638 return FALSE;
3639 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxImageCodec, guidRemoteFxImage))
3640 return FALSE;
3641 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, guidNSCodec))
3642 return FALSE;
3643 if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
3644 return FALSE;
3645 }
3646
3647 return TRUE;
3648}
3649
3650/*
3651 * Write RemoteFX Client Capability Container.
3652 */
3653WINPR_ATTR_NODISCARD
3654static BOOL rdp_write_rfx_client_capability_container(wStream* s, const rdpSettings* settings)
3655{
3656 WINPR_ASSERT(settings);
3657 if (!Stream_EnsureRemainingCapacity(s, 64))
3658 return FALSE;
3659
3660 const UINT32 captureFlags = settings->RemoteFxOnly ? 0 : CARDP_CAPS_CAPTURE_NON_CAC;
3661
3662 WINPR_ASSERT(settings->RemoteFxCodecMode <= UINT8_MAX);
3663 const UINT8 codecMode = (UINT8)settings->RemoteFxCodecMode;
3664 Stream_Write_UINT16(s, 49); /* codecPropertiesLength */
3665 /* TS_RFX_CLNT_CAPS_CONTAINER */
3666 Stream_Write_UINT32(s, 49); /* length */
3667 Stream_Write_UINT32(s, captureFlags); /* captureFlags */
3668 Stream_Write_UINT32(s, 37); /* capsLength */
3669 /* TS_RFX_CAPS */
3670 Stream_Write_UINT16(s, CBY_CAPS); /* blockType */
3671 Stream_Write_UINT32(s, 8); /* blockLen */
3672 Stream_Write_UINT16(s, 1); /* numCapsets */
3673 /* TS_RFX_CAPSET */
3674 Stream_Write_UINT16(s, CBY_CAPSET); /* blockType */
3675 Stream_Write_UINT32(s, 29); /* blockLen */
3676 Stream_Write_UINT8(s, 0x01); /* codecId (MUST be set to 0x01) */
3677 Stream_Write_UINT16(s, CLY_CAPSET); /* capsetType */
3678 Stream_Write_UINT16(s, 2); /* numIcaps */
3679 Stream_Write_UINT16(s, 8); /* icapLen */
3680 /* TS_RFX_ICAP (RLGR1) */
3681 Stream_Write_UINT16(s, CLW_VERSION_1_0); /* version */
3682 Stream_Write_UINT16(s, CT_TILE_64x64); /* tileSize */
3683 Stream_Write_UINT8(s, codecMode); /* flags */
3684 Stream_Write_UINT8(s, CLW_COL_CONV_ICT); /* colConvBits */
3685 Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3686 Stream_Write_UINT8(s, CLW_ENTROPY_RLGR1); /* entropyBits */
3687 /* TS_RFX_ICAP (RLGR3) */
3688 Stream_Write_UINT16(s, CLW_VERSION_1_0); /* version */
3689 Stream_Write_UINT16(s, CT_TILE_64x64); /* tileSize */
3690 Stream_Write_UINT8(s, codecMode); /* flags */
3691 Stream_Write_UINT8(s, CLW_COL_CONV_ICT); /* colConvBits */
3692 Stream_Write_UINT8(s, CLW_XFORM_DWT_53_A); /* transformBits */
3693 Stream_Write_UINT8(s, CLW_ENTROPY_RLGR3); /* entropyBits */
3694 return TRUE;
3695}
3696
3697/*
3698 * Write NSCODEC Client Capability Container.
3699 */
3700WINPR_ATTR_NODISCARD
3701static BOOL rdp_write_nsc_client_capability_container(wStream* s, const rdpSettings* settings)
3702{
3703 WINPR_ASSERT(settings);
3704
3705 const BOOL fAllowDynamicFidelity = settings->NSCodecAllowDynamicColorFidelity;
3706 const BOOL fAllowSubsampling = settings->NSCodecAllowSubsampling;
3707 UINT32 colorLossLevel = settings->NSCodecColorLossLevel;
3708
3709 if (colorLossLevel < 1)
3710 colorLossLevel = 1;
3711
3712 if (colorLossLevel > 7)
3713 colorLossLevel = 7;
3714
3715 if (!Stream_EnsureRemainingCapacity(s, 8))
3716 return FALSE;
3717
3718 Stream_Write_UINT16(s, 3); /* codecPropertiesLength */
3719 /* TS_NSCODEC_CAPABILITYSET */
3720 Stream_Write_UINT8(s, fAllowDynamicFidelity != 0); /* fAllowDynamicFidelity (1 byte) */
3721 Stream_Write_UINT8(s, fAllowSubsampling != 0); /* fAllowSubsampling (1 byte) */
3722 Stream_Write_UINT8(s, (UINT8)colorLossLevel); /* colorLossLevel (1 byte) */
3723 return TRUE;
3724}
3725
3726#if defined(WITH_JPEG)
3727WINPR_ATTR_NODISCARD
3728static BOOL rdp_write_jpeg_client_capability_container(wStream* s, const rdpSettings* settings)
3729{
3730 WINPR_ASSERT(settings);
3731 if (!Stream_EnsureRemainingCapacity(s, 8))
3732 return FALSE;
3733
3734 Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3735
3736 const UINT32 q = freerdp_settings_get_uint32(settings, FreeRDP_JpegQuality);
3737 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, q));
3738 return TRUE;
3739}
3740#endif
3741
3742/*
3743 * Write RemoteFX Server Capability Container.
3744 */
3745WINPR_ATTR_NODISCARD
3746static BOOL rdp_write_rfx_server_capability_container(wStream* s, const rdpSettings* settings)
3747{
3748 WINPR_UNUSED(settings);
3749 WINPR_ASSERT(settings);
3750
3751 if (!Stream_EnsureRemainingCapacity(s, 8))
3752 return FALSE;
3753
3754 Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3755 Stream_Write_UINT32(s, 0); /* reserved */
3756 return TRUE;
3757}
3758
3759#if defined(WITH_JPEG)
3760WINPR_ATTR_NODISCARD
3761static BOOL rdp_write_jpeg_server_capability_container(wStream* s, const rdpSettings* settings)
3762{
3763 WINPR_UNUSED(settings);
3764 WINPR_ASSERT(settings);
3765
3766 if (!Stream_EnsureRemainingCapacity(s, 8))
3767 return FALSE;
3768
3769 Stream_Write_UINT16(s, 1); /* codecPropertiesLength */
3770 Stream_Write_UINT8(s, 75);
3771 return TRUE;
3772}
3773#endif
3774
3775/*
3776 * Write NSCODEC Server Capability Container.
3777 */
3778WINPR_ATTR_NODISCARD
3779static BOOL rdp_write_nsc_server_capability_container(wStream* s, const rdpSettings* settings)
3780{
3781 WINPR_UNUSED(settings);
3782 WINPR_ASSERT(settings);
3783
3784 if (!Stream_EnsureRemainingCapacity(s, 8))
3785 return FALSE;
3786
3787 Stream_Write_UINT16(s, 4); /* codecPropertiesLength */
3788 Stream_Write_UINT32(s, 0); /* reserved */
3789 return TRUE;
3790}
3791
3792/*
3793 * Write bitmap codecs capability set.
3794 * msdn{dd891377}
3795 */
3796
3797WINPR_ATTR_NODISCARD
3798static BOOL rdp_write_bitmap_codecs_capability_set(wLog* log, wStream* s,
3799 const rdpSettings* settings)
3800{
3801 WINPR_ASSERT(settings);
3802 if (!Stream_EnsureRemainingCapacity(s, 64))
3803 return FALSE;
3804
3805 const size_t header = rdp_capability_set_start(log, s);
3806 BYTE bitmapCodecCount = 0;
3807
3808 if (settings->RemoteFxCodec)
3809 bitmapCodecCount++;
3810
3811 if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3812 bitmapCodecCount++;
3813
3814#if defined(WITH_JPEG)
3815
3816 if (settings->JpegCodec)
3817 bitmapCodecCount++;
3818
3819#endif
3820
3821 if (settings->RemoteFxImageCodec)
3822 bitmapCodecCount++;
3823
3824 Stream_Write_UINT8(s, bitmapCodecCount);
3825
3826 if (settings->RemoteFxCodec)
3827 {
3828 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_REMOTEFX); /* codecGUID */
3829
3830 if (settings->ServerMode)
3831 {
3832 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3833
3834 if (!rdp_write_rfx_server_capability_container(s, settings))
3835 return FALSE;
3836 }
3837 else
3838 {
3839 Stream_Write_UINT8(s, RDP_CODEC_ID_REMOTEFX); /* codecID */
3840
3841 if (!rdp_write_rfx_client_capability_container(s, settings))
3842 return FALSE;
3843 }
3844 }
3845
3846 if (freerdp_settings_get_bool(settings, FreeRDP_NSCodec))
3847 {
3848 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_NSCODEC); /* codecGUID */
3849
3850 if (settings->ServerMode)
3851 {
3852 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3853
3854 if (!rdp_write_nsc_server_capability_container(s, settings))
3855 return FALSE;
3856 }
3857 else
3858 {
3859 Stream_Write_UINT8(s, RDP_CODEC_ID_NSCODEC); /* codecID */
3860
3861 if (!rdp_write_nsc_client_capability_container(s, settings))
3862 return FALSE;
3863 }
3864 }
3865
3866#if defined(WITH_JPEG)
3867
3868 if (settings->JpegCodec)
3869 {
3870 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_JPEG); /* codecGUID */
3871
3872 if (settings->ServerMode)
3873 {
3874 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3875
3876 if (!rdp_write_jpeg_server_capability_container(s, settings))
3877 return FALSE;
3878 }
3879 else
3880 {
3881 Stream_Write_UINT8(s, RDP_CODEC_ID_JPEG); /* codecID */
3882
3883 if (!rdp_write_jpeg_client_capability_container(s, settings))
3884 return FALSE;
3885 }
3886 }
3887
3888#endif
3889
3890 if (settings->RemoteFxImageCodec)
3891 {
3892 rdp_write_bitmap_codec_guid(s, &CODEC_GUID_IMAGE_REMOTEFX); /* codecGUID */
3893
3894 if (settings->ServerMode)
3895 {
3896 Stream_Write_UINT8(s, 0); /* codecID is defined by the client */
3897
3898 if (!rdp_write_rfx_server_capability_container(s, settings))
3899 return FALSE;
3900 }
3901 else
3902 {
3903 Stream_Write_UINT8(s, RDP_CODEC_ID_IMAGE_REMOTEFX); /* codecID */
3904
3905 if (!rdp_write_rfx_client_capability_container(s, settings))
3906 return FALSE;
3907 }
3908 }
3909
3910 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CODECS);
3911}
3912
3913#ifdef WITH_DEBUG_CAPABILITIES
3914WINPR_ATTR_NODISCARD
3915static BOOL rdp_print_bitmap_codecs_capability_set(wLog* log, wStream* s)
3916{
3917 GUID codecGuid = WINPR_C_ARRAY_INIT;
3918 BYTE bitmapCodecCount = 0;
3919 BYTE codecId = 0;
3920 UINT16 codecPropertiesLength = 0;
3921
3922 WLog_Print(log, WLOG_TRACE,
3923 "BitmapCodecsCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
3924
3925 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
3926 return FALSE;
3927
3928 Stream_Read_UINT8(s, bitmapCodecCount); /* bitmapCodecCount (1 byte) */
3929 WLog_Print(log, WLOG_TRACE, "\tbitmapCodecCount: %" PRIu8 "", bitmapCodecCount);
3930
3931 while (bitmapCodecCount > 0)
3932 {
3933 if (!rdp_read_bitmap_codec_guid(log, s, &codecGuid)) /* codecGuid (16 bytes) */
3934 return FALSE;
3935 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 3))
3936 return FALSE;
3937 Stream_Read_UINT8(s, codecId); /* codecId (1 byte) */
3938 WLog_Print(log, WLOG_TRACE, "\tcodecGuid: 0x");
3939 rdp_print_bitmap_codec_guid(log, &codecGuid);
3940 WLog_Print(log, WLOG_TRACE, " (%s)", rdp_get_bitmap_codec_guid_name(&codecGuid));
3941 WLog_Print(log, WLOG_TRACE, "\tcodecId: %" PRIu8 "", codecId);
3942 Stream_Read_UINT16(s, codecPropertiesLength); /* codecPropertiesLength (2 bytes) */
3943 WLog_Print(log, WLOG_TRACE, "\tcodecPropertiesLength: %" PRIu16 "", codecPropertiesLength);
3944
3945 if (!Stream_SafeSeek(s, codecPropertiesLength)) /* codecProperties */
3946 return FALSE;
3947 bitmapCodecCount--;
3948 }
3949
3950 return TRUE;
3951}
3952#endif
3953
3954WINPR_ATTR_NODISCARD
3955static BOOL rdp_apply_frame_acknowledge_capability_set(rdpSettings* settings,
3956 const rdpSettings* src)
3957{
3958 WINPR_ASSERT(settings);
3959 WINPR_ASSERT(src);
3960
3961 if (settings->ServerMode)
3962 settings->FrameAcknowledge = src->FrameAcknowledge;
3963
3964 return TRUE;
3965}
3966
3967/*
3968 * Read frame acknowledge capability set.
3969 */
3970WINPR_ATTR_NODISCARD
3971static BOOL rdp_read_frame_acknowledge_capability_set(wLog* log, wStream* s, rdpSettings* settings)
3972{
3973 WINPR_ASSERT(settings);
3974 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
3975 return FALSE;
3976
3977 Stream_Read_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3978
3979 return TRUE;
3980}
3981
3982/*
3983 * Write frame acknowledge capability set.
3984 */
3985WINPR_ATTR_NODISCARD
3986static BOOL rdp_write_frame_acknowledge_capability_set(wLog* log, wStream* s,
3987 const rdpSettings* settings)
3988{
3989 WINPR_ASSERT(settings);
3990 if (!Stream_EnsureRemainingCapacity(s, 32))
3991 return FALSE;
3992
3993 const size_t header = rdp_capability_set_start(log, s);
3994 Stream_Write_UINT32(s, settings->FrameAcknowledge); /* (4 bytes) */
3995 return rdp_capability_set_finish(s, header, CAPSET_TYPE_FRAME_ACKNOWLEDGE);
3996}
3997
3998#ifdef WITH_DEBUG_CAPABILITIES
3999WINPR_ATTR_NODISCARD
4000static BOOL rdp_print_frame_acknowledge_capability_set(wLog* log, wStream* s)
4001{
4002 UINT32 frameAcknowledge = 0;
4003 WLog_Print(log, WLOG_TRACE,
4004 "FrameAcknowledgeCapabilitySet (length %" PRIuz "):", Stream_GetRemainingLength(s));
4005
4006 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4007 return FALSE;
4008
4009 Stream_Read_UINT32(s, frameAcknowledge); /* frameAcknowledge (4 bytes) */
4010 WLog_Print(log, WLOG_TRACE, "\tframeAcknowledge: 0x%08" PRIX32 "", frameAcknowledge);
4011 return TRUE;
4012}
4013#endif
4014
4015WINPR_ATTR_NODISCARD
4016static BOOL rdp_apply_bitmap_cache_v3_codec_id_capability_set(rdpSettings* settings,
4017 const rdpSettings* src)
4018{
4019 WINPR_ASSERT(settings);
4020 WINPR_ASSERT(src);
4021
4022 settings->BitmapCacheV3CodecId = src->BitmapCacheV3CodecId;
4023 return TRUE;
4024}
4025
4026WINPR_ATTR_NODISCARD
4027static BOOL rdp_read_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
4028 rdpSettings* settings)
4029{
4030 BYTE bitmapCacheV3CodecId = 0;
4031
4032 WINPR_ASSERT(settings);
4033 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
4034 return FALSE;
4035
4036 Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
4037 settings->BitmapCacheV3CodecId = bitmapCacheV3CodecId;
4038 return TRUE;
4039}
4040
4041WINPR_ATTR_NODISCARD
4042static BOOL rdp_write_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s,
4043 const rdpSettings* settings)
4044{
4045 WINPR_ASSERT(settings);
4046 if (!Stream_EnsureRemainingCapacity(s, 32))
4047 return FALSE;
4048
4049 const size_t header = rdp_capability_set_start(log, s);
4050 if (settings->BitmapCacheV3CodecId > UINT8_MAX)
4051 return FALSE;
4052 Stream_Write_UINT8(s, (UINT8)settings->BitmapCacheV3CodecId);
4053 return rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID);
4054}
4055
4056#ifdef WITH_DEBUG_CAPABILITIES
4057WINPR_ATTR_NODISCARD
4058static BOOL rdp_print_bitmap_cache_v3_codec_id_capability_set(wLog* log, wStream* s)
4059{
4060 BYTE bitmapCacheV3CodecId = 0;
4061 WLog_Print(log, WLOG_TRACE, "BitmapCacheV3CodecIdCapabilitySet (length %" PRIuz "):",
4062 Stream_GetRemainingLength(s));
4063
4064 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
4065 return FALSE;
4066
4067 Stream_Read_UINT8(s, bitmapCacheV3CodecId); /* bitmapCacheV3CodecId (1 byte) */
4068 WLog_Print(log, WLOG_TRACE, "\tbitmapCacheV3CodecId: 0x%02" PRIX8 "", bitmapCacheV3CodecId);
4069 return TRUE;
4070}
4071
4072BOOL rdp_print_capability_sets(wLog* log, wStream* s, size_t start, BOOL receiving)
4073{
4074 BOOL rc = FALSE;
4075 UINT16 type = 0;
4076 UINT16 length = 0;
4077 UINT16 numberCapabilities = 0;
4078
4079 size_t pos = Stream_GetPosition(s);
4080
4081 if (!Stream_SetPosition(s, start))
4082 goto fail;
4083
4084 if (receiving)
4085 {
4086 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4087 goto fail;
4088 }
4089 else
4090 {
4091 if (!Stream_CheckAndLogRequiredCapacityWLog(log, (s), 4))
4092 goto fail;
4093 }
4094
4095 Stream_Read_UINT16(s, numberCapabilities);
4096 Stream_Seek(s, 2);
4097
4098 while (numberCapabilities > 0)
4099 {
4100 size_t rest = 0;
4101 wStream subBuffer;
4102 wStream* sub = nullptr;
4103
4104 if (!rdp_read_capability_set_header(log, s, &length, &type))
4105 goto fail;
4106
4107 WLog_Print(log, WLOG_TRACE, "%s ", receiving ? "Receiving" : "Sending");
4108 sub = Stream_StaticInit(&subBuffer, Stream_Pointer(s), length - 4);
4109 if (!Stream_SafeSeek(s, length - 4))
4110 goto fail;
4111
4112 switch (type)
4113 {
4114 case CAPSET_TYPE_GENERAL:
4115 if (!rdp_print_general_capability_set(log, sub))
4116 goto fail;
4117
4118 break;
4119
4120 case CAPSET_TYPE_BITMAP:
4121 if (!rdp_print_bitmap_capability_set(log, sub))
4122 goto fail;
4123
4124 break;
4125
4126 case CAPSET_TYPE_ORDER:
4127 if (!rdp_print_order_capability_set(log, sub))
4128 goto fail;
4129
4130 break;
4131
4132 case CAPSET_TYPE_BITMAP_CACHE:
4133 if (!rdp_print_bitmap_cache_capability_set(log, sub))
4134 goto fail;
4135
4136 break;
4137
4138 case CAPSET_TYPE_CONTROL:
4139 if (!rdp_print_control_capability_set(log, sub))
4140 goto fail;
4141
4142 break;
4143
4144 case CAPSET_TYPE_ACTIVATION:
4145 if (!rdp_print_window_activation_capability_set(log, sub))
4146 goto fail;
4147
4148 break;
4149
4150 case CAPSET_TYPE_POINTER:
4151 if (!rdp_print_pointer_capability_set(log, sub))
4152 goto fail;
4153
4154 break;
4155
4156 case CAPSET_TYPE_SHARE:
4157 if (!rdp_print_share_capability_set(log, sub))
4158 goto fail;
4159
4160 break;
4161
4162 case CAPSET_TYPE_COLOR_CACHE:
4163 if (!rdp_print_color_cache_capability_set(log, sub))
4164 goto fail;
4165
4166 break;
4167
4168 case CAPSET_TYPE_SOUND:
4169 if (!rdp_print_sound_capability_set(log, sub))
4170 goto fail;
4171
4172 break;
4173
4174 case CAPSET_TYPE_INPUT:
4175 if (!rdp_print_input_capability_set(log, sub))
4176 goto fail;
4177
4178 break;
4179
4180 case CAPSET_TYPE_FONT:
4181 if (!rdp_print_font_capability_set(log, sub))
4182 goto fail;
4183
4184 break;
4185
4186 case CAPSET_TYPE_BRUSH:
4187 if (!rdp_print_brush_capability_set(log, sub))
4188 goto fail;
4189
4190 break;
4191
4192 case CAPSET_TYPE_GLYPH_CACHE:
4193 if (!rdp_print_glyph_cache_capability_set(log, sub))
4194 goto fail;
4195
4196 break;
4197
4198 case CAPSET_TYPE_OFFSCREEN_CACHE:
4199 if (!rdp_print_offscreen_bitmap_cache_capability_set(log, sub))
4200 goto fail;
4201
4202 break;
4203
4204 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4205 if (!rdp_print_bitmap_cache_host_support_capability_set(log, sub))
4206 goto fail;
4207
4208 break;
4209
4210 case CAPSET_TYPE_BITMAP_CACHE_V2:
4211 if (!rdp_print_bitmap_cache_v2_capability_set(log, sub))
4212 goto fail;
4213
4214 break;
4215
4216 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4217 if (!rdp_print_virtual_channel_capability_set(log, sub))
4218 goto fail;
4219
4220 break;
4221
4222 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4223 if (!rdp_print_draw_nine_grid_cache_capability_set(log, sub))
4224 goto fail;
4225
4226 break;
4227
4228 case CAPSET_TYPE_DRAW_GDI_PLUS:
4229 if (!rdp_print_draw_gdiplus_cache_capability_set(log, sub))
4230 goto fail;
4231
4232 break;
4233
4234 case CAPSET_TYPE_RAIL:
4235 if (!rdp_print_remote_programs_capability_set(log, sub))
4236 goto fail;
4237
4238 break;
4239
4240 case CAPSET_TYPE_WINDOW:
4241 if (!rdp_print_window_list_capability_set(log, sub))
4242 goto fail;
4243
4244 break;
4245
4246 case CAPSET_TYPE_COMP_DESK:
4247 if (!rdp_print_desktop_composition_capability_set(log, sub))
4248 goto fail;
4249
4250 break;
4251
4252 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4253 if (!rdp_print_multifragment_update_capability_set(log, sub))
4254 goto fail;
4255
4256 break;
4257
4258 case CAPSET_TYPE_LARGE_POINTER:
4259 if (!rdp_print_large_pointer_capability_set(log, sub))
4260 goto fail;
4261
4262 break;
4263
4264 case CAPSET_TYPE_SURFACE_COMMANDS:
4265 if (!rdp_print_surface_commands_capability_set(log, sub))
4266 goto fail;
4267
4268 break;
4269
4270 case CAPSET_TYPE_BITMAP_CODECS:
4271 if (!rdp_print_bitmap_codecs_capability_set(log, sub))
4272 goto fail;
4273
4274 break;
4275
4276 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4277 if (!rdp_print_frame_acknowledge_capability_set(log, sub))
4278 goto fail;
4279
4280 break;
4281
4282 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4283 if (!rdp_print_bitmap_cache_v3_codec_id_capability_set(log, sub))
4284 goto fail;
4285
4286 break;
4287
4288 default:
4289 WLog_Print(log, WLOG_ERROR, "unknown capability type %" PRIu16 "", type);
4290 break;
4291 }
4292
4293 rest = Stream_GetRemainingLength(sub);
4294 if (rest > 0)
4295 {
4296 WLog_Print(log, WLOG_WARN,
4297 "incorrect capability offset, type:0x%04" PRIX16 " %" PRIu16
4298 " bytes expected, %" PRIuz "bytes remaining",
4299 type, length, rest);
4300 }
4301
4302 numberCapabilities--;
4303 }
4304
4305 rc = TRUE;
4306fail:
4307 if (!Stream_SetPosition(s, pos))
4308 return FALSE;
4309
4310 return rc;
4311}
4312#endif
4313
4314WINPR_ATTR_NODISCARD
4315static BOOL rdp_apply_from_received(UINT16 type, rdpSettings* dst, const rdpSettings* src)
4316{
4317 switch (type)
4318 {
4319 case CAPSET_TYPE_GENERAL:
4320 return rdp_apply_general_capability_set(dst, src);
4321 case CAPSET_TYPE_BITMAP:
4322 return rdp_apply_bitmap_capability_set(dst, src);
4323 case CAPSET_TYPE_ORDER:
4324 return rdp_apply_order_capability_set(dst, src);
4325 case CAPSET_TYPE_POINTER:
4326 return rdp_apply_pointer_capability_set(dst, src);
4327 case CAPSET_TYPE_INPUT:
4328 return rdp_apply_input_capability_set(dst, src);
4329 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4330 return rdp_apply_virtual_channel_capability_set(dst, src);
4331 case CAPSET_TYPE_SHARE:
4332 return rdp_apply_share_capability_set(dst, src);
4333 case CAPSET_TYPE_COLOR_CACHE:
4334 return rdp_apply_color_cache_capability_set(dst, src);
4335 case CAPSET_TYPE_FONT:
4336 return rdp_apply_font_capability_set(dst, src);
4337 case CAPSET_TYPE_DRAW_GDI_PLUS:
4338 return rdp_apply_draw_gdiplus_cache_capability_set(dst, src);
4339 case CAPSET_TYPE_RAIL:
4340 return rdp_apply_remote_programs_capability_set(dst, src);
4341 case CAPSET_TYPE_WINDOW:
4342 return rdp_apply_window_list_capability_set(dst, src);
4343 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4344 return rdp_apply_multifragment_update_capability_set(dst, src);
4345 case CAPSET_TYPE_LARGE_POINTER:
4346 return rdp_apply_large_pointer_capability_set(dst, src);
4347 case CAPSET_TYPE_COMP_DESK:
4348 return rdp_apply_desktop_composition_capability_set(dst, src);
4349 case CAPSET_TYPE_SURFACE_COMMANDS:
4350 return rdp_apply_surface_commands_capability_set(dst, src);
4351 case CAPSET_TYPE_BITMAP_CODECS:
4352 return rdp_apply_bitmap_codecs_capability_set(dst, src);
4353 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4354 return rdp_apply_frame_acknowledge_capability_set(dst, src);
4355 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4356 return rdp_apply_bitmap_cache_v3_codec_id_capability_set(dst, src);
4357 case CAPSET_TYPE_BITMAP_CACHE:
4358 return rdp_apply_bitmap_cache_capability_set(dst, src);
4359 case CAPSET_TYPE_BITMAP_CACHE_V2:
4360 return rdp_apply_bitmap_cache_v2_capability_set(dst, src);
4361 case CAPSET_TYPE_BRUSH:
4362 return rdp_apply_brush_capability_set(dst, src);
4363 case CAPSET_TYPE_GLYPH_CACHE:
4364 return rdp_apply_glyph_cache_capability_set(dst, src);
4365 case CAPSET_TYPE_OFFSCREEN_CACHE:
4366 return rdp_apply_offscreen_bitmap_cache_capability_set(dst, src);
4367 case CAPSET_TYPE_SOUND:
4368 return rdp_apply_sound_capability_set(dst, src);
4369 case CAPSET_TYPE_CONTROL:
4370 return rdp_apply_control_capability_set(dst, src);
4371 case CAPSET_TYPE_ACTIVATION:
4372 return rdp_apply_window_activation_capability_set(dst, src);
4373 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4374 return rdp_apply_draw_nine_grid_cache_capability_set(dst, src);
4375 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4376 return rdp_apply_bitmap_cache_host_support_capability_set(dst, src);
4377 default:
4378 return TRUE;
4379 }
4380}
4381
4382BOOL rdp_read_capability_set(wLog* log, wStream* sub, UINT16 type, rdpSettings* settings,
4383 BOOL isServer)
4384{
4385 WINPR_ASSERT(settings);
4386
4387 if (type <= CAPSET_TYPE_FRAME_ACKNOWLEDGE)
4388 {
4389 const size_t size = Stream_Length(sub);
4390 if (size > UINT32_MAX)
4391 return FALSE;
4392
4393 WINPR_ASSERT(settings->ReceivedCapabilities);
4394 settings->ReceivedCapabilities[type] = TRUE;
4395
4396 WINPR_ASSERT(settings->ReceivedCapabilityDataSizes);
4397 settings->ReceivedCapabilityDataSizes[type] = (UINT32)size;
4398
4399 WINPR_ASSERT(settings->ReceivedCapabilityData);
4400 void* tmp = realloc(settings->ReceivedCapabilityData[type], size);
4401 if (!tmp && (size > 0))
4402 return FALSE;
4403 if (tmp)
4404 memcpy(tmp, Stream_Buffer(sub), size);
4405 settings->ReceivedCapabilityData[type] = tmp;
4406 }
4407 else
4408 WLog_Print(log, WLOG_WARN, "not handling capability type %" PRIu16 " yet", type);
4409
4410 BOOL treated = TRUE;
4411
4412 switch (type)
4413 {
4414 case CAPSET_TYPE_GENERAL:
4415 if (!rdp_read_general_capability_set(log, sub, settings))
4416 return FALSE;
4417
4418 break;
4419
4420 case CAPSET_TYPE_BITMAP:
4421 if (!rdp_read_bitmap_capability_set(log, sub, settings))
4422 return FALSE;
4423
4424 break;
4425
4426 case CAPSET_TYPE_ORDER:
4427 if (!rdp_read_order_capability_set(log, sub, settings))
4428 return FALSE;
4429
4430 break;
4431
4432 case CAPSET_TYPE_POINTER:
4433 if (!rdp_read_pointer_capability_set(log, sub, settings))
4434 return FALSE;
4435
4436 break;
4437
4438 case CAPSET_TYPE_INPUT:
4439 if (!rdp_read_input_capability_set(log, sub, settings, isServer))
4440 return FALSE;
4441
4442 break;
4443
4444 case CAPSET_TYPE_VIRTUAL_CHANNEL:
4445 if (!rdp_read_virtual_channel_capability_set(log, sub, settings))
4446 return FALSE;
4447
4448 break;
4449
4450 case CAPSET_TYPE_SHARE:
4451 if (!rdp_read_share_capability_set(log, sub, settings))
4452 return FALSE;
4453
4454 break;
4455
4456 case CAPSET_TYPE_COLOR_CACHE:
4457 if (!rdp_read_color_cache_capability_set(log, sub, settings))
4458 return FALSE;
4459
4460 break;
4461
4462 case CAPSET_TYPE_FONT:
4463 if (!rdp_read_font_capability_set(log, sub, settings))
4464 return FALSE;
4465
4466 break;
4467
4468 case CAPSET_TYPE_DRAW_GDI_PLUS:
4469 if (!rdp_read_draw_gdiplus_cache_capability_set(log, sub, settings))
4470 return FALSE;
4471
4472 break;
4473
4474 case CAPSET_TYPE_RAIL:
4475 if (!rdp_read_remote_programs_capability_set(log, sub, settings))
4476 return FALSE;
4477
4478 break;
4479
4480 case CAPSET_TYPE_WINDOW:
4481 if (!rdp_read_window_list_capability_set(log, sub, settings))
4482 return FALSE;
4483
4484 break;
4485
4486 case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE:
4487 if (!rdp_read_multifragment_update_capability_set(log, sub, settings))
4488 return FALSE;
4489
4490 break;
4491
4492 case CAPSET_TYPE_LARGE_POINTER:
4493 if (!rdp_read_large_pointer_capability_set(log, sub, settings))
4494 return FALSE;
4495
4496 break;
4497
4498 case CAPSET_TYPE_COMP_DESK:
4499 if (!rdp_read_desktop_composition_capability_set(log, sub, settings))
4500 return FALSE;
4501
4502 break;
4503
4504 case CAPSET_TYPE_SURFACE_COMMANDS:
4505 if (!rdp_read_surface_commands_capability_set(log, sub, settings))
4506 return FALSE;
4507
4508 break;
4509
4510 case CAPSET_TYPE_BITMAP_CODECS:
4511 if (!rdp_read_bitmap_codecs_capability_set(log, sub, settings, isServer))
4512 return FALSE;
4513
4514 break;
4515
4516 case CAPSET_TYPE_FRAME_ACKNOWLEDGE:
4517 if (!rdp_read_frame_acknowledge_capability_set(log, sub, settings))
4518 return FALSE;
4519
4520 break;
4521
4522 case CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID:
4523 if (!rdp_read_bitmap_cache_v3_codec_id_capability_set(log, sub, settings))
4524 return FALSE;
4525
4526 break;
4527
4528 default:
4529 treated = FALSE;
4530 break;
4531 }
4532
4533 if (!treated)
4534 {
4535 if (isServer)
4536 {
4537 /* treating capabilities that are supposed to be send only from the client */
4538 switch (type)
4539 {
4540 case CAPSET_TYPE_BITMAP_CACHE:
4541 if (!rdp_read_bitmap_cache_capability_set(log, sub, settings))
4542 return FALSE;
4543
4544 break;
4545
4546 case CAPSET_TYPE_BITMAP_CACHE_V2:
4547 if (!rdp_read_bitmap_cache_v2_capability_set(log, sub, settings))
4548 return FALSE;
4549
4550 break;
4551
4552 case CAPSET_TYPE_BRUSH:
4553 if (!rdp_read_brush_capability_set(log, sub, settings))
4554 return FALSE;
4555
4556 break;
4557
4558 case CAPSET_TYPE_GLYPH_CACHE:
4559 if (!rdp_read_glyph_cache_capability_set(log, sub, settings))
4560 return FALSE;
4561
4562 break;
4563
4564 case CAPSET_TYPE_OFFSCREEN_CACHE:
4565 if (!rdp_read_offscreen_bitmap_cache_capability_set(log, sub, settings))
4566 return FALSE;
4567
4568 break;
4569
4570 case CAPSET_TYPE_SOUND:
4571 if (!rdp_read_sound_capability_set(log, sub, settings))
4572 return FALSE;
4573
4574 break;
4575
4576 case CAPSET_TYPE_CONTROL:
4577 if (!rdp_read_control_capability_set(log, sub, settings))
4578 return FALSE;
4579
4580 break;
4581
4582 case CAPSET_TYPE_ACTIVATION:
4583 if (!rdp_read_window_activation_capability_set(log, sub, settings))
4584 return FALSE;
4585
4586 break;
4587
4588 case CAPSET_TYPE_DRAW_NINE_GRID_CACHE:
4589 if (!rdp_read_draw_nine_grid_cache_capability_set(log, sub, settings))
4590 return FALSE;
4591
4592 break;
4593
4594 default:
4595 WLog_Print(log, WLOG_ERROR,
4596 "capability %s(%" PRIu16 ") not expected from client",
4597 get_capability_name(type), type);
4598 return FALSE;
4599 }
4600 }
4601 else
4602 {
4603 /* treating capabilities that are supposed to be send only from the server */
4604 switch (type)
4605 {
4606 case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT:
4607 if (!rdp_read_bitmap_cache_host_support_capability_set(log, sub, settings))
4608 return FALSE;
4609
4610 break;
4611
4612 default:
4613 WLog_Print(log, WLOG_ERROR,
4614 "capability %s(%" PRIu16 ") not expected from server",
4615 get_capability_name(type), type);
4616 return FALSE;
4617 }
4618 }
4619 }
4620
4621 const size_t rest = Stream_GetRemainingLength(sub);
4622 if (rest > 0)
4623 {
4624 const size_t length = Stream_Capacity(sub);
4625 WLog_Print(log, WLOG_ERROR,
4626 "incorrect offset, type:0x%04" PRIx16 " actual:%" PRIuz " expected:%" PRIuz "",
4627 type, length - rest, length);
4628 }
4629 return TRUE;
4630}
4631
4632WINPR_ATTR_NODISCARD
4633static BOOL rdp_read_capability_sets(wLog* log, wStream* s, rdpSettings* settings,
4634 rdpSettings* rcvSettings, UINT16 totalLength)
4635{
4636 BOOL rc = FALSE;
4637 size_t start = 0;
4638 size_t end = 0;
4639 size_t len = 0;
4640 UINT16 numberCapabilities = 0;
4641 UINT16 count = 0;
4642
4643#ifdef WITH_DEBUG_CAPABILITIES
4644 const size_t capstart = Stream_GetPosition(s);
4645#endif
4646
4647 WINPR_ASSERT(s);
4648 WINPR_ASSERT(settings);
4649
4650 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
4651 return FALSE;
4652
4653 Stream_Read_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4654 Stream_Seek(s, 2); /* pad2Octets (2 bytes) */
4655 count = numberCapabilities;
4656
4657 start = Stream_GetPosition(s);
4658 while (numberCapabilities > 0 && Stream_GetRemainingLength(s) >= 4)
4659 {
4660 UINT16 type = 0;
4661 UINT16 length = 0;
4662 wStream subbuffer;
4663 wStream* sub = nullptr;
4664
4665 if (!rdp_read_capability_set_header(log, s, &length, &type))
4666 goto fail;
4667 sub = Stream_StaticInit(&subbuffer, Stream_Pointer(s), length - 4);
4668 if (!Stream_SafeSeek(s, length - 4))
4669 goto fail;
4670
4671 if (!rdp_read_capability_set(log, sub, type, rcvSettings, settings->ServerMode))
4672 goto fail;
4673
4674 if (!rdp_apply_from_received(type, settings, rcvSettings))
4675 goto fail;
4676 numberCapabilities--;
4677 }
4678
4679 end = Stream_GetPosition(s);
4680 len = end - start;
4681
4682 if (numberCapabilities)
4683 {
4684 WLog_Print(log, WLOG_ERROR,
4685 "strange we haven't read the number of announced capacity sets, read=%d "
4686 "expected=%" PRIu16 "",
4687 count - numberCapabilities, count);
4688 }
4689
4690#ifdef WITH_DEBUG_CAPABILITIES
4691 rdp_print_capability_sets(log, s, capstart, TRUE);
4692#endif
4693
4694 if (len > totalLength)
4695 {
4696 WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIuz,
4697 totalLength, len);
4698 goto fail;
4699 }
4700 rc = freerdp_capability_buffer_copy(settings, rcvSettings);
4701fail:
4702 return rc;
4703}
4704
4705BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId, UINT16* length)
4706{
4707 WINPR_ASSERT(rdp);
4708 WINPR_ASSERT(rdp->context);
4709
4710 if (!rdp_read_header(rdp, s, length, pChannelId))
4711 return FALSE;
4712
4713 if (freerdp_shall_disconnect_context(rdp->context))
4714 return TRUE;
4715
4716 if (*pChannelId != MCS_GLOBAL_CHANNEL_ID)
4717 {
4718 UINT16 mcsMessageChannelId = rdp->mcs->messageChannelId;
4719
4720 if ((mcsMessageChannelId == 0) || (*pChannelId != mcsMessageChannelId))
4721 {
4722 WLog_Print(rdp->log, WLOG_ERROR, "unexpected MCS channel id %04" PRIx16 " received",
4723 *pChannelId);
4724 return FALSE;
4725 }
4726 }
4727
4728 return TRUE;
4729}
4730
4731BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s, UINT16 pduSource, UINT16 length)
4732{
4733 UINT16 lengthSourceDescriptor = 0;
4734 UINT16 lengthCombinedCapabilities = 0;
4735
4736 WINPR_ASSERT(rdp);
4737 WINPR_ASSERT(rdp->settings);
4738 WINPR_ASSERT(rdp->context);
4739 WINPR_ASSERT(s);
4740
4741 rdp->settings->PduSource = pduSource;
4742
4743 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 8))
4744 return FALSE;
4745
4746 Stream_Read_UINT32(s, rdp->settings->ShareId); /* shareId (4 bytes) */
4747 Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4748 Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4749
4750 if (!Stream_SafeSeek(s, lengthSourceDescriptor) ||
4751 !Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4)) /* sourceDescriptor */
4752 return FALSE;
4753
4754 /* capabilitySets */
4755 if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4756 lengthCombinedCapabilities))
4757 {
4758 WLog_Print(rdp->log, WLOG_ERROR, "rdp_read_capability_sets failed");
4759 return FALSE;
4760 }
4761
4762 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 4))
4763 return FALSE;
4764
4765 /* [MS-RDPBCGR] 2.2.1.13.1.1 Demand Active PDU Data (TS_DEMAND_ACTIVE_PDU)::sessionId
4766 * is ignored by client */
4767 Stream_Seek_UINT32(s); /* SessionId */
4768
4769 {
4770 rdp_secondary_update_internal* secondary = secondary_update_cast(rdp->update->secondary);
4771 secondary->glyph_v2 = (rdp->settings->GlyphSupportLevel > GLYPH_SUPPORT_FULL);
4772 }
4773
4774 return tpkt_ensure_stream_consumed(rdp->log, s, length);
4775}
4776
4777WINPR_ATTR_NODISCARD
4778static BOOL rdp_write_demand_active(wLog* log, wStream* s, rdpSettings* settings)
4779{
4780 size_t bm = 0;
4781 size_t em = 0;
4782 size_t lm = 0;
4783 UINT16 numberCapabilities = 0;
4784 size_t lengthCombinedCapabilities = 0;
4785
4786 if (!Stream_EnsureRemainingCapacity(s, 64))
4787 return FALSE;
4788
4789 Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4790 Stream_Write_UINT16(s, 4); /* lengthSourceDescriptor (2 bytes) */
4791 lm = Stream_GetPosition(s);
4792 Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4793 Stream_Write(s, "RDP", 4); /* sourceDescriptor */
4794 bm = Stream_GetPosition(s);
4795 Stream_Seek_UINT16(s); /* numberCapabilities (2 bytes) */
4796 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4797 numberCapabilities = 14;
4798
4799 if (!rdp_write_general_capability_set(log, s, settings) ||
4800 !rdp_write_bitmap_capability_set(log, s, settings) ||
4801 !rdp_write_order_capability_set(log, s, settings) ||
4802 !rdp_write_pointer_capability_set(log, s, settings) ||
4803 !rdp_write_input_capability_set(log, s, settings) ||
4804 !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4805 !rdp_write_share_capability_set(log, s, settings) ||
4806 !rdp_write_font_capability_set(log, s, settings) ||
4807 !rdp_write_multifragment_update_capability_set(log, s, settings) ||
4808 !rdp_write_large_pointer_capability_set(log, s, settings) ||
4809 !rdp_write_desktop_composition_capability_set(log, s, settings) ||
4810 !rdp_write_surface_commands_capability_set(log, s, settings) ||
4811 !rdp_write_bitmap_codecs_capability_set(log, s, settings) ||
4812 !rdp_write_frame_acknowledge_capability_set(log, s, settings))
4813 {
4814 return FALSE;
4815 }
4816
4817 if (freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
4818 {
4819 numberCapabilities++;
4820
4821 if (!rdp_write_bitmap_cache_host_support_capability_set(log, s, settings))
4822 return FALSE;
4823 }
4824
4825 if (settings->RemoteApplicationMode)
4826 {
4827 numberCapabilities += 2;
4828
4829 if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
4830 !rdp_write_window_list_capability_set(log, s, settings))
4831 return FALSE;
4832 }
4833
4834 em = Stream_GetPosition(s);
4835 if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
4836 return FALSE;
4837 lengthCombinedCapabilities = (em - bm);
4838 if (lengthCombinedCapabilities > UINT16_MAX)
4839 return FALSE;
4840 Stream_Write_UINT16(
4841 s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4842 if (!Stream_SetPosition(s, bm)) /* go back to numberCapabilities */
4843 return FALSE;
4844 Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
4845#ifdef WITH_DEBUG_CAPABILITIES
4846 rdp_print_capability_sets(log, s, bm, FALSE);
4847#endif
4848 if (!Stream_SetPosition(s, em))
4849 return FALSE;
4850 Stream_Write_UINT32(s, 0); /* sessionId */
4851 return TRUE;
4852}
4853
4854BOOL rdp_send_demand_active(rdpRdp* rdp)
4855{
4856 UINT16 sec_flags = 0;
4857 wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
4858 BOOL status = 0;
4859
4860 if (!s)
4861 return FALSE;
4862
4863 rdp->settings->ShareId = 0x10000 + rdp->mcs->userId;
4864 status = rdp_write_demand_active(rdp->log, s, rdp->settings) &&
4865 rdp_send_pdu(rdp, s, PDU_TYPE_DEMAND_ACTIVE, rdp->mcs->userId, sec_flags);
4866 Stream_Release(s);
4867 return status;
4868}
4869
4870BOOL rdp_recv_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength)
4871{
4872 rdpSettings* settings = nullptr;
4873 UINT16 lengthSourceDescriptor = 0;
4874 UINT16 lengthCombinedCapabilities = 0;
4875
4876 WINPR_ASSERT(rdp);
4877 WINPR_ASSERT(s);
4878 settings = rdp->settings;
4879 WINPR_ASSERT(settings);
4880
4881 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, 10))
4882 return FALSE;
4883
4884 Stream_Seek_UINT32(s); /* shareId (4 bytes) */
4885 Stream_Seek_UINT16(s); /* originatorId (2 bytes) */
4886 Stream_Read_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4887 Stream_Read_UINT16(s, lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
4888
4889 if (!Stream_CheckAndLogRequiredLengthWLog(rdp->log, s, lengthSourceDescriptor + 4U))
4890 return FALSE;
4891
4892 Stream_Seek(s, lengthSourceDescriptor); /* sourceDescriptor */
4893 if (!rdp_read_capability_sets(rdp->log, s, rdp->settings, rdp->remoteSettings,
4894 lengthCombinedCapabilities))
4895 return FALSE;
4896
4897 if (!settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
4898 {
4899 /* client does not support surface commands */
4900 settings->SurfaceCommandsEnabled = FALSE;
4901 settings->SurfaceFrameMarkerEnabled = FALSE;
4902 }
4903
4904 if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
4905 {
4906 /* client does not support frame acks */
4907 settings->FrameAcknowledge = 0;
4908 }
4909
4910 if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
4911 {
4912 /* client does not support bitmap cache v3 */
4913 settings->BitmapCacheV3Enabled = FALSE;
4914 }
4915
4916 if (!settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
4917 {
4918 /* client does not support bitmap codecs */
4919 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, FALSE))
4920 return FALSE;
4921 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, FALSE))
4922 return FALSE;
4923 if (!freerdp_settings_set_bool(settings, FreeRDP_JpegCodec, FALSE))
4924 return FALSE;
4925 }
4926
4927 if (!settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
4928 {
4929 /* client does not support multi fragment updates - make sure packages are not fragmented */
4930 if (!freerdp_settings_set_uint32(settings, FreeRDP_MultifragMaxRequestSize,
4931 FASTPATH_FRAGMENT_SAFE_SIZE))
4932 return FALSE;
4933 }
4934
4935 if (!settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
4936 {
4937 /* client does not support large pointers */
4938 settings->LargePointerFlag = 0;
4939 }
4940
4941 return tpkt_ensure_stream_consumed(rdp->log, s, pduLength);
4942}
4943
4944WINPR_ATTR_NODISCARD
4945static BOOL rdp_write_confirm_active(wLog* log, wStream* s, rdpSettings* settings)
4946{
4947 size_t bm = 0;
4948 size_t em = 0;
4949 size_t lm = 0;
4950 UINT16 numberCapabilities = 0;
4951 UINT16 lengthSourceDescriptor = 0;
4952 size_t lengthCombinedCapabilities = 0;
4953 BOOL ret = 0;
4954
4955 WINPR_ASSERT(settings);
4956
4957 lengthSourceDescriptor = sizeof(SOURCE_DESCRIPTOR);
4958 Stream_Write_UINT32(s, settings->ShareId); /* shareId (4 bytes) */
4959 Stream_Write_UINT16(s, 0x03EA); /* originatorId (2 bytes) */
4960 Stream_Write_UINT16(s, lengthSourceDescriptor); /* lengthSourceDescriptor (2 bytes) */
4961 lm = Stream_GetPosition(s);
4962 Stream_Seek_UINT16(s); /* lengthCombinedCapabilities (2 bytes) */
4963 Stream_Write(s, SOURCE_DESCRIPTOR, lengthSourceDescriptor); /* sourceDescriptor */
4964 bm = Stream_GetPosition(s);
4965 Stream_Seek_UINT16(s); /* numberCapabilities (2 bytes) */
4966 Stream_Write_UINT16(s, 0); /* pad2Octets (2 bytes) */
4967 /* Capability Sets */
4968 numberCapabilities = 15;
4969
4970 if (!rdp_write_general_capability_set(log, s, settings) ||
4971 !rdp_write_bitmap_capability_set(log, s, settings) ||
4972 !rdp_write_order_capability_set(log, s, settings))
4973 return FALSE;
4974
4975 if (settings->RdpVersion >= RDP_VERSION_5_PLUS)
4976 ret = rdp_write_bitmap_cache_v2_capability_set(log, s, settings);
4977 else
4978 ret = rdp_write_bitmap_cache_capability_set(log, s, settings);
4979
4980 if (!ret)
4981 return FALSE;
4982
4983 if (!rdp_write_pointer_capability_set(log, s, settings) ||
4984 !rdp_write_input_capability_set(log, s, settings) ||
4985 !rdp_write_brush_capability_set(log, s, settings) ||
4986 !rdp_write_glyph_cache_capability_set(log, s, settings) ||
4987 !rdp_write_virtual_channel_capability_set(log, s, settings) ||
4988 !rdp_write_sound_capability_set(log, s, settings) ||
4989 !rdp_write_share_capability_set(log, s, settings) ||
4990 !rdp_write_font_capability_set(log, s, settings) ||
4991 !rdp_write_control_capability_set(log, s, settings) ||
4992 !rdp_write_color_cache_capability_set(log, s, settings) ||
4993 !rdp_write_window_activation_capability_set(log, s, settings))
4994 {
4995 return FALSE;
4996 }
4997
4998 {
4999 numberCapabilities++;
5000
5001 if (!rdp_write_offscreen_bitmap_cache_capability_set(log, s, settings))
5002 return FALSE;
5003 }
5004
5005 if (settings->DrawNineGridEnabled)
5006 {
5007 numberCapabilities++;
5008
5009 if (!rdp_write_draw_nine_grid_cache_capability_set(log, s, settings))
5010 return FALSE;
5011 }
5012
5013 if (settings->ReceivedCapabilities[CAPSET_TYPE_LARGE_POINTER])
5014 {
5015 if (settings->LargePointerFlag)
5016 {
5017 numberCapabilities++;
5018
5019 if (!rdp_write_large_pointer_capability_set(log, s, settings))
5020 return FALSE;
5021 }
5022 }
5023
5024 if (settings->RemoteApplicationMode)
5025 {
5026 numberCapabilities += 2;
5027
5028 if (!rdp_write_remote_programs_capability_set(log, s, settings) ||
5029 !rdp_write_window_list_capability_set(log, s, settings))
5030 return FALSE;
5031 }
5032
5033 if (settings->ReceivedCapabilities[CAPSET_TYPE_MULTI_FRAGMENT_UPDATE])
5034 {
5035 numberCapabilities++;
5036
5037 if (!rdp_write_multifragment_update_capability_set(log, s, settings))
5038 return FALSE;
5039 }
5040
5041 if (settings->ReceivedCapabilities[CAPSET_TYPE_SURFACE_COMMANDS])
5042 {
5043 numberCapabilities++;
5044
5045 if (!rdp_write_surface_commands_capability_set(log, s, settings))
5046 return FALSE;
5047 }
5048
5049 if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CODECS])
5050 {
5051 numberCapabilities++;
5052
5053 if (!rdp_write_bitmap_codecs_capability_set(log, s, settings))
5054 return FALSE;
5055 }
5056
5057 if (!settings->ReceivedCapabilities[CAPSET_TYPE_FRAME_ACKNOWLEDGE])
5058 settings->FrameAcknowledge = 0;
5059
5060 if (settings->FrameAcknowledge)
5061 {
5062 numberCapabilities++;
5063
5064 if (!rdp_write_frame_acknowledge_capability_set(log, s, settings))
5065 return FALSE;
5066 }
5067
5068 if (settings->ReceivedCapabilities[CAPSET_TYPE_BITMAP_CACHE_V3_CODEC_ID])
5069 {
5070 if (settings->BitmapCacheV3CodecId != 0)
5071 {
5072 numberCapabilities++;
5073
5074 if (!rdp_write_bitmap_cache_v3_codec_id_capability_set(log, s, settings))
5075 return FALSE;
5076 }
5077 }
5078
5079 em = Stream_GetPosition(s);
5080 if (!Stream_SetPosition(s, lm)) /* go back to lengthCombinedCapabilities */
5081 return FALSE;
5082 lengthCombinedCapabilities = (em - bm);
5083 if (lengthCombinedCapabilities > UINT16_MAX)
5084 return FALSE;
5085 Stream_Write_UINT16(
5086 s, (UINT16)lengthCombinedCapabilities); /* lengthCombinedCapabilities (2 bytes) */
5087 if (!Stream_SetPosition(s, bm)) /* go back to numberCapabilities */
5088 return FALSE;
5089 Stream_Write_UINT16(s, numberCapabilities); /* numberCapabilities (2 bytes) */
5090#ifdef WITH_DEBUG_CAPABILITIES
5091 rdp_print_capability_sets(log, s, bm, FALSE);
5092#endif
5093 return Stream_SetPosition(s, em);
5094}
5095
5096BOOL rdp_send_confirm_active(rdpRdp* rdp)
5097{
5098 UINT16 sec_flags = 0;
5099 wStream* s = rdp_send_stream_pdu_init(rdp, &sec_flags);
5100 BOOL status = 0;
5101
5102 if (!s)
5103 return FALSE;
5104
5105 status = rdp_write_confirm_active(rdp->log, s, rdp->settings) &&
5106 rdp_send_pdu(rdp, s, PDU_TYPE_CONFIRM_ACTIVE, rdp->mcs->userId, sec_flags);
5107 Stream_Release(s);
5108 return status;
5109}
5110
5111const char* rdp_input_flag_string(UINT16 flags, char* buffer, size_t len)
5112{
5113 char prefix[16] = WINPR_C_ARRAY_INIT;
5114
5115 (void)_snprintf(prefix, sizeof(prefix), "[0x%04" PRIx16 "][", flags);
5116 winpr_str_append(prefix, buffer, len, "");
5117 if ((flags & INPUT_FLAG_SCANCODES) != 0)
5118 winpr_str_append("INPUT_FLAG_SCANCODES", buffer, len, "|");
5119 if ((flags & INPUT_FLAG_MOUSEX) != 0)
5120 winpr_str_append("INPUT_FLAG_MOUSEX", buffer, len, "|");
5121 if ((flags & INPUT_FLAG_FASTPATH_INPUT) != 0)
5122 winpr_str_append("INPUT_FLAG_FASTPATH_INPUT", buffer, len, "|");
5123 if ((flags & INPUT_FLAG_UNICODE) != 0)
5124 winpr_str_append("INPUT_FLAG_UNICODE", buffer, len, "|");
5125 if ((flags & INPUT_FLAG_FASTPATH_INPUT2) != 0)
5126 winpr_str_append("INPUT_FLAG_FASTPATH_INPUT2", buffer, len, "|");
5127 if ((flags & INPUT_FLAG_UNUSED1) != 0)
5128 winpr_str_append("INPUT_FLAG_UNUSED1", buffer, len, "|");
5129 if ((flags & INPUT_FLAG_MOUSE_RELATIVE) != 0)
5130 winpr_str_append("INPUT_FLAG_MOUSE_RELATIVE", buffer, len, "|");
5131 if ((flags & TS_INPUT_FLAG_MOUSE_HWHEEL) != 0)
5132 winpr_str_append("TS_INPUT_FLAG_MOUSE_HWHEEL", buffer, len, "|");
5133 if ((flags & TS_INPUT_FLAG_QOE_TIMESTAMPS) != 0)
5134 winpr_str_append("TS_INPUT_FLAG_QOE_TIMESTAMPS", buffer, len, "|");
5135 winpr_str_append("]", buffer, len, "");
5136 return buffer;
5137}
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