libfreerdp-codec: make MPPC compressor produce output identical to Microsoft implementation
This commit is contained in:
parent
2f756745e9
commit
f31676e4e4
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user