Coverage Report

Created: 2026-09-03 07:14

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