FreeRDP
Loading...
Searching...
No Matches
clear.c
1
22#include <freerdp/config.h>
23
24#include <winpr/crt.h>
25#include <winpr/print.h>
26#include <winpr/bitstream.h>
27
28#include <freerdp/codec/color.h>
29#include <freerdp/codec/clear.h>
30#include <freerdp/log.h>
31
32#define TAG FREERDP_TAG("codec.clear")
33
34#define CLEARCODEC_FLAG_GLYPH_INDEX 0x01
35#define CLEARCODEC_FLAG_GLYPH_HIT 0x02
36#define CLEARCODEC_FLAG_CACHE_RESET 0x04
37
38#define CLEARCODEC_VBAR_SIZE 32768
39#define CLEARCODEC_VBAR_SHORT_SIZE 16384
40
41typedef struct
42{
43 UINT32 size;
44 UINT32 count;
45 UINT32* pixels;
46} CLEAR_GLYPH_ENTRY;
47
48typedef struct
49{
50 UINT32 size;
51 UINT32 count;
52 BYTE* pixels;
53} CLEAR_VBAR_ENTRY;
54
55struct S_CLEAR_CONTEXT
56{
57 BOOL Compressor;
58 NSC_CONTEXT* nsc;
59 UINT32 seqNumber;
60 BYTE* TempBuffer;
61 size_t TempSize;
62 UINT32 format;
63 BOOL formatSet;
64 CLEAR_GLYPH_ENTRY GlyphCache[4000];
65 UINT32 VBarStorageCursor;
66 CLEAR_VBAR_ENTRY VBarStorage[CLEARCODEC_VBAR_SIZE];
67 UINT32 ShortVBarStorageCursor;
68 CLEAR_VBAR_ENTRY ShortVBarStorage[CLEARCODEC_VBAR_SHORT_SIZE];
69 wLog* log;
70};
71
72static const UINT32 CLEAR_LOG2_FLOOR[256] = {
73 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
74 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
75 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
76 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
77 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
78 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
79 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
80 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
81};
82
83static const BYTE CLEAR_8BIT_MASKS[9] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
84
85static void clear_reset_vbar_storage(CLEAR_CONTEXT* WINPR_RESTRICT clear, BOOL zero)
86{
87 if (zero)
88 {
89 for (size_t i = 0; i < ARRAYSIZE(clear->VBarStorage); i++)
90 winpr_aligned_free(clear->VBarStorage[i].pixels);
91
92 ZeroMemory(clear->VBarStorage, sizeof(clear->VBarStorage));
93 }
94
95 clear->VBarStorageCursor = 0;
96
97 if (zero)
98 {
99 for (size_t i = 0; i < ARRAYSIZE(clear->ShortVBarStorage); i++)
100 winpr_aligned_free(clear->ShortVBarStorage[i].pixels);
101
102 ZeroMemory(clear->ShortVBarStorage, sizeof(clear->ShortVBarStorage));
103 }
104
105 clear->ShortVBarStorageCursor = 0;
106}
107
108static void clear_reset_glyph_cache(CLEAR_CONTEXT* WINPR_RESTRICT clear)
109{
110 for (size_t i = 0; i < ARRAYSIZE(clear->GlyphCache); i++)
111 winpr_aligned_free(clear->GlyphCache[i].pixels);
112
113 ZeroMemory(clear->GlyphCache, sizeof(clear->GlyphCache));
114}
115
116static BOOL convert_color(BYTE* WINPR_RESTRICT dst, UINT32 nDstStep, UINT32 DstFormat, UINT32 nXDst,
117 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
118 const BYTE* WINPR_RESTRICT src, UINT32 nSrcStep, UINT32 SrcFormat,
119 UINT32 nDstWidth, UINT32 nDstHeight,
120 const gdiPalette* WINPR_RESTRICT palette)
121{
122 if (nWidth + nXDst > nDstWidth)
123 nWidth = nDstWidth - nXDst;
124
125 if (nHeight + nYDst > nDstHeight)
126 nHeight = nDstHeight - nYDst;
127
128 return freerdp_image_copy_no_overlap(dst, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
129 src, SrcFormat, nSrcStep, 0, 0, palette,
130 FREERDP_KEEP_DST_ALPHA);
131}
132
133static BOOL clear_decompress_nscodec(wLog* log, NSC_CONTEXT* WINPR_RESTRICT nsc, UINT32 width,
134 UINT32 height, wStream* WINPR_RESTRICT s,
135 UINT32 bitmapDataByteCount, BYTE* WINPR_RESTRICT pDstData,
136 UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDstRel,
137 UINT32 nYDstRel, UINT32 nDstWidth, UINT32 nDstHeight)
138{
139 BOOL rc = 0;
140
141 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, bitmapDataByteCount))
142 return FALSE;
143
144 rc = nsc_process_message(nsc, 32, width, height, Stream_Pointer(s), bitmapDataByteCount,
145 pDstData, DstFormat, nDstStep, nXDstRel, nYDstRel, nDstWidth,
146 nDstHeight, FREERDP_FLIP_NONE);
147 Stream_Seek(s, bitmapDataByteCount);
148 return rc;
149}
150
151static BOOL clear_decompress_subcode_rlex(wLog* log, wStream* WINPR_RESTRICT s,
152 UINT32 bitmapDataByteCount, UINT32 width, UINT32 height,
153 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
154 UINT32 nDstStep, UINT32 nXDstRel, UINT32 nYDstRel,
155 UINT32 nDstWidth, UINT32 nDstHeight)
156{
157 UINT32 x = 0;
158 UINT32 y = 0;
159 UINT32 pixelCount = 0;
160 UINT32 bitmapDataOffset = 0;
161 size_t pixelIndex = 0;
162 UINT32 numBits = 0;
163 BYTE startIndex = 0;
164 BYTE stopIndex = 0;
165 BYTE suiteIndex = 0;
166 BYTE suiteDepth = 0;
167 BYTE paletteCount = 0;
168 UINT32 palette[128] = WINPR_C_ARRAY_INIT;
169
170 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, bitmapDataByteCount))
171 return FALSE;
172
173 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
174 return FALSE;
175 Stream_Read_UINT8(s, paletteCount);
176 bitmapDataOffset = 1 + (paletteCount * 3);
177
178 if ((paletteCount > 127) || (paletteCount < 1))
179 {
180 WLog_Print(log, WLOG_ERROR, "paletteCount %" PRIu8 "", paletteCount);
181 return FALSE;
182 }
183
184 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, paletteCount, 3ull))
185 return FALSE;
186
187 for (UINT32 i = 0; i < paletteCount; i++)
188 {
189 BYTE r = 0;
190 BYTE g = 0;
191 BYTE b = 0;
192 Stream_Read_UINT8(s, b);
193 Stream_Read_UINT8(s, g);
194 Stream_Read_UINT8(s, r);
195 palette[i] = FreeRDPGetColor(DstFormat, r, g, b, 0xFF);
196 }
197
198 pixelIndex = 0;
199 pixelCount = width * height;
200 numBits = CLEAR_LOG2_FLOOR[paletteCount - 1] + 1;
201
202 while (bitmapDataOffset < bitmapDataByteCount)
203 {
204 UINT32 tmp = 0;
205 UINT32 color = 0;
206 UINT32 runLengthFactor = 0;
207
208 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
209 return FALSE;
210
211 Stream_Read_UINT8(s, tmp);
212 Stream_Read_UINT8(s, runLengthFactor);
213 bitmapDataOffset += 2;
214 suiteDepth = (tmp >> numBits) & CLEAR_8BIT_MASKS[(8 - numBits)];
215 stopIndex = tmp & CLEAR_8BIT_MASKS[numBits];
216 startIndex = stopIndex - suiteDepth;
217
218 if (runLengthFactor >= 0xFF)
219 {
220 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
221 return FALSE;
222
223 Stream_Read_UINT16(s, runLengthFactor);
224 bitmapDataOffset += 2;
225
226 if (runLengthFactor >= 0xFFFF)
227 {
228 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
229 return FALSE;
230
231 Stream_Read_UINT32(s, runLengthFactor);
232 bitmapDataOffset += 4;
233 }
234 }
235
236 if (startIndex >= paletteCount)
237 {
238 WLog_Print(log, WLOG_ERROR, "startIndex %" PRIu8 " > paletteCount %" PRIu8 "]",
239 startIndex, paletteCount);
240 return FALSE;
241 }
242
243 if (stopIndex >= paletteCount)
244 {
245 WLog_Print(log, WLOG_ERROR, "stopIndex %" PRIu8 " > paletteCount %" PRIu8 "]",
246 stopIndex, paletteCount);
247 return FALSE;
248 }
249
250 suiteIndex = startIndex;
251
252 if (suiteIndex > 127)
253 {
254 WLog_Print(log, WLOG_ERROR, "suiteIndex %" PRIu8 " > 127]", suiteIndex);
255 return FALSE;
256 }
257
258 color = palette[suiteIndex];
259
260 if ((pixelIndex + runLengthFactor) > pixelCount)
261 {
262 WLog_Print(log, WLOG_ERROR,
263 "pixelIndex %" PRIuz " + runLengthFactor %" PRIu32 " > pixelCount %" PRIu32
264 "",
265 pixelIndex, runLengthFactor, pixelCount);
266 return FALSE;
267 }
268
269 for (UINT32 i = 0; i < runLengthFactor; i++)
270 {
271 BYTE* pTmpData = &pDstData[(nXDstRel + x) * FreeRDPGetBytesPerPixel(DstFormat) +
272 (nYDstRel + y) * nDstStep];
273
274 if ((nXDstRel + x < nDstWidth) && (nYDstRel + y < nDstHeight))
275 FreeRDPWriteColor(pTmpData, DstFormat, color);
276
277 if (++x >= width)
278 {
279 y++;
280 x = 0;
281 }
282 }
283
284 pixelIndex += runLengthFactor;
285
286 if ((pixelIndex + (suiteDepth + 1)) > pixelCount)
287 {
288 WLog_Print(log, WLOG_ERROR,
289 "pixelIndex %" PRIuz " + suiteDepth %" PRIu8 " + 1 > pixelCount %" PRIu32 "",
290 pixelIndex, suiteDepth, pixelCount);
291 return FALSE;
292 }
293
294 for (UINT32 i = 0; i <= suiteDepth; i++)
295 {
296 BYTE* pTmpData = &pDstData[(nXDstRel + x) * FreeRDPGetBytesPerPixel(DstFormat) +
297 (nYDstRel + y) * nDstStep];
298 UINT32 ccolor = palette[suiteIndex];
299
300 if (suiteIndex > 127)
301 {
302 WLog_Print(log, WLOG_ERROR, "suiteIndex %" PRIu8 " > 127", suiteIndex);
303 return FALSE;
304 }
305
306 suiteIndex++;
307
308 if ((nXDstRel + x < nDstWidth) && (nYDstRel + y < nDstHeight))
309 FreeRDPWriteColor(pTmpData, DstFormat, ccolor);
310
311 if (++x >= width)
312 {
313 y++;
314 x = 0;
315 }
316 }
317
318 pixelIndex += (suiteDepth + 1);
319 }
320
321 if (pixelIndex != pixelCount)
322 {
323 WLog_Print(log, WLOG_ERROR, "pixelIndex %" PRIuz " != pixelCount %" PRIu32 "", pixelIndex,
324 pixelCount);
325 return FALSE;
326 }
327
328 return TRUE;
329}
330
331static BOOL clear_resize_buffer(CLEAR_CONTEXT* WINPR_RESTRICT clear, UINT32 width, UINT32 height)
332{
333 if (!clear)
334 return FALSE;
335
336 const UINT64 size = 1ull * (width + 16ull) * (height + 16ull);
337 const size_t bpp = FreeRDPGetBytesPerPixel(clear->format);
338 if (size > UINT32_MAX / bpp)
339 return FALSE;
340
341 if (size > clear->TempSize / bpp)
342 {
343 BYTE* tmp = (BYTE*)winpr_aligned_recalloc(clear->TempBuffer,
344 WINPR_ASSERTING_INT_CAST(size_t, size), bpp, 32);
345
346 if (!tmp)
347 {
348 WLog_Print(clear->log, WLOG_ERROR,
349 "clear->TempBuffer winpr_aligned_recalloc failed for %" PRIu64 " bytes",
350 size);
351 return FALSE;
352 }
353
354 clear->TempSize = WINPR_ASSERTING_INT_CAST(size_t, size* bpp);
355 clear->TempBuffer = tmp;
356 }
357
358 return TRUE;
359}
360
361static BOOL clear_decompress_residual_data(CLEAR_CONTEXT* WINPR_RESTRICT clear,
362 wStream* WINPR_RESTRICT s, UINT32 residualByteCount,
363 UINT32 nWidth, UINT32 nHeight,
364 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
365 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
366 UINT32 nDstWidth, UINT32 nDstHeight,
367 const gdiPalette* WINPR_RESTRICT palette)
368{
369 UINT32 nSrcStep = 0;
370 UINT32 suboffset = 0;
371 BYTE* dstBuffer = nullptr;
372 UINT32 pixelIndex = 0;
373 UINT32 pixelCount = 0;
374
375 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, residualByteCount))
376 return FALSE;
377
378 suboffset = 0;
379 pixelIndex = 0;
380 pixelCount = nWidth * nHeight;
381
382 if (!clear_resize_buffer(clear, nWidth, nHeight))
383 return FALSE;
384
385 dstBuffer = clear->TempBuffer;
386
387 while (suboffset < residualByteCount)
388 {
389 BYTE r = 0;
390 BYTE g = 0;
391 BYTE b = 0;
392 UINT32 runLengthFactor = 0;
393 UINT32 color = 0;
394
395 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 4))
396 return FALSE;
397
398 Stream_Read_UINT8(s, b);
399 Stream_Read_UINT8(s, g);
400 Stream_Read_UINT8(s, r);
401 Stream_Read_UINT8(s, runLengthFactor);
402 suboffset += 4;
403 color = FreeRDPGetColor(clear->format, r, g, b, 0xFF);
404
405 if (runLengthFactor >= 0xFF)
406 {
407 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
408 return FALSE;
409
410 Stream_Read_UINT16(s, runLengthFactor);
411 suboffset += 2;
412
413 if (runLengthFactor >= 0xFFFF)
414 {
415 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 4))
416 return FALSE;
417
418 Stream_Read_UINT32(s, runLengthFactor);
419 suboffset += 4;
420 }
421 }
422
423 if ((pixelIndex >= pixelCount) || (runLengthFactor > (pixelCount - pixelIndex)))
424 {
425 WLog_Print(clear->log, WLOG_ERROR,
426 "pixelIndex %" PRIu32 " + runLengthFactor %" PRIu32 " > pixelCount %" PRIu32
427 "",
428 pixelIndex, runLengthFactor, pixelCount);
429 return FALSE;
430 }
431
432 for (UINT32 i = 0; i < runLengthFactor; i++)
433 {
434 FreeRDPWriteColor(dstBuffer, clear->format, color);
435 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
436 }
437
438 pixelIndex += runLengthFactor;
439 }
440
441 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(clear->format);
442
443 if (pixelIndex != pixelCount)
444 {
445 WLog_Print(clear->log, WLOG_ERROR, "pixelIndex %" PRIu32 " != pixelCount %" PRIu32 "",
446 pixelIndex, pixelCount);
447 return FALSE;
448 }
449
450 return convert_color(pDstData, nDstStep, DstFormat, nXDst, nYDst, nWidth, nHeight,
451 clear->TempBuffer, nSrcStep, clear->format, nDstWidth, nDstHeight,
452 palette);
453}
454
455static BOOL clear_decompress_subcodecs_data(CLEAR_CONTEXT* WINPR_RESTRICT clear,
456 wStream* WINPR_RESTRICT s, UINT32 subcodecByteCount,
457 UINT32 nWidth, UINT32 nHeight,
458 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
459 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
460 UINT32 nDstWidth, UINT32 nDstHeight,
461 const gdiPalette* WINPR_RESTRICT palette)
462{
463 UINT32 suboffset = 0;
464
465 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, subcodecByteCount))
466 return FALSE;
467
468 while (suboffset < subcodecByteCount)
469 {
470 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 13))
471 return FALSE;
472
473 const UINT16 xStart = Stream_Get_UINT16(s);
474 const UINT16 yStart = Stream_Get_UINT16(s);
475 const UINT16 width = Stream_Get_UINT16(s);
476 const UINT16 height = Stream_Get_UINT16(s);
477 const UINT32 bitmapDataByteCount = Stream_Get_UINT32(s);
478 const UINT8 subcodecId = Stream_Get_UINT8(s);
479 suboffset += 13;
480
481 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, bitmapDataByteCount))
482 return FALSE;
483
484 const UINT32 nXDstRel = nXDst + xStart;
485 const UINT32 nYDstRel = nYDst + yStart;
486 if (1ull * nXDstRel + width > nDstWidth)
487 {
488 WLog_Print(clear->log, WLOG_ERROR,
489 "nXDstRel %" PRIu32 " + width %" PRIu16 " > nDstWidth %" PRIu32 "", nXDstRel,
490 width, nDstWidth);
491 return FALSE;
492 }
493 if (1ull * nYDstRel + height > nDstHeight)
494 {
495 WLog_Print(clear->log, WLOG_ERROR,
496 "nYDstRel %" PRIu32 " + height %" PRIu16 " > nDstHeight %" PRIu32 "",
497 nYDstRel, height, nDstHeight);
498 return FALSE;
499 }
500
501 if (1ull * xStart + width > nWidth)
502 {
503 WLog_Print(clear->log, WLOG_ERROR,
504 "xStart %" PRIu16 " + width %" PRIu16 " > nWidth %" PRIu32 "", xStart, width,
505 nWidth);
506 return FALSE;
507 }
508 if (1ull * yStart + height > nHeight)
509 {
510 WLog_Print(clear->log, WLOG_ERROR,
511 "yStart %" PRIu16 " + height %" PRIu16 " > nHeight %" PRIu32 "", yStart,
512 height, nHeight);
513 return FALSE;
514 }
515
516 if (!clear_resize_buffer(clear, width, height))
517 return FALSE;
518
519 switch (subcodecId)
520 {
521 case 0: /* Uncompressed */
522 {
523 const UINT32 nSrcStep = width * FreeRDPGetBytesPerPixel(PIXEL_FORMAT_BGR24);
524 const size_t nSrcSize = 1ull * nSrcStep * height;
525
526 if (bitmapDataByteCount != nSrcSize)
527 {
528 WLog_Print(clear->log, WLOG_ERROR,
529 "bitmapDataByteCount %" PRIu32 " != nSrcSize %" PRIuz "",
530 bitmapDataByteCount, nSrcSize);
531 return FALSE;
532 }
533
534 if (!convert_color(pDstData, nDstStep, DstFormat, nXDstRel, nYDstRel, width, height,
535 Stream_Pointer(s), nSrcStep, PIXEL_FORMAT_BGR24, nDstWidth,
536 nDstHeight, palette))
537 return FALSE;
538
539 Stream_Seek(s, bitmapDataByteCount);
540 }
541 break;
542
543 case 1: /* NSCodec */
544 if (!clear_decompress_nscodec(clear->log, clear->nsc, width, height, s,
545 bitmapDataByteCount, pDstData, DstFormat, nDstStep,
546 nXDstRel, nYDstRel, nDstWidth, nDstHeight))
547 return FALSE;
548
549 break;
550
551 case 2: /* CLEARCODEC_SUBCODEC_RLEX */
552 if (!clear_decompress_subcode_rlex(clear->log, s, bitmapDataByteCount, width,
553 height, pDstData, DstFormat, nDstStep, nXDstRel,
554 nYDstRel, nDstWidth, nDstHeight))
555 return FALSE;
556
557 break;
558
559 default:
560 WLog_Print(clear->log, WLOG_ERROR, "Unknown subcodec ID %" PRIu8 "", subcodecId);
561 return FALSE;
562 }
563
564 suboffset += bitmapDataByteCount;
565 }
566
567 return TRUE;
568}
569
570static BOOL resize_vbar_entry(CLEAR_CONTEXT* WINPR_RESTRICT clear,
571 CLEAR_VBAR_ENTRY* WINPR_RESTRICT vBarEntry)
572{
573 if (vBarEntry->count > vBarEntry->size)
574 {
575 const UINT32 bpp = FreeRDPGetBytesPerPixel(clear->format);
576 const UINT32 oldPos = vBarEntry->size * bpp;
577 const UINT32 diffSize = (vBarEntry->count - vBarEntry->size) * bpp;
578
579 BYTE* tmp =
580 (BYTE*)winpr_aligned_recalloc(vBarEntry->pixels, vBarEntry->count, 1ull * bpp, 32);
581
582 if (!tmp)
583 {
584 WLog_Print(clear->log, WLOG_ERROR,
585 "vBarEntry->pixels winpr_aligned_recalloc %" PRIu32 " failed",
586 vBarEntry->count * bpp);
587 return FALSE;
588 }
589
590 memset(&tmp[oldPos], 0, diffSize);
591 vBarEntry->pixels = tmp;
592 vBarEntry->size = vBarEntry->count;
593 }
594
595 if (!vBarEntry->pixels && vBarEntry->size)
596 {
597 WLog_Print(clear->log, WLOG_ERROR,
598 "vBarEntry->pixels is nullptr but vBarEntry->size is %" PRIu32 "",
599 vBarEntry->size);
600 return FALSE;
601 }
602
603 return TRUE;
604}
605
606static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* WINPR_RESTRICT clear,
607 wStream* WINPR_RESTRICT s, UINT32 bandsByteCount,
608 UINT32 nWidth, UINT32 nHeight,
609 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
610 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
611 UINT32 nDstWidth, UINT32 nDstHeight)
612{
613 UINT32 suboffset = 0;
614
615 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, bandsByteCount))
616 return FALSE;
617
618 while (suboffset < bandsByteCount)
619 {
620 BYTE cr = 0;
621 BYTE cg = 0;
622 BYTE cb = 0;
623 UINT16 xStart = 0;
624 UINT16 xEnd = 0;
625 UINT16 yStart = 0;
626 UINT16 yEnd = 0;
627 UINT32 colorBkg = 0;
628 UINT16 vBarHeader = 0;
629 UINT16 vBarYOn = 0;
630 UINT16 vBarYOff = 0;
631 UINT32 vBarCount = 0;
632 UINT32 vBarPixelCount = 0;
633 UINT32 vBarShortPixelCount = 0;
634
635 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 11))
636 return FALSE;
637
638 Stream_Read_UINT16(s, xStart);
639 Stream_Read_UINT16(s, xEnd);
640 Stream_Read_UINT16(s, yStart);
641 Stream_Read_UINT16(s, yEnd);
642 Stream_Read_UINT8(s, cb);
643 Stream_Read_UINT8(s, cg);
644 Stream_Read_UINT8(s, cr);
645 suboffset += 11;
646 colorBkg = FreeRDPGetColor(clear->format, cr, cg, cb, 0xFF);
647
648 if (xEnd < xStart)
649 {
650 WLog_Print(clear->log, WLOG_ERROR, "xEnd %" PRIu16 " < xStart %" PRIu16 "", xEnd,
651 xStart);
652 return FALSE;
653 }
654
655 if (yEnd < yStart)
656 {
657 WLog_Print(clear->log, WLOG_ERROR, "yEnd %" PRIu16 " < yStart %" PRIu16 "", yEnd,
658 yStart);
659 return FALSE;
660 }
661
662 vBarCount = (xEnd - xStart) + 1;
663
664 for (UINT32 i = 0; i < vBarCount; i++)
665 {
666 UINT32 vBarHeight = 0;
667 CLEAR_VBAR_ENTRY* vBarEntry = nullptr;
668 CLEAR_VBAR_ENTRY* vBarShortEntry = nullptr;
669 BOOL vBarUpdate = FALSE;
670 const BYTE* cpSrcPixel = nullptr;
671
672 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
673 return FALSE;
674
675 Stream_Read_UINT16(s, vBarHeader);
676 suboffset += 2;
677 vBarHeight = (yEnd - yStart + 1);
678
679 if (vBarHeight > 52)
680 {
681 WLog_Print(clear->log, WLOG_ERROR, "vBarHeight (%" PRIu32 ") > 52", vBarHeight);
682 return FALSE;
683 }
684
685 if ((vBarHeader & 0xC000) == 0x4000) /* SHORT_VBAR_CACHE_HIT */
686 {
687 const UINT16 vBarIndex = (vBarHeader & 0x3FFF);
688 vBarShortEntry = &(clear->ShortVBarStorage[vBarIndex]);
689
690 if (!vBarShortEntry)
691 {
692 WLog_Print(clear->log, WLOG_ERROR, "missing vBarShortEntry %" PRIu16 "",
693 vBarIndex);
694 return FALSE;
695 }
696
697 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 1))
698 return FALSE;
699
700 Stream_Read_UINT8(s, vBarYOn);
701 suboffset += 1;
702 vBarShortPixelCount = vBarShortEntry->count;
703 vBarUpdate = TRUE;
704 }
705 else if ((vBarHeader & 0xC000) == 0x0000) /* SHORT_VBAR_CACHE_MISS */
706 {
707 vBarYOn = (vBarHeader & 0xFF);
708 vBarYOff = ((vBarHeader >> 8) & 0x3F);
709
710 if (vBarYOff < vBarYOn)
711 {
712 WLog_Print(clear->log, WLOG_ERROR, "vBarYOff %" PRIu16 " < vBarYOn %" PRIu16 "",
713 vBarYOff, vBarYOn);
714 return FALSE;
715 }
716
717 vBarShortPixelCount = (vBarYOff - vBarYOn);
718
719 if (vBarShortPixelCount > 52)
720 {
721 WLog_Print(clear->log, WLOG_ERROR, "vBarShortPixelCount %" PRIu32 " > 52",
722 vBarShortPixelCount);
723 return FALSE;
724 }
725
726 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(clear->log, s, vBarShortPixelCount,
727 3ull))
728 return FALSE;
729
730 if (clear->ShortVBarStorageCursor >= CLEARCODEC_VBAR_SHORT_SIZE)
731 {
732 WLog_Print(clear->log, WLOG_ERROR,
733 "clear->ShortVBarStorageCursor %" PRIu32
734 " >= CLEARCODEC_VBAR_SHORT_SIZE (%" PRId32 ")",
735 clear->ShortVBarStorageCursor, CLEARCODEC_VBAR_SHORT_SIZE);
736 return FALSE;
737 }
738
739 vBarShortEntry = &(clear->ShortVBarStorage[clear->ShortVBarStorageCursor]);
740 vBarShortEntry->count = vBarShortPixelCount;
741
742 if (!resize_vbar_entry(clear, vBarShortEntry))
743 return FALSE;
744
745 for (size_t y = 0; y < vBarShortPixelCount; y++)
746 {
747 BYTE r = 0;
748 BYTE g = 0;
749 BYTE b = 0;
750 BYTE* dstBuffer =
751 &vBarShortEntry->pixels[y * FreeRDPGetBytesPerPixel(clear->format)];
752 UINT32 color = 0;
753 Stream_Read_UINT8(s, b);
754 Stream_Read_UINT8(s, g);
755 Stream_Read_UINT8(s, r);
756 color = FreeRDPGetColor(clear->format, r, g, b, 0xFF);
757
758 if (!FreeRDPWriteColor(dstBuffer, clear->format, color))
759 return FALSE;
760 }
761
762 suboffset += (vBarShortPixelCount * 3);
763 clear->ShortVBarStorageCursor =
764 (clear->ShortVBarStorageCursor + 1) % CLEARCODEC_VBAR_SHORT_SIZE;
765 vBarUpdate = TRUE;
766 }
767 else if ((vBarHeader & 0x8000) == 0x8000) /* VBAR_CACHE_HIT */
768 {
769 const UINT16 vBarIndex = (vBarHeader & 0x7FFF);
770 vBarEntry = &(clear->VBarStorage[vBarIndex]);
771
772 /* If the cache was reset we need to fill in some dummy data. */
773 if (vBarEntry->size == 0)
774 {
775 WLog_Print(clear->log, WLOG_WARN,
776 "Empty cache index %" PRIu16 ", filling dummy data", vBarIndex);
777 vBarEntry->count = vBarHeight;
778
779 if (!resize_vbar_entry(clear, vBarEntry))
780 return FALSE;
781 }
782 }
783 else
784 {
785 WLog_Print(clear->log, WLOG_ERROR, "invalid vBarHeader 0x%04" PRIX16 "",
786 vBarHeader);
787 return FALSE; /* invalid vBarHeader */
788 }
789
790 if (vBarUpdate)
791 {
792 BYTE* pSrcPixel = nullptr;
793 BYTE* dstBuffer = nullptr;
794
795 if (clear->VBarStorageCursor >= CLEARCODEC_VBAR_SIZE)
796 {
797 WLog_Print(clear->log, WLOG_ERROR,
798 "clear->VBarStorageCursor %" PRIu32
799 " >= CLEARCODEC_VBAR_SIZE %" PRId32 "",
800 clear->VBarStorageCursor, CLEARCODEC_VBAR_SIZE);
801 return FALSE;
802 }
803
804 vBarEntry = &(clear->VBarStorage[clear->VBarStorageCursor]);
805 vBarPixelCount = vBarHeight;
806 vBarEntry->count = vBarPixelCount;
807
808 if (!resize_vbar_entry(clear, vBarEntry))
809 return FALSE;
810
811 dstBuffer = vBarEntry->pixels;
812 /* if (y < vBarYOn), use colorBkg */
813 UINT32 y = 0;
814 UINT32 count = vBarYOn;
815
816 if ((y + count) > vBarPixelCount)
817 count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
818
819 if (count > 0)
820 {
821 while (count--)
822 {
823 FreeRDPWriteColor(dstBuffer, clear->format, colorBkg);
824 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
825 }
826 }
827
828 /*
829 * if ((y >= vBarYOn) && (y < (vBarYOn + vBarShortPixelCount))),
830 * use vBarShortPixels at index (y - shortVBarYOn)
831 */
832 y = vBarYOn;
833 count = vBarShortPixelCount;
834
835 if ((y + count) > vBarPixelCount)
836 count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
837
838 if (count > 0)
839 {
840 const size_t offset =
841 (1ull * y - vBarYOn) * FreeRDPGetBytesPerPixel(clear->format);
842 pSrcPixel = &vBarShortEntry->pixels[offset];
843 if (offset + count > vBarShortEntry->count)
844 {
845 WLog_Print(clear->log, WLOG_ERROR,
846 "offset + count > vBarShortEntry->count");
847 return FALSE;
848 }
849 }
850 for (size_t x = 0; x < count; x++)
851 {
852 UINT32 color = 0;
853 color = FreeRDPReadColor(&pSrcPixel[x * FreeRDPGetBytesPerPixel(clear->format)],
854 clear->format);
855
856 if (!FreeRDPWriteColor(dstBuffer, clear->format, color))
857 return FALSE;
858
859 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
860 }
861
862 /* if (y >= (vBarYOn + vBarShortPixelCount)), use colorBkg */
863 y = vBarYOn + vBarShortPixelCount;
864 count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
865
866 if (count > 0)
867 {
868 while (count--)
869 {
870 if (!FreeRDPWriteColor(dstBuffer, clear->format, colorBkg))
871 return FALSE;
872
873 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
874 }
875 }
876
877 vBarEntry->count = vBarPixelCount;
878 clear->VBarStorageCursor = (clear->VBarStorageCursor + 1) % CLEARCODEC_VBAR_SIZE;
879 }
880
881 if (vBarEntry->count != vBarHeight)
882 {
883 WLog_Print(clear->log, WLOG_ERROR,
884 "vBarEntry->count %" PRIu32 " != vBarHeight %" PRIu32 "",
885 vBarEntry->count, vBarHeight);
886 vBarEntry->count = vBarHeight;
887
888 if (!resize_vbar_entry(clear, vBarEntry))
889 return FALSE;
890 }
891
892 const UINT32 nXDstRel = nXDst + xStart;
893 const UINT32 nYDstRel = nYDst + yStart;
894 cpSrcPixel = vBarEntry->pixels;
895
896 if (i < nWidth)
897 {
898 UINT32 count = vBarEntry->count;
899
900 if (count > nHeight)
901 count = nHeight;
902
903 if (nXDstRel + i >= nDstWidth)
904 return FALSE;
905
906 for (UINT32 y = 0; y < count; y++)
907 {
908 if (nYDstRel + y >= nDstHeight)
909 return FALSE;
910
911 BYTE* pDstPixel8 =
912 &pDstData[((nYDstRel + y) * nDstStep) +
913 ((nXDstRel + i) * FreeRDPGetBytesPerPixel(DstFormat))];
914 UINT32 color = FreeRDPReadColor(cpSrcPixel, clear->format);
915 color = FreeRDPConvertColor(color, clear->format, DstFormat, nullptr);
916
917 if (!FreeRDPWriteColor(pDstPixel8, DstFormat, color))
918 return FALSE;
919
920 cpSrcPixel += FreeRDPGetBytesPerPixel(clear->format);
921 }
922 }
923 }
924 }
925
926 return TRUE;
927}
928
929static BOOL clear_decompress_glyph_data(CLEAR_CONTEXT* WINPR_RESTRICT clear,
930 wStream* WINPR_RESTRICT s, UINT32 glyphFlags, UINT32 nWidth,
931 UINT32 nHeight, BYTE* WINPR_RESTRICT pDstData,
932 UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst,
933 UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight,
934 const gdiPalette* WINPR_RESTRICT palette,
935 BYTE** WINPR_RESTRICT ppGlyphData)
936{
937 UINT16 glyphIndex = 0;
938
939 if (ppGlyphData)
940 *ppGlyphData = nullptr;
941
942 if ((glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT) && !(glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX))
943 {
944 WLog_Print(clear->log, WLOG_ERROR, "Invalid glyph flags %08" PRIX32 "", glyphFlags);
945 return FALSE;
946 }
947
948 if ((glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX) == 0)
949 return TRUE;
950
951 if ((nWidth * nHeight) > (1024 * 1024))
952 {
953 WLog_Print(clear->log, WLOG_ERROR, "glyph too large: %" PRIu32 "x%" PRIu32 "", nWidth,
954 nHeight);
955 return FALSE;
956 }
957
958 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
959 return FALSE;
960
961 Stream_Read_UINT16(s, glyphIndex);
962
963 if (glyphIndex >= 4000)
964 {
965 WLog_Print(clear->log, WLOG_ERROR, "Invalid glyphIndex %" PRIu16 "", glyphIndex);
966 return FALSE;
967 }
968
969 if (glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT)
970 {
971 UINT32 nSrcStep = 0;
972 CLEAR_GLYPH_ENTRY* glyphEntry = &(clear->GlyphCache[glyphIndex]);
973 BYTE* glyphData = nullptr;
974
975 if (!glyphEntry)
976 {
977 WLog_Print(clear->log, WLOG_ERROR, "clear->GlyphCache[%" PRIu16 "]=nullptr",
978 glyphIndex);
979 return FALSE;
980 }
981
982 glyphData = (BYTE*)glyphEntry->pixels;
983
984 if (!glyphData)
985 {
986 WLog_Print(clear->log, WLOG_ERROR, "clear->GlyphCache[%" PRIu16 "]->pixels=nullptr",
987 glyphIndex);
988 return FALSE;
989 }
990
991 if ((nWidth * nHeight) > glyphEntry->count)
992 {
993 WLog_Print(clear->log, WLOG_ERROR,
994 "(nWidth %" PRIu32 " * nHeight %" PRIu32 ") > glyphEntry->count %" PRIu32 "",
995 nWidth, nHeight, glyphEntry->count);
996 return FALSE;
997 }
998
999 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(clear->format);
1000 return convert_color(pDstData, nDstStep, DstFormat, nXDst, nYDst, nWidth, nHeight,
1001 glyphData, nSrcStep, clear->format, nDstWidth, nDstHeight, palette);
1002 }
1003
1004 if (glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX)
1005 {
1006 const UINT32 bpp = FreeRDPGetBytesPerPixel(clear->format);
1007 CLEAR_GLYPH_ENTRY* glyphEntry = &(clear->GlyphCache[glyphIndex]);
1008 const size_t count = 1ull * nWidth * nHeight;
1009 const size_t hlimit = SIZE_MAX / ((nWidth > 0) ? nWidth : 1);
1010 if ((nWidth == 0) || (nHeight == 0) || (hlimit < nHeight))
1011 {
1012 const char* exceeded = (hlimit < nHeight) ? "within" : "outside";
1013 WLog_Print(clear->log, WLOG_ERROR,
1014 "CLEARCODEC_FLAG_GLYPH_INDEX: nWidth=%" PRIu32 ", nHeight=%" PRIu32
1015 ", nWidth * nHeight is %s allowed range",
1016 nWidth, nHeight, exceeded);
1017 return FALSE;
1018 }
1019
1020 if (count > glyphEntry->size)
1021 {
1022 BYTE* tmp = winpr_aligned_recalloc(glyphEntry->pixels, count, 1ull * bpp, 32);
1023
1024 if (!tmp)
1025 {
1026 WLog_Print(clear->log, WLOG_ERROR,
1027 "glyphEntry->pixels winpr_aligned_recalloc %" PRIuz " failed!",
1028 count * bpp);
1029 return FALSE;
1030 }
1031
1032 glyphEntry->count = WINPR_ASSERTING_INT_CAST(UINT32, count);
1033 glyphEntry->size = glyphEntry->count;
1034 glyphEntry->pixels = (UINT32*)tmp;
1035 }
1036
1037 if (!glyphEntry->pixels)
1038 {
1039 WLog_Print(clear->log, WLOG_ERROR, "glyphEntry->pixels=nullptr");
1040 return FALSE;
1041 }
1042
1043 if (ppGlyphData)
1044 *ppGlyphData = (BYTE*)glyphEntry->pixels;
1045
1046 return TRUE;
1047 }
1048
1049 return TRUE;
1050}
1051
1052static inline BOOL updateContextFormat(CLEAR_CONTEXT* WINPR_RESTRICT clear, UINT32 DstFormat,
1053 BOOL fromNew)
1054{
1055 if (!clear || !clear->nsc)
1056 return FALSE;
1057
1058 if (!fromNew)
1059 {
1060 if (clear->formatSet)
1061 {
1062 if (clear->format != DstFormat)
1063 {
1064 WLog_Print(
1065 clear->log, WLOG_ERROR,
1066 "Color format changed from %s to %s during decompression calls, usage error!",
1067 FreeRDPGetColorFormatName(clear->format), FreeRDPGetColorFormatName(DstFormat));
1068 return FALSE;
1069 }
1070 }
1071 else
1072 clear->formatSet = TRUE;
1073 }
1074 clear->format = DstFormat;
1075 return nsc_context_set_parameters(clear->nsc, NSC_COLOR_FORMAT, DstFormat);
1076}
1077
1078INT32 clear_decompress(CLEAR_CONTEXT* WINPR_RESTRICT clear, const BYTE* WINPR_RESTRICT pSrcData,
1079 UINT32 SrcSize, UINT32 nWidth, UINT32 nHeight, BYTE* WINPR_RESTRICT pDstData,
1080 UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
1081 UINT32 nDstWidth, UINT32 nDstHeight,
1082 const gdiPalette* WINPR_RESTRICT palette)
1083{
1084 INT32 rc = -1;
1085 BYTE seqNumber = 0;
1086 BYTE glyphFlags = 0;
1087 UINT32 residualByteCount = 0;
1088 UINT32 bandsByteCount = 0;
1089 UINT32 subcodecByteCount = 0;
1090 wStream sbuffer = WINPR_C_ARRAY_INIT;
1091 BYTE* glyphData = nullptr;
1092
1093 if (!pDstData)
1094 return -1002;
1095
1096 if ((nDstWidth == 0) || (nDstHeight == 0))
1097 return -1022;
1098
1099 if ((nWidth > 0xFFFF) || (nHeight > 0xFFFF))
1100 return -1004;
1101
1102 if (nXDst > nDstWidth)
1103 {
1104 WLog_Print(clear->log, WLOG_WARN, "nXDst %" PRIu32 " > nDstWidth %" PRIu32, nXDst,
1105 nDstWidth);
1106 return -1005;
1107 }
1108
1109 if (nYDst > nDstHeight)
1110 {
1111 WLog_Print(clear->log, WLOG_WARN, "nYDst %" PRIu32 " > nDstHeight %" PRIu32, nYDst,
1112 nDstHeight);
1113 return -1006;
1114 }
1115
1116 wStream* s = Stream_StaticConstInit(&sbuffer, pSrcData, SrcSize);
1117
1118 if (!s)
1119 return -2005;
1120
1121 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
1122 goto fail;
1123
1124 if (!updateContextFormat(clear, DstFormat, FALSE))
1125 goto fail;
1126
1127 Stream_Read_UINT8(s, glyphFlags);
1128 Stream_Read_UINT8(s, seqNumber);
1129
1130 if (!clear->seqNumber && seqNumber)
1131 clear->seqNumber = seqNumber;
1132
1133 if (seqNumber != clear->seqNumber)
1134 {
1135 WLog_Print(clear->log, WLOG_ERROR, "Sequence number unexpected %" PRIu8 " - %" PRIu32 "",
1136 seqNumber, clear->seqNumber);
1137 WLog_Print(clear->log, WLOG_ERROR, "seqNumber %" PRIu8 " != clear->seqNumber %" PRIu32 "",
1138 seqNumber, clear->seqNumber);
1139 goto fail;
1140 }
1141
1142 clear->seqNumber = (seqNumber + 1) % 256;
1143
1144 if (glyphFlags & CLEARCODEC_FLAG_CACHE_RESET)
1145 {
1146 clear_reset_vbar_storage(clear, FALSE);
1147 }
1148
1149 if (!clear_decompress_glyph_data(clear, s, glyphFlags, nWidth, nHeight, pDstData, DstFormat,
1150 nDstStep, nXDst, nYDst, nDstWidth, nDstHeight, palette,
1151 &glyphData))
1152 {
1153 WLog_Print(clear->log, WLOG_ERROR, "clear_decompress_glyph_data failed!");
1154 goto fail;
1155 }
1156
1157 /* Read composition payload header parameters */
1158 if (Stream_GetRemainingLength(s) < 12)
1159 {
1160 const UINT32 mask = (CLEARCODEC_FLAG_GLYPH_HIT | CLEARCODEC_FLAG_GLYPH_INDEX);
1161
1162 if ((glyphFlags & mask) == mask)
1163 goto finish;
1164
1165 WLog_Print(clear->log, WLOG_ERROR,
1166 "invalid glyphFlags, missing flags: 0x%02" PRIx8 " & 0x%02" PRIx32
1167 " == 0x%02" PRIx32,
1168 glyphFlags, mask, glyphFlags & mask);
1169 goto fail;
1170 }
1171
1172 Stream_Read_UINT32(s, residualByteCount);
1173 Stream_Read_UINT32(s, bandsByteCount);
1174 Stream_Read_UINT32(s, subcodecByteCount);
1175
1176 if (residualByteCount > 0)
1177 {
1178 if (!clear_decompress_residual_data(clear, s, residualByteCount, nWidth, nHeight, pDstData,
1179 DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
1180 nDstHeight, palette))
1181 {
1182 WLog_Print(clear->log, WLOG_ERROR, "clear_decompress_residual_data failed!");
1183 goto fail;
1184 }
1185 }
1186
1187 if (bandsByteCount > 0)
1188 {
1189 if (!clear_decompress_bands_data(clear, s, bandsByteCount, nWidth, nHeight, pDstData,
1190 DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight))
1191 {
1192 WLog_Print(clear->log, WLOG_ERROR, "clear_decompress_bands_data failed!");
1193 goto fail;
1194 }
1195 }
1196
1197 if (subcodecByteCount > 0)
1198 {
1199 if (!clear_decompress_subcodecs_data(clear, s, subcodecByteCount, nWidth, nHeight, pDstData,
1200 DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
1201 nDstHeight, palette))
1202 {
1203 WLog_Print(clear->log, WLOG_ERROR, "clear_decompress_subcodecs_data failed!");
1204 goto fail;
1205 }
1206 }
1207
1208 if (glyphData)
1209 {
1210 uint32_t w = MIN(nWidth, nDstWidth);
1211 if (nXDst > nDstWidth)
1212 {
1213 WLog_Print(clear->log, WLOG_WARN,
1214 "glyphData copy area x exceeds destination: x=%" PRIu32 " > %" PRIu32, nXDst,
1215 nDstWidth);
1216 w = 0;
1217 }
1218 else if (nXDst + w > nDstWidth)
1219 {
1220 WLog_Print(clear->log, WLOG_WARN,
1221 "glyphData copy area x + width exceeds destination: x=%" PRIu32 " + %" PRIu32
1222 " > %" PRIu32,
1223 nXDst, w, nDstWidth);
1224 w = nDstWidth - nXDst;
1225 }
1226
1227 if (w != nWidth)
1228 {
1229 WLog_Print(clear->log, WLOG_WARN,
1230 "glyphData copy area width truncated: requested=%" PRIu32
1231 ", truncated to %" PRIu32,
1232 nWidth, w);
1233 }
1234
1235 uint32_t h = MIN(nHeight, nDstHeight);
1236 if (nYDst > nDstHeight)
1237 {
1238 WLog_Print(clear->log, WLOG_WARN,
1239 "glyphData copy area y exceeds destination: y=%" PRIu32 " > %" PRIu32, nYDst,
1240 nDstHeight);
1241 h = 0;
1242 }
1243 else if (nYDst + h > nDstHeight)
1244 {
1245 WLog_Print(clear->log, WLOG_WARN,
1246 "glyphData copy area y + height exceeds destination: x=%" PRIu32
1247 " + %" PRIu32 " > %" PRIu32,
1248 nYDst, h, nDstHeight);
1249 h = nDstHeight - nYDst;
1250 }
1251
1252 if (h != nHeight)
1253 {
1254 WLog_Print(clear->log, WLOG_WARN,
1255 "glyphData copy area height truncated: requested=%" PRIu32
1256 ", truncated to %" PRIu32,
1257 nHeight, h);
1258 }
1259
1260 if (!freerdp_image_copy_no_overlap(glyphData, clear->format, 0, 0, 0, w, h, pDstData,
1261 DstFormat, nDstStep, nXDst, nYDst, palette,
1262 FREERDP_KEEP_DST_ALPHA))
1263 goto fail;
1264 }
1265
1266finish:
1267 rc = 0;
1268fail:
1269 return rc;
1270}
1271
1272#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
1273int clear_compress(WINPR_ATTR_UNUSED CLEAR_CONTEXT* WINPR_RESTRICT clear,
1274 WINPR_ATTR_UNUSED const BYTE* WINPR_RESTRICT pSrcData,
1275 WINPR_ATTR_UNUSED UINT32 SrcSize,
1276 WINPR_ATTR_UNUSED BYTE** WINPR_RESTRICT ppDstData,
1277 WINPR_ATTR_UNUSED UINT32* WINPR_RESTRICT pDstSize)
1278{
1279 WLog_Print(clear->log, WLOG_ERROR, "TODO: not implemented!");
1280 return 1;
1281}
1282#endif
1283
1284BOOL clear_context_reset(CLEAR_CONTEXT* WINPR_RESTRICT clear)
1285{
1286 if (!clear)
1287 return FALSE;
1288
1293 clear->seqNumber = 0;
1294 return TRUE;
1295}
1296
1297CLEAR_CONTEXT* clear_context_new(BOOL Compressor)
1298{
1299 CLEAR_CONTEXT* clear = (CLEAR_CONTEXT*)winpr_aligned_calloc(1, sizeof(CLEAR_CONTEXT), 32);
1300
1301 if (!clear)
1302 return nullptr;
1303 clear->log = WLog_Get(TAG);
1304 clear->Compressor = Compressor;
1305 clear->nsc = nsc_context_new();
1306
1307 if (!clear->nsc)
1308 goto error_nsc;
1309
1310 if (!updateContextFormat(clear, PIXEL_FORMAT_BGRX32, TRUE))
1311 goto error_nsc;
1312
1313 if (!clear_resize_buffer(clear, 512, 512))
1314 goto error_nsc;
1315
1316 if (!clear->TempBuffer)
1317 goto error_nsc;
1318
1319 if (!clear_context_reset(clear))
1320 goto error_nsc;
1321
1322 return clear;
1323error_nsc:
1324 WINPR_PRAGMA_DIAG_PUSH
1325 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1326 clear_context_free(clear);
1327 WINPR_PRAGMA_DIAG_POP
1328 return nullptr;
1329}
1330
1331void clear_context_free(CLEAR_CONTEXT* WINPR_RESTRICT clear)
1332{
1333 if (!clear)
1334 return;
1335
1336 nsc_context_free(clear->nsc);
1337 winpr_aligned_free(clear->TempBuffer);
1338
1339 clear_reset_vbar_storage(clear, TRUE);
1340 clear_reset_glyph_cache(clear);
1341
1342 winpr_aligned_free(clear);
1343}