Coverage Report

Created: 2023-09-25 06:56

/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;
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;
137
0
  rdpCache* cache;
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;
176
0
  rdpCache* cache;
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;
248
0
  rdpCache* cache;
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;
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;
286
0
  const size_t id = colorCache ? FreeRDP_ColorPointerCacheSize : FreeRDP_PointerCacheSize;
287
288
0
  WINPR_ASSERT(pointer_cache);
289
0
  WINPR_ASSERT(pointer_cache->context);
290
291
0
  const UINT32 size = freerdp_settings_get_uint32(pointer_cache->context->settings, id);
292
0
  if (index >= pointer_cache->cacheSize)
293
0
  {
294
0
    WLog_ERR(TAG,
295
0
             "invalid pointer index:%" PRIu32 " [allocated %" PRIu32 ", %s size %" PRIu32 "]",
296
0
             index, pointer_cache->cacheSize,
297
0
             colorCache ? "color-pointer-cache" : "pointer-cache", size);
298
0
    return FALSE;
299
0
  }
300
0
  if (index >= size)
301
0
  {
302
0
    WLog_WARN(TAG,
303
0
              "suspicious pointer index:%" PRIu32 " [allocated %" PRIu32 ", %s size %" PRIu32
304
0
              "]",
305
0
              index, pointer_cache->cacheSize,
306
0
              colorCache ? "color-pointer-cache" : "pointer-cache", size);
307
0
  }
308
309
0
  WINPR_ASSERT(pointer_cache->entries);
310
0
  prevPointer = pointer_cache->entries[index];
311
0
  pointer_free(pointer_cache->context, prevPointer);
312
0
  pointer_cache->entries[index] = pointer;
313
0
  return TRUE;
314
0
}
315
316
void pointer_cache_register_callbacks(rdpUpdate* update)
317
0
{
318
0
  rdpPointerUpdate* pointer;
319
320
0
  WINPR_ASSERT(update);
321
0
  WINPR_ASSERT(update->context);
322
323
0
  pointer = update->pointer;
324
0
  WINPR_ASSERT(pointer);
325
326
0
  if (!freerdp_settings_get_bool(update->context->settings, FreeRDP_DeactivateClientDecoding))
327
0
  {
328
0
    pointer->PointerPosition = update_pointer_position;
329
0
    pointer->PointerSystem = update_pointer_system;
330
0
    pointer->PointerColor = update_pointer_color;
331
0
    pointer->PointerLarge = update_pointer_large;
332
0
    pointer->PointerNew = update_pointer_new;
333
0
    pointer->PointerCached = update_pointer_cached;
334
0
  }
335
0
}
336
337
rdpPointerCache* pointer_cache_new(rdpContext* context)
338
0
{
339
0
  rdpPointerCache* pointer_cache;
340
0
  rdpSettings* settings;
341
342
0
  WINPR_ASSERT(context);
343
344
0
  settings = context->settings;
345
0
  WINPR_ASSERT(settings);
346
347
0
  pointer_cache = (rdpPointerCache*)calloc(1, sizeof(rdpPointerCache));
348
349
0
  if (!pointer_cache)
350
0
    return NULL;
351
352
0
  pointer_cache->context = context;
353
354
  /* seen invalid pointer cache requests by mstsc (off by 1) so we ensure the cache entry size
355
   * matches */
356
0
  const UINT32 size = freerdp_settings_get_uint32(settings, FreeRDP_PointerCacheSize);
357
0
  const UINT32 colorSize = freerdp_settings_get_uint32(settings, FreeRDP_ColorPointerCacheSize);
358
0
  pointer_cache->cacheSize = MAX(size, colorSize) + 1;
359
360
0
  pointer_cache->entries = (rdpPointer**)calloc(pointer_cache->cacheSize, sizeof(rdpPointer*));
361
362
0
  if (!pointer_cache->entries)
363
0
  {
364
0
    free(pointer_cache);
365
0
    return NULL;
366
0
  }
367
368
0
  return pointer_cache;
369
0
}
370
371
void pointer_cache_free(rdpPointerCache* pointer_cache)
372
0
{
373
0
  if (pointer_cache != NULL)
374
0
  {
375
0
    UINT32 i;
376
0
    rdpPointer* pointer;
377
378
0
    if (pointer_cache->entries)
379
0
    {
380
0
      for (i = 0; i < pointer_cache->cacheSize; i++)
381
0
      {
382
0
        pointer = pointer_cache->entries[i];
383
0
        pointer_free(pointer_cache->context, pointer);
384
0
      }
385
0
    }
386
387
0
    free(pointer_cache->entries);
388
0
    free(pointer_cache);
389
0
  }
390
0
}
391
392
POINTER_COLOR_UPDATE* copy_pointer_color_update(rdpContext* context,
393
                                                const POINTER_COLOR_UPDATE* src)
