From f31676e4e42104d38f5357453aa7f124ccc44a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 10 Mar 2014 15:06:23 -0400 Subject: [PATCH] libfreerdp-codec: make MPPC compressor produce output identical to Microsoft implementation --- include/freerdp/codec/mppc.h | 2 + libfreerdp/codec/mppc.c | 101 ++++++++++--------- libfreerdp/codec/test/TestFreeRDPCodecMppc.c | 22 ++++ libfreerdp/core/bulk.c | 29 ++++-- libfreerdp/core/bulk.h | 3 + libfreerdp/core/fastpath.c | 2 - 6 files changed, 105 insertions(+), 54 deletions(-) diff --git a/include/freerdp/codec/mppc.h b/include/freerdp/codec/mppc.h index 7d03dba7d..88489ccdb 100644 --- a/include/freerdp/codec/mppc.h +++ b/include/freerdp/codec/mppc.h @@ -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); diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index bdcd681a5..a0cc469a0 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -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; diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index 720a78ce6..edd00c794 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -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); diff --git a/libfreerdp/core/bulk.c b/libfreerdp/core/bulk.c index fb452855e..607e765c7 100644 --- a/libfreerdp/core/bulk.c +++ b/libfreerdp/core/bulk.c @@ -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; - status = 0; - } + 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); } } diff --git a/libfreerdp/core/bulk.h b/libfreerdp/core/bulk.h index d589b96b3..b6cf74a40 100644 --- a/libfreerdp/core/bulk.h +++ b/libfreerdp/core/bulk.h @@ -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; }; diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c index bbabb34c9..099173287 100644 --- a/libfreerdp/core/fastpath.c +++ b/libfreerdp/core/fastpath.c @@ -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;