From 0e27f5abe40f9f5da4c9939da7acc1c1841b42ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 13 Jun 2014 12:17:16 -0400 Subject: [PATCH] libfreerdp-codec: start working on clearcodec decompressor --- include/freerdp/codec/clear.h | 4 + libfreerdp/codec/clear.c | 231 ++++++++++++++++++ libfreerdp/codec/test/TestFreeRDPCodecClear.c | 134 ++++++++++ 3 files changed, 369 insertions(+) diff --git a/include/freerdp/codec/clear.h b/include/freerdp/codec/clear.h index dc5e81a83..c7fc22433 100644 --- a/include/freerdp/codec/clear.h +++ b/include/freerdp/codec/clear.h @@ -23,6 +23,10 @@ #include #include +#define CLEARCODEC_FLAG_GLYPH_INDEX 0x01 +#define CLEARCODEC_FLAG_GLYPH_HIT 0x02 +#define CLEARCODEC_FLAG_CACHE_RESET 0x03 + struct _CLEAR_CONTEXT { BOOL Compressor; diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index 564e5d364..d0bc0924f 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -29,6 +29,237 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize) { + BYTE glyphFlags; + BYTE seqNumber; + UINT16 glyphIndex; + UINT32 offset = 0; + UINT32 residualByteCount; + UINT32 bandsByteCount; + UINT32 subcodecByteCount; + + if (SrcSize < 2) + return -1; + + glyphFlags = pSrcData[0]; + seqNumber = pSrcData[1]; + offset += 2; + + printf("glyphFlags: 0x%02X seqNumber: %d\n", glyphFlags, seqNumber); + + if (glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX) + { + if (SrcSize < 4) + return -1; + + glyphIndex = *((UINT16*) &pSrcData[2]); + offset += 2; + + if (glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT) + { + /** + * Copy pixels from the Decompressor Glyph Storage position + * specified by the glyphIndex field to the output bitmap + */ + + return 1; /* Finish */ + } + } + + /* Read composition payload header parameters */ + + if ((SrcSize - offset) < 12) + return -1; + + residualByteCount = *((UINT32*) &pSrcData[offset]); + bandsByteCount = *((UINT32*) &pSrcData[offset + 4]); + subcodecByteCount = *((UINT32*) &pSrcData[offset + 8]); + offset += 12; + + printf("residualByteCount: %d bandsByteCount: %d subcodecByteCount: %d\n", + residualByteCount, bandsByteCount, subcodecByteCount); + + if (residualByteCount > 0) + { + BYTE blueValue; + BYTE greenValue; + BYTE redValue; + UINT32 suboffset; + BYTE* residualData; + BYTE runLengthFactor1 = 0; + UINT16 runLengthFactor2 = 0; + UINT32 runLengthFactor3 = 0; + UINT32 runLengthFactor = 0; + + if ((SrcSize - offset) < residualByteCount) + return -1; + + suboffset = 0; + residualData = &pSrcData[offset]; + + while (suboffset < residualByteCount) + { + if ((residualByteCount - suboffset) < 4) + return -1; + + blueValue = residualData[suboffset]; + greenValue = residualData[suboffset + 1]; + redValue = residualData[suboffset + 2]; + suboffset += 3; + + runLengthFactor1 = residualData[suboffset]; + runLengthFactor = runLengthFactor1; + suboffset += 1; + + if (runLengthFactor1 >= 0xFF) + { + if ((residualByteCount - suboffset) < 2) + return -1; + + runLengthFactor2 = *((UINT16*) &residualData[suboffset]); + runLengthFactor = runLengthFactor2; + suboffset += 2; + + if (runLengthFactor2 >= 0xFFFF) + { + if ((residualByteCount - suboffset) < 4) + return -1; + + runLengthFactor3 = *((UINT32*) &residualData[suboffset]); + runLengthFactor = runLengthFactor3; + suboffset += 4; + } + } + } + + /* Decompress residual layer and write to output bitmap */ + offset += residualByteCount; + } + + if (bandsByteCount > 0) + { + BYTE* bandsData; + UINT32 suboffset; + + if ((SrcSize - offset) < bandsByteCount) + return -1; + + suboffset = 0; + bandsData = &pSrcData[offset]; + + while (suboffset < bandsByteCount) + { + UINT16 xStart; + UINT16 xEnd; + UINT16 yStart; + UINT16 yEnd; + BYTE blueBkg; + BYTE greenBkg; + BYTE redBkg; + BYTE* vBars; + UINT16 vBarHeader; + + if ((bandsByteCount - suboffset) < 11) + return -1; + + xStart = *((UINT16*) &bandsData[suboffset]); + xEnd = *((UINT16*) &bandsData[suboffset + 2]); + yStart = *((UINT16*) &bandsData[suboffset + 4]); + yEnd = *((UINT16*) &bandsData[suboffset + 6]); + blueBkg = bandsData[suboffset + 8]; + greenBkg = bandsData[suboffset + 9]; + redBkg = bandsData[suboffset + 10]; + suboffset += 11; + + vBars = &bandsData[suboffset]; + + vBarHeader = *((UINT16*) &vBars[0]); + + if ((vBarHeader & 0xC000) == 0x8000) /* VBAR_CACHE_HIT */ + { + printf("VBAR_CACHE_HIT\n"); + suboffset += 2; + } + else if ((vBarHeader & 0xC000) == 0xC000) /* SHORT_VBAR_CACHE_HIT */ + { + printf("SHORT_VBAR_CACHE_HIT\n"); + suboffset += 3; + } + else if ((vBarHeader & 0xC000) == 0) /* SHORT_VBAR_CACHE_MISS */ + { + printf("SHORT_VBAR_CACHE_MISS\n"); + suboffset += 2; + } + else + { + return -1; /* invalid vBarHeader */ + } + + /* shortVBarPixels: variable */ + } + + /* Decompress bands layer and write to output bitmap */ + offset += bandsByteCount; + } + + if (subcodecByteCount > 0) + { + UINT16 xStart; + UINT16 yStart; + UINT16 width; + UINT16 height; + BYTE* bitmapData; + UINT32 bitmapDataByteCount; + BYTE subcodecId; + BYTE* subcodecs; + UINT32 suboffset; + + if ((SrcSize - offset) < subcodecByteCount) + return -1; + + suboffset = 0; + subcodecs = &pSrcData[offset]; + + while (suboffset < subcodecByteCount) + { + if ((subcodecByteCount - suboffset) < 13) + return -1; + + xStart = *((UINT16*) &subcodecs[suboffset]); + yStart = *((UINT16*) &subcodecs[suboffset + 2]); + width = *((UINT16*) &subcodecs[suboffset + 4]); + height = *((UINT16*) &subcodecs[suboffset + 6]); + bitmapDataByteCount = *((UINT32*) &subcodecs[suboffset + 8]); + subcodecId = subcodecs[suboffset + 12]; + suboffset += 13; + + printf("bitmapDataByteCount: %d subcodecByteCount: %d suboffset: %d\n", + bitmapDataByteCount, subcodecByteCount, suboffset); + + if ((subcodecByteCount - suboffset) < bitmapDataByteCount) + return -1; + + bitmapData = &subcodecs[suboffset]; + + suboffset += bitmapDataByteCount; + } + + /* Decompress subcodec layer and write to output bitmap */ + offset += subcodecByteCount; + } + + if (glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX) + { + /** + * Copy decompressed bitmap to the Decompressor Glyph + * Storage position specified by the glyphIndex field + */ + } + + if (offset != SrcSize) + { + printf("clear_decompress: incomplete processing of bytes: Actual: %d, Expected: %d\n", offset, SrcSize); + } + return 1; } diff --git a/libfreerdp/codec/test/TestFreeRDPCodecClear.c b/libfreerdp/codec/test/TestFreeRDPCodecClear.c index 6db7e6e12..c83993b0f 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecClear.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecClear.c @@ -3,8 +3,142 @@ #include +static BYTE TEST_CLEAR_EXAMPLE_1[] = "\x03\xc3\x11\x00"; + +static BYTE TEST_CLEAR_EXAMPLE_2[] = + "\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x82\x00\x00\x00\x00\x00" + "\x00\x00\x4e\x00\x11\x00\x75\x00\x00\x00\x02\x0e\xff\xff\xff\x00" + "\x00\x00\xdb\xff\xff\x00\x3a\x90\xff\xb6\x66\x66\xb6\xff\xb6\x66" + "\x00\x90\xdb\xff\x00\x00\x3a\xdb\x90\x3a\x3a\x90\xdb\x66\x00\x00" + "\xff\xff\xb6\x64\x64\x64\x11\x04\x11\x4c\x11\x4c\x11\x4c\x11\x4c" + "\x11\x4c\x00\x47\x13\x00\x01\x01\x04\x00\x01\x00\x00\x47\x16\x00" + "\x11\x02\x00\x47\x29\x00\x11\x01\x00\x49\x0a\x00\x01\x00\x04\x00" + "\x01\x00\x00\x4a\x0a\x00\x09\x00\x01\x00\x00\x47\x05\x00\x01\x01" + "\x1c\x00\x01\x00\x11\x4c\x11\x4c\x11\x4c\x00\x47\x0d\x4d\x00\x4d"; + +static BYTE TEST_CLEAR_EXAMPLE_3[] = + "\x00\xdf\x0e\x00\x00\x00\x8b\x00\x00\x00\x00\x00\x00\x00\xfe\xfe" + "\xfe\xff\x80\x05\xff\xff\xff\x40\xfe\xfe\xfe\x40\x00\x00\x3f\x00" + "\x03\x00\x0b\x00\xfe\xfe\xfe\xc5\xd0\xc6\xd0\xc7\xd0\x68\xd4\x69" + "\xd4\x6a\xd4\x6b\xd4\x6c\xd4\x6d\xd4\x1a\xd4\x1a\xd4\xa6\xd0\x6e" + "\xd4\x6f\xd4\x70\xd4\x71\xd4\x72\xd4\x73\xd4\x74\xd4\x21\xd4\x22" + "\xd4\x23\xd4\x24\xd4\x25\xd4\xd9\xd0\xda\xd0\xdb\xd0\xc5\xd0\xc5" + "\xd0\xdc\xd0\xc2\xd0\x21\xd4\x22\xd4\x23\xd4\x24\xd4\x25\xd4\xc9" + "\xd0\xca\xd0\x5a\xd4\x2b\xd1\x28\xd1\x2c\xd1\x75\xd4\x27\xd4\x28" + "\xd4\x29\xd4\x2a\xd4\x1a\xd4\x1a\xd4\x1a\xd4\xb7\xd0\xb8\xd0\xb9" + "\xd0\xba\xd0\xbb\xd0\xbc\xd0\xbd\xd0\xbe\xd0\xbf\xd0\xc0\xd0\xc1" + "\xd0\xc2\xd0\xc3\xd0\xc4\xd0"; + +static BYTE TEST_CLEAR_EXAMPLE_4[] = + "\x01\x0b\x78\x00\x00\x00\x00\x00\x46\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x06\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x0f\xff\xff\xff" + "\xff\xff\xff\xff\xff\xff\xb6\xff\xff\xff\xff\xff\xff\xff\xff\xff" + "\xb6\x66\xff\xff\xff\xff\xff\xff\xff\xb6\x66\xdb\x90\x3a\xff\xff" + "\xb6\xff\xff\xff\xff\xff\xff\xff\xff\xff\x46\x91\x47\x91\x48\x91" + "\x49\x91\x4a\x91\x1b\x91"; + +int test_ClearDecompressExample1() +{ + int status; + BYTE* pSrcData; + UINT32 SrcSize; + UINT32 DstSize; + BYTE* pDstData = NULL; + CLEAR_CONTEXT* clear; + + clear = clear_context_new(FALSE); + + SrcSize = sizeof(TEST_CLEAR_EXAMPLE_1) - 1; + pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_1; + + status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize); + + printf("clear_decompress example 1 status: %d\n", status); + + clear_context_free(clear); + + return 1; +} + +int test_ClearDecompressExample2() +{ + int status; + BYTE* pSrcData; + UINT32 SrcSize; + UINT32 DstSize; + BYTE* pDstData = NULL; + CLEAR_CONTEXT* clear; + + clear = clear_context_new(FALSE); + + SrcSize = sizeof(TEST_CLEAR_EXAMPLE_2) - 1; + pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_2; + + status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize); + + printf("clear_decompress example 2 status: %d\n", status); + + clear_context_free(clear); + + return 1; +} + +int test_ClearDecompressExample3() +{ + int status; + BYTE* pSrcData; + UINT32 SrcSize; + UINT32 DstSize; + BYTE* pDstData = NULL; + CLEAR_CONTEXT* clear; + + clear = clear_context_new(FALSE); + + SrcSize = sizeof(TEST_CLEAR_EXAMPLE_3) - 1; + pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_3; + + status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize); + + printf("clear_decompress example 3 status: %d\n", status); + + clear_context_free(clear); + + return 1; +} + +int test_ClearDecompressExample4() +{ + int status; + BYTE* pSrcData; + UINT32 SrcSize; + UINT32 DstSize; + BYTE* pDstData = NULL; + CLEAR_CONTEXT* clear; + + clear = clear_context_new(FALSE); + + SrcSize = sizeof(TEST_CLEAR_EXAMPLE_4) - 1; + pSrcData = (BYTE*) TEST_CLEAR_EXAMPLE_4; + + status = clear_decompress(clear, pSrcData, SrcSize, &pDstData, &DstSize); + + printf("clear_decompress example 4 status: %d\n", status); + + clear_context_free(clear); + + return 1; +} + int TestFreeRDPCodecClear(int argc, char* argv[]) { + //test_ClearDecompressExample1(); + + //test_ClearDecompressExample2(); + + test_ClearDecompressExample3(); + + //test_ClearDecompressExample4(); + return 0; }