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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include <stdio.h>
25 
26 #include <winpr/crt.h>
27 
28 #include <winpr/stream.h>
29 
30 #include <freerdp/log.h>
31 #include <freerdp/cache/pointer.h>
32 
33 #include "pointer.h"
34 
35 #define TAG FREERDP_TAG("cache.pointer")
36 
37 static BOOL pointer_cache_put(rdpPointerCache* pointer_cache, UINT32 index, rdpPointer* pointer);
38 static const rdpPointer* pointer_cache_get(rdpPointerCache* pointer_cache, UINT32 index);
39 
pointer_free(rdpContext * context,rdpPointer * pointer)40 static void pointer_free(rdpContext* context, rdpPointer* pointer)
41 {
42 	if (pointer)
43 	{
44 		IFCALL(pointer->Free, context, pointer);
45 
46 		if (pointer->xorMaskData)
47 		{
48 			free(pointer->xorMaskData);
49 			pointer->xorMaskData = NULL;
50 		}
51 
52 		if (pointer->andMaskData)
53 		{
54 			free(pointer->andMaskData);
55 			pointer->andMaskData = NULL;
56 		}
57 
58 		free(pointer);
59 	}
60 }
61 
update_pointer_position(rdpContext * context,const POINTER_POSITION_UPDATE * pointer_position)62 static BOOL update_pointer_position(rdpContext* context,
63                                     const POINTER_POSITION_UPDATE* pointer_position)
64 {
65 	rdpPointer* pointer;
66 
67 	if (!context || !context->graphics || !context->graphics->Pointer_Prototype ||
68 	    !pointer_position)
69 		return FALSE;
70 
71 	pointer = context->graphics->Pointer_Prototype;
72 	return IFCALLRESULT(TRUE, pointer->SetPosition, context, pointer_position->xPos,
73 	                    pointer_position->yPos);
74 }
75 
update_pointer_system(rdpContext * context,const POINTER_SYSTEM_UPDATE * pointer_system)76 static BOOL update_pointer_system(rdpContext* context, const POINTER_SYSTEM_UPDATE* pointer_system)
77 {
78 	rdpPointer* pointer;
79 
80 	if (!context || !context->graphics || !context->graphics->Pointer_Prototype || !pointer_system)
81 		return FALSE;
82 
83 	pointer = context->graphics->Pointer_Prototype;
84 
85 	switch (pointer_system->type)
86 	{
87 		case SYSPTR_NULL:
88 			return IFCALLRESULT(TRUE, pointer->SetNull, context);
89 
90 		case SYSPTR_DEFAULT:
91 			return IFCALLRESULT(TRUE, pointer->SetDefault, context);
92 
93 		default:
94 			WLog_ERR(TAG, "Unknown system pointer type (0x%08" PRIX32 ")", pointer_system->type);
95 	}
96 	return TRUE;
97 }
98 
upate_pointer_copy_andxor(rdpPointer * pointer,const BYTE * andMaskData,size_t lengthAndMask,const BYTE * xorMaskData,size_t lengthXorMask)99 static BOOL upate_pointer_copy_andxor(rdpPointer* pointer, const BYTE* andMaskData,
100                                       size_t lengthAndMask, const BYTE* xorMaskData,
101                                       size_t lengthXorMask)
102 {
103 	pointer->lengthAndMask = 0;
104 	pointer->lengthXorMask = 0;
105 
106 	if (lengthAndMask && andMaskData)
107 	{
108 		pointer->lengthAndMask = lengthAndMask;
109 		pointer->andMaskData = (BYTE*)malloc(lengthAndMask);
110 
111 		if (!pointer->andMaskData)
112 			return FALSE;
113 
114 		CopyMemory(pointer->andMaskData, andMaskData, lengthAndMask);
115 	}
116 
117 	if (lengthXorMask && xorMaskData)
118 	{
119 		pointer->lengthXorMask = lengthXorMask;
120 		pointer->xorMaskData = (BYTE*)malloc(lengthXorMask);
121 
122 		if (!pointer->xorMaskData)
123 			return FALSE;
124 
125 		CopyMemory(pointer->xorMaskData, xorMaskData, lengthXorMask);
126 	}
127 
128 	return TRUE;
129 }
130 
update_pointer_color(rdpContext * context,const POINTER_COLOR_UPDATE * pointer_color)131 static BOOL update_pointer_color(rdpContext* context, const POINTER_COLOR_UPDATE* pointer_color)
132 {
133 	rdpPointer* pointer;
134 	rdpCache* cache = context->cache;
135 	pointer = Pointer_Alloc(context);
136 
137 	if (pointer != NULL)
138 	{
139 		pointer->xorBpp = 24;
140 		pointer->xPos = pointer_color->xPos;
141 		pointer->yPos = pointer_color->yPos;
142 		pointer->width = pointer_color->width;
143 		pointer->height = pointer_color->height;
144 
145 		if (!upate_pointer_copy_andxor(pointer, pointer_color->andMaskData,
146 		                               pointer_color->lengthAndMask, pointer_color->xorMaskData,
147 		                               pointer_color->lengthXorMask))
148 			goto out_fail;
149 
150 		if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
151 			goto out_fail;
152 
153 		if (!pointer_cache_put(cache->pointer, pointer_color->cacheIndex, pointer))
154 			goto out_fail;
155 
156 		return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
157 	}
158 
159 	return FALSE;
160 out_fail:
161 	pointer_free(context, pointer);
162 	return FALSE;
163 }
164 
update_pointer_large(rdpContext * context,const POINTER_LARGE_UPDATE * pointer_large)165 static BOOL update_pointer_large(rdpContext* context, const POINTER_LARGE_UPDATE* pointer_large)
166 {
167 	rdpPointer* pointer = Pointer_Alloc(context);
168 	rdpCache* cache = context->cache;
169 
170 	if (pointer != NULL)
171 	{
172 		pointer->xorBpp = pointer_large->xorBpp;
173 		pointer->xPos = pointer_large->hotSpotX;
174 		pointer->yPos = pointer_large->hotSpotY;
175 		pointer->width = pointer_large->width;
176 		pointer->height = pointer_large->height;
177 
178 		if (!upate_pointer_copy_andxor(pointer, pointer_large->andMaskData,
179 		                               pointer_large->lengthAndMask, pointer_large->xorMaskData,
180 		                               pointer_large->lengthXorMask))
181 			goto out_fail;
182 
183 		if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
184 			goto out_fail;
185 
186 		if (!pointer_cache_put(cache->pointer, pointer_large->cacheIndex, pointer))
187 			goto out_fail;
188 
189 		return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
190 	}
191 
192 	return FALSE;
193 out_fail:
194 	pointer_free(context, pointer);
195 	return FALSE;
196 }
197 
update_pointer_new(rdpContext * context,const POINTER_NEW_UPDATE * pointer_new)198 static BOOL update_pointer_new(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new)
199 {
200 	rdpPointer* pointer;
201 	rdpCache* cache;
202 
203 	if (!context || !pointer_new)
204 		return FALSE;
205 
206 	cache = context->cache;
207 	pointer = Pointer_Alloc(context);
208 
209 	if (!pointer)
210 		return FALSE;
211 
212 	pointer->xorBpp = pointer_new->xorBpp;
213 	pointer->xPos = pointer_new->colorPtrAttr.xPos;
214 	pointer->yPos = pointer_new->colorPtrAttr.yPos;
215 	pointer->width = pointer_new->colorPtrAttr.width;
216 	pointer->height = pointer_new->colorPtrAttr.height;
217 	if (!upate_pointer_copy_andxor(
218 	        pointer, pointer_new->colorPtrAttr.andMaskData, pointer_new->colorPtrAttr.lengthAndMask,
219 	        pointer_new->colorPtrAttr.xorMaskData, pointer_new->colorPtrAttr.lengthXorMask))
220 		goto out_fail;
221 
222 	if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
223 		goto out_fail;
224 
225 	if (!pointer_cache_put(cache->pointer, pointer_new->colorPtrAttr.cacheIndex, pointer))
226 		goto out_fail;
227 
228 	return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
229 out_fail:
230 	pointer_free(context, pointer);
231 	return FALSE;
232 }
233 
update_pointer_cached(rdpContext * context,const POINTER_CACHED_UPDATE * pointer_cached)234 static BOOL update_pointer_cached(rdpContext* context, const POINTER_CACHED_UPDATE* pointer_cached)
235 {
236 	const rdpPointer* pointer;
237 	rdpCache* cache = context->cache;
238 	pointer = pointer_cache_get(cache->pointer, pointer_cached->cacheIndex);
239 
240 	if (pointer != NULL)
241 		return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
242 
243 	return FALSE;
244 }
245 
pointer_cache_get(rdpPointerCache * pointer_cache,UINT32 index)246 const rdpPointer* pointer_cache_get(rdpPointerCache* pointer_cache, UINT32 index)
247 {
248 	const rdpPointer* pointer;
249 
250 	if (index >= pointer_cache->cacheSize)
251 	{
252 		WLog_ERR(TAG, "invalid pointer index:%" PRIu32 "", index);
253 		return NULL;
254 	}
255 
256 	pointer = pointer_cache->entries[index];
257 	return pointer;
258 }
259 
pointer_cache_put(rdpPointerCache * pointer_cache,UINT32 index,rdpPointer * pointer)260 BOOL pointer_cache_put(rdpPointerCache* pointer_cache, UINT32 index, rdpPointer* pointer)
261 {
262 	rdpPointer* prevPointer;
263 
264 	if (index >= pointer_cache->cacheSize)
265 	{
266 		WLog_ERR(TAG, "invalid pointer index:%" PRIu32 "", index);
267 		return FALSE;
268 	}
269 
270 	prevPointer = pointer_cache->entries[index];
271 	pointer_free(pointer_cache->update->context, prevPointer);
272 	pointer_cache->entries[index] = pointer;
273 	return TRUE;
274 }
275 
pointer_cache_register_callbacks(rdpUpdate * update)276 void pointer_cache_register_callbacks(rdpUpdate* update)
277 {
278 	rdpPointerUpdate* pointer = update->pointer;
279 	pointer->PointerPosition = update_pointer_position;
280 	pointer->PointerSystem = update_pointer_system;
281 	pointer->PointerColor = update_pointer_color;
282 	pointer->PointerLarge = update_pointer_large;
283 	pointer->PointerNew = update_pointer_new;
284 	pointer->PointerCached = update_pointer_cached;
285 }
286 
pointer_cache_new(rdpSettings * settings)287 rdpPointerCache* pointer_cache_new(rdpSettings* settings)
288 {
289 	rdpPointerCache* pointer_cache;
290 	pointer_cache = (rdpPointerCache*)calloc(1, sizeof(rdpPointerCache));
291 
292 	if (!pointer_cache)
293 		return NULL;
294 
295 	pointer_cache->settings = settings;
296 	pointer_cache->cacheSize = settings->PointerCacheSize;
297 	pointer_cache->update = ((freerdp*)settings->instance)->update;
298 	pointer_cache->entries = (rdpPointer**)calloc(pointer_cache->cacheSize, sizeof(rdpPointer*));
299 
300 	if (!pointer_cache->entries)
301 	{
302 		free(pointer_cache);
303 		return NULL;
304 	}
305 
306 	return pointer_cache;
307 }
308 
pointer_cache_free(rdpPointerCache * pointer_cache)309 void pointer_cache_free(rdpPointerCache* pointer_cache)
310 {
311 	if (pointer_cache != NULL)
312 	{
313 		UINT32 i;
314 		rdpPointer* pointer;
315 
316 		for (i = 0; i < pointer_cache->cacheSize; i++)
317 		{
318 			pointer = pointer_cache->entries[i];
319 			pointer_free(pointer_cache->update->context, pointer);
320 		}
321 
322 		free(pointer_cache->entries);
323 		free(pointer_cache);
324 	}
325 }
326 
copy_pointer_color_update(rdpContext * context,const POINTER_COLOR_UPDATE * src)327 POINTER_COLOR_UPDATE* copy_pointer_color_update(rdpContext* context,
328                                                 const POINTER_COLOR_UPDATE* src)
329 {
330 	POINTER_COLOR_UPDATE* dst = calloc(1, sizeof(POINTER_COLOR_UPDATE));
331 
332 	if (!dst || !src)
333 		goto fail;
334 
335 	*dst = *src;
336 
337 	if (src->lengthAndMask > 0)
338 	{
339 		dst->andMaskData = calloc(src->lengthAndMask, sizeof(BYTE));
340 
341 		if (!dst->andMaskData)
342 			goto fail;
343 
344 		memcpy(dst->andMaskData, src->andMaskData, src->lengthAndMask);
345 	}
346 
347 	if (src->lengthXorMask > 0)
348 	{
349 		dst->xorMaskData = calloc(src->lengthXorMask, sizeof(BYTE));
350 
351 		if (!dst->xorMaskData)
352 			goto fail;
353 
354 		memcpy(dst->xorMaskData, src->xorMaskData, src->lengthXorMask);
355 	}
356 
357 	return dst;
358 fail:
359 	free_pointer_color_update(context, dst);
360 	return NULL;
361 }
362 
free_pointer_color_update(rdpContext * context,POINTER_COLOR_UPDATE * pointer)363 void free_pointer_color_update(rdpContext* context, POINTER_COLOR_UPDATE* pointer)
364 {
365 	if (!pointer)
366 		return;
367 
368 	free(pointer->xorMaskData);
369 	free(pointer->andMaskData);
370 	free(pointer);
371 }
372 
copy_pointer_large_update(rdpContext * context,const POINTER_LARGE_UPDATE * src)373 POINTER_LARGE_UPDATE* copy_pointer_large_update(rdpContext* context,
374                                                 const POINTER_LARGE_UPDATE* src)
375 {
376 	POINTER_LARGE_UPDATE* dst = calloc(1, sizeof(POINTER_LARGE_UPDATE));
377 
378 	if (!dst || !src)
379 		goto fail;
380 
381 	*dst = *src;
382 
383 	if (src->lengthAndMask > 0)
384 	{
385 		dst->andMaskData = calloc(src->lengthAndMask, sizeof(BYTE));
386 
387 		if (!dst->andMaskData)
388 			goto fail;
389 
390 		memcpy(dst->andMaskData, src->andMaskData, src->lengthAndMask);
391 	}
392 
393 	if (src->lengthXorMask > 0)
394 	{
395 		dst->xorMaskData = calloc(src->lengthXorMask, sizeof(BYTE));
396 
397 		if (!dst->xorMaskData)
398 			goto fail;
399 
400 		memcpy(dst->xorMaskData, src->xorMaskData, src->lengthXorMask);
401 	}
402 
403 	return dst;
404 fail:
405 	free_pointer_large_update(context, dst);
406 	return NULL;
407 }
408 
free_pointer_large_update(rdpContext * context,POINTER_LARGE_UPDATE * pointer)409 void free_pointer_large_update(rdpContext* context, POINTER_LARGE_UPDATE* pointer)
410 {
411 	WINPR_UNUSED(context);
412 	if (!pointer)
413 		return;
414 
415 	free(pointer->xorMaskData);
416 	free(pointer->andMaskData);
417 	free(pointer);
418 }
419 
copy_pointer_new_update(rdpContext * context,const POINTER_NEW_UPDATE * src)420 POINTER_NEW_UPDATE* copy_pointer_new_update(rdpContext* context, const POINTER_NEW_UPDATE* src)
421 {
422 	POINTER_NEW_UPDATE* dst = calloc(1, sizeof(POINTER_NEW_UPDATE));
423 
424 	if (!dst || !src)
425 		goto fail;
426 
427 	*dst = *src;
428 
429 	if (src->colorPtrAttr.lengthAndMask > 0)
430 	{
431 		dst->colorPtrAttr.andMaskData = calloc(src->colorPtrAttr.lengthAndMask, sizeof(BYTE));
432 
433 		if (!dst->colorPtrAttr.andMaskData)
434 			goto fail;
435 
436 		memcpy(dst->colorPtrAttr.andMaskData, src->colorPtrAttr.andMaskData,
437 		       src->colorPtrAttr.lengthAndMask);
438 	}
439 
440 	if (src->colorPtrAttr.lengthXorMask > 0)
441 	{
442 		dst->colorPtrAttr.xorMaskData = calloc(src->colorPtrAttr.lengthXorMask, sizeof(BYTE));
443 
444 		if (!dst->colorPtrAttr.xorMaskData)
445 			goto fail;
446 
447 		memcpy(dst->colorPtrAttr.xorMaskData, src->colorPtrAttr.xorMaskData,
448 		       src->colorPtrAttr.lengthXorMask);
449 	}
450 
451 	return dst;
452 fail:
453 	free_pointer_new_update(context, dst);
454 	return NULL;
455 }
456 
free_pointer_new_update(rdpContext * context,POINTER_NEW_UPDATE * pointer)457 void free_pointer_new_update(rdpContext* context, POINTER_NEW_UPDATE* pointer)
458 {
459 	if (!pointer)
460 		return;
461 
462 	free(pointer->colorPtrAttr.xorMaskData);
463 	free(pointer->colorPtrAttr.andMaskData);
464 	free(pointer);
465 }
466 
copy_pointer_cached_update(rdpContext * context,const POINTER_CACHED_UPDATE * pointer)467 POINTER_CACHED_UPDATE* copy_pointer_cached_update(rdpContext* context,
468                                                   const POINTER_CACHED_UPDATE* pointer)
469 {
470 	POINTER_CACHED_UPDATE* dst = calloc(1, sizeof(POINTER_CACHED_UPDATE));
471 
472 	if (!dst)
473 		goto fail;
474 
475 	*dst = *pointer;
476 	return dst;
477 fail:
478 	free_pointer_cached_update(context, dst);
479 	return NULL;
480 }
481 
free_pointer_cached_update(rdpContext * context,POINTER_CACHED_UPDATE * pointer)482 void free_pointer_cached_update(rdpContext* context, POINTER_CACHED_UPDATE* pointer)
483 {
484 	free(pointer);
485 }
486 
free_pointer_position_update(rdpContext * context,POINTER_POSITION_UPDATE * pointer)487 void free_pointer_position_update(rdpContext* context, POINTER_POSITION_UPDATE* pointer)
488 {
489 	free(pointer);
490 }
491 
copy_pointer_position_update(rdpContext * context,const POINTER_POSITION_UPDATE * pointer)492 POINTER_POSITION_UPDATE* copy_pointer_position_update(rdpContext* context,
493                                                       const POINTER_POSITION_UPDATE* pointer)
494 {
495 	POINTER_POSITION_UPDATE* dst = calloc(1, sizeof(POINTER_POSITION_UPDATE));
496 
497 	if (!dst || !pointer)
498 		goto fail;
499 
500 	*dst = *pointer;
501 	return dst;
502 fail:
503 	free_pointer_position_update(context, dst);
504 	return NULL;
505 }
506 
free_pointer_system_update(rdpContext * context,POINTER_SYSTEM_UPDATE * pointer)507 void free_pointer_system_update(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer)
508 {
509 	free(pointer);
510 }
511 
copy_pointer_system_update(rdpContext * context,const POINTER_SYSTEM_UPDATE * pointer)512 POINTER_SYSTEM_UPDATE* copy_pointer_system_update(rdpContext* context,
513                                                   const POINTER_SYSTEM_UPDATE* pointer)
514 {
515 	POINTER_SYSTEM_UPDATE* dst = calloc(1, sizeof(POINTER_SYSTEM_UPDATE));
516 
517 	if (!dst || !pointer)
518 		goto fail;
519 
520 	*dst = *pointer;
521 	return dst;
522 fail:
523 	free_pointer_system_update(context, dst);
524 	return NULL;
525 }
526