libfreerdp-codec: make MPPC compressor produce output identical to Microsoft implementation

This commit is contained in:
Marc-André Moreau 2014-03-10 15:06:23 -04:00
parent 2f756745e9
commit f31676e4e4
6 changed files with 105 additions and 54 deletions

View File

@ -45,6 +45,8 @@ extern "C" {
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** ppDstData, UINT32* pSize, UINT32 flags);
FREERDP_API void mppc_context_reset(MPPC_CONTEXT* mppc);
FREERDP_API MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor);
FREERDP_API void mppc_context_free(MPPC_CONTEXT* mppc);

View File

@ -435,6 +435,7 @@ 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* pSrcPtr;
BYTE* pSrcEnd;
BYTE* pDstEnd;
BYTE* MatchPtr;
@ -446,6 +447,7 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32*
BYTE* HistoryPtr;
UINT32 HistoryOffset;
UINT32 HistoryBufferSize;
BYTE Sym1, Sym2, Sym3;
UINT32 CompressionLevel;
wBitStream* bs = mppc->bs;
@ -458,8 +460,6 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32*
BitStream_Attach(bs, pDstData, *pSize);
CopyMemory(&(HistoryBuffer[HistoryOffset]), pSrcData, *pSize);
if (((HistoryOffset + *pSize) < (HistoryBufferSize - 3)) && HistoryOffset)
{
Flags = 0;
@ -471,41 +471,46 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32*
}
HistoryPtr = &(HistoryBuffer[HistoryOffset]);
HistoryOffset += *pSize;
pSrcEnd = &(HistoryBuffer[*pSize - 1]);
pSrcPtr = pSrcData;
pSrcEnd = &(pSrcData[*pSize - 1]);
pDstEnd = &(pDstData[*pSize - 1]);
while (HistoryPtr < (pSrcEnd - 2))
while (pSrcPtr < (pSrcEnd - 2))
{
MatchIndex = MPPC_MATCH_INDEX(HistoryPtr[0], HistoryPtr[1], HistoryPtr[2]);
Sym1 = pSrcPtr[0];
Sym2 = pSrcPtr[1];
Sym3 = pSrcPtr[2];
*HistoryPtr++ = *pSrcPtr++;
MatchIndex = MPPC_MATCH_INDEX(Sym1, Sym2, Sym3);
MatchPtr = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]);
/* if (&MatchPtr[1] != HistoryPtr) */
if (MatchPtr != &HistoryPtr[-1])
mppc->MatchBuffer[MatchIndex] = (UINT16) (HistoryPtr - HistoryBuffer);
if (mppc->HistoryPtr < HistoryPtr)
mppc->HistoryPtr = HistoryPtr;
if ((HistoryPtr[0] != MatchPtr[0]) || (HistoryPtr[1] != MatchPtr[1]) ||
(HistoryPtr[2] != MatchPtr[2]) || (&MatchPtr[2] > mppc->HistoryPtr) ||
(MatchPtr == HistoryPtr) || (&MatchPtr[1] == HistoryPtr) ||
(MatchPtr == HistoryBuffer))
if ((Sym1 != MatchPtr[-1]) || (Sym2 != MatchPtr[0]) || (Sym3 != MatchPtr[1]) ||
(&MatchPtr[1] > mppc->HistoryPtr) || (MatchPtr == HistoryBuffer) ||
(MatchPtr == &HistoryPtr[-1]) || (MatchPtr == HistoryPtr))
{
accumulator = *(HistoryPtr);
#ifdef DEBUG_MPPC
//printf("%c", accumulator);
#endif
if (((bs->position / 8) + 2) > (*pSize - 1))
{
Flags = PACKET_FLUSHED;
Flags |= PACKET_FLUSHED;
ZeroMemory(HistoryBuffer, HistoryBufferSize);
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
return Flags;
}
accumulator = Sym1;
#ifdef DEBUG_MPPC
printf("%c", accumulator);
#endif
if (accumulator < 0x80)
{
/* 8 bits of literal are encoded as-is */
@ -517,27 +522,27 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32*
accumulator = 0x100 | (accumulator & 0x7F);
BitStream_Write_Bits(bs, accumulator, 9);
}
HistoryPtr++;
}
else
{
LengthOfMatch = 3;
HistoryPtr += 3;
MatchPtr += 3;
CopyOffset = (HistoryBufferSize - 1) & (HistoryPtr - MatchPtr);
while ((*HistoryPtr == *MatchPtr) && /* (MatchPtr <= mppc->HistoryPtr) && */
((HistoryPtr - HistoryBuffer) < (*pSize - 1)))
*HistoryPtr++ = Sym2;
*HistoryPtr++ = Sym3;
pSrcPtr += 2;
LengthOfMatch = 3;
MatchPtr += 2;
while ((*pSrcPtr == *MatchPtr) && (pSrcPtr < pSrcEnd) && (MatchPtr <= mppc->HistoryPtr))
{
LengthOfMatch++;
HistoryPtr++;
MatchPtr++;
*HistoryPtr++ = *pSrcPtr++;
LengthOfMatch++;
}
#ifdef DEBUG_MPPC
printf("<%d,%d>\n", (int) CopyOffset, (int) LengthOfMatch);
printf("<%d,%d>", (int) CopyOffset, (int) LengthOfMatch);
#endif
/* Encode CopyOffset */
@ -695,26 +700,22 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32*
/* Encode trailing symbols as literals */
while (HistoryPtr <= pSrcEnd)
while (pSrcPtr <= pSrcEnd)
{
MatchIndex = MPPC_MATCH_INDEX(HistoryPtr[0], HistoryPtr[1], HistoryPtr[2]);
MatchPtr = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]);
mppc->MatchBuffer[MatchIndex] = (UINT16) (HistoryPtr - HistoryBuffer);
accumulator = *(HistoryPtr);
#ifdef DEBUG_MPPC
//printf("%c", accumulator);
#endif
if (((bs->position / 8) + 2) > (*pSize - 1))
{
Flags = PACKET_FLUSHED;
Flags |= PACKET_FLUSHED;
ZeroMemory(HistoryBuffer, HistoryBufferSize);
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
return Flags;
}
accumulator = *pSrcPtr;
#ifdef DEBUG_MPPC
printf("%c", accumulator);
#endif
if (accumulator < 0x80)
{
/* 8 bits of literal are encoded as-is */
@ -727,12 +728,13 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32*
BitStream_Write_Bits(bs, accumulator, 9);
}
HistoryPtr++;
*HistoryPtr++ = *pSrcPtr++;
}
BitStream_Flush(bs);
Flags |= PACKET_COMPRESSED;
Flags |= CompressionLevel;
*pSize = ((bs->position + 7) / 8);
mppc->HistoryPtr = HistoryPtr;
@ -745,6 +747,15 @@ UINT32 mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, BYTE* pDstData, UINT32*
return Flags;
}
void mppc_context_reset(MPPC_CONTEXT* mppc)
{
ZeroMemory(&(mppc->HistoryBuffer), sizeof(mppc->HistoryBuffer));
ZeroMemory(&(mppc->MatchBuffer), sizeof(mppc->MatchBuffer));
mppc->HistoryOffset = 0;
mppc->HistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryOffset]);
}
MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor)
{
MPPC_CONTEXT* mppc;
@ -766,13 +777,13 @@ MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor)
mppc->HistoryBufferSize = 65536;
}
mppc->bs = BitStream_New();
ZeroMemory(&(mppc->HistoryBuffer), sizeof(mppc->HistoryBuffer));
ZeroMemory(&(mppc->MatchBuffer), sizeof(mppc->MatchBuffer));
mppc->bs = BitStream_New();
mppc->HistoryPtr = &(mppc->HistoryBuffer[0]);
mppc->HistoryOffset = 0;
mppc->HistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryOffset]);
}
return mppc;