394
0
{
395
0
  POINTER_COLOR_UPDATE* dst = calloc(1, sizeof(POINTER_COLOR_UPDATE));
396
397
0
  if (!dst || !src)
398
0
    goto fail;
399
400
0
  *dst = *src;
401
402
0
  if (src->lengthAndMask > 0)
403
0
  {
404
0
    dst->andMaskData = calloc(src->lengthAndMask, sizeof(BYTE));
405
406
0
    if (!dst->andMaskData)
407
0
      goto fail;
408
409
0
    memcpy(dst->andMaskData, src->andMaskData, src->lengthAndMask);
410
0
  }
411
412
0
  if (src->lengthXorMask > 0)
413
0
  {
414
0
    dst->xorMaskData = calloc(src->lengthXorMask, sizeof(BYTE));
415
416
0
    if (!dst->xorMaskData)
417
0
      goto fail;
418
419
0
    memcpy(dst->xorMaskData, src->xorMaskData, src->lengthXorMask);
420
0
  }
421
422
0
  return dst;
423
0
fail:
424
0
  free_pointer_color_update(context, dst);
425
0
  return NULL;
426
0
}
427
428
void free_pointer_color_update(rdpContext* context, POINTER_COLOR_UPDATE* pointer)
429
0
{
430
0
  WINPR_UNUSED(context);
431
432
0
  if (!pointer)
433
0
    return;
434
435
0
  free(pointer->xorMaskData);
436
0
  free(pointer->andMaskData);
437
0
  free(pointer);
438
0
}
439
440
POINTER_LARGE_UPDATE* copy_pointer_large_update(rdpContext* context,
441
                                                const POINTER_LARGE_UPDATE* src)
