Coverage Report

Created: 2026-09-14 06:31

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
static void resetPointer(rdpPointerCache* pointerCache)
345
0
{
346
0
  WINPR_ASSERT(pointerCache);
347
348
0
  if (!pointerCache->context || !pointerCache->context->graphics)
349
0
    return;
350
351
0
  rdpPointer* pointer = pointerCache->context->graphics->Pointer_Prototype;
352
0
  if (!pointer || !pointer->SetDefault)
353
0
    return;
354
355
0
  if (!pointer->SetDefault(pointerCache->context))
356
0
    WLog_WARN(TAG, "rdpPointer::SetDefault failed");
357
0
}
358
359
BOOL pointer_cache_resize(rdpPointerCache* pointerCache)
360
0
{
361
0
  WINPR_ASSERT(pointerCache);
362
363
0
  rdpContext* context = pointerCache->context;
364
0
  WINPR_ASSERT(context);
365
366
0
  rdpSettings* settings = context->settings;
367
0
  WINPR_ASSERT(settings);
368
369
  /* seen invalid pointer cache requests by mstsc (off by 1) so we ensure the cache entry size
370
   * matches */
371
0
  const UINT32 size = freerdp_settings_get_uint32(settings, FreeRDP_PointerCacheSize);
372
0
  const UINT32 colorSize = freerdp_settings_get_uint32(settings, FreeRDP_ColorPointerCacheSize);
373
374
0
  const size_t cacheSize = MAX(size, colorSize) + 1;
375
0
  if (cacheSize > SIZE_MAX / sizeof(rdpPointer*))
376
0
    return FALSE;
377
378
0
  WLog_DBG(TAG,
379
0
           "setting cacheSize=%" PRIuz "[ColorPointerCache=%" PRIu32 ", PointerCache=%" PRIu32
380
0
           "]",
381
0
           cacheSize, colorSize, size);
382
383
  /* Reset pointer to default before deleting the cache.
384
   */
385
0
  resetPointer(pointerCache);
386
387
0
  for (size_t i = cacheSize; i < pointerCache->cacheSize; i++)
388
0
  {
389
0
    rdpPointer* pointer = pointerCache->entries[i];
390
0
    pointer_free(pointerCache->context, pointer);
391
0
  }
392
393
0
  void* tmp = realloc((void*)pointerCache->entries, cacheSize * sizeof(rdpPointer*));
394
0
  if (!tmp)
395
0
    return FALSE;
396
397
0
  pointerCache->entries = (rdpPointer**)tmp;
398
0
  if (cacheSize > pointerCache->cacheSize)
399
0
  {
400
0
    const size_t rsize = (cacheSize - pointerCache->cacheSize) * sizeof(rdpPointer*);
401
0
    void* dst = (void*)&pointerCache->entries[pointerCache->cacheSize];
402
0
    memset(dst, 0, rsize);
403
0
  }
404
0
  pointerCache->cacheSize = WINPR_ASSERTING_INT_CAST(UINT32, cacheSize);
405
406
0
  return TRUE;
407
0
}
408
409
rdpPointerCache* pointer_cache_new(rdpContext* context)
410
0
{
411
0
  WINPR_ASSERT(context);
412
413
0
  rdpPointerCache* pointer_cache = (rdpPointerCache*)calloc(1, sizeof(rdpPointerCache));
414
415
0
  if (!pointer_cache)
416
0
    return nullptr;
417
418
0
  pointer_cache->context = context;
419
420
0
  if (!pointer_cache_resize(pointer_cache))
421
0
  {
422
0
    free(pointer_cache);
423
0
    return nullptr;
424
0
  }
425
426
0
  return pointer_cache;
427
0
}
428
429
void pointer_cache_free(rdpPointerCache* pointer_cache)
430
0
{
431
0
  if (pointer_cache != nullptr)
432
0
  {
433
    /* Reset pointer to default before deleting the cache.
434
     */
435
0
    resetPointer(pointer_cache);
436
437
0
    if (pointer_cache->entries)
438
0
    {
439
0
      for (UINT32 i = 0; i < pointer_cache->cacheSize; i++)
440
0
      {
441
0
        rdpPointer* pointer = pointer_cache->entries[i];
442
0
        pointer_free(pointer_cache->context, pointer);
443
0
      }
444
0
    }
445
446
0
    free((void*)pointer_cache->entries);
447
0
    free(pointer_cache);
448
0
  }
449
0
}
450
451
POINTER_COLOR_UPDATE* copy_pointer_color_update(rdpContext* context,
452
                                                const POINTER_COLOR_UPDATE* pointer)