View File

@ -991,6 +991,28 @@ int test_MppcCompressBufferRdp5()
return -1;
}
/* Compare against Microsoft implementation */
size = sizeof(TEST_RDP5_UNCOMPRESSED_DATA);
pSrcData = (BYTE*) TEST_RDP5_UNCOMPRESSED_DATA;
expectedSize = sizeof(TEST_RDP5_COMPRESSED_DATA);
mppc_context_reset(mppc);
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;
}
if (memcmp(OutputBuffer, TEST_RDP5_COMPRESSED_DATA, size) != 0)
{
printf("MppcCompressBufferRdp5: output mismatch: compressed output does not match Microsoft implementation\n");
return -1;
}
mppc_context_free(mppc);
mppc_context_free(mppcRecv);

View File

@ -42,6 +42,7 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD
status = decompress_rdp_5(bulk->mppc_dec, pSrcData, SrcSize, flags, &roff, &rlen);
*ppDstData = (bulk->mppc_dec->history_buf + roff);
*pDstSize = rlen;
printf("BulkDecompress: SrcSize: %d DstSize: %d Flags: 0x%04X\n", SrcSize, *pDstSize, flags);
break;
case PACKET_COMPR_TYPE_RDP6:
@ -64,21 +65,28 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD
int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
{
UINT32 size;
UINT32 flags;
int status = -1;
if (compress_rdp(bulk->mppc_enc, pSrcData, SrcSize))
{
*pFlags = (UINT32) bulk->mppc_enc->flags;
*pDstSize = (UINT32) bulk->mppc_enc->bytes_in_opb;
*ppDstData = (BYTE*) bulk->mppc_enc->outputBuffer;
size = SrcSize;
flags = mppc_compress(bulk->mppcSend, pSrcData, bulk->OutputBuffer, &size);
*pFlags = flags;
*pDstSize = size;
*ppDstData = bulk->OutputBuffer;
status = 0;
}
printf("BulkCompress: SrcSize: %d DstSize: %d Flags: 0x%04X\n", SrcSize, *pDstSize, flags);
return status;
}
void bulk_reset(rdpBulk* bulk)
{
mppc_context_reset(bulk->mppcSend);
mppc_context_reset(bulk->mppcRecv);
mppc_dec_free(bulk->mppc_dec);
mppc_enc_free(bulk->mppc_enc);
bulk->mppc_dec = mppc_dec_new();
@ -95,6 +103,9 @@ rdpBulk* bulk_new(rdpContext* context)
{
bulk->context = context;
bulk->mppcSend = mppc_context_new(1, TRUE);
bulk->mppcRecv = mppc_context_new(1, FALSE);
bulk->mppc_dec = mppc_dec_new();
bulk->mppc_enc = mppc_enc_new(PROTO_RDP_50);
}
@ -106,8 +117,12 @@ void bulk_free(rdpBulk* bulk)
{
if (bulk)
{
mppc_context_free(bulk->mppcSend);
mppc_context_free(bulk->mppcRecv);
mppc_dec_free(bulk->mppc_dec);
mppc_enc_free(bulk->mppc_enc);
free(bulk);
}
}

View File

@ -31,6 +31,9 @@ typedef struct rdp_bulk rdpBulk;
struct rdp_bulk
{
rdpContext* context;
MPPC_CONTEXT* mppcSend;
MPPC_CONTEXT* mppcRecv;
BYTE OutputBuffer[65536];
struct rdp_mppc_dec* mppc_dec;
struct rdp_mppc_enc* mppc_enc;
};

View File

@ -857,8 +857,6 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
header_bytes = 6 + sec_bytes;
pdu_data_bytes = dlen;
try_comp = FALSE;
if (try_comp)
{
SrcSize = dlen;