FreeRDP
Loading...
Searching...
No Matches
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
35static BOOL pointer_cache_put(rdpPointerCache* pointer_cache, UINT32 index, rdpPointer* pointer,
36 BOOL colorCache);
37static rdpPointer* pointer_cache_get(rdpPointerCache* pointer_cache, UINT32 index);
38
39static 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
53static 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
63static 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
81static 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
104static 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
138static 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
172out_fail:
173 pointer_free(context, pointer);
174 return FALSE;
175}
176
177static 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
210out_fail:
211 pointer_free(context, pointer);
212 return FALSE;
213}
214
215static 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
244out_fail:
245 pointer_free(context, pointer);
246 return FALSE;
247}
248
249static 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
268rdpPointer* 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
286BOOL 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
321void 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
342rdpPointerCache* 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
376void 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((void*)pointer_cache->entries);
390 free(pointer_cache);
391 }
392}
393
394POINTER_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;
425fail:
426 free_pointer_color_update(context, dst);
427 return NULL;
428}
429
430void 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
442POINTER_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;
473fail:
474 free_pointer_large_update(context, dst);
475 return NULL;
476}
477
478void 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
489POINTER_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;
521fail:
522 free_pointer_new_update(context, dst);
523 return NULL;
524}
525
526void free_pointer_new_update(WINPR_ATTR_UNUSED 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
536POINTER_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;
546fail:
547 free_pointer_cached_update(context, dst);
548 return NULL;
549}
550
551void free_pointer_cached_update(rdpContext* context, POINTER_CACHED_UPDATE* pointer)
552{
553 WINPR_UNUSED(context);
554 free(pointer);
555}
556
557void free_pointer_position_update(rdpContext* context, POINTER_POSITION_UPDATE* pointer)
558{
559 WINPR_UNUSED(context);
560 free(pointer);
561}
562
563POINTER_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;
573fail:
574 free_pointer_position_update(context, dst);
575 return NULL;
576}
577
578void free_pointer_system_update(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer)
579{
580 WINPR_UNUSED(context);
581 free(pointer);
582}
583
584POINTER_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;
594fail:
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.