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