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