442
0
{
443
0
  POINTER_LARGE_UPDATE* dst = calloc(1, sizeof(POINTER_LARGE_UPDATE));
444
445
0
  if (!dst || !src)
446
0
    goto fail;
447
448
0
  *dst = *src;
449
450
0
  if (src->lengthAndMask > 0)
451
0
  {
452
0
    dst->andMaskData = calloc(src->lengthAndMask, sizeof(BYTE));
453
454
0
    if (!dst->andMaskData)
455
0
      goto fail;
456
457
0
    memcpy(dst->andMaskData, src->andMaskData, src->lengthAndMask);
458
0
  }
459
460
0
  if (src->lengthXorMask > 0)
461
0
  {
462
0
    dst->xorMaskData = calloc(src->lengthXorMask, sizeof(BYTE));
463
464
0
    if (!dst->xorMaskData)
465
0
      goto fail;
466
467
0
    memcpy(dst->xorMaskData, src->xorMaskData, src->lengthXorMask);
468
0
  }
469
470
0
  return dst;
471
0
fail:
472
0
  free_pointer_large_update(context, dst);
473
0
  return NULL;
474
0
}
475
476
void free_pointer_large_update(rdpContext* context, POINTER_LARGE_UPDATE* pointer)
477
0
{
478
0
  WINPR_UNUSED(context);
479
0
  if (!pointer)
480
0
    return;
481
482
0
  free(pointer->xorMaskData);
483
0
  free(pointer->andMaskData);
484
0
  free(pointer);
485
0
}
486
487
POINTER_NEW_UPDATE* copy_pointer_new_update(rdpContext* context, const POINTER_NEW_UPDATE* src)
488
0
{
489
0
  POINTER_NEW_UPDATE* dst = calloc(1, sizeof(POINTER_NEW_UPDATE));
490
491
0
  if (!dst || !src)
492
0
    goto fail;
493
494
0
  *dst = *src;
495
496
0
  if (src->colorPtrAttr.lengthAndMask > 0)
497
0
  {
498
0
    dst->colorPtrAttr.andMaskData = calloc(src->colorPtrAttr.lengthAndMask, sizeof(BYTE));
499
500
0
    if (!dst->colorPtrAttr.andMaskData)
501
0
      goto fail;
502
503
0
    memcpy(dst->colorPtrAttr.andMaskData, src->colorPtrAttr.andMaskData,
504
0
           src->colorPtrAttr.lengthAndMask);
505
0
  }
506
507
0
  if (src->colorPtrAttr.lengthXorMask > 0)
508
0
  {
509
0
    dst->colorPtrAttr.xorMaskData = calloc(src->colorPtrAttr.lengthXorMask, sizeof(BYTE));
510
511
0
    if (!dst->colorPtrAttr.xorMaskData)
512
0
      goto fail;
513
514
0
    memcpy(dst->colorPtrAttr.xorMaskData, src->colorPtrAttr.xorMaskData,
515
0
           src->colorPtrAttr.lengthXorMask);
516
0
  }
517
518
0
  return dst;
519
0
fail:
520
0
  free_pointer_new_update(context, dst);
521
0
  return NULL;
522
0
}
523
524
void free_pointer_new_update(rdpContext* context, POINTER_NEW_UPDATE* pointer)
525
0
{
526
0
  if (!pointer)
527
0
    return;
528
529
0
  free(pointer->colorPtrAttr.xorMaskData);
530
0
  free(pointer->colorPtrAttr.andMaskData);
531
0
  free(pointer);
532
0
}
533
534
POINTER_CACHED_UPDATE* copy_pointer_cached_update(rdpContext* context,
535
                                                  const POINTER_CACHED_UPDATE* pointer)
536
0
{
537
0
  POINTER_CACHED_UPDATE* dst = calloc(1, sizeof(POINTER_CACHED_UPDATE));
538
539
0
  if (!dst)
540
0
    goto fail;
541
542
0
  *dst = *pointer;
543
0
  return dst;
544
0
fail:
545
0
  free_pointer_cached_update(context, dst);
546
0
  return NULL;
547
0
}
548
549
void free_pointer_cached_update(rdpContext* context, POINTER_CACHED_UPDATE* pointer)
550
0
{
551
0
  WINPR_UNUSED(context);
552
0
  free(pointer);
553
0
}
554
555
void free_pointer_position_update(rdpContext* context, POINTER_POSITION_UPDATE* pointer)
556
0
{
557
0
  WINPR_UNUSED(context);
558
0
  free(pointer);
559
0
}
560
561
POINTER_POSITION_UPDATE* copy_pointer_position_update(rdpContext* context,
562
                                                      const POINTER_POSITION_UPDATE* pointer)
563
0
{
564
0
  POINTER_POSITION_UPDATE* dst = calloc(1, sizeof(POINTER_POSITION_UPDATE));
565
566
0
  if (!dst || !pointer)
567
0
    goto fail;
568
569
0
  *dst = *pointer;
570
0
  return dst;
571
0
fail:
572
0
  free_pointer_position_update(context, dst);
573
0
  return NULL;
574
0
}
575
576
void free_pointer_system_update(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer)
577
0
{
578
0
  WINPR_UNUSED(context);
579
0
  free(pointer);
580
0
}
581
582
POINTER_SYSTEM_UPDATE* copy_pointer_system_update(rdpContext* context,
583
                                                  const POINTER_SYSTEM_UPDATE* pointer)
584
0
{
585
0
  POINTER_SYSTEM_UPDATE* dst = calloc(1, sizeof(POINTER_SYSTEM_UPDATE));
586
587
0
  if (!dst || !pointer)
588
0
    goto fail;
589
590
0
  *dst = *pointer;
591
0
  return dst;
592
0
fail:
593
0
  free_pointer_system_update(context, dst);
594
0
  return NULL;
595
0
}