FreeRDP
pointer.c
1 
20 #include <freerdp/config.h>
21 
22 #include <stdio.h>
23 
24 #include <winpr/crt.h>
25 #include <winpr/assert.h>
26 #include <winpr/stream.h>
27 
28 #include <freerdp/log.h>
29 
30 #include "pointer.h"
31 #include "cache.h"
32 
33 #define TAG FREERDP_TAG("cache.pointer")
34 
35 static BOOL pointer_cache_put(rdpPointerCache* pointer_cache, UINT32 index, rdpPointer* pointer,
36  BOOL colorCache);
37 static rdpPointer* pointer_cache_get(rdpPointerCache* pointer_cache, UINT32 index);
38 
39 static void pointer_clear(rdpPointer* pointer)
40 {
41  if (pointer)
42  {
43  pointer->lengthAndMask = 0;
44  free(pointer->andMaskData);
45  pointer->andMaskData = NULL;
46 
47  pointer->lengthXorMask = 0;
48  free(pointer->xorMaskData);
49  pointer->xorMaskData = NULL;
50  }
51 }
52 
53 static void pointer_free(rdpContext* context, rdpPointer* pointer)
54 {
55  if (pointer)
56  {
57  IFCALL(pointer->Free, context, pointer);
58  pointer_clear(pointer);
59  }
60  free(pointer);
61 }
62 
63 static BOOL update_pointer_position(rdpContext* context,
64  const POINTER_POSITION_UPDATE* pointer_position)
65 {
66  if (!context || !context->graphics || !context->graphics->Pointer_Prototype ||
67  !pointer_position)
68  return FALSE;
69 
70  const BOOL GrabMouse = freerdp_settings_get_bool(context->settings, FreeRDP_GrabMouse);
71  if (!GrabMouse)
72  return TRUE;
73 
74  const rdpPointer* pointer = context->graphics->Pointer_Prototype;
75  WINPR_ASSERT(pointer);
76 
77  return IFCALLRESULT(TRUE, pointer->SetPosition, context, pointer_position->xPos,
78  pointer_position->yPos);
79 }
80 
81 static BOOL update_pointer_system(rdpContext* context, const POINTER_SYSTEM_UPDATE* pointer_system)
82 {
83  rdpPointer* pointer = NULL;
84 
85  if (!context || !context->graphics || !context->graphics->Pointer_Prototype || !pointer_system)
86  return FALSE;
87 
88  pointer = context->graphics->Pointer_Prototype;
89 
90  switch (pointer_system->type)
91  {
92  case SYSPTR_NULL:
93  return IFCALLRESULT(TRUE, pointer->SetNull, context);
94 
95  case SYSPTR_DEFAULT:
96  return IFCALLRESULT(TRUE, pointer->SetDefault, context);
97 
98  default:
99  WLog_ERR(TAG, "Unknown system pointer type (0x%08" PRIX32 ")", pointer_system->type);
100  }
101  return TRUE;
102 }
103 
104 static BOOL upate_pointer_copy_andxor(rdpPointer* pointer, const BYTE* andMaskData,
105  size_t lengthAndMask, const BYTE* xorMaskData,
106  size_t lengthXorMask)
107 {
108  WINPR_ASSERT(pointer);
109 
110  pointer_clear(pointer);
111  if (lengthAndMask && andMaskData)
112  {
113  if (lengthAndMask > UINT32_MAX)
114  return FALSE;
115  pointer->lengthAndMask = (UINT32)lengthAndMask;
116  pointer->andMaskData = (BYTE*)malloc(lengthAndMask);
117  if (!pointer->andMaskData)
118  return FALSE;
119 
120  CopyMemory(pointer->andMaskData, andMaskData, lengthAndMask);
121  }
122 
123  if (lengthXorMask && xorMaskData)
124  {
125  if (lengthXorMask > UINT32_MAX)
126  return FALSE;
127  pointer->lengthXorMask = (UINT32)lengthXorMask;
128  pointer->xorMaskData = (BYTE*)malloc(lengthXorMask);
129  if (!pointer->xorMaskData)
130  return FALSE;
131 
132  CopyMemory(pointer->xorMaskData, xorMaskData, lengthXorMask);
133  }
134 
135  return TRUE;
136 }
137 
138 static BOOL update_pointer_color(rdpContext* context, const POINTER_COLOR_UPDATE* pointer_color)
139 {
140  rdpPointer* pointer = NULL;
141  rdpCache* cache = NULL;
142 
143  WINPR_ASSERT(context);
144  WINPR_ASSERT(pointer_color);
145 
146  cache = context->cache;
147  WINPR_ASSERT(cache);
148 
149  pointer = Pointer_Alloc(context);
150 
151  if (pointer == NULL)
152  return FALSE;
153  pointer->xorBpp = 24;
154  pointer->xPos = pointer_color->hotSpotX;
155  pointer->yPos = pointer_color->hotSpotY;
156  pointer->width = pointer_color->width;
157  pointer->height = pointer_color->height;
158 
159  if (!upate_pointer_copy_andxor(pointer, pointer_color->andMaskData,
160  pointer_color->lengthAndMask, pointer_color->xorMaskData,
161  pointer_color->lengthXorMask))
162  goto out_fail;
163 
164  if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
165  goto out_fail;
166 
167  if (!pointer_cache_put(cache->pointer, pointer_color->cacheIndex, pointer, TRUE))
168  goto out_fail;
169 
170  return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
171 
172 out_fail:
173  pointer_free(context, pointer);
174  return FALSE;
175 }
176 
177 static BOOL update_pointer_large(rdpContext* context, const POINTER_LARGE_UPDATE* pointer_large)
178 {
179  rdpPointer* pointer = NULL;
180  rdpCache* cache = NULL;
181 
182  WINPR_ASSERT(context);
183  WINPR_ASSERT(pointer_large);
184 
185  cache = context->cache;
186  WINPR_ASSERT(cache);
187 
188  pointer = Pointer_Alloc(context);
189  if (pointer == NULL)
190  return FALSE;
191  pointer->xorBpp = pointer_large->xorBpp;
192  pointer->xPos = pointer_large->hotSpotX;
193  pointer->yPos = pointer_large->hotSpotY;
194  pointer->width = pointer_large->width;
195  pointer->height = pointer_large->height;
196 
197  if (!upate_pointer_copy_andxor(pointer, pointer_large->andMaskData,
198  pointer_large->lengthAndMask, pointer_large->xorMaskData,
199  pointer_large->lengthXorMask))
200  goto out_fail;
201 
202  if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
203  goto out_fail;
204 
205  if (!pointer_cache_put(cache->pointer, pointer_large->cacheIndex, pointer, FALSE))
206  goto out_fail;
207 
208  return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
209 
210 out_fail:
211  pointer_free(context, pointer);
212  return FALSE;
213 }
214 
215 static BOOL update_pointer_new(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new)
216 {
217  if (!context || !pointer_new)
218  return FALSE;
219 
220  rdpCache* cache = context->cache;
221  rdpPointer* pointer = Pointer_Alloc(context);
222 
223  if (!pointer)
224  return FALSE;
225 
226  pointer->xorBpp = pointer_new->xorBpp;
227  pointer->xPos = pointer_new->colorPtrAttr.hotSpotX;
228  pointer->yPos = pointer_new->colorPtrAttr.hotSpotY;
229  pointer->width = pointer_new->colorPtrAttr.width;
230  pointer->height = pointer_new->colorPtrAttr.height;
231  if (!upate_pointer_copy_andxor(
232  pointer, pointer_new->colorPtrAttr.andMaskData, pointer_new->colorPtrAttr.lengthAndMask,
233  pointer_new->colorPtrAttr.xorMaskData, pointer_new->colorPtrAttr.lengthXorMask))
234  goto out_fail;
235 
236  if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
237  goto out_fail;
238 
239  if (!pointer_cache_put(cache->pointer, pointer_new->colorPtrAttr.cacheIndex, pointer, FALSE))
240  goto out_fail;
241 
242  return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
243 
244 out_fail:
245  pointer_free(context, pointer);
246  return FALSE;
247 }
248 
249 static BOOL update_pointer_cached(rdpContext* context, const POINTER_CACHED_UPDATE* pointer_cached)
250 {
251  rdpPointer* pointer = NULL;
252  rdpCache* cache = NULL;
253 
254  WINPR_ASSERT(context);
255  WINPR_ASSERT(pointer_cached);
256 
257  cache = context->cache;
258  WINPR_ASSERT(cache);
259 
260  pointer = pointer_cache_get(cache->pointer, pointer_cached->cacheIndex);
261 
262  if (pointer != NULL)
263  return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
264 
265  return FALSE;
266 }
267 
268 rdpPointer* pointer_cache_get(rdpPointerCache* pointer_cache, UINT32 index)
269 {
270  rdpPointer* pointer = NULL;
271 
272  WINPR_ASSERT(pointer_cache);
273 
274  if (index >= pointer_cache->cacheSize)
275  {
276  WLog_ERR(TAG, "invalid pointer index:%" PRIu32 " [%" PRIu32 "]", index,
277  pointer_cache->cacheSize);
278  return NULL;
279  }
280 
281  WINPR_ASSERT(pointer_cache->entries);
282  pointer = pointer_cache->entries[index];
283  return pointer;
284 }
285 
286 BOOL pointer_cache_put(rdpPointerCache* pointer_cache, UINT32 index, rdpPointer* pointer,
287  BOOL colorCache)
288 {
289  rdpPointer* prevPointer = NULL;
290  const FreeRDP_Settings_Keys_UInt32 id =
291  colorCache ? FreeRDP_ColorPointerCacheSize : FreeRDP_PointerCacheSize;
292 
293  WINPR_ASSERT(pointer_cache);
294  WINPR_ASSERT(pointer_cache->context);
295 
296  const UINT32 size = freerdp_settings_get_uint32(pointer_cache->context->settings, id);
297  if (index >= pointer_cache->cacheSize)
298  {
299  WLog_ERR(TAG,
300  "invalid pointer index:%" PRIu32 " [allocated %" PRIu32 ", %s size %" PRIu32 "]",
301  index, pointer_cache->cacheSize,
302  colorCache ? "color-pointer-cache" : "pointer-cache", size);
303  return FALSE;
304  }
305  if (index >= size)
306  {
307  WLog_WARN(TAG,
308  "suspicious pointer index:%" PRIu32 " [allocated %" PRIu32 ", %s size %" PRIu32
309  "]",
310  index, pointer_cache->cacheSize,
311  colorCache ? "color-pointer-cache" : "pointer-cache", size);
312  }
313 
314  WINPR_ASSERT(pointer_cache->entries);
315  prevPointer = pointer_cache->entries[index];
316  pointer_free(pointer_cache->context, prevPointer);
317  pointer_cache->entries[index] = pointer;
318  return TRUE;
319 }
320 
321 void pointer_cache_register_callbacks(rdpUpdate* update)
322 {
323  rdpPointerUpdate* pointer = NULL;
324 
325  WINPR_ASSERT(update);
326  WINPR_ASSERT(update->context);
327 
328  pointer = update->pointer;
329  WINPR_ASSERT(pointer);
330 
331  if (!freerdp_settings_get_bool(update->context->settings, FreeRDP_DeactivateClientDecoding))
332  {
333  pointer->PointerPosition = update_pointer_position;
334  pointer->PointerSystem = update_pointer_system;
335  pointer->PointerColor = update_pointer_color;
336  pointer->PointerLarge = update_pointer_large;
337  pointer->PointerNew = update_pointer_new;
338  pointer->PointerCached = update_pointer_cached;
339  }
340 }
341 
342 rdpPointerCache* pointer_cache_new(rdpContext* context)
343 {
344  rdpPointerCache* pointer_cache = NULL;
345  rdpSettings* settings = NULL;
346 
347  WINPR_ASSERT(context);
348 
349  settings = context->settings;
350  WINPR_ASSERT(settings);
351 
352  pointer_cache = (rdpPointerCache*)calloc(1, sizeof(rdpPointerCache));
353 
354  if (!pointer_cache)
355  return NULL;
356 
357  pointer_cache->context = context;
358 
359  /* seen invalid pointer cache requests by mstsc (off by 1) so we ensure the cache entry size
360  * matches */
361  const UINT32 size = freerdp_settings_get_uint32(settings, FreeRDP_PointerCacheSize);
362  const UINT32 colorSize = freerdp_settings_get_uint32(settings, FreeRDP_ColorPointerCacheSize);
363  pointer_cache->cacheSize = MAX(size, colorSize) + 1;
364 
365  pointer_cache->entries = (rdpPointer**)calloc(pointer_cache->cacheSize, sizeof(rdpPointer*));
366 
367  if (!pointer_cache->entries)
368  {
369  free(pointer_cache);
370  return NULL;
371  }
372 
373  return pointer_cache;
374 }
375 
376 void pointer_cache_free(rdpPointerCache* pointer_cache)
377 {
378  if (pointer_cache != NULL)
379  {
380  if (pointer_cache->entries)
381  {
382  for (UINT32 i = 0; i < pointer_cache->cacheSize; i++)
383  {
384  rdpPointer* pointer = pointer_cache->entries[i];
385  pointer_free(pointer_cache->context, pointer);
386  }
387  }
388 
389  free(pointer_cache->entries);
390  free(pointer_cache);
391  }
392 }
393 
394 POINTER_COLOR_UPDATE* copy_pointer_color_update(rdpContext* context,
395  const POINTER_COLOR_UPDATE* src)
396 {
397  POINTER_COLOR_UPDATE* dst = calloc(1, sizeof(POINTER_COLOR_UPDATE));
398 
399  if (!dst || !src)
400  goto fail;
401 
402  *dst = *src;
403 
404  if (src->lengthAndMask > 0)
405  {
406  dst->andMaskData = calloc(src->lengthAndMask, sizeof(BYTE));
407 
408  if (!dst->andMaskData)
409  goto fail;
410 
411  memcpy(dst->andMaskData, src->andMaskData, src->lengthAndMask);
412  }
413 
414  if (src->lengthXorMask > 0)
415  {
416  dst->xorMaskData = calloc(src->lengthXorMask, sizeof(BYTE));
417 
418  if (!dst->xorMaskData)
419  goto fail;
420 
421  memcpy(dst->xorMaskData, src->xorMaskData, src->lengthXorMask);
422  }
423 
424  return dst;
425 fail:
426  free_pointer_color_update(context, dst);
427  return NULL;
428 }
429 
430 void free_pointer_color_update(rdpContext* context, POINTER_COLOR_UPDATE* pointer)
431 {
432  WINPR_UNUSED(context);
433 
434  if (!pointer)
435  return;
436 
437  free(pointer->xorMaskData);
438  free(pointer->andMaskData);
439  free(pointer);
440 }
441 
442 POINTER_LARGE_UPDATE* copy_pointer_large_update(rdpContext* context,
443  const POINTER_LARGE_UPDATE* src)
444 {
445  POINTER_LARGE_UPDATE* dst = calloc(1, sizeof(POINTER_LARGE_UPDATE));
446 
447  if (!dst || !src)
448  goto fail;
449 
450  *dst = *src;
451 
452  if (src->lengthAndMask > 0)
453  {
454  dst->andMaskData = calloc(src->lengthAndMask, sizeof(BYTE));
455 
456  if (!dst->andMaskData)
457  goto fail;
458 
459  memcpy(dst->andMaskData, src->andMaskData, src->lengthAndMask);
460  }
461 
462  if (src->lengthXorMask > 0)
463  {
464  dst->xorMaskData = calloc(src->lengthXorMask, sizeof(BYTE));
465 
466  if (!dst->xorMaskData)
467  goto fail;
468 
469  memcpy(dst->xorMaskData, src->xorMaskData, src->lengthXorMask);
470  }
471 
472  return dst;
473 fail:
474  free_pointer_large_update(context, dst);
475  return NULL;
476 }
477 
478 void free_pointer_large_update(rdpContext* context, POINTER_LARGE_UPDATE* pointer)
479 {
480  WINPR_UNUSED(context);
481  if (!pointer)
482  return;
483 
484  free(pointer->xorMaskData);
485  free(pointer->andMaskData);
486  free(pointer);
487 }
488 
489 POINTER_NEW_UPDATE* copy_pointer_new_update(rdpContext* context, const POINTER_NEW_UPDATE* src)
490 {
491  POINTER_NEW_UPDATE* dst = calloc(1, sizeof(POINTER_NEW_UPDATE));
492 
493  if (!dst || !src)
494  goto fail;
495 
496  *dst = *src;
497 
498  if (src->colorPtrAttr.lengthAndMask > 0)
499  {
500  dst->colorPtrAttr.andMaskData = calloc(src->colorPtrAttr.lengthAndMask, sizeof(BYTE));
501 
502  if (!dst->colorPtrAttr.andMaskData)
503  goto fail;
504 
505  memcpy(dst->colorPtrAttr.andMaskData, src->colorPtrAttr.andMaskData,
506  src->colorPtrAttr.lengthAndMask);
507  }
508 
509  if (src->colorPtrAttr.lengthXorMask > 0)
510  {
511  dst->colorPtrAttr.xorMaskData = calloc(src->colorPtrAttr.lengthXorMask, sizeof(BYTE));
512 
513  if (!dst->colorPtrAttr.xorMaskData)
514  goto fail;
515 
516  memcpy(dst->colorPtrAttr.xorMaskData, src->colorPtrAttr.xorMaskData,
517  src->colorPtrAttr.lengthXorMask);
518  }
519 
520  return dst;
521 fail:
522  free_pointer_new_update(context, dst);
523  return NULL;
524 }
525 
526 void free_pointer_new_update(rdpContext* context, POINTER_NEW_UPDATE* pointer)
527 {
528  if (!pointer)
529  return;
530 
531  free(pointer->colorPtrAttr.xorMaskData);
532  free(pointer->colorPtrAttr.andMaskData);
533  free(pointer);
534 }
535 
536 POINTER_CACHED_UPDATE* copy_pointer_cached_update(rdpContext* context,
537  const POINTER_CACHED_UPDATE* pointer)
538 {
539  POINTER_CACHED_UPDATE* dst = calloc(1, sizeof(POINTER_CACHED_UPDATE));
540 
541  if (!dst)
542  goto fail;
543 
544  *dst = *pointer;
545  return dst;
546 fail:
547  free_pointer_cached_update(context, dst);
548  return NULL;
549 }
550 
551 void free_pointer_cached_update(rdpContext* context, POINTER_CACHED_UPDATE* pointer)
552 {
553  WINPR_UNUSED(context);
554  free(pointer);
555 }
556 
557 void free_pointer_position_update(rdpContext* context, POINTER_POSITION_UPDATE* pointer)
558 {
559  WINPR_UNUSED(context);
560  free(pointer);
561 }
562 
563 POINTER_POSITION_UPDATE* copy_pointer_position_update(rdpContext* context,
564  const POINTER_POSITION_UPDATE* pointer)
565 {
566  POINTER_POSITION_UPDATE* dst = calloc(1, sizeof(POINTER_POSITION_UPDATE));
567 
568  if (!dst || !pointer)
569  goto fail;
570 
571  *dst = *pointer;
572  return dst;
573 fail:
574  free_pointer_position_update(context, dst);
575  return NULL;
576 }
577 
578 void free_pointer_system_update(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer)
579 {
580  WINPR_UNUSED(context);
581  free(pointer);
582 }
583 
584 POINTER_SYSTEM_UPDATE* copy_pointer_system_update(rdpContext* context,
585  const POINTER_SYSTEM_UPDATE* pointer)
586 {
587  POINTER_SYSTEM_UPDATE* dst = calloc(1, sizeof(POINTER_SYSTEM_UPDATE));
588 
589  if (!dst || !pointer)
590  goto fail;
591 
592  *dst = *pointer;
593  return dst;
594 fail:
595  free_pointer_system_update(context, dst);
596  return NULL;
597 }
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_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.