453
0
{
454
0
  POINTER_COLOR_UPDATE* dst = calloc(1, sizeof(POINTER_COLOR_UPDATE));
455
456
0
  if (!dst || !pointer)
457
0
    goto fail;
458
459
0
  *dst = *pointer;
460
461
0
  if (pointer->lengthAndMask > 0)
462
0
  {
463
0
    dst->andMaskData = calloc(pointer->lengthAndMask, sizeof(BYTE));
464
465
0
    if (!dst->andMaskData)
466
0
      goto fail;
467
468
0
    memcpy(dst->andMaskData, pointer->andMaskData, pointer->lengthAndMask);
469
0
  }
470
471
0
  if (pointer->lengthXorMask > 0)
472
0
  {
473
0
    dst->xorMaskData = calloc(pointer->lengthXorMask, sizeof(BYTE));
474
475
0
    if (!dst->xorMaskData)
476
0
      goto fail;
477
478
0
    memcpy(dst->xorMaskData, pointer->xorMaskData, pointer->lengthXorMask);
479
0
  }
480
481
0
  return dst;
482
0
fail:
483
0
  free_pointer_color_update(context, dst);
484
0
  return nullptr;
485
0
}
486
487
void free_pointer_color_update(rdpContext* context, POINTER_COLOR_UPDATE* pointer)
488
0
{
489
0
  WINPR_UNUSED(context);
490
491
0
  if (!pointer)
492
0
    return;
493
494
0
  free(pointer->xorMaskData);
495
0
  free(pointer->andMaskData);
496
0
  free(pointer);
497
0
}
498
499
POINTER_LARGE_UPDATE* copy_pointer_large_update(rdpContext* context,
500
                                                const POINTER_LARGE_UPDATE* pointer)
