Coverage Report

Created: 2024-05-20 06:11

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