summaryrefslogtreecommitdiffstats
path: root/libfreerdp/codec/interleaved.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfreerdp/codec/interleaved.c')
-rw-r--r--libfreerdp/codec/interleaved.c750
1 files changed, 750 insertions, 0 deletions
diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c
new file mode 100644
index 0000000..75b2e27
--- /dev/null
+++ b/libfreerdp/codec/interleaved.c
@@ -0,0 +1,750 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * Interleaved RLE Bitmap Codec
+ *
+ * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2015 Thincast Technologies GmbH
+ * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
+ * Copyright 2016 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2016 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <winpr/assert.h>
+#include <freerdp/config.h>
+
+#include <freerdp/codec/interleaved.h>
+#include <freerdp/log.h>
+
+#define TAG FREERDP_TAG("codec")
+
+#define UNROLL_BODY(_exp, _count) \
+ do \
+ { \
+ for (size_t x = 0; x < (_count); x++) \
+ { \
+ do \
+ { \
+ _exp \
+ } while (FALSE); \
+ } \
+ } while (FALSE)
+
+#define UNROLL_MULTIPLE(_condition, _exp, _count) \
+ do \
+ { \
+ while ((_condition) >= _count) \
+ { \
+ UNROLL_BODY(_exp, _count); \
+ (_condition) -= _count; \
+ } \
+ } while (FALSE)
+
+#define UNROLL(_condition, _exp) \
+ do \
+ { \
+ UNROLL_MULTIPLE(_condition, _exp, 16); \
+ UNROLL_MULTIPLE(_condition, _exp, 4); \
+ UNROLL_MULTIPLE(_condition, _exp, 1); \
+ } while (FALSE)
+
+/*
+ RLE Compressed Bitmap Stream (RLE_BITMAP_STREAM)
+ http://msdn.microsoft.com/en-us/library/cc240895%28v=prot.10%29.aspx
+ pseudo-code
+ http://msdn.microsoft.com/en-us/library/dd240593%28v=prot.10%29.aspx
+*/
+
+#define REGULAR_BG_RUN 0x00
+#define MEGA_MEGA_BG_RUN 0xF0
+#define REGULAR_FG_RUN 0x01
+#define MEGA_MEGA_FG_RUN 0xF1
+#define LITE_SET_FG_FG_RUN 0x0C
+#define MEGA_MEGA_SET_FG_RUN 0xF6
+#define LITE_DITHERED_RUN 0x0E
+#define MEGA_MEGA_DITHERED_RUN 0xF8
+#define REGULAR_COLOR_RUN 0x03
+#define MEGA_MEGA_COLOR_RUN 0xF3
+#define REGULAR_FGBG_IMAGE 0x02
+#define MEGA_MEGA_FGBG_IMAGE 0xF2
+#define LITE_SET_FG_FGBG_IMAGE 0x0D
+#define MEGA_MEGA_SET_FGBG_IMAGE 0xF7
+#define REGULAR_COLOR_IMAGE 0x04
+#define MEGA_MEGA_COLOR_IMAGE 0xF4
+#define SPECIAL_FGBG_1 0xF9
+#define SPECIAL_FGBG_2 0xFA
+#define SPECIAL_WHITE 0xFD
+#define SPECIAL_BLACK 0xFE
+
+#define BLACK_PIXEL 0x000000
+
+typedef UINT32 PIXEL;
+
+static const BYTE g_MaskSpecialFgBg1 = 0x03;
+static const BYTE g_MaskSpecialFgBg2 = 0x05;
+
+static const BYTE g_MaskRegularRunLength = 0x1F;
+static const BYTE g_MaskLiteRunLength = 0x0F;
+
+static const char* rle_code_str(UINT32 code)
+{
+ switch (code)
+ {
+ case REGULAR_BG_RUN:
+ return "REGULAR_BG_RUN";
+ case MEGA_MEGA_BG_RUN:
+ return "MEGA_MEGA_BG_RUN";
+ case REGULAR_FG_RUN:
+ return "REGULAR_FG_RUN";
+ case MEGA_MEGA_FG_RUN:
+ return "MEGA_MEGA_FG_RUN";
+ case LITE_SET_FG_FG_RUN:
+ return "LITE_SET_FG_FG_RUN";
+ case MEGA_MEGA_SET_FG_RUN:
+ return "MEGA_MEGA_SET_FG_RUN";
+ case LITE_DITHERED_RUN:
+ return "LITE_DITHERED_RUN";
+ case MEGA_MEGA_DITHERED_RUN:
+ return "MEGA_MEGA_DITHERED_RUN";
+ case REGULAR_COLOR_RUN:
+ return "REGULAR_COLOR_RUN";
+ case MEGA_MEGA_COLOR_RUN:
+ return "MEGA_MEGA_COLOR_RUN";
+ case REGULAR_FGBG_IMAGE:
+ return "REGULAR_FGBG_IMAGE";
+ case MEGA_MEGA_FGBG_IMAGE:
+ return "MEGA_MEGA_FGBG_IMAGE";
+ case LITE_SET_FG_FGBG_IMAGE:
+ return "LITE_SET_FG_FGBG_IMAGE";
+ case MEGA_MEGA_SET_FGBG_IMAGE:
+ return "MEGA_MEGA_SET_FGBG_IMAGE";
+ case REGULAR_COLOR_IMAGE:
+ return "REGULAR_COLOR_IMAGE";
+ case MEGA_MEGA_COLOR_IMAGE:
+ return "MEGA_MEGA_COLOR_IMAGE";
+ case SPECIAL_FGBG_1:
+ return "SPECIAL_FGBG_1";
+ case SPECIAL_FGBG_2:
+ return "SPECIAL_FGBG_2";
+ case SPECIAL_WHITE:
+ return "SPECIAL_WHITE";
+ case SPECIAL_BLACK:
+ return "SPECIAL_BLACK";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static const char* rle_code_str_buffer(UINT32 code, char* buffer, size_t size)
+{
+ const char* str = rle_code_str(code);
+ _snprintf(buffer, size, "%s [0x%08" PRIx32 "]", str, code);
+ return buffer;
+}
+
+#define buffer_within_range(pbSrc, size, pbEnd) \
+ buffer_within_range_((pbSrc), (size), (pbEnd), __func__, __FILE__, __LINE__)
+static INLINE BOOL buffer_within_range_(const void* pbSrc, size_t size, const void* pbEnd,
+ const char* fkt, const char* file, size_t line)
+{
+ WINPR_UNUSED(file);
+ WINPR_ASSERT(pbSrc);
+ WINPR_ASSERT(pbEnd);
+
+ if ((const char*)pbSrc + size > (const char*)pbEnd)
+ {
+ WLog_ERR(TAG, "[%s:%" PRIuz "] pbSrc=%p + %" PRIuz " > pbEnd=%p", fkt, line, pbSrc, size,
+ pbEnd);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Reads the supplied order header and extracts the compression
+ * order code ID.
+ */
+static INLINE UINT32 ExtractCodeId(BYTE bOrderHdr)
+{
+ if ((bOrderHdr & 0xC0U) != 0xC0U)
+ {
+ /* REGULAR orders
+ * (000x xxxx, 001x xxxx, 010x xxxx, 011x xxxx, 100x xxxx)
+ */
+ return bOrderHdr >> 5;
+ }
+ else if ((bOrderHdr & 0xF0U) == 0xF0U)
+ {
+ /* MEGA and SPECIAL orders (0xF*) */
+ return bOrderHdr;
+ }
+ else
+ {
+ /* LITE orders
+ * 1100 xxxx, 1101 xxxx, 1110 xxxx)
+ */
+ return bOrderHdr >> 4;
+ }
+}
+
+/**
+ * Extract the run length of a compression order.
+ */
+static UINT ExtractRunLengthRegularFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
+{
+ UINT runLength = 0;
+
+ WINPR_ASSERT(pbOrderHdr);
+ WINPR_ASSERT(pbEnd);
+ WINPR_ASSERT(advance);
+
+ runLength = (*pbOrderHdr) & g_MaskRegularRunLength;
+ if (runLength == 0)
+ {
+ if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
+ {
+ *advance = 0;
+ return 0;
+ }
+ runLength = *(pbOrderHdr + 1) + 1;
+ (*advance)++;
+ }
+ else
+ runLength = runLength * 8;
+
+ return runLength;
+}
+
+static UINT ExtractRunLengthLiteFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
+{
+ UINT runLength = 0;
+
+ WINPR_ASSERT(pbOrderHdr);
+ WINPR_ASSERT(pbEnd);
+ WINPR_ASSERT(advance);
+
+ runLength = *pbOrderHdr & g_MaskLiteRunLength;
+ if (runLength == 0)
+ {
+ if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
+ {
+ *advance = 0;
+ return 0;
+ }
+ runLength = *(pbOrderHdr + 1) + 1;
+ (*advance)++;
+ }
+ else
+ runLength = runLength * 8;
+
+ return runLength;
+}
+
+static UINT ExtractRunLengthRegular(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
+{
+ UINT runLength = 0;
+
+ WINPR_ASSERT(pbOrderHdr);
+ WINPR_ASSERT(pbEnd);
+ WINPR_ASSERT(advance);
+
+ runLength = *pbOrderHdr & g_MaskRegularRunLength;
+ if (runLength == 0)
+ {
+ if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
+ {
+ *advance = 0;
+ return 0;
+ }
+ runLength = *(pbOrderHdr + 1) + 32;
+ (*advance)++;
+ }
+
+ return runLength;
+}
+
+static UINT ExtractRunLengthMegaMega(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
+{
+ UINT runLength = 0;
+
+ WINPR_ASSERT(pbOrderHdr);
+ WINPR_ASSERT(pbEnd);
+ WINPR_ASSERT(advance);
+
+ if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
+ {
+ *advance = 0;
+ return 0;
+ }
+
+ runLength = ((UINT16)pbOrderHdr[1]) | (((UINT16)pbOrderHdr[2]) << 8);
+ (*advance) += 2;
+
+ return runLength;
+}
+
+static UINT ExtractRunLengthLite(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
+{
+ UINT runLength = 0;
+
+ WINPR_ASSERT(pbOrderHdr);
+ WINPR_ASSERT(pbEnd);
+ WINPR_ASSERT(advance);
+
+ runLength = *pbOrderHdr & g_MaskLiteRunLength;
+ if (runLength == 0)
+ {
+ if (!buffer_within_range(pbOrderHdr, 1, pbEnd))
+ {
+ *advance = 0;
+ return 0;
+ }
+ runLength = *(pbOrderHdr + 1) + 16;
+ (*advance)++;
+ }
+ return runLength;
+}
+
+static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const BYTE* pbEnd,
+ UINT32* advance)
+{
+ UINT32 runLength = 0;
+ UINT32 ladvance = 1;
+
+ WINPR_ASSERT(pbOrderHdr);
+ WINPR_ASSERT(pbEnd);
+ WINPR_ASSERT(advance);
+
+ *advance = 0;
+ if (!buffer_within_range(pbOrderHdr, 0, pbEnd))
+ return 0;
+
+ switch (code)
+ {
+ case REGULAR_FGBG_IMAGE:
+ runLength = ExtractRunLengthRegularFgBg(pbOrderHdr, pbEnd, &ladvance);
+ break;
+
+ case LITE_SET_FG_FGBG_IMAGE:
+ runLength = ExtractRunLengthLiteFgBg(pbOrderHdr, pbEnd, &ladvance);
+ break;
+
+ case REGULAR_BG_RUN:
+ case REGULAR_FG_RUN:
+ case REGULAR_COLOR_RUN:
+ case REGULAR_COLOR_IMAGE:
+ runLength = ExtractRunLengthRegular(pbOrderHdr, pbEnd, &ladvance);
+ break;
+
+ case LITE_SET_FG_FG_RUN:
+ case LITE_DITHERED_RUN:
+ runLength = ExtractRunLengthLite(pbOrderHdr, pbEnd, &ladvance);
+ break;
+
+ case MEGA_MEGA_BG_RUN:
+ case MEGA_MEGA_FG_RUN:
+ case MEGA_MEGA_SET_FG_RUN:
+ case MEGA_MEGA_DITHERED_RUN:
+ case MEGA_MEGA_COLOR_RUN:
+ case MEGA_MEGA_FGBG_IMAGE:
+ case MEGA_MEGA_SET_FGBG_IMAGE:
+ case MEGA_MEGA_COLOR_IMAGE:
+ runLength = ExtractRunLengthMegaMega(pbOrderHdr, pbEnd, &ladvance);
+ break;
+
+ default:
+ runLength = 0;
+ ladvance = 0;
+ break;
+ }
+
+ *advance = ladvance;
+ return runLength;
+}
+
+#define ensure_capacity(start, end, size, base) \
+ ensure_capacity_((start), (end), (size), (base), __func__, __FILE__, __LINE__)
+static INLINE BOOL ensure_capacity_(const BYTE* start, const BYTE* end, size_t size, size_t base,
+ const char* fkt, const char* file, size_t line)
+{
+ const size_t available = (uintptr_t)end - (uintptr_t)start;
+ const BOOL rc = available >= size * base;
+ const BOOL res = rc && (start <= end);
+
+ if (!res)
+ WLog_ERR(TAG,
+ "[%s:%" PRIuz "] failed: start=%p <= end=%p, available=%" PRIuz " >= size=%" PRIuz
+ " * base=%" PRIuz,
+ fkt, line, start, end, available, size, base);
+ return res;
+}
+
+static INLINE void write_pixel_8(BYTE* _buf, BYTE _pix)
+{
+ WINPR_ASSERT(_buf);
+ *_buf = _pix;
+}
+
+static INLINE void write_pixel_24(BYTE* _buf, UINT32 _pix)
+{
+ WINPR_ASSERT(_buf);
+ (_buf)[0] = (BYTE)(_pix);
+ (_buf)[1] = (BYTE)((_pix) >> 8);
+ (_buf)[2] = (BYTE)((_pix) >> 16);
+}
+
+static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix)
+{
+ WINPR_ASSERT(_buf);
+ _buf[0] = _pix & 0xFF;
+ _buf[1] = (_pix >> 8) & 0xFF;
+}
+
+#undef DESTWRITEPIXEL
+#undef DESTREADPIXEL
+#undef SRCREADPIXEL
+#undef WRITEFGBGIMAGE
+#undef WRITEFIRSTLINEFGBGIMAGE
+#undef RLEDECOMPRESS
+#undef RLEEXTRA
+#undef WHITE_PIXEL
+#undef PIXEL_SIZE
+#undef PIXEL
+#define PIXEL_SIZE 1
+#define PIXEL BYTE
+#define WHITE_PIXEL 0xFF
+#define DESTWRITEPIXEL(_buf, _pix) \
+ do \
+ { \
+ write_pixel_8(_buf, _pix); \
+ _buf += 1; \
+ } while (0)
+#define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0]
+#define SRCREADPIXEL(_pix, _buf) \
+ do \
+ { \
+ _pix = (_buf)[0]; \
+ _buf += 1; \
+ } while (0)
+
+#define WRITEFGBGIMAGE WriteFgBgImage8to8
+#define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage8to8
+#define RLEDECOMPRESS RleDecompress8to8
+#define RLEEXTRA
+#undef ENSURE_CAPACITY
+#define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 1)
+#include "include/bitmap.c"
+
+#undef DESTWRITEPIXEL
+#undef DESTREADPIXEL
+#undef SRCREADPIXEL
+#undef WRITEFGBGIMAGE
+#undef WRITEFIRSTLINEFGBGIMAGE
+#undef RLEDECOMPRESS
+#undef RLEEXTRA
+#undef WHITE_PIXEL
+#undef PIXEL_SIZE
+#undef PIXEL
+#define PIXEL_SIZE 2
+#define PIXEL UINT16
+#define WHITE_PIXEL 0xFFFF
+#define DESTWRITEPIXEL(_buf, _pix) \
+ do \
+ { \
+ write_pixel_16(_buf, _pix); \
+ _buf += 2; \
+ } while (0)
+#define DESTREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0]
+#define SRCREADPIXEL(_pix, _buf) \
+ do \
+ { \
+ _pix = (_buf)[0] | ((_buf)[1] << 8); \
+ _buf += 2; \
+ } while (0)
+#define WRITEFGBGIMAGE WriteFgBgImage16to16
+#define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage16to16
+#define RLEDECOMPRESS RleDecompress16to16
+#define RLEEXTRA
+#undef ENSURE_CAPACITY
+#define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 2)
+#include "include/bitmap.c"
+
+#undef DESTWRITEPIXEL
+#undef DESTREADPIXEL
+#undef SRCREADPIXEL
+#undef WRITEFGBGIMAGE
+#undef WRITEFIRSTLINEFGBGIMAGE
+#undef RLEDECOMPRESS
+#undef RLEEXTRA
+#undef WHITE_PIXEL
+#undef PIXEL_SIZE
+#undef PIXEL
+#define PIXEL_SIZE 3
+#define PIXEL UINT32
+#define WHITE_PIXEL 0xffffff
+#define DESTWRITEPIXEL(_buf, _pix) \
+ do \
+ { \
+ write_pixel_24(_buf, _pix); \
+ _buf += 3; \
+ } while (0)
+#define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16)
+#define SRCREADPIXEL(_pix, _buf) \
+ do \
+ { \
+ _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16); \
+ _buf += 3; \
+ } while (0)
+
+#define WRITEFGBGIMAGE WriteFgBgImage24to24
+#define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage24to24
+#define RLEDECOMPRESS RleDecompress24to24
+#define RLEEXTRA
+#undef ENSURE_CAPACITY
+#define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 3)
+#include "include/bitmap.c"
+
+struct S_BITMAP_INTERLEAVED_CONTEXT
+{
+ BOOL Compressor;
+
+ UINT32 TempSize;
+ BYTE* TempBuffer;
+
+ wStream* bts;
+};
+
+BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE* pSrcData,
+ UINT32 SrcSize, UINT32 nSrcWidth, UINT32 nSrcHeight, UINT32 bpp,
+ BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst,
+ UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight,
+ const gdiPalette* palette)
+{
+ UINT32 scanline = 0;
+ UINT32 SrcFormat = 0;
+ UINT32 BufferSize = 0;
+
+ if (!interleaved || !pSrcData || !pDstData)
+ {
+ WLog_ERR(TAG, "invalid arguments: interleaved=%p, pSrcData=%p, pDstData=%p", interleaved,
+ pSrcData, pDstData);
+ return FALSE;
+ }
+
+ switch (bpp)
+ {
+ case 24:
+ scanline = nSrcWidth * 3;
+ SrcFormat = PIXEL_FORMAT_BGR24;
+ break;
+
+ case 16:
+ scanline = nSrcWidth * 2;
+ SrcFormat = PIXEL_FORMAT_RGB16;
+ break;
+
+ case 15:
+ scanline = nSrcWidth * 2;
+ SrcFormat = PIXEL_FORMAT_RGB15;
+ break;
+
+ case 8:
+ scanline = nSrcWidth;
+ SrcFormat = PIXEL_FORMAT_RGB8;
+ break;
+
+ default:
+ WLog_ERR(TAG, "Invalid color depth %" PRIu32 "", bpp);
+ return FALSE;
+ }
+
+ BufferSize = scanline * nSrcHeight;
+
+ if (BufferSize > interleaved->TempSize)
+ {
+ interleaved->TempBuffer =
+ winpr_aligned_recalloc(interleaved->TempBuffer, BufferSize, sizeof(BYTE), 16);
+ interleaved->TempSize = BufferSize;
+ }
+
+ if (!interleaved->TempBuffer)
+ {
+ WLog_ERR(TAG, "interleaved->TempBuffer=%p", interleaved->TempBuffer);
+ return FALSE;
+ }
+
+ switch (bpp)
+ {
+ case 24:
+ if (!RleDecompress24to24(pSrcData, SrcSize, interleaved->TempBuffer, scanline,
+ nSrcWidth, nSrcHeight))
+ {
+ WLog_ERR(TAG, "RleDecompress24to24 failed");
+ return FALSE;
+ }
+
+ break;
+
+ case 16:
+ case 15:
+ if (!RleDecompress16to16(pSrcData, SrcSize, interleaved->TempBuffer, scanline,
+ nSrcWidth, nSrcHeight))
+ {
+ WLog_ERR(TAG, "RleDecompress16to16 failed");
+ return FALSE;
+ }
+
+ break;
+
+ case 8:
+ if (!RleDecompress8to8(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nSrcWidth,
+ nSrcHeight))
+ {
+ WLog_ERR(TAG, "RleDecompress8to8 failed");
+ return FALSE;
+ }
+
+ break;
+
+ default:
+ WLog_ERR(TAG, "Invalid color depth %" PRIu32 "", bpp);
+ return FALSE;
+ }
+
+ if (!freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight,
+ interleaved->TempBuffer, SrcFormat, scanline, 0, 0, palette,
+ FREERDP_FLIP_VERTICAL | FREERDP_KEEP_DST_ALPHA))
+ {
+ WLog_ERR(TAG, "freerdp_image_copy failed");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstData, UINT32* pDstSize,
+ UINT32 nWidth, UINT32 nHeight, const BYTE* pSrcData, UINT32 SrcFormat,
+ UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette,
+ UINT32 bpp)
+{
+ BOOL status = 0;
+ wStream* s = NULL;
+ UINT32 DstFormat = 0;
+ const UINT32 maxSize = 64 * 64 * 4;
+
+ if (!interleaved || !pDstData || !pSrcData)
+ return FALSE;
+
+ if ((nWidth == 0) || (nHeight == 0))
+ return FALSE;
+
+ if (nWidth % 4)
+ {
+ WLog_ERR(TAG, "interleaved_compress: width is not a multiple of 4");
+ return FALSE;
+ }
+
+ if ((nWidth > 64) || (nHeight > 64))
+ {
+ WLog_ERR(TAG,
+ "interleaved_compress: width (%" PRIu32 ") or height (%" PRIu32
+ ") is greater than 64",
+ nWidth, nHeight);
+ return FALSE;
+ }
+
+ switch (bpp)
+ {
+ case 24:
+ DstFormat = PIXEL_FORMAT_BGRX32;
+ break;
+
+ case 16:
+ DstFormat = PIXEL_FORMAT_RGB16;
+ break;
+
+ case 15:
+ DstFormat = PIXEL_FORMAT_RGB15;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ if (!freerdp_image_copy(interleaved->TempBuffer, DstFormat, 0, 0, 0, nWidth, nHeight, pSrcData,
+ SrcFormat, nSrcStep, nXSrc, nYSrc, palette, FREERDP_KEEP_DST_ALPHA))
+ return FALSE;
+
+ s = Stream_New(pDstData, *pDstSize);
+
+ if (!s)
+ return FALSE;
+
+ Stream_SetPosition(interleaved->bts, 0);
+
+ if (freerdp_bitmap_compress(interleaved->TempBuffer, nWidth, nHeight, s, bpp, maxSize,
+ nHeight - 1, interleaved->bts, 0) < 0)
+ status = FALSE;
+ else
+ status = TRUE;
+
+ Stream_SealLength(s);
+ *pDstSize = (UINT32)Stream_Length(s);
+ Stream_Free(s, FALSE);
+ return status;
+}
+
+BOOL bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved)
+{
+ if (!interleaved)
+ return FALSE;
+
+ return TRUE;
+}
+
+BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor)
+{
+ BITMAP_INTERLEAVED_CONTEXT* interleaved = NULL;
+ interleaved = (BITMAP_INTERLEAVED_CONTEXT*)winpr_aligned_recalloc(
+ NULL, 1, sizeof(BITMAP_INTERLEAVED_CONTEXT), 32);
+
+ if (interleaved)
+ {
+ interleaved->TempSize = 64 * 64 * 4;
+ interleaved->TempBuffer = winpr_aligned_calloc(interleaved->TempSize, sizeof(BYTE), 16);
+
+ if (!interleaved->TempBuffer)
+ goto fail;
+
+ interleaved->bts = Stream_New(NULL, interleaved->TempSize);
+
+ if (!interleaved->bts)
+ goto fail;
+ }
+
+ return interleaved;
+
+fail:
+ bitmap_interleaved_context_free(interleaved);
+ return NULL;
+}
+
+void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved)
+{
+ if (!interleaved)
+ return;
+
+ winpr_aligned_free(interleaved->TempBuffer);
+ Stream_Free(interleaved->bts, TRUE);
+ winpr_aligned_free(interleaved);
+}