From d9a2fb4ff9a4a6b921aa01e64a84b51c5269452e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 8 Mar 2014 17:38:47 -0500 Subject: [PATCH 1/9] libfreerdp-codec: start MPPC compressor --- include/freerdp/codec/mppc.h | 1 + libfreerdp/codec/mppc.c | 201 +++++++++++++++++-- libfreerdp/codec/test/TestFreeRDPCodecMppc.c | 98 ++++++++- winpr/include/winpr/bitstream.h | 95 +++++++++ winpr/include/winpr/collections.h | 60 +----- winpr/libwinpr/utils/collections/BitStream.c | 7 +- winpr/libwinpr/utils/test/TestBitStream.c | 2 +- 7 files changed, 382 insertions(+), 82 deletions(-) create mode 100644 winpr/include/winpr/bitstream.h diff --git a/include/freerdp/codec/mppc.h b/include/freerdp/codec/mppc.h index a4eae83c2..27ae01572 100644 --- a/include/freerdp/codec/mppc.h +++ b/include/freerdp/codec/mppc.h @@ -45,6 +45,7 @@ extern "C" { #endif FREERDP_API UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize); +FREERDP_API UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize, UINT32 flags); FREERDP_API MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor); FREERDP_API void mppc_context_free(MPPC_CONTEXT* mppc); diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index 51b2dc5b5..48f4b4a56 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include @@ -72,6 +72,179 @@ const UINT32 MPPC_MATCH_TABLE[256] = //#define DEBUG_MPPC 1 +void BitStream_Prefetch(wBitStream* bs) +{ + (bs->prefetch) = 0; + if ((bs->pointer - bs->buffer) < (bs->capacity + 4)) + (bs->prefetch) |= (*(bs->pointer + 4) << 24); + if ((bs->pointer - bs->buffer) < (bs->capacity + 5)) + (bs->prefetch) |= (*(bs->pointer + 5) << 16); + if ((bs->pointer - bs->buffer) < (bs->capacity + 6)) + (bs->prefetch) |= (*(bs->pointer + 6) << 8); + if ((bs->pointer - bs->buffer) < (bs->capacity + 7)) + (bs->prefetch) |= (*(bs->pointer + 7) << 0); +} + +void BitStream_Fetch(wBitStream* bs) +{ + (bs->accumulator) = 0; + if ((bs->pointer - bs->buffer) < (bs->capacity + 0)) + (bs->accumulator) |= (*(bs->pointer + 0) << 24); + if ((bs->pointer - bs->buffer) < (bs->capacity + 1)) + (bs->accumulator) |= (*(bs->pointer + 1) << 16); + if ((bs->pointer - bs->buffer) < (bs->capacity + 2)) + (bs->accumulator) |= (*(bs->pointer + 2) << 8); + if ((bs->pointer - bs->buffer) < (bs->capacity + 3)) + (bs->accumulator) |= (*(bs->pointer + 3) << 0); + + BitStream_Prefetch(bs); +} + +void BitStream_Shift(wBitStream* bs, UINT32 nbits) +{ + printf("BitStream_Shift: nbits: %d position: %d offset: %d Accumulator: 0x%04X\n", + nbits, bs->position, bs->offset, bs->accumulator); + + bs->accumulator <<= nbits; + bs->position += nbits; + bs->offset += nbits; + + printf("BitStream_Shift Accumulator shifted: 0x%04X\n", bs->accumulator); + + bs->mask = ((1 << nbits) - 1); + bs->accumulator |= ((bs->prefetch >> (32 - nbits)) & bs->mask); + bs->prefetch <<= nbits; + + if (bs->offset >= 32) + { + bs->offset = bs->offset - 32; + bs->pointer += 4; + + if (bs->offset) + printf("%d bits missing\n", bs->offset); + + BitStream_Prefetch(bs); + } +} + +UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize, UINT32 flags) +{ + int index; + BYTE Literal; + UINT32 CopyOffset; + UINT32 accumulator; + wBitStream* bs = mppc->bs; + + BitStream_Attach(bs, pSrcData, *pSize); + + if (flags & PACKET_AT_FRONT) + { + mppc->HistoryPtr = 0; + mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); + } + + if (flags & PACKET_FLUSHED) + { + mppc->HistoryPtr = 0; + mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); + + ZeroMemory(mppc->HistoryBuffer, mppc->HistoryBufferSize); + } + + if (!(flags & PACKET_COMPRESSED)) + { + CopyMemory(mppc->pHistoryPtr, pSrcData, *pSize); + mppc->HistoryPtr += *pSize; + mppc->pHistoryPtr += *pSize; + return 0; + } + + BitStream_Fetch(bs); + + for (index = 0; index < *pSize; index++) + { + accumulator = bs->accumulator; + + if ((accumulator & 0x80000000) == 0x00000000) + { + /** + * Literal, less than 0x80 + * bit 0 followed by the lower 7 bits of the literal + */ + + Literal = ((accumulator & 0x7F000000) >> 24); + printf("%c\n", Literal); + + BitStream_Shift(bs, 8); + } + else if ((accumulator & 0xC0000000) == 0x80000000) + { + /** + * Literal, greater than 0x7F + * bits 10 followed by the lower 7 bits of the literal + */ + + Literal = ((accumulator & 0x3F800000) >> 23) + 0x80; + printf("%c\n", Literal); + + BitStream_Shift(bs, 9); + } + else if ((accumulator & 0xF8000000) == 0xF8000000) + { + /** + * CopyOffset, range [0, 63] + * bits 11111 + lower 6 bits of CopyOffset + */ + + CopyOffset = ((accumulator >> 21) & 0x3F); + printf("CopyOffset: %d\n", (int) CopyOffset); + BitStream_Shift(bs, 11); + } + else if ((accumulator & 0xF8000000) == 0xF0000000) + { + /** + * CopyOffset, range [64, 319] + * bits 11110 + lower 8 bits of (CopyOffset - 64) + */ + + CopyOffset = ((accumulator >> 19) & 0xFF) + 64; + printf("CopyOffset: %d\n", (int) CopyOffset); + + BitStream_Shift(bs, 13); + } + else if ((accumulator & 0xF0000000) == 0xE0000000) + { + /** + * CopyOffset, range [320, 2367] + * bits 1110 + lower 11 bits of (CopyOffset - 320) + */ + + CopyOffset = ((accumulator >> 17) & 0x7FF) + 320; + printf("CopyOffset: %d\n", (int) CopyOffset); + + BitStream_Shift(bs, 15); + } + else if ((accumulator & 0xE0000000) == 0xC0000000) + { + /** + * CopyOffset, range [2368, ] + * bits 110 + lower 16 bits of (CopyOffset - 2368) + */ + + CopyOffset = ((accumulator >> 13) & 0xFFFF) + 2368; + printf("CopyOffset: %d\n", (int) CopyOffset); + + BitStream_Shift(bs, 19); + } + else + { + /* invalid encoding */ + } + } + + return 0; +} + UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize) { BYTE* pEnd; @@ -80,32 +253,28 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* UINT32 MatchIndex; UINT32 accumulator; - Flags = mppc->CompressionLevel; - BitStream_Attach(mppc->bs, pDstData, *pSize); - if (((mppc->HistoryOffset + *pSize) < (mppc->HistoryBufferSize - 3)) /* && mppc->HistoryOffset */) + CopyMemory(&(mppc->HistoryBuffer[mppc->HistoryOffset]), pSrcData, *pSize); + + mppc->HistoryPtr = 0; + mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); + + if (((mppc->HistoryOffset + *pSize) < (mppc->HistoryBufferSize - 3)) && mppc->HistoryOffset) { - /* SrcData fits into HistoryBuffer? (YES) */ - - CopyMemory(&(mppc->HistoryBuffer[mppc->HistoryOffset]), pSrcData, *pSize); - - mppc->HistoryPtr = 0; - mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); - - mppc->HistoryOffset += *pSize; - mppc->pHistoryOffset = &(mppc->HistoryBuffer[mppc->HistoryOffset]); + Flags = mppc->CompressionLevel; } else { - /* SrcData fits into HistoryBuffer? (NO) */ - mppc->HistoryOffset = 0; mppc->pHistoryOffset = &(mppc->HistoryBuffer[mppc->HistoryOffset]); - Flags |= PACKET_AT_FRONT; + Flags = PACKET_AT_FRONT | mppc->CompressionLevel; } + mppc->HistoryOffset += *pSize; + mppc->pHistoryOffset = &(mppc->HistoryBuffer[mppc->HistoryOffset]); + if (mppc->HistoryPtr < mppc->HistoryOffset) { /* HistoryPtr < HistoryOffset? (YES) */ diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index 78565c58d..a0b8ea0b5 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -684,9 +685,28 @@ int test_mppc_old() return 0; } -const char TEST_MPPC_BELL_TOLLS[] = "for.whom.the.bell.tolls,.the.bell.tolls.for.thee!"; +/** + * for.whom.the.bell.tolls,.the.bell.tolls.for.thee! + * for.whom.the.bell.tolls,<16,15>.<40,4><19,3>e! + */ -int TestFreeRDPCodecMppc(int argc, char* argv[]) +const BYTE TEST_MPPC_BELLS[] = "for.whom.the.bell.tolls,.the.bell.tolls.for.thee!"; + +/* Flags: 0x0060 Length: 33 */ + +const BYTE TEST_MPPC_BELLS_RDP4[] = + "\x66\x6f\x72\x2e\x77\x68\x6f\x6d\x2e\x74\x68\x65\x2e\x62\x65\x6c" + "\x6c\x2e\x74\x6f\x6c\x6c\x73\x2c\xf4\x37\x2e\x66\xfa\x1f\x19\x94" + "\x84"; + +/* Flags: 0x0061 Length: 34 */ + +const BYTE TEST_MPPC_BELLS_RDP5[] = + "\x66\x6f\x72\x2e\x77\x68\x6f\x6d\x2e\x74\x68\x65\x2e\x62\x65\x6c" + "\x6c\x2e\x74\x6f\x6c\x6c\x73\x2c\xfa\x1b\x97\x33\x7e\x87\xe3\x32" + "\x90\x80"; + +int test_MppcCompressBells() { UINT32 size; UINT32 flags; @@ -696,15 +716,75 @@ int TestFreeRDPCodecMppc(int argc, char* argv[]) mppc = mppc_context_new(1, TRUE); -#if 0 - size = sizeof(TEST_MPPC_BELL_TOLLS) - 1; - pSrcData = (BYTE*) TEST_MPPC_BELL_TOLLS; + size = sizeof(TEST_MPPC_BELLS) - 1; + pSrcData = (BYTE*) TEST_MPPC_BELLS; printf("%s\n", pSrcData); flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); + printf("flags: 0x%04X size: %d\n", flags, size); + + if (memcmp(OutputBuffer, TEST_MPPC_BELLS_RDP5, size) != 0) + { + printf("Actual:\n"); + BitDump(OutputBuffer, size * 8, BITDUMP_MSB_FIRST); + + printf("Expected:\n"); + BitDump(TEST_MPPC_BELLS_RDP5, size * 8, BITDUMP_MSB_FIRST); + } + + mppc_context_free(mppc); + + return 0; +} + +int test_MppcDecompressBells() +{ + UINT32 size; + UINT32 flags; + BYTE* pSrcData; + MPPC_CONTEXT* mppc; + BYTE OutputBuffer[65536]; + + mppc = mppc_context_new(1, FALSE); + + size = sizeof(TEST_MPPC_BELLS_RDP5) - 1; + pSrcData = (BYTE*) TEST_MPPC_BELLS_RDP5; + flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1; + + flags = mppc_decompress(mppc, pSrcData, OutputBuffer, &size, flags); + + printf("flags: 0x%04X size: %d\n", flags, size); + printf("%s\n", OutputBuffer); + +#if 0 + size = sizeof(TEST_MPPC_BELLS) - 1; + + if (memcmp(OutputBuffer, TEST_MPPC_BELLS, sizeof(TEST_MPPC_BELLS) - 1) != 0) + { + printf("Actual:\n"); + BitDump(OutputBuffer, size * 8, BITDUMP_MSB_FIRST); + + printf("Expected:\n"); + BitDump(TEST_MPPC_BELLS, size * 8, BITDUMP_MSB_FIRST); + } #endif + mppc_context_free(mppc); + + return 0; +} + +int test_MppcCompressBuffer() +{ + UINT32 size; + UINT32 flags; + BYTE* pSrcData; + MPPC_CONTEXT* mppc; + BYTE OutputBuffer[65536]; + + mppc = mppc_context_new(1, TRUE); + size = sizeof(TEST_RDP5_UNCOMPRESSED_DATA); pSrcData = (BYTE*) TEST_RDP5_UNCOMPRESSED_DATA; @@ -720,3 +800,11 @@ int TestFreeRDPCodecMppc(int argc, char* argv[]) return 0; } + +int TestFreeRDPCodecMppc(int argc, char* argv[]) +{ + //test_MppcCompressBells(); + test_MppcDecompressBells(); + + return 0; +} diff --git a/winpr/include/winpr/bitstream.h b/winpr/include/winpr/bitstream.h new file mode 100644 index 000000000..47a5a68e3 --- /dev/null +++ b/winpr/include/winpr/bitstream.h @@ -0,0 +1,95 @@ +/* + * WinPR: Windows Portable Runtime + * BitStream Utils + * + * Copyright 2014 Marc-Andre Moreau + * + * 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. + */ + +#ifndef WINPR_UTILS_BITSTREAM_H +#define WINPR_UTILS_BITSTREAM_H + +#include +#include + +#include + +struct _wBitStream +{ + BYTE* buffer; + BYTE* pointer; + DWORD position; + DWORD length; + DWORD capacity; + UINT32 mask; + UINT32 offset; + UINT32 prefetch; + UINT32 accumulator; +}; +typedef struct _wBitStream wBitStream; + +#define BitStream_Attach(_bs, _buffer, _capacity) { \ + _bs->position = 0; \ + _bs->buffer = _buffer; \ + _bs->offset = 0; \ + _bs->accumulator = 0; \ + _bs->pointer = _bs->buffer; \ + _bs->capacity = _capacity; \ + _bs->length = _bs->capacity; \ +} + +#define BitStream_Write_Bits(_bs, _bits, _nbits) { \ + _bs->accumulator |= (_bits << _bs->offset); \ + _bs->position += _nbits; \ + _bs->offset += _nbits; \ + if (_bs->offset >= 32) { \ + *((UINT32*) _bs->pointer) = (_bs->accumulator); \ + _bs->offset = _bs->offset - 32; \ + _bs->accumulator = _bits >> (_nbits - _bs->offset); \ + _bs->pointer += 4; \ + } \ +} + +#define BitStream_Flush(_bs) { \ + if ((_bs->pointer - _bs->buffer) < (_bs->capacity + 3)) { \ + *((UINT32*) _bs->pointer) = (_bs->accumulator); \ + } else { \ + if ((_bs->pointer - _bs->buffer) < (_bs->capacity + 0)) \ + *(_bs->pointer + 0) = (_bs->accumulator >> 0); \ + if ((_bs->pointer - _bs->buffer) < (_bs->capacity + 1)) \ + *(_bs->pointer + 1) = (_bs->accumulator >> 8); \ + if ((_bs->pointer - _bs->buffer) < (_bs->capacity + 2)) \ + *(_bs->pointer + 2) = (_bs->accumulator >> 16); \ + if ((_bs->pointer - _bs->buffer) < (_bs->capacity + 3)) \ + *(_bs->pointer + 3) = (_bs->accumulator >> 24); \ + } \ +} + +#define BITDUMP_MSB_FIRST 0x00000001 +#define BITDUMP_STDERR 0x00000002 + +#ifdef __cplusplus +extern "C" { +#endif + +WINPR_API void BitDump(const BYTE* buffer, UINT32 length, UINT32 flags); + +WINPR_API wBitStream* BitStream_New(); +WINPR_API void BitStream_Free(wBitStream* bs); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_UTILS_BITSTREAM_H */ diff --git a/winpr/include/winpr/collections.h b/winpr/include/winpr/collections.h index 6268a9817..86bd34a87 100644 --- a/winpr/include/winpr/collections.h +++ b/winpr/include/winpr/collections.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -596,65 +597,8 @@ WINPR_API int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* conte WINPR_API wPubSub* PubSub_New(BOOL synchronized); WINPR_API void PubSub_Free(wPubSub* pubSub); -/* BitStream */ - -struct _wBitStream -{ - BYTE* buffer; - BYTE* pointer; - DWORD position; - DWORD length; - DWORD capacity; - UINT32 offset; - UINT32 accumulator; -}; -typedef struct _wBitStream wBitStream; - -#define BitStream_Attach(_bs, _buffer, _capacity) { \ - _bs->position = 0; \ - _bs->buffer = _buffer; \ - _bs->offset = 0; \ - _bs->accumulator = 0; \ - _bs->pointer = _bs->buffer; \ - _bs->capacity = _capacity; \ - _bs->length = _bs->capacity; \ -} - -#define BitStream_Write_Bits(_bs, _bits, _nbits) { \ - _bs->accumulator |= (_bits << _bs->offset); \ - _bs->position += _nbits; \ - _bs->offset += _nbits; \ - if (_bs->offset >= 32) { \ - *(_bs->pointer + 0) = (_bs->accumulator >> 0); \ - *(_bs->pointer + 1) = (_bs->accumulator >> 8); \ - *(_bs->pointer + 2) = (_bs->accumulator >> 16); \ - *(_bs->pointer + 3) = (_bs->accumulator >> 24); \ - _bs->offset = _bs->offset - 32; \ - _bs->accumulator = _bits >> (_nbits - _bs->offset); \ - _bs->pointer += 4; \ - } \ -} - -#define BitStream_Flush(_bs) { \ - if ((_bs->pointer - _bs->buffer) > 0) \ - *(_bs->pointer + 0) = (_bs->accumulator >> 0); \ - if ((_bs->pointer - _bs->buffer) > 1) \ - *(_bs->pointer + 1) = (_bs->accumulator >> 8); \ - if ((_bs->pointer - _bs->buffer) > 2) \ - *(_bs->pointer + 2) = (_bs->accumulator >> 16); \ - if ((_bs->pointer - _bs->buffer) > 3) \ - *(_bs->pointer + 3) = (_bs->accumulator >> 24); \ -} - -#define BITDUMP_MSB_FIRST 0x00000001 -#define BITDUMP_STDERR 0x00000002 - -WINPR_API void BitDump(BYTE* buffer, UINT32 length, UINT32 flags); - -WINPR_API wBitStream* BitStream_New(); -WINPR_API void BitStream_Free(wBitStream* bs); - #ifdef __cplusplus } #endif + #endif /* WINPR_COLLECTIONS_H */ diff --git a/winpr/libwinpr/utils/collections/BitStream.c b/winpr/libwinpr/utils/collections/BitStream.c index a2cb244e6..35ca916d9 100644 --- a/winpr/libwinpr/utils/collections/BitStream.c +++ b/winpr/libwinpr/utils/collections/BitStream.c @@ -21,7 +21,7 @@ #include "config.h" #endif -#include +#include const char* BYTE_BIT_STRINGS_LSB[256] = { @@ -159,7 +159,7 @@ const char* BYTE_BIT_STRINGS_MSB[256] = "00111111", "10111111", "01111111", "11111111" }; -void BitDump(BYTE* buffer, UINT32 length, UINT32 flags) +void BitDump(const BYTE* buffer, UINT32 length, UINT32 flags) { DWORD i; int nbits; @@ -174,6 +174,9 @@ void BitDump(BYTE* buffer, UINT32 length, UINT32 flags) nbits = (length - i) > 8 ? 8 : (length - i); + if ((i % 64) == 0) + printf("\n"); + printf("%.*s ", nbits, str); } diff --git a/winpr/libwinpr/utils/test/TestBitStream.c b/winpr/libwinpr/utils/test/TestBitStream.c index 4afbb575e..ec1d0d25b 100644 --- a/winpr/libwinpr/utils/test/TestBitStream.c +++ b/winpr/libwinpr/utils/test/TestBitStream.c @@ -2,7 +2,7 @@ #include #include #include -#include +#include void BitStrGen() { From 16c176dd5fc8f28406db84221c33dde5cf1bdd0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 8 Mar 2014 19:10:30 -0500 Subject: [PATCH 2/9] libfreerdp-codec: decode LengthOfMatch --- libfreerdp/codec/mppc.c | 242 ++++++++++++++++++++++++++++++++++------ 1 file changed, 209 insertions(+), 33 deletions(-) diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index 48f4b4a56..418c22c5e 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -102,40 +102,46 @@ void BitStream_Fetch(wBitStream* bs) void BitStream_Shift(wBitStream* bs, UINT32 nbits) { - printf("BitStream_Shift: nbits: %d position: %d offset: %d Accumulator: 0x%04X\n", - nbits, bs->position, bs->offset, bs->accumulator); - bs->accumulator <<= nbits; bs->position += nbits; bs->offset += nbits; - printf("BitStream_Shift Accumulator shifted: 0x%04X\n", bs->accumulator); - - bs->mask = ((1 << nbits) - 1); - bs->accumulator |= ((bs->prefetch >> (32 - nbits)) & bs->mask); - bs->prefetch <<= nbits; - - if (bs->offset >= 32) + if (bs->offset < 32) { - bs->offset = bs->offset - 32; + bs->mask = ((1 << nbits) - 1); + bs->accumulator |= ((bs->prefetch >> (32 - nbits)) & bs->mask); + bs->prefetch <<= nbits; + } + else + { + bs->mask = ((1 << nbits) - 1); + bs->accumulator |= ((bs->prefetch >> (32 - nbits)) & bs->mask); + bs->prefetch <<= nbits; + + bs->offset -= 32; bs->pointer += 4; - if (bs->offset) - printf("%d bits missing\n", bs->offset); - BitStream_Prefetch(bs); + + if (bs->offset) + { + bs->mask = ((1 << bs->offset) - 1); + bs->accumulator |= ((bs->prefetch >> (32 - bs->offset)) & bs->mask); + bs->prefetch <<= bs->offset; + } } } UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize, UINT32 flags) { - int index; BYTE Literal; UINT32 CopyOffset; + UINT32 LengthOfMatch; UINT32 accumulator; wBitStream* bs = mppc->bs; BitStream_Attach(bs, pSrcData, *pSize); + BitStream_Fetch(bs); if (flags & PACKET_AT_FRONT) { @@ -159,12 +165,14 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 return 0; } - BitStream_Fetch(bs); - - for (index = 0; index < *pSize; index++) + while (bs->position < (*pSize * 8)) { accumulator = bs->accumulator; + /** + * Literal Encoding + */ + if ((accumulator & 0x80000000) == 0x00000000) { /** @@ -173,9 +181,11 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 */ Literal = ((accumulator & 0x7F000000) >> 24); - printf("%c\n", Literal); + printf("L1: %c\n", Literal); BitStream_Shift(bs, 8); + + continue; } else if ((accumulator & 0xC0000000) == 0x80000000) { @@ -185,11 +195,20 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 */ Literal = ((accumulator & 0x3F800000) >> 23) + 0x80; - printf("%c\n", Literal); + printf("L2: %c\n", Literal); BitStream_Shift(bs, 9); + + continue; } - else if ((accumulator & 0xF8000000) == 0xF8000000) + + /** + * CopyOffset Encoding + */ + + CopyOffset = 0; + + if ((accumulator & 0xF8000000) == 0xF8000000) { /** * CopyOffset, range [0, 63] @@ -197,7 +216,6 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 */ CopyOffset = ((accumulator >> 21) & 0x3F); - printf("CopyOffset: %d\n", (int) CopyOffset); BitStream_Shift(bs, 11); } else if ((accumulator & 0xF8000000) == 0xF0000000) @@ -208,8 +226,6 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 */ CopyOffset = ((accumulator >> 19) & 0xFF) + 64; - printf("CopyOffset: %d\n", (int) CopyOffset); - BitStream_Shift(bs, 13); } else if ((accumulator & 0xF0000000) == 0xE0000000) @@ -220,8 +236,6 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 */ CopyOffset = ((accumulator >> 17) & 0x7FF) + 320; - printf("CopyOffset: %d\n", (int) CopyOffset); - BitStream_Shift(bs, 15); } else if ((accumulator & 0xE0000000) == 0xC0000000) @@ -232,14 +246,176 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 */ CopyOffset = ((accumulator >> 13) & 0xFFFF) + 2368; - printf("CopyOffset: %d\n", (int) CopyOffset); - BitStream_Shift(bs, 19); } else { - /* invalid encoding */ + /* Invalid CopyOffset Encoding */ } + + /** + * LengthOfMatch Encoding + */ + + LengthOfMatch = 0; + accumulator = bs->accumulator; + + if ((accumulator & 0x80000000) == 0x00000000) + { + /** + * LengthOfMatch [3] + * bit 0 + 0 lower bits of LengthOfMatch + */ + + LengthOfMatch = 3; + BitStream_Shift(bs, 1); + } + else if ((accumulator & 0xC0000000) == 0x80000000) + { + /** + * LengthOfMatch [4, 7] + * bits 10 + 2 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 28) & 0x0003) + 0x0004; + BitStream_Shift(bs, 4); + } + else if ((accumulator & 0xE0000000) == 0xC0000000) + { + /** + * LengthOfMatch [8, 15] + * bits 110 + 3 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 26) & 0x0007) + 0x0008; + BitStream_Shift(bs, 6); + } + else if ((accumulator & 0xF0000000) == 0xE0000000) + { + /** + * LengthOfMatch [16, 31] + * bits 1110 + 4 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 24) & 0x000F) + 0x0010; + BitStream_Shift(bs, 8); + } + else if ((accumulator & 0xF8000000) == 0xF0000000) + { + /** + * LengthOfMatch [32, 63] + * bits 11110 + 5 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 22) & 0x001F) + 0x0020; + BitStream_Shift(bs, 10); + } + else if ((accumulator & 0xFC000000) == 0xF8000000) + { + /** + * LengthOfMatch [64, 127] + * bits 111110 + 6 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 20) & 0x003F) + 0x0040; + BitStream_Shift(bs, 12); + } + else if ((accumulator & 0xFE000000) == 0xFC000000) + { + /** + * LengthOfMatch [128, 255] + * bits 1111110 + 7 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 18) & 0x007F) + 0x0080; + BitStream_Shift(bs, 14); + } + else if ((accumulator & 0xFF000000) == 0xFE000000) + { + /** + * LengthOfMatch [256, 511] + * bits 11111110 + 8 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 16) & 0x00FF) + 0x0100; + BitStream_Shift(bs, 16); + } + else if ((accumulator & 0xFF800000) == 0xFF000000) + { + /** + * LengthOfMatch [512, 1023] + * bits 111111110 + 9 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 14) & 0x01FF) + 0x0200; + BitStream_Shift(bs, 18); + } + else if ((accumulator & 0xFFC00000) == 0xFF800000) + { + /** + * LengthOfMatch [1024, 2047] + * bits 1111111110 + 10 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 12) & 0x03FF) + 0x0400; + BitStream_Shift(bs, 20); + } + else if ((accumulator & 0xFFE00000) == 0xFFC00000) + { + /** + * LengthOfMatch [2048, 4095] + * bits 11111111110 + 11 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 10) & 0x07FF) + 0x0800; + BitStream_Shift(bs, 22); + } + else if ((accumulator & 0xFFF00000) == 0xFFE00000) + { + /** + * LengthOfMatch [4096, 8191] + * bits 111111111110 + 12 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 8) & 0x0FFF) + 0x1000; + BitStream_Shift(bs, 24); + } + else if ((accumulator & 0xFFF80000) == 0xFFF00000) + { + /** + * LengthOfMatch [8192, 16383] + * bits 1111111111110 + 13 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 6) & 0x1FFF) + 0x2000; + BitStream_Shift(bs, 26); + } + else if ((accumulator & 0xFFFC0000) == 0xFFF80000) + { + /** + * LengthOfMatch [16384, 32767] + * bits 11111111111110 + 14 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 4) & 0x3FFF) + 0x4000; + BitStream_Shift(bs, 28); + } + else if ((accumulator & 0xFFFE0000) == 0xFFFC0000) + { + /** + * LengthOfMatch [32768, 65535] + * bits 111111111111110 + 15 lower bits of LengthOfMatch + */ + + LengthOfMatch = ((accumulator >> 2) & 0x7FFF) + 0x8000; + BitStream_Shift(bs, 30); + } + else + { + /* Invalid LengthOfMatch Encoding */ + } + + printf("<%d,%d>\n", (int) CopyOffset, (int) LengthOfMatch); } return 0; @@ -347,25 +523,25 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* if (CopyOffset < 64) { - /* 11111 + lower 6 bits of CopyOffset */ + /* bits 11111 + lower 6 bits of CopyOffset */ accumulator = 0x07C0 | (CopyOffset & 0x003F); BitStream_Write_Bits(mppc->bs, accumulator, 11); } else if ((CopyOffset >= 64) && (CopyOffset < 320)) { - /* 11110 + lower 8 bits of (CopyOffset - 64) */ + /* bits 11110 + lower 8 bits of (CopyOffset - 64) */ accumulator = 0x1E00 | ((CopyOffset - 64) & 0x00FF); BitStream_Write_Bits(mppc->bs, accumulator, 13); } else if ((CopyOffset >= 320) && (CopyOffset < 2368)) { - /* 1110 + lower 11 bits of (CopyOffset - 320) */ + /* bits 1110 + lower 11 bits of (CopyOffset - 320) */ accumulator = 0x7000 | ((CopyOffset - 320) & 0x07FF); BitStream_Write_Bits(mppc->bs, accumulator, 15); } else { - /* 110 + lower 16 bits of (CopyOffset - 2368) */ + /* bits 110 + lower 16 bits of (CopyOffset - 2368) */ accumulator = 0x060000 | ((CopyOffset - 2368) & 0xFFFF); BitStream_Write_Bits(mppc->bs, accumulator, 19); } From 11e0830884626de11fc9ec853fe686f2c9365534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 9 Mar 2014 13:37:46 -0400 Subject: [PATCH 3/9] libfreerdp-codec: start adding support for RDP4 MPPC --- libfreerdp/codec/mppc.c | 188 +++++++++++++------ libfreerdp/codec/test/TestFreeRDPCodecMppc.c | 67 ++++++- 2 files changed, 189 insertions(+), 66 deletions(-) diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index 418c22c5e..13fa3bef2 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -208,49 +208,89 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 CopyOffset = 0; - if ((accumulator & 0xF8000000) == 0xF8000000) + if (mppc->CompressionLevel) /* RDP5 */ { - /** - * CopyOffset, range [0, 63] - * bits 11111 + lower 6 bits of CopyOffset - */ + if ((accumulator & 0xF8000000) == 0xF8000000) + { + /** + * CopyOffset, range [0, 63] + * bits 11111 + lower 6 bits of CopyOffset + */ - CopyOffset = ((accumulator >> 21) & 0x3F); - BitStream_Shift(bs, 11); - } - else if ((accumulator & 0xF8000000) == 0xF0000000) - { - /** - * CopyOffset, range [64, 319] - * bits 11110 + lower 8 bits of (CopyOffset - 64) - */ + CopyOffset = ((accumulator >> 21) & 0x3F); + BitStream_Shift(bs, 11); + } + else if ((accumulator & 0xF8000000) == 0xF0000000) + { + /** + * CopyOffset, range [64, 319] + * bits 11110 + lower 8 bits of (CopyOffset - 64) + */ - CopyOffset = ((accumulator >> 19) & 0xFF) + 64; - BitStream_Shift(bs, 13); - } - else if ((accumulator & 0xF0000000) == 0xE0000000) - { - /** - * CopyOffset, range [320, 2367] - * bits 1110 + lower 11 bits of (CopyOffset - 320) - */ + CopyOffset = ((accumulator >> 19) & 0xFF) + 64; + BitStream_Shift(bs, 13); + } + else if ((accumulator & 0xF0000000) == 0xE0000000) + { + /** + * CopyOffset, range [320, 2367] + * bits 1110 + lower 11 bits of (CopyOffset - 320) + */ - CopyOffset = ((accumulator >> 17) & 0x7FF) + 320; - BitStream_Shift(bs, 15); - } - else if ((accumulator & 0xE0000000) == 0xC0000000) - { - /** - * CopyOffset, range [2368, ] - * bits 110 + lower 16 bits of (CopyOffset - 2368) - */ + CopyOffset = ((accumulator >> 17) & 0x7FF) + 320; + BitStream_Shift(bs, 15); + } + else if ((accumulator & 0xE0000000) == 0xC0000000) + { + /** + * CopyOffset, range [2368, ] + * bits 110 + lower 16 bits of (CopyOffset - 2368) + */ - CopyOffset = ((accumulator >> 13) & 0xFFFF) + 2368; - BitStream_Shift(bs, 19); + CopyOffset = ((accumulator >> 13) & 0xFFFF) + 2368; + BitStream_Shift(bs, 19); + } + else + { + /* Invalid CopyOffset Encoding */ + } } - else + else /* RDP4 */ { - /* Invalid CopyOffset Encoding */ + if ((accumulator & 0xF0000000) == 0xF0000000) + { + /** + * CopyOffset, range [0, 63] + * bits 1111 + lower 6 bits of CopyOffset + */ + + CopyOffset = ((accumulator >> 22) & 0x3F); + BitStream_Shift(bs, 10); + } + else if ((accumulator & 0xF0000000) == 0xE0000000) + { + /** + * CopyOffset, range [64, 319] + * bits 1110 + lower 8 bits of (CopyOffset - 64) + */ + + CopyOffset = ((accumulator >> 20) & 0xFF) + 64; + BitStream_Shift(bs, 12); + } + else if ((accumulator & 0xE0000000) == 0xC0000000) + { + /** + * CopyOffset, range [320, 8191] + * bits 110 + lower 13 bits of (CopyOffset - 320) + */ + + CopyOffset = ((accumulator >> 16) & 0x1FFF) + 320; + BitStream_Shift(bs, 16); + } + else + { + /* Invalid CopyOffset Encoding */ + } } /** @@ -380,7 +420,7 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 LengthOfMatch = ((accumulator >> 8) & 0x0FFF) + 0x1000; BitStream_Shift(bs, 24); } - else if ((accumulator & 0xFFF80000) == 0xFFF00000) + else if (((accumulator & 0xFFF80000) == 0xFFF00000) && mppc->CompressionLevel) /* RDP5 */ { /** * LengthOfMatch [8192, 16383] @@ -390,7 +430,7 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 LengthOfMatch = ((accumulator >> 6) & 0x1FFF) + 0x2000; BitStream_Shift(bs, 26); } - else if ((accumulator & 0xFFFC0000) == 0xFFF80000) + else if (((accumulator & 0xFFFC0000) == 0xFFF80000) && mppc->CompressionLevel) /* RDP5 */ { /** * LengthOfMatch [16384, 32767] @@ -400,7 +440,7 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 LengthOfMatch = ((accumulator >> 4) & 0x3FFF) + 0x4000; BitStream_Shift(bs, 28); } - else if ((accumulator & 0xFFFE0000) == 0xFFFC0000) + else if (((accumulator & 0xFFFE0000) == 0xFFFC0000) && mppc->CompressionLevel) /* RDP5 */ { /** * LengthOfMatch [32768, 65535] @@ -521,29 +561,53 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* /* Encode CopyOffset */ - if (CopyOffset < 64) + if (mppc->CompressionLevel) /* RDP5 */ { - /* bits 11111 + lower 6 bits of CopyOffset */ - accumulator = 0x07C0 | (CopyOffset & 0x003F); - BitStream_Write_Bits(mppc->bs, accumulator, 11); + if (CopyOffset < 64) + { + /* bits 11111 + lower 6 bits of CopyOffset */ + accumulator = 0x07C0 | (CopyOffset & 0x003F); + BitStream_Write_Bits(mppc->bs, accumulator, 11); + } + else if ((CopyOffset >= 64) && (CopyOffset < 320)) + { + /* bits 11110 + lower 8 bits of (CopyOffset - 64) */ + accumulator = 0x1E00 | ((CopyOffset - 64) & 0x00FF); + BitStream_Write_Bits(mppc->bs, accumulator, 13); + } + else if ((CopyOffset >= 320) && (CopyOffset < 2368)) + { + /* bits 1110 + lower 11 bits of (CopyOffset - 320) */ + accumulator = 0x7000 | ((CopyOffset - 320) & 0x07FF); + BitStream_Write_Bits(mppc->bs, accumulator, 15); + } + else + { + /* bits 110 + lower 16 bits of (CopyOffset - 2368) */ + accumulator = 0x060000 | ((CopyOffset - 2368) & 0xFFFF); + BitStream_Write_Bits(mppc->bs, accumulator, 19); + } } - else if ((CopyOffset >= 64) && (CopyOffset < 320)) + else /* RDP4 */ { - /* bits 11110 + lower 8 bits of (CopyOffset - 64) */ - accumulator = 0x1E00 | ((CopyOffset - 64) & 0x00FF); - BitStream_Write_Bits(mppc->bs, accumulator, 13); - } - else if ((CopyOffset >= 320) && (CopyOffset < 2368)) - { - /* bits 1110 + lower 11 bits of (CopyOffset - 320) */ - accumulator = 0x7000 | ((CopyOffset - 320) & 0x07FF); - BitStream_Write_Bits(mppc->bs, accumulator, 15); - } - else - { - /* bits 110 + lower 16 bits of (CopyOffset - 2368) */ - accumulator = 0x060000 | ((CopyOffset - 2368) & 0xFFFF); - BitStream_Write_Bits(mppc->bs, accumulator, 19); + if (CopyOffset < 64) + { + /* bits 1111 + lower 6 bits of CopyOffset */ + accumulator = 0x03C0 | (CopyOffset & 0x003F); + BitStream_Write_Bits(mppc->bs, accumulator, 10); + } + else if ((CopyOffset >= 64) && (CopyOffset < 320)) + { + /* bits 1110 + lower 8 bits of (CopyOffset - 64) */ + accumulator = 0x0E00 | ((CopyOffset - 64) & 0x00FF); + BitStream_Write_Bits(mppc->bs, accumulator, 12); + } + else if ((CopyOffset >= 320) && (CopyOffset < 8192)) + { + /* bits 110 + lower 13 bits of (CopyOffset - 320) */ + accumulator = 0xC000 | ((CopyOffset - 320) & 0x1FFF); + BitStream_Write_Bits(mppc->bs, accumulator, 16); + } } /* Encode LengthOfMatch */ @@ -619,19 +683,19 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* accumulator = 0xFFE000 | (LengthOfMatch & 0x0FFF); BitStream_Write_Bits(mppc->bs, accumulator, 24); } - else if ((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) + else if (((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) && mppc->CompressionLevel) /* RDP5 */ { /* 1111111111110 + 13 lower bits of LengthOfMatch */ accumulator = 0x3FFC000 | (LengthOfMatch & 0x1FFF); BitStream_Write_Bits(mppc->bs, accumulator, 26); } - else if ((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) + else if (((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) && mppc->CompressionLevel) /* RDP5 */ { /* 11111111111110 + 14 lower bits of LengthOfMatch */ accumulator = 0xFFF8000 | (LengthOfMatch & 0x3FFF); BitStream_Write_Bits(mppc->bs, accumulator, 28); } - else if ((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) + else if (((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) && mppc->CompressionLevel) /* RDP5 */ { /* 111111111111110 + 15 lower bits of LengthOfMatch */ accumulator = 0x3FFF0000 | (LengthOfMatch & 0x7FFF); diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index a0b8ea0b5..9765f1945 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -706,7 +706,7 @@ const BYTE TEST_MPPC_BELLS_RDP5[] = "\x6c\x2e\x74\x6f\x6c\x6c\x73\x2c\xfa\x1b\x97\x33\x7e\x87\xe3\x32" "\x90\x80"; -int test_MppcCompressBells() +int test_MppcCompressBellsRdp5() { UINT32 size; UINT32 flags; @@ -738,7 +738,39 @@ int test_MppcCompressBells() return 0; } -int test_MppcDecompressBells() +int test_MppcCompressBellsRdp4() +{ + UINT32 size; + UINT32 flags; + BYTE* pSrcData; + MPPC_CONTEXT* mppc; + BYTE OutputBuffer[65536]; + + mppc = mppc_context_new(0, TRUE); + + size = sizeof(TEST_MPPC_BELLS) - 1; + pSrcData = (BYTE*) TEST_MPPC_BELLS; + + printf("%s\n", pSrcData); + flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); + + printf("flags: 0x%04X size: %d\n", flags, size); + + if (memcmp(OutputBuffer, TEST_MPPC_BELLS_RDP4, size) != 0) + { + printf("Actual:\n"); + BitDump(OutputBuffer, size * 8, BITDUMP_MSB_FIRST); + + printf("Expected:\n"); + BitDump(TEST_MPPC_BELLS_RDP4, size * 8, BITDUMP_MSB_FIRST); + } + + mppc_context_free(mppc); + + return 0; +} + +int test_MppcDecompressBellsRdp5() { UINT32 size; UINT32 flags; @@ -775,6 +807,30 @@ int test_MppcDecompressBells() return 0; } +int test_MppcDecompressBellsRdp4() +{ + UINT32 size; + UINT32 flags; + BYTE* pSrcData; + MPPC_CONTEXT* mppc; + BYTE OutputBuffer[65536]; + + mppc = mppc_context_new(0, FALSE); + + size = sizeof(TEST_MPPC_BELLS_RDP4) - 1; + pSrcData = (BYTE*) TEST_MPPC_BELLS_RDP4; + flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 0; + + flags = mppc_decompress(mppc, pSrcData, OutputBuffer, &size, flags); + + printf("flags: 0x%04X size: %d\n", flags, size); + printf("%s\n", OutputBuffer); + + mppc_context_free(mppc); + + return 0; +} + int test_MppcCompressBuffer() { UINT32 size; @@ -803,8 +859,11 @@ int test_MppcCompressBuffer() int TestFreeRDPCodecMppc(int argc, char* argv[]) { - //test_MppcCompressBells(); - test_MppcDecompressBells(); + //test_MppcCompressBellsRdp5(); + //test_MppcDecompressBellsRdp5(); + + test_MppcCompressBellsRdp4(); + //test_MppcDecompressBellsRdp4(); return 0; } From 3530b83291f9c5d7c791e83240e8000fd1d4218e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 9 Mar 2014 14:35:11 -0400 Subject: [PATCH 4/9] libfreerdp-codec: add annotated MPPC compression samples --- libfreerdp/codec/mppc.c | 2 +- libfreerdp/codec/test/TestFreeRDPCodecMppc.c | 89 +++++++++++++++----- winpr/include/winpr/bitstream.h | 2 +- 3 files changed, 70 insertions(+), 23 deletions(-) diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index 13fa3bef2..7e052f5c8 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -165,7 +165,7 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 return 0; } - while (bs->position < (*pSize * 8)) + while ((bs->length - bs->position) >= 8) { accumulator = bs->accumulator; diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index 9765f1945..8e84f3e26 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -686,8 +686,73 @@ int test_mppc_old() } /** + * * for.whom.the.bell.tolls,.the.bell.tolls.for.thee! - * for.whom.the.bell.tolls,<16,15>.<40,4><19,3>e! + * for.whom.the.bell.tolls,<16,15>.<40,4><19,3>e! ([MS-RDPBCGR]) + * for.whom.the.bell.tolls,<16,15>.f<40,3><35,3>e! (Microsoft Encoder) + * + * RDP5: + * 01100110 Literal 'f' + * 01101111 Literal 'o' + * 01110010 Literal 'r' + * 00101110 Literal '.' + * 01110111 Literal 'w' + * 01101000 Literal 'h' + * 01101111 Literal 'o' + * 01101101 Literal 'm' + * 00101110 Literal '.' + * 01110100 Literal 't' + * 01101000 Literal 'h' + * 01100101 Literal 'e' + * 00101110 Literal '.' + * 01100010 Literal 'b' + * 01100101 Literal 'e' + * 01101100 Literal 'l' + * 01101100 Literal 'l' + * 00101110 Literal '.' + * 01110100 Literal 't' + * 01101111 Literal 'o' + * 01101100 Literal 'l' + * 01101100 Literal 'l' + * 01110011 Literal 's' + * 00101100 Literal ',' + * + * RDP4: + * 01100110 Literal 'f' + * 01101111 Literal 'o' + * 01110010 Literal 'r' + * 00101110 Literal '.' + * 01110111 Literal 'w' + * 01101000 Literal 'h' + * 01101111 Literal 'o' + * 01101101 Literal 'm' + * 00101110 Literal '.' + * 01110100 Literal 't' + * 01101000 Literal 'h' + * 01100101 Literal 'e' + * 00101110 Literal '.' + * 01100010 Literal 'b' + * 01100101 Literal 'e' + * 01101100 Literal 'l' + * 01101100 Literal 'l' + * 00101110 Literal '.' + * 01110100 Literal 't' + * 01101111 Literal 'o' + * 01101100 Literal 'l' + * 01101100 Literal 'l' + * 01110011 Literal 's' + * 00101100 Literal ',' + * 1111+010000 CopyOffset 16 + * 110+111 LengthOfMatch 15 + * 00101110 Literal '.' + * 01100110 Literal 'f' + * 1111+101000 CopyOffset 40 + * 0 LengthOfMatch 3 + * 1111+100011 CopyOffset 35 + * 0 LengthOfMatch 3 + * 01100101 Literal 'e' + * 00100001 Literal '!' + * 00 Trailing Bits */ const BYTE TEST_MPPC_BELLS[] = "for.whom.the.bell.tolls,.the.bell.tolls.for.thee!"; @@ -789,19 +854,6 @@ int test_MppcDecompressBellsRdp5() printf("flags: 0x%04X size: %d\n", flags, size); printf("%s\n", OutputBuffer); -#if 0 - size = sizeof(TEST_MPPC_BELLS) - 1; - - if (memcmp(OutputBuffer, TEST_MPPC_BELLS, sizeof(TEST_MPPC_BELLS) - 1) != 0) - { - printf("Actual:\n"); - BitDump(OutputBuffer, size * 8, BITDUMP_MSB_FIRST); - - printf("Expected:\n"); - BitDump(TEST_MPPC_BELLS, size * 8, BITDUMP_MSB_FIRST); - } -#endif - mppc_context_free(mppc); return 0; @@ -847,11 +899,6 @@ int test_MppcCompressBuffer() flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); printf("flags: 0x%04X size: %d\n", flags, size); - winpr_HexDump(OutputBuffer, size); - //winpr_HexDump(TEST_RDP5_COMPRESSED_DATA, sizeof(TEST_RDP5_COMPRESSED_DATA)); - - printf("sizeof(TEST_RDP5_COMPRESSED_DATA): %d\n", (int) sizeof(TEST_RDP5_COMPRESSED_DATA)); - mppc_context_free(mppc); return 0; @@ -860,9 +907,9 @@ int test_MppcCompressBuffer() int TestFreeRDPCodecMppc(int argc, char* argv[]) { //test_MppcCompressBellsRdp5(); - //test_MppcDecompressBellsRdp5(); + test_MppcDecompressBellsRdp5(); - test_MppcCompressBellsRdp4(); + //test_MppcCompressBellsRdp4(); //test_MppcDecompressBellsRdp4(); return 0; diff --git a/winpr/include/winpr/bitstream.h b/winpr/include/winpr/bitstream.h index 47a5a68e3..c15f0720e 100644 --- a/winpr/include/winpr/bitstream.h +++ b/winpr/include/winpr/bitstream.h @@ -46,7 +46,7 @@ typedef struct _wBitStream wBitStream; _bs->accumulator = 0; \ _bs->pointer = _bs->buffer; \ _bs->capacity = _capacity; \ - _bs->length = _bs->capacity; \ + _bs->length = _bs->capacity * 8; \ } #define BitStream_Write_Bits(_bs, _bits, _nbits) { \ From ccf71a1fa385c4b5a069e9697f4016456db9d363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 9 Mar 2014 16:02:46 -0400 Subject: [PATCH 5/9] libfreerdp-codec: improve MPPC compressor consistency with Microsoft implementation --- libfreerdp/codec/mppc.c | 174 +++++++++++-------- libfreerdp/codec/test/TestFreeRDPCodecMppc.c | 52 ++++-- 2 files changed, 140 insertions(+), 86 deletions(-) diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index 7e052f5c8..b8130920c 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -70,7 +70,7 @@ const UINT32 MPPC_MATCH_TABLE[256] = 0x97E91668, 0x9885E5FB, 0x9922B58E, 0x99BF8521, 0x9A5C54B4, 0x9AF92447, 0x9B95F3DA, 0x9C32C36D }; -//#define DEBUG_MPPC 1 +#define DEBUG_MPPC 1 void BitStream_Prefetch(wBitStream* bs) { @@ -468,30 +468,40 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* BYTE* pMatch; UINT32 MatchIndex; UINT32 accumulator; + BYTE* HistoryBuffer; + UINT32 HistoryPtr; + BYTE* pHistoryPtr; + UINT32 HistoryOffset; + BYTE* pHistoryOffset; + wBitStream* bs = mppc->bs; - BitStream_Attach(mppc->bs, pDstData, *pSize); + HistoryBuffer = mppc->HistoryBuffer; - CopyMemory(&(mppc->HistoryBuffer[mppc->HistoryOffset]), pSrcData, *pSize); + HistoryPtr = mppc->HistoryPtr; + pHistoryPtr = mppc->pHistoryPtr; + HistoryOffset = mppc->HistoryOffset; + pHistoryOffset = mppc->pHistoryOffset; - mppc->HistoryPtr = 0; - mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); + BitStream_Attach(bs, pDstData, *pSize); - if (((mppc->HistoryOffset + *pSize) < (mppc->HistoryBufferSize - 3)) && mppc->HistoryOffset) + CopyMemory(&(HistoryBuffer[HistoryOffset]), pSrcData, *pSize); + + if (((HistoryOffset + *pSize) < (mppc->HistoryBufferSize - 3)) && HistoryOffset) { Flags = mppc->CompressionLevel; } else { - mppc->HistoryOffset = 0; - mppc->pHistoryOffset = &(mppc->HistoryBuffer[mppc->HistoryOffset]); + HistoryOffset = 0; + pHistoryOffset = &(HistoryBuffer[HistoryOffset]); Flags = PACKET_AT_FRONT | mppc->CompressionLevel; } - mppc->HistoryOffset += *pSize; - mppc->pHistoryOffset = &(mppc->HistoryBuffer[mppc->HistoryOffset]); + HistoryOffset += *pSize; + pHistoryOffset = &(HistoryBuffer[HistoryOffset]); - if (mppc->HistoryPtr < mppc->HistoryOffset) + if (HistoryPtr < HistoryOffset) { /* HistoryPtr < HistoryOffset? (YES) */ @@ -500,57 +510,70 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* * to (HistoryPtr - 1) for the data that immediately follows HistoryPtr */ - mppc->HistoryPtr = 0; - mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); + HistoryPtr = 0; + pHistoryPtr = &(HistoryBuffer[HistoryPtr]); - pEnd = &(mppc->HistoryBuffer[*pSize - 1]); + pEnd = &(HistoryBuffer[*pSize - 1]); - while (mppc->pHistoryPtr < (pEnd - 2)) + while (pHistoryPtr < (pEnd - 2)) { - MatchIndex = MPPC_MATCH_INDEX(mppc->pHistoryPtr[0], mppc->pHistoryPtr[1], mppc->pHistoryPtr[2]); + MatchIndex = MPPC_MATCH_INDEX(pHistoryPtr[0], pHistoryPtr[1], pHistoryPtr[2]); - pMatch = &(mppc->HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); + pMatch = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); - mppc->MatchBuffer[MatchIndex] = (UINT16) mppc->HistoryPtr; + mppc->MatchBuffer[MatchIndex] = (UINT16) HistoryPtr; - if ((mppc->pHistoryPtr[0] != pMatch[0]) || (mppc->pHistoryPtr[1] != pMatch[1]) || - (mppc->pHistoryPtr[2] != pMatch[2]) || (mppc->pHistoryPtr == pMatch)) + if (mppc->pHistoryPtr < pHistoryPtr) + mppc->pHistoryPtr = pHistoryPtr; + + /** + * Some additional undocumented checks are done here to + * match the Microsoft implementation as closely as possible + */ + + if ((pHistoryPtr[0] != pMatch[0]) || (pHistoryPtr[1] != pMatch[1]) || + (pHistoryPtr[2] != pMatch[2]) || (&pMatch[2] > mppc->pHistoryPtr) || + (pMatch == pHistoryPtr) || (&pMatch[1] == pHistoryPtr) || + (pMatch == HistoryBuffer)) { - accumulator = *(mppc->pHistoryPtr); + accumulator = *(pHistoryPtr); #ifdef DEBUG_MPPC - printf("0x%02X", accumulator); + printf("%c", accumulator); #endif if (accumulator < 0x80) { /* 8 bits of literal are encoded as-is */ - BitStream_Write_Bits(mppc->bs, accumulator, 8); + BitStream_Write_Bits(bs, accumulator, 8); } else { /* bits 10 followed by lower 7 bits of literal */ accumulator = 0x100 | (accumulator & 0x7F); - BitStream_Write_Bits(mppc->bs, accumulator, 9); + BitStream_Write_Bits(bs, accumulator, 9); } - mppc->HistoryPtr++; - mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); + HistoryPtr++; + pHistoryPtr = &(HistoryBuffer[HistoryPtr]); } else { DWORD CopyOffset; - DWORD LengthOfMatch = 1; + DWORD LengthOfMatch = 0; - CopyOffset = (DWORD) (mppc->pHistoryPtr - pMatch); + CopyOffset = (DWORD) (pHistoryPtr - pMatch); - while ((mppc->pHistoryPtr[LengthOfMatch] == pMatch[LengthOfMatch]) && - ((mppc->HistoryPtr + LengthOfMatch) < (*pSize - 1))) + while ((pHistoryPtr[LengthOfMatch] == pMatch[LengthOfMatch]) && + ((HistoryPtr + LengthOfMatch) < (*pSize - 1))) { - MatchIndex = MPPC_MATCH_INDEX(mppc->pHistoryPtr[LengthOfMatch], - mppc->pHistoryPtr[LengthOfMatch + 1], mppc->pHistoryPtr[LengthOfMatch + 2]); + MatchIndex = MPPC_MATCH_INDEX(pHistoryPtr[LengthOfMatch], + pHistoryPtr[LengthOfMatch + 1], pHistoryPtr[LengthOfMatch + 2]); - mppc->MatchBuffer[MatchIndex] = (UINT16) (mppc->HistoryPtr + LengthOfMatch); + /** + * This behavior fits [MS-RDPBCGR] but not the Microsoft implementation + */ + //mppc->MatchBuffer[MatchIndex] = (UINT16) (HistoryPtr + LengthOfMatch); LengthOfMatch++; } @@ -567,25 +590,25 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* { /* bits 11111 + lower 6 bits of CopyOffset */ accumulator = 0x07C0 | (CopyOffset & 0x003F); - BitStream_Write_Bits(mppc->bs, accumulator, 11); + BitStream_Write_Bits(bs, accumulator, 11); } else if ((CopyOffset >= 64) && (CopyOffset < 320)) { /* bits 11110 + lower 8 bits of (CopyOffset - 64) */ accumulator = 0x1E00 | ((CopyOffset - 64) & 0x00FF); - BitStream_Write_Bits(mppc->bs, accumulator, 13); + BitStream_Write_Bits(bs, accumulator, 13); } else if ((CopyOffset >= 320) && (CopyOffset < 2368)) { /* bits 1110 + lower 11 bits of (CopyOffset - 320) */ accumulator = 0x7000 | ((CopyOffset - 320) & 0x07FF); - BitStream_Write_Bits(mppc->bs, accumulator, 15); + BitStream_Write_Bits(bs, accumulator, 15); } else { /* bits 110 + lower 16 bits of (CopyOffset - 2368) */ accumulator = 0x060000 | ((CopyOffset - 2368) & 0xFFFF); - BitStream_Write_Bits(mppc->bs, accumulator, 19); + BitStream_Write_Bits(bs, accumulator, 19); } } else /* RDP4 */ @@ -594,19 +617,19 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* { /* bits 1111 + lower 6 bits of CopyOffset */ accumulator = 0x03C0 | (CopyOffset & 0x003F); - BitStream_Write_Bits(mppc->bs, accumulator, 10); + BitStream_Write_Bits(bs, accumulator, 10); } else if ((CopyOffset >= 64) && (CopyOffset < 320)) { /* bits 1110 + lower 8 bits of (CopyOffset - 64) */ accumulator = 0x0E00 | ((CopyOffset - 64) & 0x00FF); - BitStream_Write_Bits(mppc->bs, accumulator, 12); + BitStream_Write_Bits(bs, accumulator, 12); } else if ((CopyOffset >= 320) && (CopyOffset < 8192)) { /* bits 110 + lower 13 bits of (CopyOffset - 320) */ accumulator = 0xC000 | ((CopyOffset - 320) & 0x1FFF); - BitStream_Write_Bits(mppc->bs, accumulator, 16); + BitStream_Write_Bits(bs, accumulator, 16); } } @@ -615,109 +638,109 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* if (LengthOfMatch == 3) { /* 0 + 0 lower bits of LengthOfMatch */ - BitStream_Write_Bits(mppc->bs, 0, 1); + BitStream_Write_Bits(bs, 0, 1); } else if ((LengthOfMatch >= 4) && (LengthOfMatch < 8)) { /* 10 + 2 lower bits of LengthOfMatch */ accumulator = 0x0008 | (LengthOfMatch & 0x0003); - BitStream_Write_Bits(mppc->bs, accumulator, 4); + BitStream_Write_Bits(bs, accumulator, 4); } else if ((LengthOfMatch >= 8) && (LengthOfMatch < 16)) { /* 110 + 3 lower bits of LengthOfMatch */ accumulator = 0x0030 | (LengthOfMatch & 0x0007); - BitStream_Write_Bits(mppc->bs, accumulator, 6); + BitStream_Write_Bits(bs, accumulator, 6); } else if ((LengthOfMatch >= 16) && (LengthOfMatch < 32)) { /* 1110 + 4 lower bits of LengthOfMatch */ accumulator = 0x00E0 | (LengthOfMatch & 0x000F); - BitStream_Write_Bits(mppc->bs, accumulator, 8); + BitStream_Write_Bits(bs, accumulator, 8); } else if ((LengthOfMatch >= 32) && (LengthOfMatch < 64)) { /* 11110 + 5 lower bits of LengthOfMatch */ accumulator = 0x03C0 | (LengthOfMatch & 0x001F); - BitStream_Write_Bits(mppc->bs, accumulator, 10); + BitStream_Write_Bits(bs, accumulator, 10); } else if ((LengthOfMatch >= 64) && (LengthOfMatch < 128)) { /* 111110 + 6 lower bits of LengthOfMatch */ accumulator = 0x0F80 | (LengthOfMatch & 0x003F); - BitStream_Write_Bits(mppc->bs, accumulator, 12); + BitStream_Write_Bits(bs, accumulator, 12); } else if ((LengthOfMatch >= 128) && (LengthOfMatch < 256)) { /* 1111110 + 7 lower bits of LengthOfMatch */ accumulator = 0x3F00 | (LengthOfMatch & 0x007F); - BitStream_Write_Bits(mppc->bs, accumulator, 14); + BitStream_Write_Bits(bs, accumulator, 14); } else if ((LengthOfMatch >= 256) && (LengthOfMatch < 512)) { /* 11111110 + 8 lower bits of LengthOfMatch */ accumulator = 0xFE00 | (LengthOfMatch & 0x00FF); - BitStream_Write_Bits(mppc->bs, accumulator, 16); + BitStream_Write_Bits(bs, accumulator, 16); } else if ((LengthOfMatch >= 512) && (LengthOfMatch < 1024)) { /* 111111110 + 9 lower bits of LengthOfMatch */ accumulator = 0x3FC00 | (LengthOfMatch & 0x01FF); - BitStream_Write_Bits(mppc->bs, accumulator, 18); + BitStream_Write_Bits(bs, accumulator, 18); } else if ((LengthOfMatch >= 1024) && (LengthOfMatch < 2048)) { /* 1111111110 + 10 lower bits of LengthOfMatch */ accumulator = 0xFF800 | (LengthOfMatch & 0x03FF); - BitStream_Write_Bits(mppc->bs, accumulator, 20); + BitStream_Write_Bits(bs, accumulator, 20); } else if ((LengthOfMatch >= 2048) && (LengthOfMatch < 4096)) { /* 11111111110 + 11 lower bits of LengthOfMatch */ accumulator = 0x3FF000 | (LengthOfMatch & 0x07FF); - BitStream_Write_Bits(mppc->bs, accumulator, 22); + BitStream_Write_Bits(bs, accumulator, 22); } else if ((LengthOfMatch >= 4096) && (LengthOfMatch < 8192)) { /* 111111111110 + 12 lower bits of LengthOfMatch */ accumulator = 0xFFE000 | (LengthOfMatch & 0x0FFF); - BitStream_Write_Bits(mppc->bs, accumulator, 24); + BitStream_Write_Bits(bs, accumulator, 24); } else if (((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) && mppc->CompressionLevel) /* RDP5 */ { /* 1111111111110 + 13 lower bits of LengthOfMatch */ accumulator = 0x3FFC000 | (LengthOfMatch & 0x1FFF); - BitStream_Write_Bits(mppc->bs, accumulator, 26); + BitStream_Write_Bits(bs, accumulator, 26); } else if (((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) && mppc->CompressionLevel) /* RDP5 */ { /* 11111111111110 + 14 lower bits of LengthOfMatch */ accumulator = 0xFFF8000 | (LengthOfMatch & 0x3FFF); - BitStream_Write_Bits(mppc->bs, accumulator, 28); + BitStream_Write_Bits(bs, accumulator, 28); } else if (((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) && mppc->CompressionLevel) /* RDP5 */ { /* 111111111111110 + 15 lower bits of LengthOfMatch */ accumulator = 0x3FFF0000 | (LengthOfMatch & 0x7FFF); - BitStream_Write_Bits(mppc->bs, accumulator, 30); + BitStream_Write_Bits(bs, accumulator, 30); } - mppc->HistoryPtr += LengthOfMatch; - mppc->pHistoryPtr += LengthOfMatch; + HistoryPtr += LengthOfMatch; + pHistoryPtr += LengthOfMatch; } } /* Encode trailing symbols as literals */ - while (mppc->pHistoryPtr <= pEnd) + while (pHistoryPtr <= pEnd) { - MatchIndex = MPPC_MATCH_INDEX(mppc->pHistoryPtr[0], mppc->pHistoryPtr[1], mppc->pHistoryPtr[2]); + MatchIndex = MPPC_MATCH_INDEX(pHistoryPtr[0], pHistoryPtr[1], pHistoryPtr[2]); - pMatch = &(mppc->HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); + pMatch = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); - mppc->MatchBuffer[MatchIndex] = (UINT16) mppc->HistoryPtr; + mppc->MatchBuffer[MatchIndex] = (UINT16) HistoryPtr; - accumulator = *(mppc->pHistoryPtr); + accumulator = *(pHistoryPtr); #ifdef DEBUG_MPPC printf("%c", accumulator); @@ -726,17 +749,17 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* if (accumulator < 0x80) { /* 8 bits of literal are encoded as-is */ - BitStream_Write_Bits(mppc->bs, accumulator, 8); + BitStream_Write_Bits(bs, accumulator, 8); } else { /* bits 10 followed by lower 7 bits of literal */ accumulator = 0x100 | (accumulator & 0x7F); - BitStream_Write_Bits(mppc->bs, accumulator, 9); + BitStream_Write_Bits(bs, accumulator, 9); } - mppc->HistoryPtr++; - mppc->pHistoryPtr++; + HistoryPtr++; + pHistoryPtr++; } } @@ -744,8 +767,17 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* Flags |= PACKET_COMPRESSED; - BitStream_Flush(mppc->bs); - *pSize = (mppc->bs->position / 8); + BitStream_Flush(bs); + *pSize = ((bs->position + 7) / 8); + + mppc->HistoryPtr = HistoryPtr; + mppc->pHistoryPtr = pHistoryPtr; + mppc->HistoryOffset = HistoryOffset; + mppc->pHistoryOffset = pHistoryOffset; + +#ifdef DEBUG_MPPC + printf("\n"); +#endif return Flags; } @@ -775,6 +807,12 @@ MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor) ZeroMemory(&(mppc->MatchBuffer), sizeof(mppc->MatchBuffer)); mppc->bs = BitStream_New(); + + mppc->HistoryPtr = 0; + mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); + + mppc->HistoryOffset = 0; + mppc->pHistoryOffset = &(mppc->HistoryBuffer[mppc->HistoryOffset]); } return mppc; diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index 8e84f3e26..84a6dac22 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -688,8 +688,18 @@ int test_mppc_old() /** * * for.whom.the.bell.tolls,.the.bell.tolls.for.thee! + * * for.whom.the.bell.tolls,<16,15>.<40,4><19,3>e! ([MS-RDPBCGR]) - * for.whom.the.bell.tolls,<16,15>.f<40,3><35,3>e! (Microsoft Encoder) + * + * <16,15> : ".the.bell.tolls" + * <40,4> : "for." + * <19,3> : "the" + * + * for.whom.the.bell.tolls,<16,15>.f<40,3><35,3>e! (Microsoft implementation) + * + * <16,15> : ".the.bell.tolls" + * <40,3> : "or." + * <19,3> " "the" * * RDP5: * 01100110 Literal 'f' @@ -777,25 +787,30 @@ int test_MppcCompressBellsRdp5() UINT32 flags; BYTE* pSrcData; MPPC_CONTEXT* mppc; + UINT32 expectedSize; BYTE OutputBuffer[65536]; mppc = mppc_context_new(1, TRUE); size = sizeof(TEST_MPPC_BELLS) - 1; pSrcData = (BYTE*) TEST_MPPC_BELLS; + expectedSize = sizeof(TEST_MPPC_BELLS_RDP5) - 1; printf("%s\n", pSrcData); flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); printf("flags: 0x%04X size: %d\n", flags, size); + if (size != expectedSize) + { + printf("MppcCompressBellsRdp5: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } + if (memcmp(OutputBuffer, TEST_MPPC_BELLS_RDP5, size) != 0) { - printf("Actual:\n"); - BitDump(OutputBuffer, size * 8, BITDUMP_MSB_FIRST); - - printf("Expected:\n"); - BitDump(TEST_MPPC_BELLS_RDP5, size * 8, BITDUMP_MSB_FIRST); + printf("MppcCompressBellsRdp5: output mismatch\n"); + return -1; } mppc_context_free(mppc); @@ -809,25 +824,30 @@ int test_MppcCompressBellsRdp4() UINT32 flags; BYTE* pSrcData; MPPC_CONTEXT* mppc; + UINT32 expectedSize; BYTE OutputBuffer[65536]; mppc = mppc_context_new(0, TRUE); size = sizeof(TEST_MPPC_BELLS) - 1; pSrcData = (BYTE*) TEST_MPPC_BELLS; + expectedSize = sizeof(TEST_MPPC_BELLS_RDP4) - 1; printf("%s\n", pSrcData); flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); printf("flags: 0x%04X size: %d\n", flags, size); + if (size != expectedSize) + { + printf("MppcCompressBellsRdp4: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } + if (memcmp(OutputBuffer, TEST_MPPC_BELLS_RDP4, size) != 0) { - printf("Actual:\n"); - BitDump(OutputBuffer, size * 8, BITDUMP_MSB_FIRST); - - printf("Expected:\n"); - BitDump(TEST_MPPC_BELLS_RDP4, size * 8, BITDUMP_MSB_FIRST); + printf("MppcCompressBellsRdp4: output mismatch\n"); + return -1; } mppc_context_free(mppc); @@ -850,9 +870,7 @@ int test_MppcDecompressBellsRdp5() flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1; flags = mppc_decompress(mppc, pSrcData, OutputBuffer, &size, flags); - printf("flags: 0x%04X size: %d\n", flags, size); - printf("%s\n", OutputBuffer); mppc_context_free(mppc); @@ -874,9 +892,7 @@ int test_MppcDecompressBellsRdp4() flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 0; flags = mppc_decompress(mppc, pSrcData, OutputBuffer, &size, flags); - printf("flags: 0x%04X size: %d\n", flags, size); - printf("%s\n", OutputBuffer); mppc_context_free(mppc); @@ -906,10 +922,10 @@ int test_MppcCompressBuffer() int TestFreeRDPCodecMppc(int argc, char* argv[]) { - //test_MppcCompressBellsRdp5(); - test_MppcDecompressBellsRdp5(); + test_MppcCompressBellsRdp5(); + //test_MppcDecompressBellsRdp5(); - //test_MppcCompressBellsRdp4(); + test_MppcCompressBellsRdp4(); //test_MppcDecompressBellsRdp4(); return 0; From c686d434b710ffc08b542145992a3c2bc90cdaeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 9 Mar 2014 17:32:49 -0400 Subject: [PATCH 6/9] libfreerdp-codec: initial RDP4/RDP5 MPPC compression test case success --- libfreerdp/codec/mppc.c | 64 +---------- libfreerdp/codec/test/TestFreeRDPCodecMppc.c | 25 +++++ winpr/include/winpr/bitstream.h | 44 ++------ winpr/libwinpr/utils/collections/BitStream.c | 111 +++++++++++++++++++ 4 files changed, 144 insertions(+), 100 deletions(-) diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index b8130920c..bf5f93129 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -72,66 +72,6 @@ const UINT32 MPPC_MATCH_TABLE[256] = #define DEBUG_MPPC 1 -void BitStream_Prefetch(wBitStream* bs) -{ - (bs->prefetch) = 0; - if ((bs->pointer - bs->buffer) < (bs->capacity + 4)) - (bs->prefetch) |= (*(bs->pointer + 4) << 24); - if ((bs->pointer - bs->buffer) < (bs->capacity + 5)) - (bs->prefetch) |= (*(bs->pointer + 5) << 16); - if ((bs->pointer - bs->buffer) < (bs->capacity + 6)) - (bs->prefetch) |= (*(bs->pointer + 6) << 8); - if ((bs->pointer - bs->buffer) < (bs->capacity + 7)) - (bs->prefetch) |= (*(bs->pointer + 7) << 0); -} - -void BitStream_Fetch(wBitStream* bs) -{ - (bs->accumulator) = 0; - if ((bs->pointer - bs->buffer) < (bs->capacity + 0)) - (bs->accumulator) |= (*(bs->pointer + 0) << 24); - if ((bs->pointer - bs->buffer) < (bs->capacity + 1)) - (bs->accumulator) |= (*(bs->pointer + 1) << 16); - if ((bs->pointer - bs->buffer) < (bs->capacity + 2)) - (bs->accumulator) |= (*(bs->pointer + 2) << 8); - if ((bs->pointer - bs->buffer) < (bs->capacity + 3)) - (bs->accumulator) |= (*(bs->pointer + 3) << 0); - - BitStream_Prefetch(bs); -} - -void BitStream_Shift(wBitStream* bs, UINT32 nbits) -{ - bs->accumulator <<= nbits; - bs->position += nbits; - bs->offset += nbits; - - if (bs->offset < 32) - { - bs->mask = ((1 << nbits) - 1); - bs->accumulator |= ((bs->prefetch >> (32 - nbits)) & bs->mask); - bs->prefetch <<= nbits; - } - else - { - bs->mask = ((1 << nbits) - 1); - bs->accumulator |= ((bs->prefetch >> (32 - nbits)) & bs->mask); - bs->prefetch <<= nbits; - - bs->offset -= 32; - bs->pointer += 4; - - BitStream_Prefetch(bs); - - if (bs->offset) - { - bs->mask = ((1 << bs->offset) - 1); - bs->accumulator |= ((bs->prefetch >> (32 - bs->offset)) & bs->mask); - bs->prefetch <<= bs->offset; - } - } -} - UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize, UINT32 flags) { BYTE Literal; @@ -735,9 +675,7 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* while (pHistoryPtr <= pEnd) { MatchIndex = MPPC_MATCH_INDEX(pHistoryPtr[0], pHistoryPtr[1], pHistoryPtr[2]); - pMatch = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); - mppc->MatchBuffer[MatchIndex] = (UINT16) HistoryPtr; accumulator = *(pHistoryPtr); @@ -759,7 +697,7 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* } HistoryPtr++; - pHistoryPtr++; + pHistoryPtr = &(HistoryBuffer[HistoryPtr]); } } diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index 84a6dac22..2f4989c39 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -726,6 +726,17 @@ int test_mppc_old() * 01101100 Literal 'l' * 01110011 Literal 's' * 00101100 Literal ',' + * 11111+010000 CopyOffset 16 + * 110+111 LengthOfMatch 15 + * 00101110 Literal '.' + * 01100110 Literal 'f' + * 11111+101000 CopyOffset 40 + * 0 LengthOfMatch 3 + * 11111+100011 CopyOffset 35 + * 0 LengthOfMatch 3 + * 01100101 Literal 'e' + * 00100001 Literal '!' + * 0000000 Trailing Bits * * RDP4: * 01100110 Literal 'f' @@ -810,6 +821,13 @@ int test_MppcCompressBellsRdp5() if (memcmp(OutputBuffer, TEST_MPPC_BELLS_RDP5, size) != 0) { printf("MppcCompressBellsRdp5: output mismatch\n"); + + printf("Actual\n"); + BitDump(OutputBuffer, size * 8, 0); + + printf("Expected\n"); + BitDump(TEST_MPPC_BELLS_RDP5, size * 8, 0); + return -1; } @@ -847,6 +865,13 @@ int test_MppcCompressBellsRdp4() if (memcmp(OutputBuffer, TEST_MPPC_BELLS_RDP4, size) != 0) { printf("MppcCompressBellsRdp4: output mismatch\n"); + + printf("Actual\n"); + BitDump(OutputBuffer, size * 8, 0); + + printf("Expected\n"); + BitDump(TEST_MPPC_BELLS_RDP4, size * 8, 0); + return -1; } diff --git a/winpr/include/winpr/bitstream.h b/winpr/include/winpr/bitstream.h index c15f0720e..4f988b6e2 100644 --- a/winpr/include/winpr/bitstream.h +++ b/winpr/include/winpr/bitstream.h @@ -39,43 +39,6 @@ struct _wBitStream }; typedef struct _wBitStream wBitStream; -#define BitStream_Attach(_bs, _buffer, _capacity) { \ - _bs->position = 0; \ - _bs->buffer = _buffer; \ - _bs->offset = 0; \ - _bs->accumulator = 0; \ - _bs->pointer = _bs->buffer; \ - _bs->capacity = _capacity; \ - _bs->length = _bs->capacity * 8; \ -} - -#define BitStream_Write_Bits(_bs, _bits, _nbits) { \ - _bs->accumulator |= (_bits << _bs->offset); \ - _bs->position += _nbits; \ - _bs->offset += _nbits; \ - if (_bs->offset >= 32) { \ - *((UINT32*) _bs->pointer) = (_bs->accumulator); \ - _bs->offset = _bs->offset - 32; \ - _bs->accumulator = _bits >> (_nbits - _bs->offset); \ - _bs->pointer += 4; \ - } \ -} - -#define BitStream_Flush(_bs) { \ - if ((_bs->pointer - _bs->buffer) < (_bs->capacity + 3)) { \ - *((UINT32*) _bs->pointer) = (_bs->accumulator); \ - } else { \ - if ((_bs->pointer - _bs->buffer) < (_bs->capacity + 0)) \ - *(_bs->pointer + 0) = (_bs->accumulator >> 0); \ - if ((_bs->pointer - _bs->buffer) < (_bs->capacity + 1)) \ - *(_bs->pointer + 1) = (_bs->accumulator >> 8); \ - if ((_bs->pointer - _bs->buffer) < (_bs->capacity + 2)) \ - *(_bs->pointer + 2) = (_bs->accumulator >> 16); \ - if ((_bs->pointer - _bs->buffer) < (_bs->capacity + 3)) \ - *(_bs->pointer + 3) = (_bs->accumulator >> 24); \ - } \ -} - #define BITDUMP_MSB_FIRST 0x00000001 #define BITDUMP_STDERR 0x00000002 @@ -83,6 +46,13 @@ typedef struct _wBitStream wBitStream; extern "C" { #endif +WINPR_API void BitStream_Attach(wBitStream* bs, BYTE* buffer, UINT32 capacity); +WINPR_API void BitStream_Write_Bits(wBitStream* bs, UINT32 bits, UINT32 nbits); +WINPR_API void BitStream_Flush(wBitStream* bs); +WINPR_API void BitStream_Prefetch(wBitStream* bs); +WINPR_API void BitStream_Fetch(wBitStream* bs); +WINPR_API void BitStream_Shift(wBitStream* bs, UINT32 nbits); + WINPR_API void BitDump(const BYTE* buffer, UINT32 length, UINT32 flags); WINPR_API wBitStream* BitStream_New(); diff --git a/winpr/libwinpr/utils/collections/BitStream.c b/winpr/libwinpr/utils/collections/BitStream.c index 35ca916d9..2a1b2ccd7 100644 --- a/winpr/libwinpr/utils/collections/BitStream.c +++ b/winpr/libwinpr/utils/collections/BitStream.c @@ -183,6 +183,117 @@ void BitDump(const BYTE* buffer, UINT32 length, UINT32 flags) printf("\n"); } +void BitStream_Attach(wBitStream* bs, BYTE* buffer, UINT32 capacity) +{ + bs->position = 0; + bs->buffer = buffer; + bs->offset = 0; + bs->accumulator = 0; + bs->pointer = bs->buffer; + bs->capacity = capacity; + bs->length = bs->capacity * 8; +} + +void BitStream_Flush(wBitStream* bs) +{ + if ((bs->pointer - bs->buffer) < (bs->capacity + 0)) + *(bs->pointer + 0) = (bs->accumulator >> 24); + if ((bs->pointer - bs->buffer) < (bs->capacity + 1)) + *(bs->pointer + 1) = (bs->accumulator >> 16); + if ((bs->pointer - bs->buffer) < (bs->capacity + 2)) + *(bs->pointer + 2) = (bs->accumulator >> 8); + if ((bs->pointer - bs->buffer) < (bs->capacity + 3)) + *(bs->pointer + 3) = (bs->accumulator >> 0); +} + +void BitStream_Prefetch(wBitStream* bs) +{ + (bs->prefetch) = 0; + if ((bs->pointer - bs->buffer) < (bs->capacity + 4)) + (bs->prefetch) |= (*(bs->pointer + 4) << 24); + if ((bs->pointer - bs->buffer) < (bs->capacity + 5)) + (bs->prefetch) |= (*(bs->pointer + 5) << 16); + if ((bs->pointer - bs->buffer) < (bs->capacity + 6)) + (bs->prefetch) |= (*(bs->pointer + 6) << 8); + if ((bs->pointer - bs->buffer) < (bs->capacity + 7)) + (bs->prefetch) |= (*(bs->pointer + 7) << 0); +} + +void BitStream_Fetch(wBitStream* bs) +{ + (bs->accumulator) = 0; + + if ((bs->pointer - bs->buffer) < (bs->capacity + 0)) + (bs->accumulator) |= (*(bs->pointer + 0) << 24); + if ((bs->pointer - bs->buffer) < (bs->capacity + 1)) + (bs->accumulator) |= (*(bs->pointer + 1) << 16); + if ((bs->pointer - bs->buffer) < (bs->capacity + 2)) + (bs->accumulator) |= (*(bs->pointer + 2) << 8); + if ((bs->pointer - bs->buffer) < (bs->capacity + 3)) + (bs->accumulator) |= (*(bs->pointer + 3) << 0); + + BitStream_Prefetch(bs); +} + +void BitStream_Write_Bits(wBitStream* bs, UINT32 bits, UINT32 nbits) +{ + bs->position += nbits; + bs->offset += nbits; + + if (bs->offset < 32) + { + bs->accumulator |= (bits << (32 - bs->offset)); + } + else + { + bs->offset -= 32; + bs->mask = ((1 << (nbits - bs->offset)) - 1); + bs->accumulator |= ((bits >> bs->offset) & bs->mask); + + BitStream_Flush(bs); + bs->accumulator = 0; + bs->pointer += 4; + + if (bs->offset) + { + bs->mask = ((1 << bs->offset) - 1); + bs->accumulator |= ((bits & bs->mask) << (32 - bs->offset)); + } + } +} + +void BitStream_Shift(wBitStream* bs, UINT32 nbits) +{ + bs->accumulator <<= nbits; + bs->position += nbits; + bs->offset += nbits; + + if (bs->offset < 32) + { + bs->mask = ((1 << nbits) - 1); + bs->accumulator |= ((bs->prefetch >> (32 - nbits)) & bs->mask); + bs->prefetch <<= nbits; + } + else + { + bs->mask = ((1 << nbits) - 1); + bs->accumulator |= ((bs->prefetch >> (32 - nbits)) & bs->mask); + bs->prefetch <<= nbits; + + bs->offset -= 32; + bs->pointer += 4; + + BitStream_Prefetch(bs); + + if (bs->offset) + { + bs->mask = ((1 << bs->offset) - 1); + bs->accumulator |= ((bs->prefetch >> (32 - bs->offset)) & bs->mask); + bs->prefetch <<= bs->offset; + } + } +} + wBitStream* BitStream_New() { wBitStream* bs = NULL; From 6c89e3cff7254e913ca283b25967e4c89cc58fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 9 Mar 2014 19:55:52 -0400 Subject: [PATCH 7/9] libfreerdp-codec: initial MPPC decompression support --- include/freerdp/codec/mppc.h | 2 +- libfreerdp/codec/mppc.c | 54 ++++++++-- libfreerdp/codec/test/TestFreeRDPCodecMppc.c | 105 +++++++++++++++++-- 3 files changed, 141 insertions(+), 20 deletions(-) diff --git a/include/freerdp/codec/mppc.h b/include/freerdp/codec/mppc.h index 27ae01572..0adf52233 100644 --- a/include/freerdp/codec/mppc.h +++ b/include/freerdp/codec/mppc.h @@ -45,7 +45,7 @@ extern "C" { #endif FREERDP_API UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize); -FREERDP_API UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize, UINT32 flags); +FREERDP_API UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UINT32* pSize, UINT32 flags); FREERDP_API MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor); FREERDP_API void mppc_context_free(MPPC_CONTEXT* mppc); diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index bf5f93129..7b206590a 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -70,31 +70,39 @@ const UINT32 MPPC_MATCH_TABLE[256] = 0x97E91668, 0x9885E5FB, 0x9922B58E, 0x99BF8521, 0x9A5C54B4, 0x9AF92447, 0x9B95F3DA, 0x9C32C36D }; -#define DEBUG_MPPC 1 +//#define DEBUG_MPPC 1 -UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize, UINT32 flags) +UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UINT32* pSize, UINT32 flags) { BYTE Literal; + BYTE* SrcPtr; UINT32 CopyOffset; UINT32 LengthOfMatch; UINT32 accumulator; + BYTE* HistoryBuffer; + UINT32 HistoryPtr; + BYTE* pHistoryPtr; + UINT32 HistoryOffset; + BYTE* pHistoryOffset; wBitStream* bs = mppc->bs; + HistoryBuffer = mppc->HistoryBuffer; + *ppDstData = HistoryBuffer; + BitStream_Attach(bs, pSrcData, *pSize); BitStream_Fetch(bs); if (flags & PACKET_AT_FRONT) { mppc->HistoryPtr = 0; - mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); + mppc->pHistoryPtr = &(HistoryBuffer[mppc->HistoryPtr]); } if (flags & PACKET_FLUSHED) { mppc->HistoryPtr = 0; - mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); - - ZeroMemory(mppc->HistoryBuffer, mppc->HistoryBufferSize); + mppc->pHistoryPtr = &(HistoryBuffer[mppc->HistoryPtr]); + ZeroMemory(HistoryBuffer, mppc->HistoryBufferSize); } if (!(flags & PACKET_COMPRESSED)) @@ -105,6 +113,11 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 return 0; } + HistoryPtr = mppc->HistoryPtr; + pHistoryPtr = mppc->pHistoryPtr; + HistoryOffset = mppc->HistoryOffset; + pHistoryOffset = mppc->pHistoryOffset; + while ((bs->length - bs->position) >= 8) { accumulator = bs->accumulator; @@ -121,7 +134,10 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 */ Literal = ((accumulator & 0x7F000000) >> 24); - printf("L1: %c\n", Literal); + + *(pHistoryPtr) = Literal; + pHistoryPtr++; + HistoryPtr++; BitStream_Shift(bs, 8); @@ -135,7 +151,10 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 */ Literal = ((accumulator & 0x3F800000) >> 23) + 0x80; - printf("L2: %c\n", Literal); + + *(pHistoryPtr) = Literal; + pHistoryPtr++; + HistoryPtr++; BitStream_Shift(bs, 9); @@ -395,9 +414,28 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT3 /* Invalid LengthOfMatch Encoding */ } +#ifdef DEBUG_MPPC printf("<%d,%d>\n", (int) CopyOffset, (int) LengthOfMatch); +#endif + + SrcPtr = pHistoryPtr - CopyOffset; + + while (LengthOfMatch > 0) + { + *(pHistoryPtr) = *SrcPtr; + + pHistoryPtr++; + HistoryPtr++; + SrcPtr++; + + LengthOfMatch--; + } } + *pSize = (UINT32) (pHistoryPtr - mppc->pHistoryPtr); + mppc->pHistoryPtr = pHistoryPtr; + mppc->HistoryPtr = HistoryPtr; + return 0; } diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index 2f4989c39..8a2bbbce3 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -807,7 +807,6 @@ int test_MppcCompressBellsRdp5() pSrcData = (BYTE*) TEST_MPPC_BELLS; expectedSize = sizeof(TEST_MPPC_BELLS_RDP5) - 1; - printf("%s\n", pSrcData); flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); printf("flags: 0x%04X size: %d\n", flags, size); @@ -851,7 +850,6 @@ int test_MppcCompressBellsRdp4() pSrcData = (BYTE*) TEST_MPPC_BELLS; expectedSize = sizeof(TEST_MPPC_BELLS_RDP4) - 1; - printf("%s\n", pSrcData); flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); printf("flags: 0x%04X size: %d\n", flags, size); @@ -886,17 +884,31 @@ int test_MppcDecompressBellsRdp5() UINT32 flags; BYTE* pSrcData; MPPC_CONTEXT* mppc; - BYTE OutputBuffer[65536]; + UINT32 expectedSize; + BYTE* pDstData = NULL; mppc = mppc_context_new(1, FALSE); size = sizeof(TEST_MPPC_BELLS_RDP5) - 1; pSrcData = (BYTE*) TEST_MPPC_BELLS_RDP5; flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1; + expectedSize = sizeof(TEST_MPPC_BELLS) - 1; - flags = mppc_decompress(mppc, pSrcData, OutputBuffer, &size, flags); + flags = mppc_decompress(mppc, pSrcData, &pDstData, &size, flags); printf("flags: 0x%04X size: %d\n", flags, size); + if (size != expectedSize) + { + printf("MppcDecompressBellsRdp5: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } + + if (memcmp(pDstData, TEST_MPPC_BELLS, size) != 0) + { + printf("MppcDecompressBellsRdp5: output mismatch\n"); + return -1; + } + mppc_context_free(mppc); return 0; @@ -908,38 +920,96 @@ int test_MppcDecompressBellsRdp4() UINT32 flags; BYTE* pSrcData; MPPC_CONTEXT* mppc; - BYTE OutputBuffer[65536]; + UINT32 expectedSize; + BYTE* pDstData = NULL; mppc = mppc_context_new(0, FALSE); size = sizeof(TEST_MPPC_BELLS_RDP4) - 1; pSrcData = (BYTE*) TEST_MPPC_BELLS_RDP4; flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 0; + expectedSize = sizeof(TEST_MPPC_BELLS) - 1; - flags = mppc_decompress(mppc, pSrcData, OutputBuffer, &size, flags); + flags = mppc_decompress(mppc, pSrcData, &pDstData, &size, flags); printf("flags: 0x%04X size: %d\n", flags, size); + if (size != expectedSize) + { + printf("MppcDecompressBellsRdp4: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } + + if (memcmp(pDstData, TEST_MPPC_BELLS, size) != 0) + { + printf("MppcDecompressBellsRdp4: output mismatch\n"); + return -1; + } + mppc_context_free(mppc); return 0; } -int test_MppcCompressBuffer() +int test_MppcCompressBufferRdp5() { UINT32 size; UINT32 flags; BYTE* pSrcData; MPPC_CONTEXT* mppc; + UINT32 expectedSize; BYTE OutputBuffer[65536]; mppc = mppc_context_new(1, TRUE); size = sizeof(TEST_RDP5_UNCOMPRESSED_DATA); pSrcData = (BYTE*) TEST_RDP5_UNCOMPRESSED_DATA; + expectedSize = sizeof(TEST_RDP5_COMPRESSED_DATA); flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); printf("flags: 0x%04X size: %d\n", flags, size); + if (size != expectedSize) + { + printf("MppcCompressBufferRdp5: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } + + mppc_context_free(mppc); + + return 0; +} + +int test_MppcDecompressBufferRdp5() +{ + UINT32 size; + UINT32 flags; + BYTE* pSrcData; + MPPC_CONTEXT* mppc; + UINT32 expectedSize; + BYTE* pDstData = NULL; + + mppc = mppc_context_new(1, FALSE); + + size = sizeof(TEST_RDP5_COMPRESSED_DATA); + pSrcData = (BYTE*) TEST_RDP5_COMPRESSED_DATA; + flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1; + expectedSize = sizeof(TEST_RDP5_UNCOMPRESSED_DATA); + + flags = mppc_decompress(mppc, pSrcData, &pDstData, &size, flags); + printf("flags: 0x%04X size: %d\n", flags, size); + + if (size != expectedSize) + { + printf("MppcDecompressBufferRdp5: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); + return -1; + } + + if (memcmp(pDstData, TEST_RDP5_UNCOMPRESSED_DATA, size) != 0) + { + printf("MppcDecompressBufferRdp5: output mismatch\n"); + return -1; + } + mppc_context_free(mppc); return 0; @@ -947,11 +1017,24 @@ int test_MppcCompressBuffer() int TestFreeRDPCodecMppc(int argc, char* argv[]) { - test_MppcCompressBellsRdp5(); - //test_MppcDecompressBellsRdp5(); + if (test_MppcCompressBellsRdp5() < 0) + return -1; - test_MppcCompressBellsRdp4(); - //test_MppcDecompressBellsRdp4(); + if (test_MppcDecompressBellsRdp5() < 0) + return -1; + + if (test_MppcCompressBellsRdp4() < 0) + return -1; + + if (test_MppcDecompressBellsRdp4() < 0) + return -1; + + test_MppcCompressBufferRdp5(); + + if (test_MppcDecompressBufferRdp5() < 0) + return -1; + + //test_mppc_old(); return 0; } From ad7ed25d30ad443e606e7d97a37ee4f9cb806c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 9 Mar 2014 20:45:42 -0400 Subject: [PATCH 8/9] libfreerdp-codec: reduce amount of MPPC context variables --- include/freerdp/codec/mppc.h | 4 +- libfreerdp/codec/mppc.c | 499 +++++++++---------- libfreerdp/codec/test/TestFreeRDPCodecMppc.c | 6 +- 3 files changed, 232 insertions(+), 277 deletions(-) diff --git a/include/freerdp/codec/mppc.h b/include/freerdp/codec/mppc.h index 0adf52233..174820474 100644 --- a/include/freerdp/codec/mppc.h +++ b/include/freerdp/codec/mppc.h @@ -29,10 +29,8 @@ struct _MPPC_CONTEXT { wBitStream* bs; BOOL Compressor; - UINT32 HistoryPtr; - BYTE* pHistoryPtr; + BYTE* HistoryPtr; UINT32 HistoryOffset; - BYTE* pHistoryOffset; UINT32 HistoryBufferSize; BYTE HistoryBuffer[65536]; UINT16 MatchBuffer[32768]; diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index 7b206590a..f31baccae 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -70,7 +70,7 @@ const UINT32 MPPC_MATCH_TABLE[256] = 0x97E91668, 0x9885E5FB, 0x9922B58E, 0x99BF8521, 0x9A5C54B4, 0x9AF92447, 0x9B95F3DA, 0x9C32C36D }; -//#define DEBUG_MPPC 1 +#define DEBUG_MPPC 1 UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UINT32* pSize, UINT32 flags) { @@ -80,10 +80,8 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN UINT32 LengthOfMatch; UINT32 accumulator; BYTE* HistoryBuffer; - UINT32 HistoryPtr; - BYTE* pHistoryPtr; + BYTE* HistoryPtr; UINT32 HistoryOffset; - BYTE* pHistoryOffset; wBitStream* bs = mppc->bs; HistoryBuffer = mppc->HistoryBuffer; @@ -94,29 +92,24 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN if (flags & PACKET_AT_FRONT) { - mppc->HistoryPtr = 0; - mppc->pHistoryPtr = &(HistoryBuffer[mppc->HistoryPtr]); + mppc->HistoryPtr = &(HistoryBuffer[0]); } if (flags & PACKET_FLUSHED) { - mppc->HistoryPtr = 0; - mppc->pHistoryPtr = &(HistoryBuffer[mppc->HistoryPtr]); + mppc->HistoryPtr = &(HistoryBuffer[0]); ZeroMemory(HistoryBuffer, mppc->HistoryBufferSize); } if (!(flags & PACKET_COMPRESSED)) { - CopyMemory(mppc->pHistoryPtr, pSrcData, *pSize); + CopyMemory(mppc->HistoryPtr, pSrcData, *pSize); mppc->HistoryPtr += *pSize; - mppc->pHistoryPtr += *pSize; return 0; } HistoryPtr = mppc->HistoryPtr; - pHistoryPtr = mppc->pHistoryPtr; HistoryOffset = mppc->HistoryOffset; - pHistoryOffset = mppc->pHistoryOffset; while ((bs->length - bs->position) >= 8) { @@ -135,8 +128,7 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN Literal = ((accumulator & 0x7F000000) >> 24); - *(pHistoryPtr) = Literal; - pHistoryPtr++; + *(HistoryPtr) = Literal; HistoryPtr++; BitStream_Shift(bs, 8); @@ -152,8 +144,7 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN Literal = ((accumulator & 0x3F800000) >> 23) + 0x80; - *(pHistoryPtr) = Literal; - pHistoryPtr++; + *(HistoryPtr) = Literal; HistoryPtr++; BitStream_Shift(bs, 9); @@ -418,13 +409,12 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN printf("<%d,%d>\n", (int) CopyOffset, (int) LengthOfMatch); #endif - SrcPtr = pHistoryPtr - CopyOffset; + SrcPtr = HistoryPtr - CopyOffset; while (LengthOfMatch > 0) { - *(pHistoryPtr) = *SrcPtr; + *(HistoryPtr) = *SrcPtr; - pHistoryPtr++; HistoryPtr++; SrcPtr++; @@ -432,8 +422,8 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN } } - *pSize = (UINT32) (pHistoryPtr - mppc->pHistoryPtr); - mppc->pHistoryPtr = pHistoryPtr; + *pSize = (UINT32) (HistoryPtr - mppc->HistoryPtr); + mppc->HistoryPtr = HistoryPtr; return 0; @@ -441,24 +431,25 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize) { - BYTE* pEnd; UINT32 Flags; BYTE* pMatch; + BYTE* pSrcEnd; + BYTE* pDstEnd; + DWORD CopyOffset; + DWORD LengthOfMatch; UINT32 MatchIndex; UINT32 accumulator; BYTE* HistoryBuffer; - UINT32 HistoryPtr; - BYTE* pHistoryPtr; + BYTE* HistoryPtr; UINT32 HistoryOffset; - BYTE* pHistoryOffset; + UINT32 HistoryBufferSize; wBitStream* bs = mppc->bs; HistoryBuffer = mppc->HistoryBuffer; + HistoryBufferSize = mppc->HistoryBufferSize; HistoryPtr = mppc->HistoryPtr; - pHistoryPtr = mppc->pHistoryPtr; HistoryOffset = mppc->HistoryOffset; - pHistoryOffset = mppc->pHistoryOffset; BitStream_Attach(bs, pDstData, *pSize); @@ -471,255 +462,35 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* else { HistoryOffset = 0; - pHistoryOffset = &(HistoryBuffer[HistoryOffset]); - Flags = PACKET_AT_FRONT | mppc->CompressionLevel; } HistoryOffset += *pSize; - pHistoryOffset = &(HistoryBuffer[HistoryOffset]); + HistoryPtr = &(HistoryBuffer[0]); - if (HistoryPtr < HistoryOffset) + pSrcEnd = &(HistoryBuffer[*pSize - 1]); + pDstEnd = &(pDstData[*pSize - 1]); + + while (HistoryPtr < (pSrcEnd - 2)) { - /* HistoryPtr < HistoryOffset? (YES) */ + MatchIndex = MPPC_MATCH_INDEX(HistoryPtr[0], HistoryPtr[1], HistoryPtr[2]); + pMatch = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); - /* - * Search for a match of at least 3 bytes from the start of the history buffer - * to (HistoryPtr - 1) for the data that immediately follows HistoryPtr - */ + //if (&pMatch[1] != HistoryPtr) + mppc->MatchBuffer[MatchIndex] = (UINT16) (HistoryPtr - HistoryBuffer); - HistoryPtr = 0; - pHistoryPtr = &(HistoryBuffer[HistoryPtr]); + if (mppc->HistoryPtr < HistoryPtr) + mppc->HistoryPtr = HistoryPtr; - pEnd = &(HistoryBuffer[*pSize - 1]); - - while (pHistoryPtr < (pEnd - 2)) + if ((HistoryPtr[0] != pMatch[0]) || (HistoryPtr[1] != pMatch[1]) || + (HistoryPtr[2] != pMatch[2]) || (&pMatch[2] > mppc->HistoryPtr) || + (pMatch == HistoryPtr) || (&pMatch[1] == HistoryPtr) || + (pMatch == HistoryBuffer)) { - MatchIndex = MPPC_MATCH_INDEX(pHistoryPtr[0], pHistoryPtr[1], pHistoryPtr[2]); - - pMatch = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); - - mppc->MatchBuffer[MatchIndex] = (UINT16) HistoryPtr; - - if (mppc->pHistoryPtr < pHistoryPtr) - mppc->pHistoryPtr = pHistoryPtr; - - /** - * Some additional undocumented checks are done here to - * match the Microsoft implementation as closely as possible - */ - - if ((pHistoryPtr[0] != pMatch[0]) || (pHistoryPtr[1] != pMatch[1]) || - (pHistoryPtr[2] != pMatch[2]) || (&pMatch[2] > mppc->pHistoryPtr) || - (pMatch == pHistoryPtr) || (&pMatch[1] == pHistoryPtr) || - (pMatch == HistoryBuffer)) - { - accumulator = *(pHistoryPtr); + accumulator = *(HistoryPtr); #ifdef DEBUG_MPPC - printf("%c", accumulator); -#endif - - if (accumulator < 0x80) - { - /* 8 bits of literal are encoded as-is */ - BitStream_Write_Bits(bs, accumulator, 8); - } - else - { - /* bits 10 followed by lower 7 bits of literal */ - accumulator = 0x100 | (accumulator & 0x7F); - BitStream_Write_Bits(bs, accumulator, 9); - } - - HistoryPtr++; - pHistoryPtr = &(HistoryBuffer[HistoryPtr]); - } - else - { - DWORD CopyOffset; - DWORD LengthOfMatch = 0; - - CopyOffset = (DWORD) (pHistoryPtr - pMatch); - - while ((pHistoryPtr[LengthOfMatch] == pMatch[LengthOfMatch]) && - ((HistoryPtr + LengthOfMatch) < (*pSize - 1))) - { - MatchIndex = MPPC_MATCH_INDEX(pHistoryPtr[LengthOfMatch], - pHistoryPtr[LengthOfMatch + 1], pHistoryPtr[LengthOfMatch + 2]); - - /** - * This behavior fits [MS-RDPBCGR] but not the Microsoft implementation - */ - //mppc->MatchBuffer[MatchIndex] = (UINT16) (HistoryPtr + LengthOfMatch); - - LengthOfMatch++; - } - -#ifdef DEBUG_MPPC - printf("<%d,%d>", (int) CopyOffset, (int) LengthOfMatch); -#endif - - /* Encode CopyOffset */ - - if (mppc->CompressionLevel) /* RDP5 */ - { - if (CopyOffset < 64) - { - /* bits 11111 + lower 6 bits of CopyOffset */ - accumulator = 0x07C0 | (CopyOffset & 0x003F); - BitStream_Write_Bits(bs, accumulator, 11); - } - else if ((CopyOffset >= 64) && (CopyOffset < 320)) - { - /* bits 11110 + lower 8 bits of (CopyOffset - 64) */ - accumulator = 0x1E00 | ((CopyOffset - 64) & 0x00FF); - BitStream_Write_Bits(bs, accumulator, 13); - } - else if ((CopyOffset >= 320) && (CopyOffset < 2368)) - { - /* bits 1110 + lower 11 bits of (CopyOffset - 320) */ - accumulator = 0x7000 | ((CopyOffset - 320) & 0x07FF); - BitStream_Write_Bits(bs, accumulator, 15); - } - else - { - /* bits 110 + lower 16 bits of (CopyOffset - 2368) */ - accumulator = 0x060000 | ((CopyOffset - 2368) & 0xFFFF); - BitStream_Write_Bits(bs, accumulator, 19); - } - } - else /* RDP4 */ - { - if (CopyOffset < 64) - { - /* bits 1111 + lower 6 bits of CopyOffset */ - accumulator = 0x03C0 | (CopyOffset & 0x003F); - BitStream_Write_Bits(bs, accumulator, 10); - } - else if ((CopyOffset >= 64) && (CopyOffset < 320)) - { - /* bits 1110 + lower 8 bits of (CopyOffset - 64) */ - accumulator = 0x0E00 | ((CopyOffset - 64) & 0x00FF); - BitStream_Write_Bits(bs, accumulator, 12); - } - else if ((CopyOffset >= 320) && (CopyOffset < 8192)) - { - /* bits 110 + lower 13 bits of (CopyOffset - 320) */ - accumulator = 0xC000 | ((CopyOffset - 320) & 0x1FFF); - BitStream_Write_Bits(bs, accumulator, 16); - } - } - - /* Encode LengthOfMatch */ - - if (LengthOfMatch == 3) - { - /* 0 + 0 lower bits of LengthOfMatch */ - BitStream_Write_Bits(bs, 0, 1); - } - else if ((LengthOfMatch >= 4) && (LengthOfMatch < 8)) - { - /* 10 + 2 lower bits of LengthOfMatch */ - accumulator = 0x0008 | (LengthOfMatch & 0x0003); - BitStream_Write_Bits(bs, accumulator, 4); - } - else if ((LengthOfMatch >= 8) && (LengthOfMatch < 16)) - { - /* 110 + 3 lower bits of LengthOfMatch */ - accumulator = 0x0030 | (LengthOfMatch & 0x0007); - BitStream_Write_Bits(bs, accumulator, 6); - } - else if ((LengthOfMatch >= 16) && (LengthOfMatch < 32)) - { - /* 1110 + 4 lower bits of LengthOfMatch */ - accumulator = 0x00E0 | (LengthOfMatch & 0x000F); - BitStream_Write_Bits(bs, accumulator, 8); - } - else if ((LengthOfMatch >= 32) && (LengthOfMatch < 64)) - { - /* 11110 + 5 lower bits of LengthOfMatch */ - accumulator = 0x03C0 | (LengthOfMatch & 0x001F); - BitStream_Write_Bits(bs, accumulator, 10); - } - else if ((LengthOfMatch >= 64) && (LengthOfMatch < 128)) - { - /* 111110 + 6 lower bits of LengthOfMatch */ - accumulator = 0x0F80 | (LengthOfMatch & 0x003F); - BitStream_Write_Bits(bs, accumulator, 12); - } - else if ((LengthOfMatch >= 128) && (LengthOfMatch < 256)) - { - /* 1111110 + 7 lower bits of LengthOfMatch */ - accumulator = 0x3F00 | (LengthOfMatch & 0x007F); - BitStream_Write_Bits(bs, accumulator, 14); - } - else if ((LengthOfMatch >= 256) && (LengthOfMatch < 512)) - { - /* 11111110 + 8 lower bits of LengthOfMatch */ - accumulator = 0xFE00 | (LengthOfMatch & 0x00FF); - BitStream_Write_Bits(bs, accumulator, 16); - } - else if ((LengthOfMatch >= 512) && (LengthOfMatch < 1024)) - { - /* 111111110 + 9 lower bits of LengthOfMatch */ - accumulator = 0x3FC00 | (LengthOfMatch & 0x01FF); - BitStream_Write_Bits(bs, accumulator, 18); - } - else if ((LengthOfMatch >= 1024) && (LengthOfMatch < 2048)) - { - /* 1111111110 + 10 lower bits of LengthOfMatch */ - accumulator = 0xFF800 | (LengthOfMatch & 0x03FF); - BitStream_Write_Bits(bs, accumulator, 20); - } - else if ((LengthOfMatch >= 2048) && (LengthOfMatch < 4096)) - { - /* 11111111110 + 11 lower bits of LengthOfMatch */ - accumulator = 0x3FF000 | (LengthOfMatch & 0x07FF); - BitStream_Write_Bits(bs, accumulator, 22); - } - else if ((LengthOfMatch >= 4096) && (LengthOfMatch < 8192)) - { - /* 111111111110 + 12 lower bits of LengthOfMatch */ - accumulator = 0xFFE000 | (LengthOfMatch & 0x0FFF); - BitStream_Write_Bits(bs, accumulator, 24); - } - else if (((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) && mppc->CompressionLevel) /* RDP5 */ - { - /* 1111111111110 + 13 lower bits of LengthOfMatch */ - accumulator = 0x3FFC000 | (LengthOfMatch & 0x1FFF); - BitStream_Write_Bits(bs, accumulator, 26); - } - else if (((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) && mppc->CompressionLevel) /* RDP5 */ - { - /* 11111111111110 + 14 lower bits of LengthOfMatch */ - accumulator = 0xFFF8000 | (LengthOfMatch & 0x3FFF); - BitStream_Write_Bits(bs, accumulator, 28); - } - else if (((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) && mppc->CompressionLevel) /* RDP5 */ - { - /* 111111111111110 + 15 lower bits of LengthOfMatch */ - accumulator = 0x3FFF0000 | (LengthOfMatch & 0x7FFF); - BitStream_Write_Bits(bs, accumulator, 30); - } - - HistoryPtr += LengthOfMatch; - pHistoryPtr += LengthOfMatch; - } - } - - /* Encode trailing symbols as literals */ - - while (pHistoryPtr <= pEnd) - { - MatchIndex = MPPC_MATCH_INDEX(pHistoryPtr[0], pHistoryPtr[1], pHistoryPtr[2]); - pMatch = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); - mppc->MatchBuffer[MatchIndex] = (UINT16) HistoryPtr; - - accumulator = *(pHistoryPtr); - -#ifdef DEBUG_MPPC - printf("%c", accumulator); + //printf("%c", accumulator); #endif if (accumulator < 0x80) @@ -735,21 +506,206 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* } HistoryPtr++; - pHistoryPtr = &(HistoryBuffer[HistoryPtr]); + } + else + { + LengthOfMatch = 3; + CopyOffset = (HistoryBufferSize - 1) & (HistoryPtr - pMatch); + + while ((HistoryPtr[LengthOfMatch] == pMatch[LengthOfMatch]) && + (((HistoryPtr - HistoryBuffer) + LengthOfMatch) < (*pSize - 1))) + { + LengthOfMatch++; + } + +#ifdef DEBUG_MPPC + printf("<%d,%d>\n", (int) CopyOffset, (int) LengthOfMatch); +#endif + + /* Encode CopyOffset */ + + if (mppc->CompressionLevel) /* RDP5 */ + { + if (CopyOffset < 64) + { + /* bits 11111 + lower 6 bits of CopyOffset */ + accumulator = 0x07C0 | (CopyOffset & 0x003F); + BitStream_Write_Bits(bs, accumulator, 11); + } + else if ((CopyOffset >= 64) && (CopyOffset < 320)) + { + /* bits 11110 + lower 8 bits of (CopyOffset - 64) */ + accumulator = 0x1E00 | ((CopyOffset - 64) & 0x00FF); + BitStream_Write_Bits(bs, accumulator, 13); + } + else if ((CopyOffset >= 320) && (CopyOffset < 2368)) + { + /* bits 1110 + lower 11 bits of (CopyOffset - 320) */ + accumulator = 0x7000 | ((CopyOffset - 320) & 0x07FF); + BitStream_Write_Bits(bs, accumulator, 15); + } + else + { + /* bits 110 + lower 16 bits of (CopyOffset - 2368) */ + accumulator = 0x060000 | ((CopyOffset - 2368) & 0xFFFF); + BitStream_Write_Bits(bs, accumulator, 19); + } + } + else /* RDP4 */ + { + if (CopyOffset < 64) + { + /* bits 1111 + lower 6 bits of CopyOffset */ + accumulator = 0x03C0 | (CopyOffset & 0x003F); + BitStream_Write_Bits(bs, accumulator, 10); + } + else if ((CopyOffset >= 64) && (CopyOffset < 320)) + { + /* bits 1110 + lower 8 bits of (CopyOffset - 64) */ + accumulator = 0x0E00 | ((CopyOffset - 64) & 0x00FF); + BitStream_Write_Bits(bs, accumulator, 12); + } + else if ((CopyOffset >= 320) && (CopyOffset < 8192)) + { + /* bits 110 + lower 13 bits of (CopyOffset - 320) */ + accumulator = 0xC000 | ((CopyOffset - 320) & 0x1FFF); + BitStream_Write_Bits(bs, accumulator, 16); + } + } + + /* Encode LengthOfMatch */ + + if (LengthOfMatch == 3) + { + /* 0 + 0 lower bits of LengthOfMatch */ + BitStream_Write_Bits(bs, 0, 1); + } + else if ((LengthOfMatch >= 4) && (LengthOfMatch < 8)) + { + /* 10 + 2 lower bits of LengthOfMatch */ + accumulator = 0x0008 | (LengthOfMatch & 0x0003); + BitStream_Write_Bits(bs, accumulator, 4); + } + else if ((LengthOfMatch >= 8) && (LengthOfMatch < 16)) + { + /* 110 + 3 lower bits of LengthOfMatch */ + accumulator = 0x0030 | (LengthOfMatch & 0x0007); + BitStream_Write_Bits(bs, accumulator, 6); + } + else if ((LengthOfMatch >= 16) && (LengthOfMatch < 32)) + { + /* 1110 + 4 lower bits of LengthOfMatch */ + accumulator = 0x00E0 | (LengthOfMatch & 0x000F); + BitStream_Write_Bits(bs, accumulator, 8); + } + else if ((LengthOfMatch >= 32) && (LengthOfMatch < 64)) + { + /* 11110 + 5 lower bits of LengthOfMatch */ + accumulator = 0x03C0 | (LengthOfMatch & 0x001F); + BitStream_Write_Bits(bs, accumulator, 10); + } + else if ((LengthOfMatch >= 64) && (LengthOfMatch < 128)) + { + /* 111110 + 6 lower bits of LengthOfMatch */ + accumulator = 0x0F80 | (LengthOfMatch & 0x003F); + BitStream_Write_Bits(bs, accumulator, 12); + } + else if ((LengthOfMatch >= 128) && (LengthOfMatch < 256)) + { + /* 1111110 + 7 lower bits of LengthOfMatch */ + accumulator = 0x3F00 | (LengthOfMatch & 0x007F); + BitStream_Write_Bits(bs, accumulator, 14); + } + else if ((LengthOfMatch >= 256) && (LengthOfMatch < 512)) + { + /* 11111110 + 8 lower bits of LengthOfMatch */ + accumulator = 0xFE00 | (LengthOfMatch & 0x00FF); + BitStream_Write_Bits(bs, accumulator, 16); + } + else if ((LengthOfMatch >= 512) && (LengthOfMatch < 1024)) + { + /* 111111110 + 9 lower bits of LengthOfMatch */ + accumulator = 0x3FC00 | (LengthOfMatch & 0x01FF); + BitStream_Write_Bits(bs, accumulator, 18); + } + else if ((LengthOfMatch >= 1024) && (LengthOfMatch < 2048)) + { + /* 1111111110 + 10 lower bits of LengthOfMatch */ + accumulator = 0xFF800 | (LengthOfMatch & 0x03FF); + BitStream_Write_Bits(bs, accumulator, 20); + } + else if ((LengthOfMatch >= 2048) && (LengthOfMatch < 4096)) + { + /* 11111111110 + 11 lower bits of LengthOfMatch */ + accumulator = 0x3FF000 | (LengthOfMatch & 0x07FF); + BitStream_Write_Bits(bs, accumulator, 22); + } + else if ((LengthOfMatch >= 4096) && (LengthOfMatch < 8192)) + { + /* 111111111110 + 12 lower bits of LengthOfMatch */ + accumulator = 0xFFE000 | (LengthOfMatch & 0x0FFF); + BitStream_Write_Bits(bs, accumulator, 24); + } + else if (((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) && mppc->CompressionLevel) /* RDP5 */ + { + /* 1111111111110 + 13 lower bits of LengthOfMatch */ + accumulator = 0x3FFC000 | (LengthOfMatch & 0x1FFF); + BitStream_Write_Bits(bs, accumulator, 26); + } + else if (((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) && mppc->CompressionLevel) /* RDP5 */ + { + /* 11111111111110 + 14 lower bits of LengthOfMatch */ + accumulator = 0xFFF8000 | (LengthOfMatch & 0x3FFF); + BitStream_Write_Bits(bs, accumulator, 28); + } + else if (((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) && mppc->CompressionLevel) /* RDP5 */ + { + /* 111111111111110 + 15 lower bits of LengthOfMatch */ + accumulator = 0x3FFF0000 | (LengthOfMatch & 0x7FFF); + BitStream_Write_Bits(bs, accumulator, 30); + } + + HistoryPtr += LengthOfMatch; } } - /* HistoryPtr < HistoryOffset? (NO) */ + /* Encode trailing symbols as literals */ - Flags |= PACKET_COMPRESSED; + while (HistoryPtr <= pSrcEnd) + { + MatchIndex = MPPC_MATCH_INDEX(HistoryPtr[0], HistoryPtr[1], HistoryPtr[2]); + pMatch = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); + mppc->MatchBuffer[MatchIndex] = (UINT16) (HistoryPtr - HistoryBuffer); + + accumulator = *(HistoryPtr); + +#ifdef DEBUG_MPPC + //printf("%c", accumulator); +#endif + + if (accumulator < 0x80) + { + /* 8 bits of literal are encoded as-is */ + BitStream_Write_Bits(bs, accumulator, 8); + } + else + { + /* bits 10 followed by lower 7 bits of literal */ + accumulator = 0x100 | (accumulator & 0x7F); + BitStream_Write_Bits(bs, accumulator, 9); + } + + HistoryPtr++; + } BitStream_Flush(bs); + + Flags |= PACKET_COMPRESSED; *pSize = ((bs->position + 7) / 8); + mppc->HistoryOffset = HistoryPtr - HistoryBuffer; mppc->HistoryPtr = HistoryPtr; - mppc->pHistoryPtr = pHistoryPtr; mppc->HistoryOffset = HistoryOffset; - mppc->pHistoryOffset = pHistoryOffset; #ifdef DEBUG_MPPC printf("\n"); @@ -784,11 +740,8 @@ MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor) mppc->bs = BitStream_New(); - mppc->HistoryPtr = 0; - mppc->pHistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryPtr]); - + mppc->HistoryPtr = &(mppc->HistoryBuffer[0]); mppc->HistoryOffset = 0; - mppc->pHistoryOffset = &(mppc->HistoryBuffer[mppc->HistoryOffset]); } return mppc; diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index 8a2bbbce3..b8f612c18 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -1017,6 +1017,7 @@ int test_MppcDecompressBufferRdp5() int TestFreeRDPCodecMppc(int argc, char* argv[]) { +#if 1 if (test_MppcCompressBellsRdp5() < 0) return -1; @@ -1028,11 +1029,14 @@ int TestFreeRDPCodecMppc(int argc, char* argv[]) if (test_MppcDecompressBellsRdp4() < 0) return -1; +#endif +#if 0 test_MppcCompressBufferRdp5(); - +#else if (test_MppcDecompressBufferRdp5() < 0) return -1; +#endif //test_mppc_old(); From baeefd1263a3aed0ef2f10ec0e4da52b47022978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 9 Mar 2014 21:58:00 -0400 Subject: [PATCH 9/9] libfreerdp-codec: MPPC cleanup --- libfreerdp/codec/mppc.c | 91 +++++++++++++------- libfreerdp/codec/test/TestFreeRDPCodecMppc.c | 27 ++++-- 2 files changed, 82 insertions(+), 36 deletions(-) diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index f31baccae..bdcd681a5 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -70,7 +70,7 @@ const UINT32 MPPC_MATCH_TABLE[256] = 0x97E91668, 0x9885E5FB, 0x9922B58E, 0x99BF8521, 0x9A5C54B4, 0x9AF92447, 0x9B95F3DA, 0x9C32C36D }; -#define DEBUG_MPPC 1 +//#define DEBUG_MPPC 1 UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UINT32* pSize, UINT32 flags) { @@ -82,9 +82,12 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN BYTE* HistoryBuffer; BYTE* HistoryPtr; UINT32 HistoryOffset; + UINT32 CompressionLevel; wBitStream* bs = mppc->bs; HistoryBuffer = mppc->HistoryBuffer; + CompressionLevel = mppc->CompressionLevel; + *ppDstData = HistoryBuffer; BitStream_Attach(bs, pSrcData, *pSize); @@ -158,7 +161,7 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN CopyOffset = 0; - if (mppc->CompressionLevel) /* RDP5 */ + if (CompressionLevel) /* RDP5 */ { if ((accumulator & 0xF8000000) == 0xF8000000) { @@ -370,7 +373,7 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN LengthOfMatch = ((accumulator >> 8) & 0x0FFF) + 0x1000; BitStream_Shift(bs, 24); } - else if (((accumulator & 0xFFF80000) == 0xFFF00000) && mppc->CompressionLevel) /* RDP5 */ + else if (((accumulator & 0xFFF80000) == 0xFFF00000) && CompressionLevel) /* RDP5 */ { /** * LengthOfMatch [8192, 16383] @@ -380,7 +383,7 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN LengthOfMatch = ((accumulator >> 6) & 0x1FFF) + 0x2000; BitStream_Shift(bs, 26); } - else if (((accumulator & 0xFFFC0000) == 0xFFF80000) && mppc->CompressionLevel) /* RDP5 */ + else if (((accumulator & 0xFFFC0000) == 0xFFF80000) && CompressionLevel) /* RDP5 */ { /** * LengthOfMatch [16384, 32767] @@ -390,7 +393,7 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN LengthOfMatch = ((accumulator >> 4) & 0x3FFF) + 0x4000; BitStream_Shift(bs, 28); } - else if (((accumulator & 0xFFFE0000) == 0xFFFC0000) && mppc->CompressionLevel) /* RDP5 */ + else if (((accumulator & 0xFFFE0000) == 0xFFFC0000) && CompressionLevel) /* RDP5 */ { /** * LengthOfMatch [32768, 65535] @@ -432,21 +435,23 @@ UINT32 mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE** ppDstData, UIN UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize) { UINT32 Flags; - BYTE* pMatch; BYTE* pSrcEnd; BYTE* pDstEnd; - DWORD CopyOffset; - DWORD LengthOfMatch; + BYTE* MatchPtr; UINT32 MatchIndex; UINT32 accumulator; + DWORD CopyOffset; + DWORD LengthOfMatch; BYTE* HistoryBuffer; BYTE* HistoryPtr; UINT32 HistoryOffset; UINT32 HistoryBufferSize; + UINT32 CompressionLevel; wBitStream* bs = mppc->bs; HistoryBuffer = mppc->HistoryBuffer; HistoryBufferSize = mppc->HistoryBufferSize; + CompressionLevel = mppc->CompressionLevel; HistoryPtr = mppc->HistoryPtr; HistoryOffset = mppc->HistoryOffset; @@ -455,18 +460,18 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* CopyMemory(&(HistoryBuffer[HistoryOffset]), pSrcData, *pSize); - if (((HistoryOffset + *pSize) < (mppc->HistoryBufferSize - 3)) && HistoryOffset) + if (((HistoryOffset + *pSize) < (HistoryBufferSize - 3)) && HistoryOffset) { - Flags = mppc->CompressionLevel; + Flags = 0; } else { HistoryOffset = 0; - Flags = PACKET_AT_FRONT | mppc->CompressionLevel; + Flags = PACKET_AT_FRONT; } + HistoryPtr = &(HistoryBuffer[HistoryOffset]); HistoryOffset += *pSize; - HistoryPtr = &(HistoryBuffer[0]); pSrcEnd = &(HistoryBuffer[*pSize - 1]); pDstEnd = &(pDstData[*pSize - 1]); @@ -474,18 +479,18 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* while (HistoryPtr < (pSrcEnd - 2)) { MatchIndex = MPPC_MATCH_INDEX(HistoryPtr[0], HistoryPtr[1], HistoryPtr[2]); - pMatch = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); + MatchPtr = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); - //if (&pMatch[1] != HistoryPtr) + /* if (&MatchPtr[1] != HistoryPtr) */ mppc->MatchBuffer[MatchIndex] = (UINT16) (HistoryPtr - HistoryBuffer); if (mppc->HistoryPtr < HistoryPtr) mppc->HistoryPtr = HistoryPtr; - if ((HistoryPtr[0] != pMatch[0]) || (HistoryPtr[1] != pMatch[1]) || - (HistoryPtr[2] != pMatch[2]) || (&pMatch[2] > mppc->HistoryPtr) || - (pMatch == HistoryPtr) || (&pMatch[1] == HistoryPtr) || - (pMatch == HistoryBuffer)) + if ((HistoryPtr[0] != MatchPtr[0]) || (HistoryPtr[1] != MatchPtr[1]) || + (HistoryPtr[2] != MatchPtr[2]) || (&MatchPtr[2] > mppc->HistoryPtr) || + (MatchPtr == HistoryPtr) || (&MatchPtr[1] == HistoryPtr) || + (MatchPtr == HistoryBuffer)) { accumulator = *(HistoryPtr); @@ -493,6 +498,14 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* //printf("%c", accumulator); #endif + if (((bs->position / 8) + 2) > (*pSize - 1)) + { + Flags = PACKET_FLUSHED; + ZeroMemory(HistoryBuffer, HistoryBufferSize); + ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer)); + return Flags; + } + if (accumulator < 0x80) { /* 8 bits of literal are encoded as-is */ @@ -510,12 +523,17 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* else { LengthOfMatch = 3; - CopyOffset = (HistoryBufferSize - 1) & (HistoryPtr - pMatch); + HistoryPtr += 3; + MatchPtr += 3; - while ((HistoryPtr[LengthOfMatch] == pMatch[LengthOfMatch]) && - (((HistoryPtr - HistoryBuffer) + LengthOfMatch) < (*pSize - 1))) + CopyOffset = (HistoryBufferSize - 1) & (HistoryPtr - MatchPtr); + + while ((*HistoryPtr == *MatchPtr) && /* (MatchPtr <= mppc->HistoryPtr) && */ + ((HistoryPtr - HistoryBuffer) < (*pSize - 1))) { LengthOfMatch++; + HistoryPtr++; + MatchPtr++; } #ifdef DEBUG_MPPC @@ -524,7 +542,15 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* /* Encode CopyOffset */ - if (mppc->CompressionLevel) /* RDP5 */ + if (((bs->position / 8) + 7) > (*pSize - 1)) + { + Flags = PACKET_FLUSHED; + ZeroMemory(HistoryBuffer, HistoryBufferSize); + ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer)); + return Flags; + } + + if (CompressionLevel) /* RDP5 */ { if (CopyOffset < 64) { @@ -646,26 +672,24 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* accumulator = 0xFFE000 | (LengthOfMatch & 0x0FFF); BitStream_Write_Bits(bs, accumulator, 24); } - else if (((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) && mppc->CompressionLevel) /* RDP5 */ + else if (((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) && CompressionLevel) /* RDP5 */ { /* 1111111111110 + 13 lower bits of LengthOfMatch */ accumulator = 0x3FFC000 | (LengthOfMatch & 0x1FFF); BitStream_Write_Bits(bs, accumulator, 26); } - else if (((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) && mppc->CompressionLevel) /* RDP5 */ + else if (((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) && CompressionLevel) /* RDP5 */ { /* 11111111111110 + 14 lower bits of LengthOfMatch */ accumulator = 0xFFF8000 | (LengthOfMatch & 0x3FFF); BitStream_Write_Bits(bs, accumulator, 28); } - else if (((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) && mppc->CompressionLevel) /* RDP5 */ + else if (((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) && CompressionLevel) /* RDP5 */ { /* 111111111111110 + 15 lower bits of LengthOfMatch */ accumulator = 0x3FFF0000 | (LengthOfMatch & 0x7FFF); BitStream_Write_Bits(bs, accumulator, 30); } - - HistoryPtr += LengthOfMatch; } } @@ -674,7 +698,7 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* while (HistoryPtr <= pSrcEnd) { MatchIndex = MPPC_MATCH_INDEX(HistoryPtr[0], HistoryPtr[1], HistoryPtr[2]); - pMatch = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); + MatchPtr = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]); mppc->MatchBuffer[MatchIndex] = (UINT16) (HistoryPtr - HistoryBuffer); accumulator = *(HistoryPtr); @@ -683,6 +707,14 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* //printf("%c", accumulator); #endif + if (((bs->position / 8) + 2) > (*pSize - 1)) + { + Flags = PACKET_FLUSHED; + ZeroMemory(HistoryBuffer, HistoryBufferSize); + ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer)); + return Flags; + } + if (accumulator < 0x80) { /* 8 bits of literal are encoded as-is */ @@ -702,10 +734,9 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* Flags |= PACKET_COMPRESSED; *pSize = ((bs->position + 7) / 8); - mppc->HistoryOffset = HistoryPtr - HistoryBuffer; mppc->HistoryPtr = HistoryPtr; - mppc->HistoryOffset = HistoryOffset; + mppc->HistoryOffset = HistoryPtr - HistoryBuffer; #ifdef DEBUG_MPPC printf("\n"); diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index b8f612c18..720a78ce6 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -958,6 +958,8 @@ int test_MppcCompressBufferRdp5() MPPC_CONTEXT* mppc; UINT32 expectedSize; BYTE OutputBuffer[65536]; + MPPC_CONTEXT* mppcRecv; + BYTE* pDstData = NULL; mppc = mppc_context_new(1, TRUE); @@ -968,13 +970,29 @@ int test_MppcCompressBufferRdp5() flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); printf("flags: 0x%04X size: %d\n", flags, size); + mppcRecv = mppc_context_new(1, FALSE); + + pSrcData = (BYTE*) OutputBuffer; + flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1; + expectedSize = sizeof(TEST_RDP5_UNCOMPRESSED_DATA); + + flags = mppc_decompress(mppcRecv, pSrcData, &pDstData, &size, flags); + printf("flags: 0x%04X size: %d\n", flags, size); + if (size != expectedSize) { printf("MppcCompressBufferRdp5: output size mismatch: Actual: %d, Expected: %d\n", size, expectedSize); return -1; } + if (memcmp(pDstData, TEST_RDP5_UNCOMPRESSED_DATA, size) != 0) + { + printf("MppcCompressBufferRdp5: output mismatch: Decompress(Compress(X)) != X\n"); + return -1; + } + mppc_context_free(mppc); + mppc_context_free(mppcRecv); return 0; } @@ -1017,7 +1035,6 @@ int test_MppcDecompressBufferRdp5() int TestFreeRDPCodecMppc(int argc, char* argv[]) { -#if 1 if (test_MppcCompressBellsRdp5() < 0) return -1; @@ -1029,14 +1046,12 @@ int TestFreeRDPCodecMppc(int argc, char* argv[]) if (test_MppcDecompressBellsRdp4() < 0) return -1; -#endif -#if 0 - test_MppcCompressBufferRdp5(); -#else + if (test_MppcCompressBufferRdp5() < 0) + return -1; + if (test_MppcDecompressBufferRdp5() < 0) return -1; -#endif //test_mppc_old();