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
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];
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
83static const BYTE CLEAR_8BIT_MASKS[9] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
85static void clear_reset_vbar_storage(CLEAR_CONTEXT* WINPR_RESTRICT clear, BOOL zero)
89 for (
size_t i = 0; i < ARRAYSIZE(clear->VBarStorage); i++)
90 winpr_aligned_free(clear->VBarStorage[i].pixels);
92 ZeroMemory(clear->VBarStorage,
sizeof(clear->VBarStorage));
95 clear->VBarStorageCursor = 0;
99 for (
size_t i = 0; i < ARRAYSIZE(clear->ShortVBarStorage); i++)
100 winpr_aligned_free(clear->ShortVBarStorage[i].pixels);
102 ZeroMemory(clear->ShortVBarStorage,
sizeof(clear->ShortVBarStorage));
105 clear->ShortVBarStorageCursor = 0;
108static void clear_reset_glyph_cache(CLEAR_CONTEXT* WINPR_RESTRICT clear)
110 for (
size_t i = 0; i < ARRAYSIZE(clear->GlyphCache); i++)
111 winpr_aligned_free(clear->GlyphCache[i].pixels);
113 ZeroMemory(clear->GlyphCache,
sizeof(clear->GlyphCache));
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)
122 if (nWidth + nXDst > nDstWidth)
123 nWidth = nDstWidth - nXDst;
125 if (nHeight + nYDst > nDstHeight)
126 nHeight = nDstHeight - nYDst;
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);
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)
141 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, bitmapDataByteCount))
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);
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)
159 UINT32 pixelCount = 0;
160 UINT32 bitmapDataOffset = 0;
161 size_t pixelIndex = 0;
167 BYTE paletteCount = 0;
168 UINT32 palette[128] = WINPR_C_ARRAY_INIT;
170 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, bitmapDataByteCount))
173 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
175 Stream_Read_UINT8(s, paletteCount);
176 bitmapDataOffset = 1 + (paletteCount * 3);
178 if ((paletteCount > 127) || (paletteCount < 1))
180 WLog_Print(log, WLOG_ERROR,
"paletteCount %" PRIu8
"", paletteCount);
184 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, paletteCount, 3ull))
187 for (UINT32 i = 0; i < paletteCount; i++)
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);
199 pixelCount = width * height;
200 numBits = CLEAR_LOG2_FLOOR[paletteCount - 1] + 1;
202 while (bitmapDataOffset < bitmapDataByteCount)
206 UINT32 runLengthFactor = 0;
208 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
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;
218 if (runLengthFactor >= 0xFF)
220 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
223 Stream_Read_UINT16(s, runLengthFactor);
224 bitmapDataOffset += 2;
226 if (runLengthFactor >= 0xFFFF)
228 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
231 Stream_Read_UINT32(s, runLengthFactor);
232 bitmapDataOffset += 4;
236 if (startIndex >= paletteCount)
238 WLog_Print(log, WLOG_ERROR,
"startIndex %" PRIu8
" > paletteCount %" PRIu8
"]",
239 startIndex, paletteCount);
243 if (stopIndex >= paletteCount)
245 WLog_Print(log, WLOG_ERROR,
"stopIndex %" PRIu8
" > paletteCount %" PRIu8
"]",
246 stopIndex, paletteCount);
250 suiteIndex = startIndex;
252 if (suiteIndex > 127)
254 WLog_Print(log, WLOG_ERROR,
"suiteIndex %" PRIu8
" > 127]", suiteIndex);
258 color = palette[suiteIndex];
260 if ((pixelIndex + runLengthFactor) > pixelCount)
262 WLog_Print(log, WLOG_ERROR,
263 "pixelIndex %" PRIuz
" + runLengthFactor %" PRIu32
" > pixelCount %" PRIu32
265 pixelIndex, runLengthFactor, pixelCount);
269 for (UINT32 i = 0; i < runLengthFactor; i++)
271 BYTE* pTmpData = &pDstData[(nXDstRel + x) * FreeRDPGetBytesPerPixel(DstFormat) +
272 (nYDstRel + y) * nDstStep];
274 if ((nXDstRel + x < nDstWidth) && (nYDstRel + y < nDstHeight))
275 FreeRDPWriteColor(pTmpData, DstFormat, color);
284 pixelIndex += runLengthFactor;
286 if ((pixelIndex + (suiteDepth + 1)) > pixelCount)
288 WLog_Print(log, WLOG_ERROR,
289 "pixelIndex %" PRIuz
" + suiteDepth %" PRIu8
" + 1 > pixelCount %" PRIu32
"",
290 pixelIndex, suiteDepth, pixelCount);
294 for (UINT32 i = 0; i <= suiteDepth; i++)
296 BYTE* pTmpData = &pDstData[(nXDstRel + x) * FreeRDPGetBytesPerPixel(DstFormat) +
297 (nYDstRel + y) * nDstStep];
298 UINT32 ccolor = palette[suiteIndex];
300 if (suiteIndex > 127)
302 WLog_Print(log, WLOG_ERROR,
"suiteIndex %" PRIu8
" > 127", suiteIndex);
308 if ((nXDstRel + x < nDstWidth) && (nYDstRel + y < nDstHeight))
309 FreeRDPWriteColor(pTmpData, DstFormat, ccolor);
318 pixelIndex += (suiteDepth + 1);
321 if (pixelIndex != pixelCount)
323 WLog_Print(log, WLOG_ERROR,
"pixelIndex %" PRIuz
" != pixelCount %" PRIu32
"", pixelIndex,
331static BOOL clear_resize_buffer(CLEAR_CONTEXT* WINPR_RESTRICT clear, UINT32 width, UINT32 height)
336 const UINT64 size = 1ull * (width + 16ull) * (height + 16ull);
337 const size_t bpp = FreeRDPGetBytesPerPixel(clear->format);
338 if (size > UINT32_MAX / bpp)
341 if (size > clear->TempSize / bpp)
343 BYTE* tmp = (BYTE*)winpr_aligned_recalloc(clear->TempBuffer,
344 WINPR_ASSERTING_INT_CAST(
size_t, size), bpp, 32);
348 WLog_Print(clear->log, WLOG_ERROR,
349 "clear->TempBuffer winpr_aligned_recalloc failed for %" PRIu64
" bytes",
354 clear->TempSize = WINPR_ASSERTING_INT_CAST(
size_t, size* bpp);
355 clear->TempBuffer = tmp;
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)
370 UINT32 suboffset = 0;
371 BYTE* dstBuffer =
nullptr;
372 UINT32 pixelIndex = 0;
373 UINT32 pixelCount = 0;
375 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, residualByteCount))
380 pixelCount = nWidth * nHeight;
382 if (!clear_resize_buffer(clear, nWidth, nHeight))
385 dstBuffer = clear->TempBuffer;
387 while (suboffset < residualByteCount)
392 UINT32 runLengthFactor = 0;
395 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 4))
398 Stream_Read_UINT8(s, b);
399 Stream_Read_UINT8(s, g);
400 Stream_Read_UINT8(s, r);
401 Stream_Read_UINT8(s, runLengthFactor);
403 color = FreeRDPGetColor(clear->format, r, g, b, 0xFF);
405 if (runLengthFactor >= 0xFF)
407 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
410 Stream_Read_UINT16(s, runLengthFactor);
413 if (runLengthFactor >= 0xFFFF)
415 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 4))
418 Stream_Read_UINT32(s, runLengthFactor);
423 if ((pixelIndex >= pixelCount) || (runLengthFactor > (pixelCount - pixelIndex)))
425 WLog_Print(clear->log, WLOG_ERROR,
426 "pixelIndex %" PRIu32
" + runLengthFactor %" PRIu32
" > pixelCount %" PRIu32
428 pixelIndex, runLengthFactor, pixelCount);
432 for (UINT32 i = 0; i < runLengthFactor; i++)
434 FreeRDPWriteColor(dstBuffer, clear->format, color);
435 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
438 pixelIndex += runLengthFactor;
441 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(clear->format);
443 if (pixelIndex != pixelCount)
445 WLog_Print(clear->log, WLOG_ERROR,
"pixelIndex %" PRIu32
" != pixelCount %" PRIu32
"",
446 pixelIndex, pixelCount);
450 return convert_color(pDstData, nDstStep, DstFormat, nXDst, nYDst, nWidth, nHeight,
451 clear->TempBuffer, nSrcStep, clear->format, nDstWidth, nDstHeight,
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)
463 UINT32 suboffset = 0;
465 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, subcodecByteCount))
468 while (suboffset < subcodecByteCount)
470 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 13))
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);
481 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, bitmapDataByteCount))
484 const UINT32 nXDstRel = nXDst + xStart;
485 const UINT32 nYDstRel = nYDst + yStart;
486 if (1ull * nXDstRel + width > nDstWidth)
488 WLog_Print(clear->log, WLOG_ERROR,
489 "nXDstRel %" PRIu32
" + width %" PRIu16
" > nDstWidth %" PRIu32
"", nXDstRel,
493 if (1ull * nYDstRel + height > nDstHeight)
495 WLog_Print(clear->log, WLOG_ERROR,
496 "nYDstRel %" PRIu32
" + height %" PRIu16
" > nDstHeight %" PRIu32
"",
497 nYDstRel, height, nDstHeight);
501 if (1ull * xStart + width > nWidth)
503 WLog_Print(clear->log, WLOG_ERROR,
504 "xStart %" PRIu16
" + width %" PRIu16
" > nWidth %" PRIu32
"", xStart, width,
508 if (1ull * yStart + height > nHeight)
510 WLog_Print(clear->log, WLOG_ERROR,
511 "yStart %" PRIu16
" + height %" PRIu16
" > nHeight %" PRIu32
"", yStart,
516 if (!clear_resize_buffer(clear, width, height))
523 const UINT32 nSrcStep = width * FreeRDPGetBytesPerPixel(PIXEL_FORMAT_BGR24);
524 const size_t nSrcSize = 1ull * nSrcStep * height;
526 if (bitmapDataByteCount != nSrcSize)
528 WLog_Print(clear->log, WLOG_ERROR,
529 "bitmapDataByteCount %" PRIu32
" != nSrcSize %" PRIuz
"",
530 bitmapDataByteCount, nSrcSize);
534 if (!convert_color(pDstData, nDstStep, DstFormat, nXDstRel, nYDstRel, width, height,
535 Stream_Pointer(s), nSrcStep, PIXEL_FORMAT_BGR24, nDstWidth,
536 nDstHeight, palette))
539 Stream_Seek(s, bitmapDataByteCount);
544 if (!clear_decompress_nscodec(clear->log, clear->nsc, width, height, s,
545 bitmapDataByteCount, pDstData, DstFormat, nDstStep,
546 nXDstRel, nYDstRel, nDstWidth, nDstHeight))
552 if (!clear_decompress_subcode_rlex(clear->log, s, bitmapDataByteCount, width,
553 height, pDstData, DstFormat, nDstStep, nXDstRel,
554 nYDstRel, nDstWidth, nDstHeight))
560 WLog_Print(clear->log, WLOG_ERROR,
"Unknown subcodec ID %" PRIu8
"", subcodecId);
564 suboffset += bitmapDataByteCount;
570static BOOL resize_vbar_entry(CLEAR_CONTEXT* WINPR_RESTRICT clear,
571 CLEAR_VBAR_ENTRY* WINPR_RESTRICT vBarEntry)
573 if (vBarEntry->count > vBarEntry->size)
575 const UINT32 bpp = FreeRDPGetBytesPerPixel(clear->format);
576 const UINT32 oldPos = vBarEntry->size * bpp;
577 const UINT32 diffSize = (vBarEntry->count - vBarEntry->size) * bpp;
580 (BYTE*)winpr_aligned_recalloc(vBarEntry->pixels, vBarEntry->count, 1ull * bpp, 32);
584 WLog_Print(clear->log, WLOG_ERROR,
585 "vBarEntry->pixels winpr_aligned_recalloc %" PRIu32
" failed",
586 vBarEntry->count * bpp);
590 memset(&tmp[oldPos], 0, diffSize);
591 vBarEntry->pixels = tmp;
592 vBarEntry->size = vBarEntry->count;
595 if (!vBarEntry->pixels && vBarEntry->size)
597 WLog_Print(clear->log, WLOG_ERROR,
598 "vBarEntry->pixels is nullptr but vBarEntry->size is %" PRIu32
"",
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)
613 UINT32 suboffset = 0;
615 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, bandsByteCount))
618 while (suboffset < bandsByteCount)
628 UINT16 vBarHeader = 0;
631 UINT32 vBarCount = 0;
632 UINT32 vBarPixelCount = 0;
633 UINT32 vBarShortPixelCount = 0;
635 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 11))
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);
646 colorBkg = FreeRDPGetColor(clear->format, cr, cg, cb, 0xFF);
650 WLog_Print(clear->log, WLOG_ERROR,
"xEnd %" PRIu16
" < xStart %" PRIu16
"", xEnd,
657 WLog_Print(clear->log, WLOG_ERROR,
"yEnd %" PRIu16
" < yStart %" PRIu16
"", yEnd,
662 vBarCount = (xEnd - xStart) + 1;
664 for (UINT32 i = 0; i < vBarCount; i++)
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;
672 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
675 Stream_Read_UINT16(s, vBarHeader);
677 vBarHeight = (yEnd - yStart + 1);
681 WLog_Print(clear->log, WLOG_ERROR,
"vBarHeight (%" PRIu32
") > 52", vBarHeight);
685 if ((vBarHeader & 0xC000) == 0x4000)
687 const UINT16 vBarIndex = (vBarHeader & 0x3FFF);
688 vBarShortEntry = &(clear->ShortVBarStorage[vBarIndex]);
692 WLog_Print(clear->log, WLOG_ERROR,
"missing vBarShortEntry %" PRIu16
"",
697 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 1))
700 Stream_Read_UINT8(s, vBarYOn);
702 vBarShortPixelCount = vBarShortEntry->count;
705 else if ((vBarHeader & 0xC000) == 0x0000)
707 vBarYOn = (vBarHeader & 0xFF);
708 vBarYOff = ((vBarHeader >> 8) & 0x3F);
710 if (vBarYOff < vBarYOn)
712 WLog_Print(clear->log, WLOG_ERROR,
"vBarYOff %" PRIu16
" < vBarYOn %" PRIu16
"",
717 vBarShortPixelCount = (vBarYOff - vBarYOn);
719 if (vBarShortPixelCount > 52)
721 WLog_Print(clear->log, WLOG_ERROR,
"vBarShortPixelCount %" PRIu32
" > 52",
722 vBarShortPixelCount);
726 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(clear->log, s, vBarShortPixelCount,
730 if (clear->ShortVBarStorageCursor >= CLEARCODEC_VBAR_SHORT_SIZE)
732 WLog_Print(clear->log, WLOG_ERROR,
733 "clear->ShortVBarStorageCursor %" PRIu32
734 " >= CLEARCODEC_VBAR_SHORT_SIZE (%" PRId32
")",
735 clear->ShortVBarStorageCursor, CLEARCODEC_VBAR_SHORT_SIZE);
739 vBarShortEntry = &(clear->ShortVBarStorage[clear->ShortVBarStorageCursor]);
740 vBarShortEntry->count = vBarShortPixelCount;
742 if (!resize_vbar_entry(clear, vBarShortEntry))
745 for (
size_t y = 0; y < vBarShortPixelCount; y++)
751 &vBarShortEntry->pixels[y * FreeRDPGetBytesPerPixel(clear->format)];
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);
758 if (!FreeRDPWriteColor(dstBuffer, clear->format, color))
762 suboffset += (vBarShortPixelCount * 3);
763 clear->ShortVBarStorageCursor =
764 (clear->ShortVBarStorageCursor + 1) % CLEARCODEC_VBAR_SHORT_SIZE;
767 else if ((vBarHeader & 0x8000) == 0x8000)
769 const UINT16 vBarIndex = (vBarHeader & 0x7FFF);
770 vBarEntry = &(clear->VBarStorage[vBarIndex]);
773 if (vBarEntry->size == 0)
775 WLog_Print(clear->log, WLOG_WARN,
776 "Empty cache index %" PRIu16
", filling dummy data", vBarIndex);
777 vBarEntry->count = vBarHeight;
779 if (!resize_vbar_entry(clear, vBarEntry))
785 WLog_Print(clear->log, WLOG_ERROR,
"invalid vBarHeader 0x%04" PRIX16
"",
792 BYTE* pSrcPixel =
nullptr;
793 BYTE* dstBuffer =
nullptr;
795 if (clear->VBarStorageCursor >= CLEARCODEC_VBAR_SIZE)
797 WLog_Print(clear->log, WLOG_ERROR,
798 "clear->VBarStorageCursor %" PRIu32
799 " >= CLEARCODEC_VBAR_SIZE %" PRId32
"",
800 clear->VBarStorageCursor, CLEARCODEC_VBAR_SIZE);
804 vBarEntry = &(clear->VBarStorage[clear->VBarStorageCursor]);
805 vBarPixelCount = vBarHeight;
806 vBarEntry->count = vBarPixelCount;
808 if (!resize_vbar_entry(clear, vBarEntry))
811 dstBuffer = vBarEntry->pixels;
814 UINT32 count = vBarYOn;
816 if ((y + count) > vBarPixelCount)
817 count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
823 FreeRDPWriteColor(dstBuffer, clear->format, colorBkg);
824 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
833 count = vBarShortPixelCount;
835 if ((y + count) > vBarPixelCount)
836 count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
840 const size_t offset =
841 (1ull * y - vBarYOn) * FreeRDPGetBytesPerPixel(clear->format);
842 pSrcPixel = &vBarShortEntry->pixels[offset];
843 if (offset + count > vBarShortEntry->count)
845 WLog_Print(clear->log, WLOG_ERROR,
846 "offset + count > vBarShortEntry->count");
850 for (
size_t x = 0; x < count; x++)
853 color = FreeRDPReadColor(&pSrcPixel[x * FreeRDPGetBytesPerPixel(clear->format)],
856 if (!FreeRDPWriteColor(dstBuffer, clear->format, color))
859 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
863 y = vBarYOn + vBarShortPixelCount;
864 count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
870 if (!FreeRDPWriteColor(dstBuffer, clear->format, colorBkg))
873 dstBuffer += FreeRDPGetBytesPerPixel(clear->format);
877 vBarEntry->count = vBarPixelCount;
878 clear->VBarStorageCursor = (clear->VBarStorageCursor + 1) % CLEARCODEC_VBAR_SIZE;
881 if (vBarEntry->count != vBarHeight)
883 WLog_Print(clear->log, WLOG_ERROR,
884 "vBarEntry->count %" PRIu32
" != vBarHeight %" PRIu32
"",
885 vBarEntry->count, vBarHeight);
886 vBarEntry->count = vBarHeight;
888 if (!resize_vbar_entry(clear, vBarEntry))
892 const UINT32 nXDstRel = nXDst + xStart;
893 const UINT32 nYDstRel = nYDst + yStart;
894 cpSrcPixel = vBarEntry->pixels;
898 UINT32 count = vBarEntry->count;
903 if (nXDstRel + i >= nDstWidth)
906 for (UINT32 y = 0; y < count; y++)
908 if (nYDstRel + y >= nDstHeight)
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);
917 if (!FreeRDPWriteColor(pDstPixel8, DstFormat, color))
920 cpSrcPixel += FreeRDPGetBytesPerPixel(clear->format);
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)
937 UINT16 glyphIndex = 0;
940 *ppGlyphData =
nullptr;
942 if ((glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT) && !(glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX))
944 WLog_Print(clear->log, WLOG_ERROR,
"Invalid glyph flags %08" PRIX32
"", glyphFlags);
948 if ((glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX) == 0)
951 if ((nWidth * nHeight) > (1024 * 1024))
953 WLog_Print(clear->log, WLOG_ERROR,
"glyph too large: %" PRIu32
"x%" PRIu32
"", nWidth,
958 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
961 Stream_Read_UINT16(s, glyphIndex);
963 if (glyphIndex >= 4000)
965 WLog_Print(clear->log, WLOG_ERROR,
"Invalid glyphIndex %" PRIu16
"", glyphIndex);
969 if (glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT)
972 CLEAR_GLYPH_ENTRY* glyphEntry = &(clear->GlyphCache[glyphIndex]);
973 BYTE* glyphData =
nullptr;
977 WLog_Print(clear->log, WLOG_ERROR,
"clear->GlyphCache[%" PRIu16
"]=nullptr",
982 glyphData = (BYTE*)glyphEntry->pixels;
986 WLog_Print(clear->log, WLOG_ERROR,
"clear->GlyphCache[%" PRIu16
"]->pixels=nullptr",
991 if ((nWidth * nHeight) > glyphEntry->count)
993 WLog_Print(clear->log, WLOG_ERROR,
994 "(nWidth %" PRIu32
" * nHeight %" PRIu32
") > glyphEntry->count %" PRIu32
"",
995 nWidth, nHeight, glyphEntry->count);
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);
1004 if (glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX)
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))
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);
1020 if (count > glyphEntry->size)
1022 BYTE* tmp = winpr_aligned_recalloc(glyphEntry->pixels, count, 1ull * bpp, 32);
1026 WLog_Print(clear->log, WLOG_ERROR,
1027 "glyphEntry->pixels winpr_aligned_recalloc %" PRIuz
" failed!",
1032 glyphEntry->count = WINPR_ASSERTING_INT_CAST(UINT32, count);
1033 glyphEntry->size = glyphEntry->count;
1034 glyphEntry->pixels = (UINT32*)tmp;
1037 if (!glyphEntry->pixels)
1039 WLog_Print(clear->log, WLOG_ERROR,
"glyphEntry->pixels=nullptr");
1044 *ppGlyphData = (BYTE*)glyphEntry->pixels;
1052static inline BOOL updateContextFormat(CLEAR_CONTEXT* WINPR_RESTRICT clear, UINT32 DstFormat,
1055 if (!clear || !clear->nsc)
1060 if (clear->formatSet)
1062 if (clear->format != DstFormat)
1065 clear->log, WLOG_ERROR,
1066 "Color format changed from %s to %s during decompression calls, usage error!",
1067 FreeRDPGetColorFormatName(clear->format), FreeRDPGetColorFormatName(DstFormat));
1072 clear->formatSet = TRUE;
1074 clear->format = DstFormat;
1075 return nsc_context_set_parameters(clear->nsc, NSC_COLOR_FORMAT, DstFormat);
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)
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;
1096 if ((nDstWidth == 0) || (nDstHeight == 0))
1099 if ((nWidth > 0xFFFF) || (nHeight > 0xFFFF))
1102 if (nXDst > nDstWidth)
1104 WLog_Print(clear->log, WLOG_WARN,
"nXDst %" PRIu32
" > nDstWidth %" PRIu32, nXDst,
1109 if (nYDst > nDstHeight)
1111 WLog_Print(clear->log, WLOG_WARN,
"nYDst %" PRIu32
" > nDstHeight %" PRIu32, nYDst,
1116 wStream* s = Stream_StaticConstInit(&sbuffer, pSrcData, SrcSize);
1121 if (!Stream_CheckAndLogRequiredLengthWLog(clear->log, s, 2))
1124 if (!updateContextFormat(clear, DstFormat, FALSE))
1127 Stream_Read_UINT8(s, glyphFlags);
1128 Stream_Read_UINT8(s, seqNumber);
1130 if (!clear->seqNumber && seqNumber)
1131 clear->seqNumber = seqNumber;
1133 if (seqNumber != clear->seqNumber)
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);
1142 clear->seqNumber = (seqNumber + 1) % 256;
1144 if (glyphFlags & CLEARCODEC_FLAG_CACHE_RESET)
1146 clear_reset_vbar_storage(clear, FALSE);
1149 if (!clear_decompress_glyph_data(clear, s, glyphFlags, nWidth, nHeight, pDstData, DstFormat,
1150 nDstStep, nXDst, nYDst, nDstWidth, nDstHeight, palette,
1153 WLog_Print(clear->log, WLOG_ERROR,
"clear_decompress_glyph_data failed!");
1158 if (Stream_GetRemainingLength(s) < 12)
1160 const UINT32 mask = (CLEARCODEC_FLAG_GLYPH_HIT | CLEARCODEC_FLAG_GLYPH_INDEX);
1162 if ((glyphFlags & mask) == mask)
1165 WLog_Print(clear->log, WLOG_ERROR,
1166 "invalid glyphFlags, missing flags: 0x%02" PRIx8
" & 0x%02" PRIx32
1168 glyphFlags, mask, glyphFlags & mask);
1172 Stream_Read_UINT32(s, residualByteCount);
1173 Stream_Read_UINT32(s, bandsByteCount);
1174 Stream_Read_UINT32(s, subcodecByteCount);
1176 if (residualByteCount > 0)
1178 if (!clear_decompress_residual_data(clear, s, residualByteCount, nWidth, nHeight, pDstData,
1179 DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
1180 nDstHeight, palette))
1182 WLog_Print(clear->log, WLOG_ERROR,
"clear_decompress_residual_data failed!");
1187 if (bandsByteCount > 0)
1189 if (!clear_decompress_bands_data(clear, s, bandsByteCount, nWidth, nHeight, pDstData,
1190 DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight))
1192 WLog_Print(clear->log, WLOG_ERROR,
"clear_decompress_bands_data failed!");
1197 if (subcodecByteCount > 0)
1199 if (!clear_decompress_subcodecs_data(clear, s, subcodecByteCount, nWidth, nHeight, pDstData,
1200 DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
1201 nDstHeight, palette))
1203 WLog_Print(clear->log, WLOG_ERROR,
"clear_decompress_subcodecs_data failed!");
1210 uint32_t w = MIN(nWidth, nDstWidth);
1211 if (nXDst > nDstWidth)
1213 WLog_Print(clear->log, WLOG_WARN,
1214 "glyphData copy area x exceeds destination: x=%" PRIu32
" > %" PRIu32, nXDst,
1218 else if (nXDst + w > nDstWidth)
1220 WLog_Print(clear->log, WLOG_WARN,
1221 "glyphData copy area x + width exceeds destination: x=%" PRIu32
" + %" PRIu32
1223 nXDst, w, nDstWidth);
1224 w = nDstWidth - nXDst;
1229 WLog_Print(clear->log, WLOG_WARN,
1230 "glyphData copy area width truncated: requested=%" PRIu32
1231 ", truncated to %" PRIu32,
1235 uint32_t h = MIN(nHeight, nDstHeight);
1236 if (nYDst > nDstHeight)
1238 WLog_Print(clear->log, WLOG_WARN,
1239 "glyphData copy area y exceeds destination: y=%" PRIu32
" > %" PRIu32, nYDst,
1243 else if (nYDst + h > nDstHeight)
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;
1254 WLog_Print(clear->log, WLOG_WARN,
1255 "glyphData copy area height truncated: requested=%" PRIu32
1256 ", truncated to %" PRIu32,
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))
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)
1279 WLog_Print(clear->log, WLOG_ERROR,
"TODO: not implemented!");
1284BOOL clear_context_reset(CLEAR_CONTEXT* WINPR_RESTRICT clear)
1293 clear->seqNumber = 0;
1297CLEAR_CONTEXT* clear_context_new(BOOL Compressor)
1299 CLEAR_CONTEXT* clear = (CLEAR_CONTEXT*)winpr_aligned_calloc(1,
sizeof(CLEAR_CONTEXT), 32);
1303 clear->log = WLog_Get(TAG);
1304 clear->Compressor = Compressor;
1305 clear->nsc = nsc_context_new();
1310 if (!updateContextFormat(clear, PIXEL_FORMAT_BGRX32, TRUE))
1313 if (!clear_resize_buffer(clear, 512, 512))
1316 if (!clear->TempBuffer)
1319 if (!clear_context_reset(clear))
1324 WINPR_PRAGMA_DIAG_PUSH
1325 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1326 clear_context_free(clear);
1327 WINPR_PRAGMA_DIAG_POP
1331void clear_context_free(CLEAR_CONTEXT* WINPR_RESTRICT clear)
1336 nsc_context_free(clear->nsc);
1337 winpr_aligned_free(clear->TempBuffer);
1339 clear_reset_vbar_storage(clear, TRUE);
1340 clear_reset_glyph_cache(clear);
1342 winpr_aligned_free(clear);