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