22#include <freerdp/config.h>
25#include <winpr/print.h>
26#include <winpr/bitstream.h>
28#include <freerdp/codec/color.h>
29#include <freerdp/codec/clear.h>
30#include <freerdp/log.h>
32#define TAG FREERDP_TAG("codec.clear")
34#define CLEARCODEC_FLAG_GLYPH_INDEX 0x01
35#define CLEARCODEC_FLAG_GLYPH_HIT 0x02
36#define CLEARCODEC_FLAG_CACHE_RESET 0x04
38#define CLEARCODEC_VBAR_SIZE 32768
39#define CLEARCODEC_VBAR_SHORT_SIZE 16384
65 CLEAR_GLYPH_ENTRY GlyphCache[4000];
66 UINT32 VBarStorageCursor;
67 CLEAR_VBAR_ENTRY VBarStorage[CLEARCODEC_VBAR_SIZE];
68 UINT32 ShortVBarStorageCursor;
69 CLEAR_VBAR_ENTRY ShortVBarStorage[CLEARCODEC_VBAR_SHORT_SIZE];
73static const UINT32 CLEAR_LOG2_FLOOR[256] = {
74 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,
75 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,
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 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,
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 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
84static const BYTE CLEAR_8BIT_MASKS[9] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
86static void clear_reset_vbar_storage(CLEAR_CONTEXT* WINPR_RESTRICT clear, BOOL zero)
90 for (
size_t i = 0; i < ARRAYSIZE(clear->VBarStorage); i++)
91 winpr_aligned_free(clear->VBarStorage[i].pixels);
93 ZeroMemory(clear->VBarStorage,
sizeof(clear->VBarStorage));
96 clear->VBarStorageCursor = 0;
100 for (
size_t i = 0; i < ARRAYSIZE(clear->ShortVBarStorage); i++)
101 winpr_aligned_free(clear->ShortVBarStorage[i].pixels);
103 ZeroMemory(clear->ShortVBarStorage,
sizeof(clear->ShortVBarStorage));
106 clear->ShortVBarStorageCursor = 0;
109static void clear_reset_glyph_cache(CLEAR_CONTEXT* WINPR_RESTRICT clear)
111 for (
size_t i = 0; i < ARRAYSIZE(clear->GlyphCache); i++)
112 winpr_aligned_free(clear->GlyphCache[i].pixels);
114 ZeroMemory(clear->GlyphCache,
sizeof(clear->GlyphCache));
117static BOOL convert_color(BYTE* WINPR_RESTRICT dst, UINT32 nDstStep, UINT32 DstFormat, UINT32 nXDst,
118 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
119 const BYTE* WINPR_RESTRICT src, UINT32 nSrcStep, UINT32 SrcFormat,
120 UINT32 nDstWidth, UINT32 nDstHeight,
121 const gdiPalette* WINPR_RESTRICT palette)
123 if (nWidth + nXDst > nDstWidth)
124 nWidth = nDstWidth - nXDst;
126 if (nHeight + nYDst > nDstHeight)
127 nHeight = nDstHeight - nYDst;
129 return freerdp_image_copy_no_overlap(dst, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
130 src, SrcFormat, nSrcStep, 0, 0, palette,
131 FREERDP_KEEP_DST_ALPHA);
134static BOOL clear_decompress_nscodec(wLog* log, NSC_CONTEXT* WINPR_RESTRICT nsc, UINT32 width,
135 UINT32 height,
wStream* WINPR_RESTRICT s,
136 UINT32 bitmapDataByteCount, BYTE* WINPR_RESTRICT pDstData,
137 UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDstRel,
138 UINT32 nYDstRel, UINT32 nDstWidth, UINT32 nDstHeight)
142 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, bitmapDataByteCount))
145 rc = nsc_process_message(nsc, 32, width, height, Stream_Pointer(s), bitmapDataByteCount,
146 pDstData, DstFormat, nDstStep, nXDstRel, nYDstRel, nDstWidth,
147 nDstHeight, FREERDP_FLIP_NONE);
148 Stream_Seek(s, bitmapDataByteCount);
152static BOOL clear_decompress_subcode_rlex(wLog* log,
wStream* WINPR_RESTRICT s,
153 UINT32 bitmapDataByteCount, UINT32 width, UINT32 height,
154 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
155 UINT32 nDstStep, UINT32 nXDstRel, UINT32 nYDstRel,
156 UINT32 nDstWidth, UINT32 nDstHeight)
160 UINT32 pixelCount = 0;
161 UINT32 bitmapDataOffset = 0;
162 size_t pixelIndex = 0;
168 BYTE paletteCount = 0;
169 UINT32 palette[128] = WINPR_C_ARRAY_INIT;
171 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, bitmapDataByteCount))
174 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
176 Stream_Read_UINT8(s, paletteCount);
177 bitmapDataOffset = 1 + (paletteCount * 3);
179 if ((paletteCount > 127) || (paletteCount < 1))
181 WLog_Print(log, WLOG_ERROR,
"paletteCount %" PRIu8
"", paletteCount);
185 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, paletteCount, 3ull))
188 for (UINT32 i = 0; i < paletteCount; i++)
193 Stream_Read_UINT8(s, b);
194 Stream_Read_UINT8(s, g);
195 Stream_Read_UINT8(s, r);
196 palette[i] = FreeRDPGetColor(DstFormat, r, g, b, 0xFF);
200 pixelCount = width * height;
201 numBits = CLEAR_LOG2_FLOOR[paletteCount - 1] + 1;
203 while (bitmapDataOffset < bitmapDataByteCount)
207 UINT32 runLengthFactor = 0;
209 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
212 Stream_Read_UINT8(s, tmp);
213 Stream_Read_UINT8(s, runLengthFactor);
214 bitmapDataOffset += 2;
215 suiteDepth = (tmp >> numBits) & CLEAR_8BIT_MASKS[(8 - numBits)];
216 stopIndex = tmp & CLEAR_8BIT_MASKS[numBits];
217 startIndex = stopIndex - suiteDepth;
219 if (runLengthFactor >= 0xFF)
221 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
224 Stream_Read_UINT16(s, runLengthFactor);
225 bitmapDataOffset += 2;
227 if (runLengthFactor >= 0xFFFF)
229 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
232 Stream_Read_UINT32(s, runLengthFactor);
233 bitmapDataOffset += 4;
237 if (startIndex >= paletteCount)
239 WLog_Print(log, WLOG_ERROR,
"startIndex %" PRIu8
" > paletteCount %" PRIu8
"]",
240 startIndex, paletteCount);
244 if (stopIndex >= paletteCount)
246 WLog_Print(log, WLOG_ERROR,
"stopIndex %" PRIu8
" > paletteCount %" PRIu8
"]",
247 stopIndex, paletteCount);
251 suiteIndex = startIndex;
253 if (suiteIndex > 127)
255 WLog_Print(log, WLOG_ERROR,
"suiteIndex %" PRIu8
" > 127]", suiteIndex);
259 color = palette[suiteIndex];
261 if ((pixelIndex + runLengthFactor) > pixelCount)
263 WLog_Print(log, WLOG_ERROR,
264 "pixelIndex %" PRIuz
" + runLengthFactor %" PRIu32
" > pixelCount %" PRIu32
266 pixelIndex, runLengthFactor, pixelCount);
270 for (UINT32 i = 0; i < runLengthFactor; i++)
272 BYTE* pTmpData = &pDstData[(nXDstRel + x) * FreeRDPGetBytesPerPixel(DstFormat) +
273 (nYDstRel + y) * nDstStep];
275 if ((nXDstRel + x < nDstWidth) && (nYDstRel + y < nDstHeight))
276 FreeRDPWriteColor(pTmpData, DstFormat, color);
285 pixelIndex += runLengthFactor;
287 if ((pixelIndex + (suiteDepth + 1)) > pixelCount)
289 WLog_Print(log, WLOG_ERROR,
290 "pixelIndex %" PRIuz
" + suiteDepth %" PRIu8
" + 1 > pixelCount %" PRIu32
"",
291 pixelIndex, suiteDepth, pixelCount);
295 for (UINT32 i = 0; i <= suiteDepth; i++)
297 BYTE* pTmpData = &pDstData[(nXDstRel + x) * FreeRDPGetBytesPerPixel(DstFormat) +
298 (nYDstRel + y) * nDstStep];
299 UINT32 ccolor = palette[suiteIndex];
301 if (suiteIndex > 127)
303 WLog_Print(log, WLOG_ERROR,
"suiteIndex %" PRIu8
" > 127", suiteIndex);
309 if ((nXDstRel + x < nDstWidth) && (nYDstRel + y < nDstHeight))
310 FreeRDPWriteColor(pTmpData, DstFormat, ccolor);
319 pixelIndex += (suiteDepth + 1);
322 if (pixelIndex != pixelCount)
324 WLog_Print(log, WLOG_ERROR,
"pixelIndex %" PRIuz
" != pixelCount %" PRIu32
"", pixelIndex,
332static BOOL clear_resize_buffer(CLEAR_CONTEXT* WINPR_RESTRICT clear, UINT32 width, UINT32 height)
337 const UINT64 size = 1ull * (width + 16ull) * (height + 16ull);
338 const size_t bpp = FreeRDPGetBytesPerPixel(clear->format);
339 if (size > UINT32_MAX / bpp)
342 if (size > clear->TempSize / bpp)
344 BYTE* tmp = (BYTE*)winpr_aligned_recalloc(clear->TempBuffer,
345 WINPR_ASSERTING_INT_CAST(
size_t, size), bpp, 32);
349 WLog_Print(clear->log, WLOG_ERROR,
350 "clear->TempBuffer winpr_aligned_recalloc failed for %" PRIu64
" bytes",
355 clear->TempSize = WINPR_ASSERTING_INT_CAST(
size_t, size* bpp);
356 clear->TempBuffer = tmp;
362static BOOL clear_decompress_residual_data(CLEAR_CONTEXT* WINPR_RESTRICT clear,
363 wStream* WINPR_RESTRICT s, UINT32 residualByteCount,
364 UINT32 nWidth, UINT32 nHeight,
365 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
366 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
367 UINT32 nDstWidth, UINT32 nDstHeight,
368 const gdiPalette* WINPR_RESTRICT palette)
371 UINT32 suboffset = 0;
372 BYTE* dstBuffer =
nullptr;
373 UINT32 pixelIndex = 0;
374 UINT32 pixelCount = 0;
376 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, residualByteCount))
381 pixelCount = nWidth * nHeight;
383 if (!clear_resize_buffer(clear, nWidth, nHeight))
386 dstBuffer = clear->TempBuffer;
388 while (suboffset < residualByteCount)
393 UINT32 runLengthFactor = 0;
396 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 4))
399 Stream_Read_UINT8(s, b);
400 Stream_Read_UINT8(s, g);
401 Stream_Read_UINT8(s, r);
402 Stream_Read_UINT8(s, runLengthFactor);
404 color = FreeRDPGetColor(clear->format, r, g, b, 0xFF);
406 if (runLengthFactor >= 0xFF)
408 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
411 Stream_Read_UINT16(s, runLengthFactor);
414 if (runLengthFactor >= 0xFFFF)
416 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 4))
419 Stream_Read_UINT32(s, runLengthFactor);
424 if ((pixelIndex >= pixelCount) || (runLengthFactor > (pixelCount - pixelIndex)))
426 WLog_Print(clear->log, WLOG_ERROR,
427 "pixelIndex %" PRIu32
" + runLengthFactor %" PRIu32
" > pixelCount %" PRIu32
429 pixelIndex, runLengthFactor, pixelCount);
433 for (UINT32 i = 0; i < runLengthFactor; i++)
435 FreeRDPWriteColor(dstBuffer, clear->format, color);
436 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
439 pixelIndex += runLengthFactor;
442 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(clear->format);
444 if (pixelIndex != pixelCount)
446 WLog_Print(clear->log, WLOG_ERROR,
"pixelIndex %" PRIu32
" != pixelCount %" PRIu32
"",
447 pixelIndex, pixelCount);
451 return convert_color(pDstData, nDstStep, DstFormat, nXDst, nYDst, nWidth, nHeight,
452 clear->TempBuffer, nSrcStep, clear->format, nDstWidth, nDstHeight,
456static BOOL clear_decompress_subcodecs_data(CLEAR_CONTEXT* WINPR_RESTRICT clear,
457 wStream* WINPR_RESTRICT s, UINT32 subcodecByteCount,
458 UINT32 nWidth, UINT32 nHeight,
459 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
460 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
461 UINT32 nDstWidth, UINT32 nDstHeight,
462 const gdiPalette* WINPR_RESTRICT palette)
464 UINT32 suboffset = 0;
466 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, subcodecByteCount))
469 while (suboffset < subcodecByteCount)
471 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 13))
474 const UINT16 xStart = Stream_Get_UINT16(s);
475 const UINT16 yStart = Stream_Get_UINT16(s);
476 const UINT16 width = Stream_Get_UINT16(s);
477 const UINT16 height = Stream_Get_UINT16(s);
478 const UINT32 bitmapDataByteCount = Stream_Get_UINT32(s);
479 const UINT8 subcodecId = Stream_Get_UINT8(s);
482 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, bitmapDataByteCount))
485 const UINT32 nXDstRel = nXDst + xStart;
486 const UINT32 nYDstRel = nYDst + yStart;
487 if (1ull * nXDstRel + width > nDstWidth)
489 WLog_Print(clear->log, WLOG_ERROR,
490 "nXDstRel %" PRIu32
" + width %" PRIu16
" > nDstWidth %" PRIu32
"", nXDstRel,
494 if (1ull * nYDstRel + height > nDstHeight)
496 WLog_Print(clear->log, WLOG_ERROR,
497 "nYDstRel %" PRIu32
" + height %" PRIu16
" > nDstHeight %" PRIu32
"",
498 nYDstRel, height, nDstHeight);
502 if (1ull * xStart + width > nWidth)
504 WLog_Print(clear->log, WLOG_ERROR,
505 "xStart %" PRIu16
" + width %" PRIu16
" > nWidth %" PRIu32
"", xStart, width,
509 if (1ull * yStart + height > nHeight)
511 WLog_Print(clear->log, WLOG_ERROR,
512 "yStart %" PRIu16
" + height %" PRIu16
" > nHeight %" PRIu32
"", yStart,
517 if (!clear_resize_buffer(clear, width, height))
524 const UINT32 nSrcStep = width * FreeRDPGetBytesPerPixel(PIXEL_FORMAT_BGR24);
525 const size_t nSrcSize = 1ull * nSrcStep * height;
527 if (bitmapDataByteCount != nSrcSize)
529 WLog_Print(clear->log, WLOG_ERROR,
530 "bitmapDataByteCount %" PRIu32
" != nSrcSize %" PRIuz
"",
531 bitmapDataByteCount, nSrcSize);
535 if (!convert_color(pDstData, nDstStep, DstFormat, nXDstRel, nYDstRel, width, height,
536 Stream_Pointer(s), nSrcStep, PIXEL_FORMAT_BGR24, nDstWidth,
537 nDstHeight, palette))
540 Stream_Seek(s, bitmapDataByteCount);
545 if (!clear_decompress_nscodec(clear->log, clear->nsc, width, height, s,
546 bitmapDataByteCount, pDstData, DstFormat, nDstStep,
547 nXDstRel, nYDstRel, nDstWidth, nDstHeight))
553 if (!clear_decompress_subcode_rlex(clear->log, s, bitmapDataByteCount, width,
554 height, pDstData, DstFormat, nDstStep, nXDstRel,
555 nYDstRel, nDstWidth, nDstHeight))
561 WLog_Print(clear->log, WLOG_ERROR,
"Unknown subcodec ID %" PRIu8
"", subcodecId);
565 suboffset += bitmapDataByteCount;
571static BOOL resize_vbar_entry(CLEAR_CONTEXT* WINPR_RESTRICT clear,
572 CLEAR_VBAR_ENTRY* WINPR_RESTRICT vBarEntry)
574 if (vBarEntry->count > vBarEntry->size)
576 const UINT32 bpp = FreeRDPGetBytesPerPixel(clear->format);
577 const UINT32 oldPos = vBarEntry->size * bpp;
578 const UINT32 diffSize = (vBarEntry->count - vBarEntry->size) * bpp;
581 (BYTE*)winpr_aligned_recalloc(vBarEntry->pixels, vBarEntry->count, 1ull * bpp, 32);
585 WLog_Print(clear->log, WLOG_ERROR,
586 "vBarEntry->pixels winpr_aligned_recalloc %" PRIu32
" failed",
587 vBarEntry->count * bpp);
591 memset(&tmp[oldPos], 0, diffSize);
592 vBarEntry->pixels = tmp;
593 vBarEntry->size = vBarEntry->count;
596 if (!vBarEntry->pixels && vBarEntry->size)
598 WLog_Print(clear->log, WLOG_ERROR,
599 "vBarEntry->pixels is nullptr but vBarEntry->size is %" PRIu32
"",
607static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* WINPR_RESTRICT clear,
608 wStream* WINPR_RESTRICT s, UINT32 bandsByteCount,
609 UINT32 nWidth, UINT32 nHeight,
610 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
611 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
612 UINT32 nDstWidth, UINT32 nDstHeight)
614 UINT32 suboffset = 0;
616 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, bandsByteCount))
619 while (suboffset < bandsByteCount)
629 UINT16 vBarHeader = 0;
632 UINT32 vBarCount = 0;
633 UINT32 vBarPixelCount = 0;
634 UINT32 vBarShortPixelCount = 0;
636 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 11))
639 Stream_Read_UINT16(s, xStart);
640 Stream_Read_UINT16(s, xEnd);
641 Stream_Read_UINT16(s, yStart);
642 Stream_Read_UINT16(s, yEnd);
643 Stream_Read_UINT8(s, cb);
644 Stream_Read_UINT8(s, cg);
645 Stream_Read_UINT8(s, cr);
647 colorBkg = FreeRDPGetColor(clear->format, cr, cg, cb, 0xFF);
651 WLog_Print(clear->log, WLOG_ERROR,
"xEnd %" PRIu16
" < xStart %" PRIu16
"", xEnd,
658 WLog_Print(clear->log, WLOG_ERROR,
"yEnd %" PRIu16
" < yStart %" PRIu16
"", yEnd,
663 vBarCount = (xEnd - xStart) + 1;
665 for (UINT32 i = 0; i < vBarCount; i++)
667 UINT32 vBarHeight = 0;
668 CLEAR_VBAR_ENTRY* vBarEntry =
nullptr;
669 CLEAR_VBAR_ENTRY* vBarShortEntry =
nullptr;
670 BOOL vBarUpdate = FALSE;
671 const BYTE* cpSrcPixel =
nullptr;
673 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
676 Stream_Read_UINT16(s, vBarHeader);
678 vBarHeight = (yEnd - yStart + 1);
682 WLog_Print(clear->log, WLOG_ERROR,
"vBarHeight (%" PRIu32
") > 52", vBarHeight);
686 if ((vBarHeader & 0xC000) == 0x4000)
688 const UINT16 vBarIndex = (vBarHeader & 0x3FFF);
689 vBarShortEntry = &(clear->ShortVBarStorage[vBarIndex]);
693 WLog_Print(clear->log, WLOG_ERROR,
"missing vBarShortEntry %" PRIu16
"",
698 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 1))
701 Stream_Read_UINT8(s, vBarYOn);
703 vBarShortPixelCount = vBarShortEntry->count;
706 else if ((vBarHeader & 0xC000) == 0x0000)
708 vBarYOn = (vBarHeader & 0xFF);
709 vBarYOff = ((vBarHeader >> 8) & 0x3F);
711 if (vBarYOff < vBarYOn)
713 WLog_Print(clear->log, WLOG_ERROR,
"vBarYOff %" PRIu16
" < vBarYOn %" PRIu16
"",
718 vBarShortPixelCount = (vBarYOff - vBarYOn);
720 if (vBarShortPixelCount > 52)
722 WLog_Print(clear->log, WLOG_ERROR,
"vBarShortPixelCount %" PRIu32
" > 52",
723 vBarShortPixelCount);
727 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(clear->log, s, vBarShortPixelCount,
731 if (clear->ShortVBarStorageCursor >= CLEARCODEC_VBAR_SHORT_SIZE)
733 WLog_Print(clear->log, WLOG_ERROR,
734 "clear->ShortVBarStorageCursor %" PRIu32
735 " >= CLEARCODEC_VBAR_SHORT_SIZE (%" PRId32
")",
736 clear->ShortVBarStorageCursor, CLEARCODEC_VBAR_SHORT_SIZE);
740 vBarShortEntry = &(clear->ShortVBarStorage[clear->ShortVBarStorageCursor]);
741 vBarShortEntry->count = vBarShortPixelCount;
743 if (!resize_vbar_entry(clear, vBarShortEntry))
746 for (
size_t y = 0; y < vBarShortPixelCount; y++)
752 &vBarShortEntry->pixels[y * FreeRDPGetBytesPerPixel(clear->format)];
754 Stream_Read_UINT8(s, b);
755 Stream_Read_UINT8(s, g);
756 Stream_Read_UINT8(s, r);
757 color = FreeRDPGetColor(clear->format, r, g, b, 0xFF);
759 if (!FreeRDPWriteColor(dstBuffer, clear->format, color))
763 suboffset += (vBarShortPixelCount * 3);
764 clear->ShortVBarStorageCursor =
765 (clear->ShortVBarStorageCursor + 1) % CLEARCODEC_VBAR_SHORT_SIZE;
768 else if ((vBarHeader & 0x8000) == 0x8000)
770 const UINT16 vBarIndex = (vBarHeader & 0x7FFF);
771 vBarEntry = &(clear->VBarStorage[vBarIndex]);
774 if (vBarEntry->size == 0)
776 WLog_Print(clear->log, WLOG_WARN,
777 "Empty cache index %" PRIu16
", filling dummy data", vBarIndex);
778 vBarEntry->count = vBarHeight;
780 if (!resize_vbar_entry(clear, vBarEntry))
786 WLog_Print(clear->log, WLOG_ERROR,
"invalid vBarHeader 0x%04" PRIX16
"",
793 BYTE* pSrcPixel =
nullptr;
794 BYTE* dstBuffer =
nullptr;
796 if (clear->VBarStorageCursor >= CLEARCODEC_VBAR_SIZE)
798 WLog_Print(clear->log, WLOG_ERROR,
799 "clear->VBarStorageCursor %" PRIu32
800 " >= CLEARCODEC_VBAR_SIZE %" PRId32
"",
801 clear->VBarStorageCursor, CLEARCODEC_VBAR_SIZE);
805 vBarEntry = &(clear->VBarStorage[clear->VBarStorageCursor]);
806 vBarPixelCount = vBarHeight;
807 vBarEntry->count = vBarPixelCount;
809 if (!resize_vbar_entry(clear, vBarEntry))
812 dstBuffer = vBarEntry->pixels;
815 UINT32 count = vBarYOn;
817 if ((y + count) > vBarPixelCount)
818 count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
824 FreeRDPWriteColor(dstBuffer, clear->format, colorBkg);
825 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
834 count = vBarShortPixelCount;
836 if ((y + count) > vBarPixelCount)
837 count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
841 const size_t offset =
842 (1ull * y - vBarYOn) * FreeRDPGetBytesPerPixel(clear->format);
843 pSrcPixel = &vBarShortEntry->pixels[offset];
844 if (offset + count > vBarShortEntry->count)
846 WLog_Print(clear->log, WLOG_ERROR,
847 "offset + count > vBarShortEntry->count");
851 for (
size_t x = 0; x < count; x++)
854 color = FreeRDPReadColor(&pSrcPixel[x * FreeRDPGetBytesPerPixel(clear->format)],
857 if (!FreeRDPWriteColor(dstBuffer, clear->format, color))
860 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
864 y = vBarYOn + vBarShortPixelCount;
865 count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
871 if (!FreeRDPWriteColor(dstBuffer, clear->format, colorBkg))
874 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
878 vBarEntry->count = vBarPixelCount;
879 clear->VBarStorageCursor = (clear->VBarStorageCursor + 1) % CLEARCODEC_VBAR_SIZE;
882 if (vBarEntry->count != vBarHeight)
884 WLog_Print(clear->log, WLOG_ERROR,
885 "vBarEntry->count %" PRIu32
" != vBarHeight %" PRIu32
"",
886 vBarEntry->count, vBarHeight);
887 vBarEntry->count = vBarHeight;
889 if (!resize_vbar_entry(clear, vBarEntry))
893 const UINT32 nXDstRel = nXDst + xStart;
894 const UINT32 nYDstRel = nYDst + yStart;
895 cpSrcPixel = vBarEntry->pixels;
899 UINT32 count = vBarEntry->count;
904 if (nXDstRel + i >= nDstWidth)
907 for (UINT32 y = 0; y < count; y++)
909 if (nYDstRel + y >= nDstHeight)
913 &pDstData[((nYDstRel + y) * nDstStep) +
914 ((nXDstRel + i) * FreeRDPGetBytesPerPixel(DstFormat))];
915 UINT32 color = FreeRDPReadColor(cpSrcPixel, clear->format);
916 color = FreeRDPConvertColor(color, clear->format, DstFormat,
nullptr);
918 if (!FreeRDPWriteColor(pDstPixel8, DstFormat, color))
921 cpSrcPixel += FreeRDPGetBytesPerPixel(clear->format);
930static BOOL clear_decompress_glyph_data(CLEAR_CONTEXT* WINPR_RESTRICT clear,
931 wStream* WINPR_RESTRICT s, UINT32 glyphFlags, UINT32 nWidth,
932 UINT32 nHeight, BYTE* WINPR_RESTRICT pDstData,
933 UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst,
934 UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight,
935 const gdiPalette* WINPR_RESTRICT palette,
936 BYTE** WINPR_RESTRICT ppGlyphData)
938 UINT16 glyphIndex = 0;
941 *ppGlyphData =
nullptr;
943 if ((glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT) && !(glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX))
945 WLog_Print(clear->log, WLOG_ERROR,
"Invalid glyph flags %08" PRIX32
"", glyphFlags);
949 if ((glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX) == 0)
952 if ((nWidth * nHeight) > (1024 * 1024))
954 WLog_Print(clear->log, WLOG_ERROR,
"glyph too large: %" PRIu32
"x%" PRIu32
"", nWidth,
959 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
962 Stream_Read_UINT16(s, glyphIndex);
964 if (glyphIndex >= 4000)
966 WLog_Print(clear->log, WLOG_ERROR,
"Invalid glyphIndex %" PRIu16
"", glyphIndex);
970 if (glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT)
973 CLEAR_GLYPH_ENTRY* glyphEntry = &(clear->GlyphCache[glyphIndex]);
974 BYTE* glyphData =
nullptr;
978 WLog_Print(clear->log, WLOG_ERROR,
"clear->GlyphCache[%" PRIu16
"]=nullptr",
983 glyphData = (BYTE*)glyphEntry->pixels;
987 WLog_Print(clear->log, WLOG_ERROR,
"clear->GlyphCache[%" PRIu16
"]->pixels=nullptr",
992 if ((nWidth * nHeight) > glyphEntry->count)
994 WLog_Print(clear->log, WLOG_ERROR,
995 "(nWidth %" PRIu32
" * nHeight %" PRIu32
") > glyphEntry->count %" PRIu32
"",
996 nWidth, nHeight, glyphEntry->count);
1000 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(clear->format);
1001 return convert_color(pDstData, nDstStep, DstFormat, nXDst, nYDst, nWidth, nHeight,
1002 glyphData, nSrcStep, clear->format, nDstWidth, nDstHeight, palette);
1005 if (glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX)
1007 const UINT32 bpp = FreeRDPGetBytesPerPixel(clear->format);
1008 CLEAR_GLYPH_ENTRY* glyphEntry = &(clear->GlyphCache[glyphIndex]);
1009 const size_t count = 1ull * nWidth * nHeight;
1010 const size_t hlimit = SIZE_MAX / ((nWidth > 0) ? nWidth : 1);
1011 if ((nWidth == 0) || (nHeight == 0) || (hlimit < nHeight))
1013 const char* exceeded = (hlimit < nHeight) ?
"within" :
"outside";
1014 WLog_Print(clear->log, WLOG_ERROR,
1015 "CLEARCODEC_FLAG_GLYPH_INDEX: nWidth=%" PRIu32
", nHeight=%" PRIu32
1016 ", nWidth * nHeight is %s allowed range",
1017 nWidth, nHeight, exceeded);
1021 if (count > glyphEntry->size)
1023 BYTE* tmp = winpr_aligned_recalloc(glyphEntry->pixels, count, 1ull * bpp, 32);
1027 WLog_Print(clear->log, WLOG_ERROR,
1028 "glyphEntry->pixels winpr_aligned_recalloc %" PRIuz
" failed!",
1033 glyphEntry->count = WINPR_ASSERTING_INT_CAST(UINT32, count);
1034 glyphEntry->size = glyphEntry->count;
1035 glyphEntry->pixels = (UINT32*)tmp;
1038 if (!glyphEntry->pixels)
1040 WLog_Print(clear->log, WLOG_ERROR,
"glyphEntry->pixels=nullptr");
1045 *ppGlyphData = (BYTE*)glyphEntry->pixels;
1053static inline BOOL updateContextFormat(CLEAR_CONTEXT* WINPR_RESTRICT clear, UINT32 DstFormat)
1055 if (!clear || !clear->nsc)
1058 clear->format = DstFormat;
1059 return nsc_context_set_parameters(clear->nsc, NSC_COLOR_FORMAT, DstFormat);
1062INT32 clear_decompress(CLEAR_CONTEXT* WINPR_RESTRICT clear,
const BYTE* WINPR_RESTRICT pSrcData,
1063 UINT32 SrcSize, UINT32 nWidth, UINT32 nHeight, BYTE* WINPR_RESTRICT pDstData,
1064 UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
1065 UINT32 nDstWidth, UINT32 nDstHeight,
1066 const gdiPalette* WINPR_RESTRICT palette)
1070 BYTE glyphFlags = 0;
1071 UINT32 residualByteCount = 0;
1072 UINT32 bandsByteCount = 0;
1073 UINT32 subcodecByteCount = 0;
1074 wStream sbuffer = WINPR_C_ARRAY_INIT;
1076 BYTE* glyphData =
nullptr;
1081 if ((nDstWidth == 0) || (nDstHeight == 0))
1084 if ((nWidth > 0xFFFF) || (nHeight > 0xFFFF))
1087 if (nXDst > nDstWidth)
1089 WLog_Print(clear->log, WLOG_WARN,
"nXDst %" PRIu32
" > nDstWidth %" PRIu32, nXDst,
1094 if (nYDst > nDstHeight)
1096 WLog_Print(clear->log, WLOG_WARN,
"nYDst %" PRIu32
" > nDstHeight %" PRIu32, nYDst,
1101 s = Stream_StaticConstInit(&sbuffer, pSrcData, SrcSize);
1106 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
1109 if (!updateContextFormat(clear, DstFormat))
1112 Stream_Read_UINT8(s, glyphFlags);
1113 Stream_Read_UINT8(s, seqNumber);
1115 if (!clear->seqNumber && seqNumber)
1116 clear->seqNumber = seqNumber;
1118 if (seqNumber != clear->seqNumber)
1120 WLog_Print(clear->log, WLOG_ERROR,
"Sequence number unexpected %" PRIu8
" - %" PRIu32
"",
1121 seqNumber, clear->seqNumber);
1122 WLog_Print(clear->log, WLOG_ERROR,
"seqNumber %" PRIu8
" != clear->seqNumber %" PRIu32
"",
1123 seqNumber, clear->seqNumber);
1127 clear->seqNumber = (seqNumber + 1) % 256;
1129 if (glyphFlags & CLEARCODEC_FLAG_CACHE_RESET)
1131 clear_reset_vbar_storage(clear, FALSE);
1134 if (!clear_decompress_glyph_data(clear, s, glyphFlags, nWidth, nHeight, pDstData, DstFormat,
1135 nDstStep, nXDst, nYDst, nDstWidth, nDstHeight, palette,
1138 WLog_Print(clear->log, WLOG_ERROR,
"clear_decompress_glyph_data failed!");
1143 if (Stream_GetRemainingLength(s) < 12)
1145 const UINT32 mask = (CLEARCODEC_FLAG_GLYPH_HIT | CLEARCODEC_FLAG_GLYPH_INDEX);
1147 if ((glyphFlags & mask) == mask)
1150 WLog_Print(clear->log, WLOG_ERROR,
1151 "invalid glyphFlags, missing flags: 0x%02" PRIx8
" & 0x%02" PRIx32
1153 glyphFlags, mask, glyphFlags & mask);
1157 Stream_Read_UINT32(s, residualByteCount);
1158 Stream_Read_UINT32(s, bandsByteCount);
1159 Stream_Read_UINT32(s, subcodecByteCount);
1161 if (residualByteCount > 0)
1163 if (!clear_decompress_residual_data(clear, s, residualByteCount, nWidth, nHeight, pDstData,
1164 DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
1165 nDstHeight, palette))
1167 WLog_Print(clear->log, WLOG_ERROR,
"clear_decompress_residual_data failed!");
1172 if (bandsByteCount > 0)
1174 if (!clear_decompress_bands_data(clear, s, bandsByteCount, nWidth, nHeight, pDstData,
1175 DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight))
1177 WLog_Print(clear->log, WLOG_ERROR,
"clear_decompress_bands_data failed!");
1182 if (subcodecByteCount > 0)
1184 if (!clear_decompress_subcodecs_data(clear, s, subcodecByteCount, nWidth, nHeight, pDstData,
1185 DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
1186 nDstHeight, palette))
1188 WLog_Print(clear->log, WLOG_ERROR,
"clear_decompress_subcodecs_data failed!");
1195 uint32_t w = MIN(nWidth, nDstWidth);
1196 if (nXDst > nDstWidth)
1198 WLog_Print(clear->log, WLOG_WARN,
1199 "glyphData copy area x exceeds destination: x=%" PRIu32
" > %" PRIu32, nXDst,
1203 else if (nXDst + w > nDstWidth)
1205 WLog_Print(clear->log, WLOG_WARN,
1206 "glyphData copy area x + width exceeds destination: x=%" PRIu32
" + %" PRIu32
1208 nXDst, w, nDstWidth);
1209 w = nDstWidth - nXDst;
1214 WLog_Print(clear->log, WLOG_WARN,
1215 "glyphData copy area width truncated: requested=%" PRIu32
1216 ", truncated to %" PRIu32,
1220 uint32_t h = MIN(nHeight, nDstHeight);
1221 if (nYDst > nDstHeight)
1223 WLog_Print(clear->log, WLOG_WARN,
1224 "glyphData copy area y exceeds destination: y=%" PRIu32
" > %" PRIu32, nYDst,
1228 else if (nYDst + h > nDstHeight)
1230 WLog_Print(clear->log, WLOG_WARN,
1231 "glyphData copy area y + height exceeds destination: x=%" PRIu32
1232 " + %" PRIu32
" > %" PRIu32,
1233 nYDst, h, nDstHeight);
1234 h = nDstHeight - nYDst;
1239 WLog_Print(clear->log, WLOG_WARN,
1240 "glyphData copy area height truncated: requested=%" PRIu32
1241 ", truncated to %" PRIu32,
1245 if (!freerdp_image_copy_no_overlap(glyphData, clear->format, 0, 0, 0, w, h, pDstData,
1246 DstFormat, nDstStep, nXDst, nYDst, palette,
1247 FREERDP_KEEP_DST_ALPHA))
1257int clear_compress(WINPR_ATTR_UNUSED CLEAR_CONTEXT* WINPR_RESTRICT clear,
1258 WINPR_ATTR_UNUSED
const BYTE* WINPR_RESTRICT pSrcData,
1259 WINPR_ATTR_UNUSED UINT32 SrcSize,
1260 WINPR_ATTR_UNUSED BYTE** WINPR_RESTRICT ppDstData,
1261 WINPR_ATTR_UNUSED UINT32* WINPR_RESTRICT pDstSize)
1263 WLog_Print(clear->log, WLOG_ERROR,
"TODO: not implemented!");
1267BOOL clear_context_reset(CLEAR_CONTEXT* WINPR_RESTRICT clear)
1276 clear->seqNumber = 0;
1280CLEAR_CONTEXT* clear_context_new(BOOL Compressor)
1282 CLEAR_CONTEXT* clear = (CLEAR_CONTEXT*)winpr_aligned_calloc(1,
sizeof(CLEAR_CONTEXT), 32);
1286 clear->log = WLog_Get(TAG);
1287 clear->Compressor = Compressor;
1288 clear->nsc = nsc_context_new();
1293 if (!updateContextFormat(clear, PIXEL_FORMAT_BGRX32))
1296 if (!clear_resize_buffer(clear, 512, 512))
1299 if (!clear->TempBuffer)
1302 if (!clear_context_reset(clear))
1307 WINPR_PRAGMA_DIAG_PUSH
1308 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1309 clear_context_free(clear);
1310 WINPR_PRAGMA_DIAG_POP
1314void clear_context_free(CLEAR_CONTEXT* WINPR_RESTRICT clear)
1319 nsc_context_free(clear->nsc);
1320 winpr_aligned_free(clear->TempBuffer);
1322 clear_reset_vbar_storage(clear, TRUE);
1323 clear_reset_glyph_cache(clear);
1325 winpr_aligned_free(clear);