From 9162fcc7d871ed059ec844e1e5ed92460f56b67e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sun, 4 May 2014 21:50:17 -0400 Subject: [PATCH] libfreerdp-codec: start working on XCrush decompressor --- include/freerdp/codec/xcrush.h | 5 ++ libfreerdp/codec/xcrush.c | 111 ++++++++++++++++++++++++++++++++- libfreerdp/core/bulk.c | 14 ++++- libfreerdp/core/bulk.h | 3 + 4 files changed, 130 insertions(+), 3 deletions(-) diff --git a/include/freerdp/codec/xcrush.h b/include/freerdp/codec/xcrush.h index 4be6e2d9e..cbe1a898e 100644 --- a/include/freerdp/codec/xcrush.h +++ b/include/freerdp/codec/xcrush.h @@ -46,6 +46,11 @@ typedef struct _RDP61_COMPRESSED_DATA RDP61_COMPRESSED_DATA; struct _XCRUSH_CONTEXT { BOOL Compressor; + MPPC_CONTEXT* mppc; + BYTE* HistoryPtr; + UINT32 HistoryOffset; + UINT32 HistoryBufferSize; + BYTE HistoryBuffer[2000000]; }; typedef struct _XCRUSH_CONTEXT XCRUSH_CONTEXT; diff --git a/libfreerdp/codec/xcrush.c b/libfreerdp/codec/xcrush.c index cda1d5083..fd9fabc96 100644 --- a/libfreerdp/codec/xcrush.c +++ b/libfreerdp/codec/xcrush.c @@ -27,9 +27,113 @@ #include +int xcrush_decompress_l1(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags) +{ + BYTE* pSrcEnd = NULL; + BYTE* Literals = NULL; + UINT16 MatchCount = 0; + UINT16 MatchIndex = 0; + UINT16 MatchLength = 0; + UINT32 OutputOffset = 0; + BYTE* HistoryPtr = NULL; + BYTE* HistoryBuffer = NULL; + BYTE* HistoryBufferEnd = NULL; + RDP61_MATCH_DETAILS* MatchDetails = NULL; + + if (SrcSize < 1) + return -1; + + if (flags & L1_PACKET_AT_FRONT) + xcrush->HistoryOffset = 0; + + pSrcEnd = &pSrcData[SrcSize]; + HistoryBuffer = xcrush->HistoryBuffer; + HistoryBufferEnd = &(HistoryBuffer[xcrush->HistoryBufferSize]); + xcrush->HistoryPtr = HistoryPtr = &(HistoryBuffer[xcrush->HistoryOffset]); + + if (flags & L1_NO_COMPRESSION) + { + Literals = pSrcData; + } + else + { + if (!(flags & L1_COMPRESSED)) + { + return -1; + } + + if ((pSrcData + 2) > pSrcEnd) + { + return -1; + } + + MatchCount = *((UINT16*) pSrcData); + MatchDetails = (RDP61_MATCH_DETAILS*) &pSrcData[2]; + Literals = (BYTE*) &MatchDetails[MatchCount]; + OutputOffset = 0; + + for (MatchIndex = 0; MatchIndex < MatchCount; MatchIndex++) + { + MatchLength = MatchDetails->MatchLength; + + printf("Match[%d]: Length: %d OutputOffset: %d HistoryOffset: %d\n", + (int) MatchIndex, (int) MatchDetails->MatchLength, + (int) MatchDetails->MatchOutputOffset, (int) MatchDetails->MatchHistoryOffset); + } + } + + if (Literals >= pSrcEnd) + { + xcrush->HistoryOffset = HistoryPtr - HistoryBuffer; + *pDstSize = HistoryPtr - xcrush->HistoryPtr; + *ppDstData = xcrush->HistoryPtr; + return 1; + } + + return 1; +} + int xcrush_decompress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags) { - return 1; + int status = 0; + UINT32 DstSize = 0; + BYTE* pDstData = NULL; + BYTE Level1ComprFlags; + BYTE Level2ComprFlags; + + if (SrcSize < 2) + return -1; + + Level1ComprFlags = pSrcData[0]; + Level2ComprFlags = pSrcData[1]; + + pSrcData += 2; + SrcSize -= 2; + + printf("Compression Flags: L1: 0x%04X L2: 0x%04X\n", Level1ComprFlags, Level2ComprFlags); + + if (Level2ComprFlags & PACKET_COMPRESSED) + { + printf("Level-2 PACKET_COMPRESSED\n"); + + status = mppc_decompress(xcrush->mppc, pSrcData, SrcSize, &pDstData, &DstSize, Level2ComprFlags); + + if (status < 0) + return status; + } + else + { + printf("Level-2 PACKET_UNCOMPRESSED\n"); + + pDstData = pSrcData; + DstSize = SrcSize; + } + + /* Level-1 Decompression */ + + status = xcrush_decompress_l1(xcrush, pDstData, DstSize, ppDstData, pDstSize, Level1ComprFlags); + + return status; } int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags) @@ -51,6 +155,10 @@ XCRUSH_CONTEXT* xcrush_context_new(BOOL Compressor) if (xcrush) { xcrush->Compressor = Compressor; + xcrush->mppc = mppc_context_new(1, Compressor); + + xcrush->HistoryOffset = 0; + xcrush->HistoryBufferSize = 2000000; xcrush_context_reset(xcrush); } @@ -62,6 +170,7 @@ void xcrush_context_free(XCRUSH_CONTEXT* xcrush) { if (xcrush) { + mppc_context_free(xcrush->mppc); free(xcrush); } } diff --git a/libfreerdp/core/bulk.c b/libfreerdp/core/bulk.c index f1d7eca1f..c97b43d68 100644 --- a/libfreerdp/core/bulk.c +++ b/libfreerdp/core/bulk.c @@ -23,7 +23,7 @@ #include "bulk.h" -//#define WITH_BULK_DEBUG 1 +#define WITH_BULK_DEBUG 1 const char* bulk_get_compression_flags_string(UINT32 flags) { @@ -137,7 +137,7 @@ int bulk_decompress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstD break; case PACKET_COMPR_TYPE_RDP61: - status = -1; + status = xcrush_decompress(bulk->xcrushRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags); break; case PACKET_COMPR_TYPE_RDP8: @@ -251,8 +251,12 @@ void bulk_reset(rdpBulk* bulk) { mppc_context_reset(bulk->mppcSend); mppc_context_reset(bulk->mppcRecv); + ncrush_context_reset(bulk->ncrushRecv); ncrush_context_reset(bulk->ncrushSend); + + xcrush_context_reset(bulk->xcrushRecv); + xcrush_context_reset(bulk->xcrushSend); } rdpBulk* bulk_new(rdpContext* context) @@ -271,6 +275,9 @@ rdpBulk* bulk_new(rdpContext* context) bulk->ncrushRecv = ncrush_context_new(FALSE); bulk->ncrushSend = ncrush_context_new(TRUE); + bulk->xcrushRecv = xcrush_context_new(FALSE); + bulk->xcrushSend = xcrush_context_new(TRUE); + bulk->CompressionLevel = context->settings->CompressionLevel; bulk->TotalCompressedBytes = 0; @@ -291,5 +298,8 @@ void bulk_free(rdpBulk* bulk) ncrush_context_free(bulk->ncrushRecv); ncrush_context_free(bulk->ncrushSend); + xcrush_context_free(bulk->xcrushRecv); + xcrush_context_free(bulk->xcrushSend); + free(bulk); } diff --git a/libfreerdp/core/bulk.h b/libfreerdp/core/bulk.h index 7b976f8f9..72916edb2 100644 --- a/libfreerdp/core/bulk.h +++ b/libfreerdp/core/bulk.h @@ -26,6 +26,7 @@ typedef struct rdp_bulk rdpBulk; #include #include +#include struct rdp_bulk { @@ -36,6 +37,8 @@ struct rdp_bulk MPPC_CONTEXT* mppcRecv; NCRUSH_CONTEXT* ncrushRecv; NCRUSH_CONTEXT* ncrushSend; + XCRUSH_CONTEXT* xcrushRecv; + XCRUSH_CONTEXT* xcrushSend; BYTE OutputBuffer[65536]; UINT64 TotalCompressedBytes; UINT64 TotalUncompressedBytes;