libfreerdp-codec: start MPPC compressor

This commit is contained in:
Marc-André Moreau 2014-03-08 17:38:47 -05:00
parent 77e91aa762
commit d9a2fb4ff9
7 changed files with 382 additions and 82 deletions

View File

@ -45,6 +45,7 @@ extern "C" {
#endif #endif
FREERDP_API UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize); 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 MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor);
FREERDP_API void mppc_context_free(MPPC_CONTEXT* mppc); FREERDP_API void mppc_context_free(MPPC_CONTEXT* mppc);

View File

@ -24,7 +24,7 @@
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/print.h> #include <winpr/print.h>
#include <winpr/stream.h> #include <winpr/stream.h>
#include <winpr/collections.h> #include <winpr/bitstream.h>
#include <freerdp/codec/mppc_enc.h> #include <freerdp/codec/mppc_enc.h>
#include <freerdp/codec/mppc_dec.h> #include <freerdp/codec/mppc_dec.h>
@ -72,6 +72,179 @@ const UINT32 MPPC_MATCH_TABLE[256] =
//#define DEBUG_MPPC 1 //#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) UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32* pSize)
{ {
BYTE* pEnd; BYTE* pEnd;
@ -80,32 +253,28 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32*
UINT32 MatchIndex; UINT32 MatchIndex;
UINT32 accumulator; UINT32 accumulator;
Flags = mppc->CompressionLevel;
BitStream_Attach(mppc->bs, pDstData, *pSize); 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) */ Flags = mppc->CompressionLevel;
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]);
} }
else else
{ {
/* SrcData fits into HistoryBuffer? (NO) */
mppc->HistoryOffset = 0; mppc->HistoryOffset = 0;
mppc->pHistoryOffset = &(mppc->HistoryBuffer[mppc->HistoryOffset]); 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) if (mppc->HistoryPtr < mppc->HistoryOffset)
{ {
/* HistoryPtr < HistoryOffset? (YES) */ /* HistoryPtr < HistoryOffset? (YES) */

View File

@ -1,5 +1,6 @@
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/print.h> #include <winpr/print.h>
#include <winpr/bitstream.h>
#include <freerdp/freerdp.h> #include <freerdp/freerdp.h>
#include <freerdp/codec/mppc.h> #include <freerdp/codec/mppc.h>
@ -684,9 +685,28 @@ int test_mppc_old()
return 0; 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 size;
UINT32 flags; UINT32 flags;
@ -696,15 +716,75 @@ int TestFreeRDPCodecMppc(int argc, char* argv[])
mppc = mppc_context_new(1, TRUE); mppc = mppc_context_new(1, TRUE);
#if 0 size = sizeof(TEST_MPPC_BELLS) - 1;
size = sizeof(TEST_MPPC_BELL_TOLLS) - 1; pSrcData = (BYTE*) TEST_MPPC_BELLS;
pSrcData = (BYTE*) TEST_MPPC_BELL_TOLLS;
printf("%s\n", pSrcData); printf("%s\n", pSrcData);
flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size); flags = mppc_compress(mppc, pSrcData, OutputBuffer, &size);
printf("flags: 0x%04X size: %d\n", flags, 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 #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); size = sizeof(TEST_RDP5_UNCOMPRESSED_DATA);
pSrcData = (BYTE*) TEST_RDP5_UNCOMPRESSED_DATA; pSrcData = (BYTE*) TEST_RDP5_UNCOMPRESSED_DATA;
@ -720,3 +800,11 @@ int TestFreeRDPCodecMppc(int argc, char* argv[])
return 0; return 0;
} }
int TestFreeRDPCodecMppc(int argc, char* argv[])
{
//test_MppcCompressBells();
test_MppcDecompressBells();
return 0;
}

View File

@ -0,0 +1,95 @@
/*
* WinPR: Windows Portable Runtime
* BitStream Utils
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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 <winpr/winpr.h>
#include <winpr/wtypes.h>
#include <winpr/crt.h>
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 */

View File

@ -27,6 +27,7 @@
#include <winpr/winpr.h> #include <winpr/winpr.h>
#include <winpr/wtypes.h> #include <winpr/wtypes.h>
#include <winpr/crt.h>
#include <winpr/synch.h> #include <winpr/synch.h>
#include <winpr/stream.h> #include <winpr/stream.h>
@ -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 wPubSub* PubSub_New(BOOL synchronized);
WINPR_API void PubSub_Free(wPubSub* pubSub); 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 #ifdef __cplusplus
} }
#endif #endif
#endif /* WINPR_COLLECTIONS_H */ #endif /* WINPR_COLLECTIONS_H */

View File

@ -21,7 +21,7 @@
#include "config.h" #include "config.h"
#endif #endif
#include <winpr/collections.h> #include <winpr/bitstream.h>
const char* BYTE_BIT_STRINGS_LSB[256] = const char* BYTE_BIT_STRINGS_LSB[256] =
{ {
@ -159,7 +159,7 @@ const char* BYTE_BIT_STRINGS_MSB[256] =
"00111111", "10111111", "01111111", "11111111" "00111111", "10111111", "01111111", "11111111"
}; };
void BitDump(BYTE* buffer, UINT32 length, UINT32 flags) void BitDump(const BYTE* buffer, UINT32 length, UINT32 flags)
{ {
DWORD i; DWORD i;
int nbits; int nbits;
@ -174,6 +174,9 @@ void BitDump(BYTE* buffer, UINT32 length, UINT32 flags)
nbits = (length - i) > 8 ? 8 : (length - i); nbits = (length - i) > 8 ? 8 : (length - i);
if ((i % 64) == 0)
printf("\n");
printf("%.*s ", nbits, str); printf("%.*s ", nbits, str);
} }

View File

@ -2,7 +2,7 @@
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/print.h> #include <winpr/print.h>
#include <winpr/stream.h> #include <winpr/stream.h>
#include <winpr/collections.h> #include <winpr/bitstream.h>
void BitStrGen() void BitStrGen()
{ {