501
0
{
502
0
  POINTER_LARGE_UPDATE* dst = calloc(1, sizeof(POINTER_LARGE_UPDATE));
503
504
0
  if (!dst || !pointer)
505
0
    goto fail;
506
507
0
  *dst = *pointer;
508
509
0
  if (pointer->lengthAndMask > 0)
510
0
  {
511
0
    dst->andMaskData = calloc(pointer->lengthAndMask, sizeof(BYTE));
512
513
0
    if (!dst->andMaskData)
514
0
      goto fail;
515
516
0
    memcpy(dst->andMaskData, pointer->andMaskData, pointer->lengthAndMask);
517
0
  }
518
519
0
  if (pointer->lengthXorMask > 0)
520
0
  {
521
0
    dst->xorMaskData = calloc(pointer->lengthXorMask, sizeof(BYTE));
522
523
0
    if (!dst->xorMaskData)
524
0
      goto fail;
525
526
0
    memcpy(dst->xorMaskData, pointer->xorMaskData, pointer->lengthXorMask);
527
0
  }
528
529
0
  return dst;
530
0
fail:
531
0
  free_pointer_large_update(context, dst);
532
0
  return nullptr;
533
0
}
534
535
void free_pointer_large_update(rdpContext* context, POINTER_LARGE_UPDATE* pointer)
536
0
{
537
0
  WINPR_UNUSED(context);
538
0
  if (!pointer)
539
0
    return;
540
541
0
  free(pointer->xorMaskData);
542
0
  free(pointer->andMaskData);
543
0
  free(pointer);
544
0
}
545
546
POINTER_NEW_UPDATE* copy_pointer_new_update(rdpContext* context, const POINTER_NEW_UPDATE* pointer)
547
0
{
548
0
  POINTER_NEW_UPDATE* dst = calloc(1, sizeof(POINTER_NEW_UPDATE));
549
550
0
  if (!dst || !pointer)
551
0
    goto fail;
552
553
0
  *dst = *pointer;
554
555
0
  if (pointer->colorPtrAttr.lengthAndMask > 0)
556
0
  {
557
0
    dst->colorPtrAttr.andMaskData = calloc(pointer->colorPtrAttr.lengthAndMask, sizeof(BYTE));
558
559
0
    if (!dst->colorPtrAttr.andMaskData)
560
0
      goto fail;
561
562
0
    memcpy(dst->colorPtrAttr.andMaskData, pointer->colorPtrAttr.andMaskData,
563
0
           pointer->colorPtrAttr.lengthAndMask);
564
0
  }
565
566
0
  if (pointer->colorPtrAttr.lengthXorMask > 0)
567
0
  {
568
0
    dst->colorPtrAttr.xorMaskData = calloc(pointer->colorPtrAttr.lengthXorMask, sizeof(BYTE));
569
570
0
    if (!dst->colorPtrAttr.xorMaskData)
571
0
      goto fail;
572
573
0
    memcpy(dst->colorPtrAttr.xorMaskData, pointer->colorPtrAttr.xorMaskData,
574
0
           pointer->colorPtrAttr.lengthXorMask);
575
0
  }
576
577
0
  return dst;
578
0
fail:
579
0
  free_pointer_new_update(context, dst);
580
0
  return nullptr;
581
0
}
582
583
void free_pointer_new_update(WINPR_ATTR_UNUSED rdpContext* context, POINTER_NEW_UPDATE* pointer)
584
0
{
585
0
  if (!pointer)
586
0
    return;
587
588
0
  free(pointer->colorPtrAttr.xorMaskData);
589
0
  free(pointer->colorPtrAttr.andMaskData);
590
0
  free(pointer);
591
0
}
592
593
POINTER_CACHED_UPDATE* copy_pointer_cached_update(rdpContext* context,
594
                                                  const POINTER_CACHED_UPDATE* pointer)
595
0
{
596
0
  POINTER_CACHED_UPDATE* dst = calloc(1, sizeof(POINTER_CACHED_UPDATE));
597
598
0
  if (!dst)
599
0
    goto fail;
600
601
0
  *dst = *pointer;
602
0
  return dst;
603
0
fail:
604
0
  free_pointer_cached_update(context, dst);
605
0
  return nullptr;
606
0
}
607
608
void free_pointer_cached_update(rdpContext* context, POINTER_CACHED_UPDATE* pointer)
609
0
{
610
0
  WINPR_UNUSED(context);
611
0
  free(pointer);
612
0
}
613
614
void free_pointer_position_update(rdpContext* context, POINTER_POSITION_UPDATE* pointer)
615
0
{
616
0
  WINPR_UNUSED(context);
617
0
  free(pointer);
618
0
}
619
620
POINTER_POSITION_UPDATE* copy_pointer_position_update(rdpContext* context,
621
                                                      const POINTER_POSITION_UPDATE* pointer)
622
0
{
623
0
  POINTER_POSITION_UPDATE* dst = calloc(1, sizeof(POINTER_POSITION_UPDATE));
624
625
0
  if (!dst || !pointer)
626
0
    goto fail;
627
628
0
  *dst = *pointer;
629
0
  return dst;
630
0
fail:
631
0
  free_pointer_position_update(context, dst);
632
0
  return nullptr;
633
0
}
634
635
void free_pointer_system_update(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer)
636
0
{
637
0
  WINPR_UNUSED(context);
638
0
  free(pointer);
639
0
}
640
641
POINTER_SYSTEM_UPDATE* copy_pointer_system_update(rdpContext* context,
642
                                                  const POINTER_SYSTEM_UPDATE* pointer)
643
0
{
644
0
  POINTER_SYSTEM_UPDATE* dst = calloc(1, sizeof(POINTER_SYSTEM_UPDATE));
645
646
0
  if (!dst || !pointer)
647
0
    goto fail;
648
649
0
  *dst = *pointer;
650
0
  return dst;
651
0
fail:
652
0
  free_pointer_system_update(context, dst);
653
0
  return nullptr;
654
0
}