22#include <winpr/assert.h>
23#include <winpr/cast.h>
24#include <winpr/wtypes.h>
31static inline BYTE* WRITEFGBGIMAGE(BYTE* WINPR_RESTRICT pbDest,
32 const BYTE* WINPR_RESTRICT pbDestEnd, UINT32 rowDelta,
33 BYTE bitmask, PIXEL fgPel, UINT32 cBits)
40 WLog_ERR(TAG,
"cBits %" PRIu32
" > 8", cBits);
44 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
49 DESTREADPIXEL(xorPixel, pbDest - rowDelta);
52 data = xorPixel ^ fgPel;
56 DESTWRITEPIXEL(pbDest, data);
57 mask = WINPR_ASSERTING_INT_CAST(BYTE, (mask << 1) & 0xFF);
66static inline BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* WINPR_RESTRICT pbDest,
67 const BYTE* WINPR_RESTRICT pbDestEnd, BYTE bitmask,
68 PIXEL fgPel, UINT32 cBits)
74 WLog_ERR(TAG,
"cBits %" PRIu32
" > 8", cBits);
78 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
89 DESTWRITEPIXEL(pbDest, data);
90 mask = WINPR_ASSERTING_INT_CAST(BYTE, (mask << 1) & 0xFF);
98static inline BOOL RLEDECOMPRESS(
const BYTE* WINPR_RESTRICT pbSrcBuffer, UINT32 cbSrcBuffer,
99 BYTE* WINPR_RESTRICT pbDestBuffer, UINT32 rowDelta, UINT32 width,
102 const BYTE* pbSrc = pbSrcBuffer;
103 BYTE* pbDest = pbDestBuffer;
105 PIXEL fgPel = WHITE_PIXEL;
106 BOOL fInsertFgPel = FALSE;
107 BOOL fFirstLine = TRUE;
111 UINT32 runLength = 0;
116 if ((rowDelta == 0) || (rowDelta < width))
118 WLog_ERR(TAG,
"Invalid arguments: rowDelta=%" PRIu32
" == 0 || < width=%" PRIu32, rowDelta,
123 if (!pbSrcBuffer || !pbDestBuffer)
125 WLog_ERR(TAG,
"Invalid arguments: pbSrcBuffer=%p, pbDestBuffer=%p",
126 WINPR_CXX_COMPAT_CAST(
const void*, pbSrcBuffer),
127 WINPR_CXX_COMPAT_CAST(
const void*, pbDestBuffer));
131 const BYTE* pbEnd = &pbSrcBuffer[cbSrcBuffer];
132 const BYTE* pbDestEnd = &pbDestBuffer[1ULL * rowDelta * height];
134 while (pbSrc < pbEnd)
139 if ((UINT32)(pbDest - pbDestBuffer) >= rowDelta)
142 fInsertFgPel = FALSE;
150 code = ExtractCodeId(*pbSrc);
152#if defined(WITH_DEBUG_CODECS)
153 WLog_VRB(TAG,
"pbSrc=%p code=%s, rem=%" PRIuz, pbSrc, rle_code_str(code), pbEnd - pbSrc);
157 if ((code == REGULAR_BG_RUN) || (code == MEGA_MEGA_BG_RUN))
159 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
162 pbSrc = pbSrc + advance;
168 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
171 DESTWRITEPIXEL(pbDest, fgPel);
172 runLength = runLength - 1;
175 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
178 UNROLL(runLength, { DESTWRITEPIXEL(pbDest, BLACK_PIXEL); });
184 DESTREADPIXEL(temp, pbDest - rowDelta);
186 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
189 DESTWRITEPIXEL(pbDest, temp ^ fgPel);
193 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
197 DESTREADPIXEL(temp, pbDest - rowDelta);
198 DESTWRITEPIXEL(pbDest, temp);
209 fInsertFgPel = FALSE;
215 case MEGA_MEGA_FG_RUN:
216 case LITE_SET_FG_FG_RUN:
217 case MEGA_MEGA_SET_FG_RUN:
218 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
221 pbSrc = pbSrc + advance;
223 if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
225 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
227 SRCREADPIXEL(fgPel, pbSrc);
230 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
235 UNROLL(runLength, { DESTWRITEPIXEL(pbDest, fgPel); });
240 DESTREADPIXEL(temp, pbDest - rowDelta);
241 DESTWRITEPIXEL(pbDest, temp ^ fgPel);
248 case LITE_DITHERED_RUN:
249 case MEGA_MEGA_DITHERED_RUN:
250 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
253 pbSrc = pbSrc + advance;
254 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
256 SRCREADPIXEL(pixelA, pbSrc);
257 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
259 SRCREADPIXEL(pixelB, pbSrc);
261 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2))
265 DESTWRITEPIXEL(pbDest, pixelA);
266 DESTWRITEPIXEL(pbDest, pixelB);
271 case REGULAR_COLOR_RUN:
272 case MEGA_MEGA_COLOR_RUN:
273 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
276 pbSrc = pbSrc + advance;
277 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
279 SRCREADPIXEL(pixelA, pbSrc);
281 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
284 UNROLL(runLength, { DESTWRITEPIXEL(pbDest, pixelA); });
288 case REGULAR_FGBG_IMAGE:
289 case MEGA_MEGA_FGBG_IMAGE:
290 case LITE_SET_FG_FGBG_IMAGE:
291 case MEGA_MEGA_SET_FGBG_IMAGE:
292 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
295 pbSrc = pbSrc + advance;
297 if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
299 if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
301 SRCREADPIXEL(fgPel, pbSrc);
304 if (!buffer_within_range(pbSrc, runLength / 8, pbEnd))
308 while (runLength > 8)
312 pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, 8);
317 runLength = runLength - 8;
322 while (runLength > 8)
326 pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8);
331 runLength = runLength - 8;
337 if (!buffer_within_range(pbSrc, 1, pbEnd))
344 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, runLength);
349 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, runLength);
359 case REGULAR_COLOR_IMAGE:
360 case MEGA_MEGA_COLOR_IMAGE:
361 runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
364 pbSrc = pbSrc + advance;
365 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
367 if (!ENSURE_CAPACITY(pbSrc, pbEnd, runLength))
371 SRCREADPIXEL(temp, pbSrc);
372 DESTWRITEPIXEL(pbDest, temp);
378 if (!buffer_within_range(pbSrc, 1, pbEnd))
385 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg1, fgPel, 8);
390 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg1, fgPel, 8);
400 if (!buffer_within_range(pbSrc, 1, pbEnd))
407 WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg2, fgPel, 8);
412 WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg2, fgPel, 8);
422 if (!buffer_within_range(pbSrc, 1, pbEnd))
426 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
429 DESTWRITEPIXEL(pbDest, WHITE_PIXEL);
434 if (!buffer_within_range(pbSrc, 1, pbEnd))
438 if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
441 DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
445 WLog_ERR(TAG,
"invalid code 0x%08" PRIx32
", pbSrcBuffer=%p, pbSrc=%p, pbEnd=%p",
446 code, WINPR_CXX_COMPAT_CAST(
const void*, pbSrcBuffer),
447 WINPR_CXX_COMPAT_CAST(
const void*, pbSrc),
448 WINPR_CXX_COMPAT_CAST(
const void*, pbEnd));