libfreerdp-codec: start compressing some XCrush frames

This commit is contained in:
Marc-André Moreau 2014-05-25 20:01:12 -04:00
parent 8d8e0c24fe
commit d1b5ba0f28
4 changed files with 326 additions and 27 deletions

View File

@ -207,7 +207,7 @@ int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** p
else
{
/* Invalid CopyOffset Encoding */
return -1;
return -1001;
}
}
else /* RDP4 */
@ -245,7 +245,7 @@ int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** p
else
{
/* Invalid CopyOffset Encoding */
return -1;
return -1002;
}
}
@ -409,7 +409,7 @@ int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** p
else
{
/* Invalid LengthOfMatch Encoding */
return -1;
return -1003;
}
#ifdef DEBUG_MPPC
@ -510,11 +510,6 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD
if (!pDstData)
return -1;
DstSize = *pDstSize;
if (DstSize < SrcSize)
return -1;
DstSize = SrcSize;
BitStream_Attach(bs, pDstData, DstSize);
@ -859,11 +854,7 @@ MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor)
mppc->bs = BitStream_New();
ZeroMemory(&(mppc->HistoryBuffer), sizeof(mppc->HistoryBuffer));
ZeroMemory(&(mppc->MatchBuffer), sizeof(mppc->MatchBuffer));
mppc->HistoryOffset = 0;
mppc->HistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryOffset]);
mppc_context_reset(mppc);
}
return mppc;

View File

@ -704,6 +704,38 @@ static const BYTE TEST_MPPC_BELLS_RDP5[] =
"\x6c\x2e\x74\x6f\x6c\x6c\x73\x2c\xfa\x1b\x97\x33\x7e\x87\xe3\x32"
"\x90\x80";
static const BYTE TEST_ISLAND_DATA[] =
"No man is an island entire of itself; every man "
"is a piece of the continent, a part of the main; "
"if a clod be washed away by the sea, Europe "
"is the less, as well as if a promontory were, as"
"well as any manner of thy friends or of thine "
"own were; any man's death diminishes me, "
"because I am involved in mankind. "
"And therefore never send to know for whom "
"the bell tolls; it tolls for thee.";
static const BYTE TEST_ISLAND_DATA_RDP5[] =
"\x4e\x6f\x20\x6d\x61\x6e\x20\x69\x73\x20\xf8\xd2\xd8\xc2\xdc\xc8"
"\x40\xca\xdc\xe8\xd2\xe4\xca\x40\xde\xcc\x40\xd2\xe8\xe6\xca\xd8"
"\xcc\x76\x40\xca\xec\xca\xe4\xf3\xfa\x71\x20\x70\x69\x65\x63\xfc"
"\x12\xe8\xd0\xca\x40\xc6\xdf\xfb\xcd\xdf\xd0\x58\x40\xc2\x40\xe0"
"\xc2\xe4\xe9\xfe\x63\xec\xc3\x6b\x0b\x4b\x71\xd9\x03\x4b\x37\xd7"
"\x31\xb6\x37\xb2\x10\x31\x32\x90\x3b\xb0\xb9\xb4\x32\xb2\x10\x30"
"\xbb\xb0\xbc\x90\x31\x3c\x90\x7e\x68\x73\x65\x61\x2c\x20\x45\x75"
"\x72\x6f\x70\x65\xf2\x34\x7d\x38\x6c\x65\x73\x73\xf0\x69\xcc\x81"
"\xdd\x95\xb1\xb0\x81\x85\xcf\xc0\x94\xe0\xe4\xde\xdb\xe2\xb3\x7f"
"\x92\x4e\xec\xae\x4c\xbf\x86\x3f\x06\x0c\x2d\xde\x5d\x96\xe6\x57"
"\x2f\x1e\x53\xc9\x03\x33\x93\x4b\x2b\x73\x23\x99\x03\x7f\xd2\xb6"
"\x96\xef\x38\x1d\xdb\xbc\x24\x72\x65\x3b\xf5\x5b\xf8\x49\x3b\x99"
"\x03\x23\x2b\x0b\xa3\x41\x03\x23\x4b\x6b\x4b\x73\x4f\x96\xce\x64"
"\x0d\xbe\x19\x31\x32\xb1\xb0\xba\xb9\xb2\x90\x24\x90\x30\xb6\x90"
"\x34\xb7\x3b\x37\xb6\x3b\x79\xd4\xd2\xdd\xec\x18\x6b\x69\x6e\x64"
"\x2e\x20\x41\xf7\x33\xcd\x47\x26\x56\x66\xff\x74\x9b\xbd\xbf\x04"
"\x0e\x7e\x31\x10\x3a\x37\x90\x35\xb7\x37\xbb\x90\x7d\x81\x03\xbb"
"\x43\x7b\x6f\xa8\xe5\x8b\xd0\xf0\xe8\xde\xd8\xd8\xe7\xec\xf3\xa7"
"\xe4\x7c\xa7\xe2\x9f\x01\x99\x4b\x80";
int test_MppcCompressBellsRdp5()
{
int status;
@ -878,6 +910,55 @@ int test_MppcDecompressBellsRdp4()
return 0;
}
int test_MppcCompressIslandRdp5()
{
int status;
UINT32 Flags;
UINT32 SrcSize;
BYTE* pSrcData;
UINT32 DstSize;
BYTE* pDstData;
MPPC_CONTEXT* mppc;
UINT32 expectedSize;
BYTE OutputBuffer[65536];
mppc = mppc_context_new(1, TRUE);
SrcSize = sizeof(TEST_ISLAND_DATA) - 1;
pSrcData = (BYTE*) TEST_ISLAND_DATA;
expectedSize = sizeof(TEST_ISLAND_DATA_RDP5) - 1;
DstSize = sizeof(OutputBuffer);
pDstData = OutputBuffer;
status = mppc_compress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
printf("Flags: 0x%04X DstSize: %d\n", Flags, DstSize);
if (DstSize != expectedSize)
{
printf("MppcCompressIslandRdp5: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize);
return -1;
}
if (memcmp(pDstData, TEST_ISLAND_DATA_RDP5, DstSize) != 0)
{
printf("MppcCompressIslandRdp5: output mismatch\n");
printf("Actual\n");
BitDump(pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(TEST_ISLAND_DATA_RDP5, DstSize * 8, 0);
return -1;
}
mppc_context_free(mppc);
return 0;
}
int test_MppcCompressBufferRdp5()
{
int status;
@ -960,6 +1041,9 @@ int test_MppcDecompressBufferRdp5()
int TestFreeRDPCodecMppc(int argc, char* argv[])
{
if (test_MppcCompressIslandRdp5() < 0)
return -1;
if (test_MppcCompressBellsRdp5() < 0)
return -1;

View File

@ -3,8 +3,168 @@
#include <freerdp/codec/xcrush.h>
static const BYTE TEST_BELLS_DATA[] = "for.whom.the.bell.tolls,.the.bell.tolls.for.thee!";
static const BYTE TEST_BELLS_DATA_XCRUSH[] =
"\x12\x00\x66\x6f\x72\x2e\x77\x68\x6f\x6d\x2e\x74\x68\x65\x2e\x62"
"\x65\x6c\x6c\x2e\x74\x6f\x6c\x6c\x73\x2c\x2e\x74\x68\x65\x2e\x62"
"\x65\x6c\x6c\x2e\x74\x6f\x6c\x6c\x73\x2e\x66\x6f\x72\x2e\x74\x68"
"\x65";
static const BYTE TEST_ISLAND_DATA[] =
"No man is an island entire of itself; every man "
"is a piece of the continent, a part of the main; "
"if a clod be washed away by the sea, Europe "
"is the less, as well as if a promontory were, as"
"well as any manner of thy friends or of thine "
"own were; any man's death diminishes me, "
"because I am involved in mankind. "
"And therefore never send to know for whom "
"the bell tolls; it tolls for thee.";
static const BYTE TEST_ISLAND_DATA_XCRUSH[] =
"\x12\x61\x4e\x6f\x20\x6d\x61\x6e\x20\x69\x73\x20\xf8\xd2\xd8\xc2"
"\xdc\xc8\x40\xca\xdc\xe8\xd2\xe4\xca\x40\xde\xcc\x40\xd2\xe8\xe6"
"\xca\xd8\xcc\x76\x40\xca\xec\xca\xe4\xf3\xfa\x71\x20\x70\x69\x65"
"\x63\xfc\x12\xe8\xd0\xca\x40\xc6\xdf\xfb\xcd\xdf\xd0\x58\x40\xc2"
"\x40\xe0\xc2\xe4\xe9\xfe\x63\xec\xc3\x6b\x0b\x4b\x71\xd9\x03\x4b"
"\x37\xd7\x31\xb6\x37\xb2\x10\x31\x32\x90\x3b\xb0\xb9\xb4\x32\xb2"
"\x10\x30\xbb\xb0\xbc\x90\x31\x3c\x90\x7e\x68\x73\x65\x61\x2c\x20"
"\x45\x75\x72\x6f\x70\x65\xf2\x34\x7d\x38\x6c\x65\x73\x73\xf0\x69"
"\xcc\x81\xdd\x95\xb1\xb0\x81\x85\xcf\xc0\x94\xe0\xe4\xde\xdb\xe2"
"\xb3\x7f\x92\x4e\xec\xae\x4c\xbf\x86\x3f\x06\x0c\x2d\xde\x5d\x96"
"\xe6\x57\x2f\x1e\x53\xc9\x03\x33\x93\x4b\x2b\x73\x23\x99\x03\x7f"
"\xd2\xb6\x96\xef\x38\x1d\xdb\xbc\x24\x72\x65\x3b\xf5\x5b\xf8\x49"
"\x3b\x99\x03\x23\x2b\x0b\xa3\x41\x03\x23\x4b\x6b\x4b\x73\x4f\x96"
"\xce\x64\x0d\xbe\x19\x31\x32\xb1\xb0\xba\xb9\xb2\x90\x24\x90\x30"
"\xb6\x90\x34\xb7\x3b\x37\xb6\x3b\x79\xd4\xd2\xdd\xec\x18\x6b\x69"
"\x6e\x64\x2e\x20\x41\xf7\x33\xcd\x47\x26\x56\x66\xff\x74\x9b\xbd"
"\xbf\x04\x0e\x7e\x31\x10\x3a\x37\x90\x35\xb7\x37\xbb\x90\x7d\x81"
"\x03\xbb\x43\x7b\x6f\xa8\xe5\x8b\xd0\xf0\xe8\xde\xd8\xd8\xe7\xec"
"\xf3\xa7\xe4\x7c\xa7\xe2\x9f\x01\x99\x4b\x80";
int test_XCrushCompressBells()
{
int status;
UINT32 Flags;
UINT32 SrcSize;
BYTE* pSrcData;
UINT32 DstSize;
BYTE* pDstData;
UINT32 expectedSize;
BYTE OutputBuffer[65536];
XCRUSH_CONTEXT* xcrush;
xcrush = xcrush_context_new(TRUE);
SrcSize = sizeof(TEST_BELLS_DATA) - 1;
pSrcData = (BYTE*) TEST_BELLS_DATA;
expectedSize = sizeof(TEST_BELLS_DATA_XCRUSH) - 1;
pDstData = OutputBuffer;
DstSize = sizeof(OutputBuffer);
ZeroMemory(OutputBuffer, sizeof(OutputBuffer));
status = xcrush_compress(xcrush, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
printf("status: %d Flags: 0x%04X DstSize: %d\n", status, Flags, DstSize);
if (DstSize != expectedSize)
{
printf("XCrushCompressBells: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize);
printf("Actual\n");
BitDump(pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(TEST_BELLS_DATA_XCRUSH, expectedSize * 8, 0);
return -1;
}
if (memcmp(pDstData, TEST_BELLS_DATA_XCRUSH, DstSize) != 0)
{
printf("XCrushCompressBells: output mismatch\n");
printf("Actual\n");
BitDump(pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(TEST_BELLS_DATA_XCRUSH, expectedSize * 8, 0);
return -1;
}
xcrush_context_free(xcrush);
return 1;
}
int test_XCrushCompressIsland()
{
int status;
UINT32 Flags;
UINT32 SrcSize;
BYTE* pSrcData;
UINT32 DstSize;
BYTE* pDstData;
UINT32 expectedSize;
BYTE OutputBuffer[65536];
XCRUSH_CONTEXT* xcrush;
xcrush = xcrush_context_new(TRUE);
SrcSize = sizeof(TEST_ISLAND_DATA) - 1;
pSrcData = (BYTE*) TEST_ISLAND_DATA;
expectedSize = sizeof(TEST_ISLAND_DATA_XCRUSH) - 1;
pDstData = OutputBuffer;
DstSize = sizeof(OutputBuffer);
ZeroMemory(OutputBuffer, sizeof(OutputBuffer));
status = xcrush_compress(xcrush, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
printf("status: %d Flags: 0x%04X DstSize: %d\n", status, Flags, DstSize);
if (DstSize != expectedSize)
{
printf("XCrushCompressIsland: output size mismatch: Actual: %d, Expected: %d\n", DstSize, expectedSize);
printf("Actual\n");
BitDump(pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(TEST_ISLAND_DATA_XCRUSH, expectedSize * 8, 0);
return -1;
}
if (memcmp(pDstData, TEST_ISLAND_DATA_XCRUSH, DstSize) != 0)
{
printf("XCrushCompressIsland: output mismatch\n");
printf("Actual\n");
BitDump(pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(TEST_ISLAND_DATA_XCRUSH, expectedSize * 8, 0);
return -1;
}
xcrush_context_free(xcrush);
return 1;
}
int TestFreeRDPCodecXCrush(int argc, char* argv[])
{
if (test_XCrushCompressBells() < 0)
return -1;
if (test_XCrushCompressIsland() < 0)
return -1;
return 0;
}

View File

@ -27,6 +27,70 @@
#include <freerdp/codec/xcrush.h>
const char* xcrush_get_level_2_compression_flags_string(UINT32 flags)
{
flags &= 0xE0;
if (flags == 0)
return "PACKET_UNCOMPRESSED";
else if (flags == PACKET_COMPRESSED)
return "PACKET_COMPRESSED";
else if (flags == PACKET_AT_FRONT)
return "PACKET_AT_FRONT";
else if (flags == PACKET_FLUSHED)
return "PACKET_FLUSHED";
else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT))
return "PACKET_COMPRESSED | PACKET_AT_FRONT";
else if (flags == (PACKET_COMPRESSED | PACKET_FLUSHED))
return "PACKET_COMPRESSED | PACKET_FLUSHED";
else if (flags == (PACKET_AT_FRONT | PACKET_FLUSHED))
return "PACKET_AT_FRONT | PACKET_FLUSHED";
else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED))
return "PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED";
return "PACKET_UNKNOWN";
}
const char* xcrush_get_level_1_compression_flags_string(UINT32 flags)
{
flags &= 0x17;
if (flags == 0)
return "L1_UNKNOWN";
else if (flags == L1_PACKET_AT_FRONT)
return "L1_PACKET_AT_FRONT";
else if (flags == L1_NO_COMPRESSION)
return "L1_NO_COMPRESSION";
else if (flags == L1_COMPRESSED)
return "L1_COMPRESSED";
else if (flags == L1_INNER_COMPRESSION)
return "L1_INNER_COMPRESSION";
else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION))
return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION";
else if (flags == (L1_PACKET_AT_FRONT | L1_COMPRESSED))
return "L1_PACKET_AT_FRONT | L1_COMPRESSED";
else if (flags == (L1_PACKET_AT_FRONT | L1_INNER_COMPRESSION))
return "L1_PACKET_AT_FRONT | L1_INNER_COMPRESSION";
else if (flags == (L1_NO_COMPRESSION | L1_COMPRESSED))
return "L1_NO_COMPRESSION | L1_COMPRESSED";
else if (flags == (L1_NO_COMPRESSION | L1_INNER_COMPRESSION))
return "L1_NO_COMPRESSION | L1_INNER_COMPRESSION";
else if (flags == (L1_COMPRESSED | L1_INNER_COMPRESSION))
return "L1_COMPRESSED | L1_INNER_COMPRESSION";
else if (flags == (L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION))
return "L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION";
else if (flags == (L1_PACKET_AT_FRONT | L1_COMPRESSED | L1_INNER_COMPRESSION))
return "L1_PACKET_AT_FRONT | L1_COMPRESSED | L1_INNER_COMPRESSION";
else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_INNER_COMPRESSION))
return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_INNER_COMPRESSION";
else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED))
return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED";
else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION))
return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION";
return "L1_UNKNOWN";
}
UINT32 xcrush_update_hash(BYTE* data, UINT32 size)
{
BYTE* end;
@ -583,7 +647,7 @@ int xcrush_generate_output(XCRUSH_CONTEXT* xcrush, BYTE* OutputBuffer, UINT32 Ou
if (Literals + MatchOffset - CurrentOffset >= OutputEnd)
return -6004; /* error */
CopyMemory(Literals, &xcrush->HistoryBuffer[CurrentOffset], MatchOffsetDiff);
MoveMemory(Literals, &xcrush->HistoryBuffer[CurrentOffset], MatchOffsetDiff);
if (Literals >= OutputEnd)
return -6005; /* error */
@ -598,7 +662,7 @@ int xcrush_generate_output(XCRUSH_CONTEXT* xcrush, BYTE* OutputBuffer, UINT32 Ou
if (Literals + HistoryOffsetDiff >= OutputEnd)
return -6006; /* error */
CopyMemory(Literals, &xcrush->HistoryBuffer[CurrentOffset], HistoryOffsetDiff);
MoveMemory(Literals, &xcrush->HistoryBuffer[CurrentOffset], HistoryOffsetDiff);
*pDstSize = Literals + HistoryOffsetDiff - OutputBuffer;
return 1;
@ -786,7 +850,7 @@ int xcrush_compress_l1(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, B
HistoryBuffer = xcrush->HistoryBuffer;
HistoryPtr = &HistoryBuffer[HistoryOffset];
CopyMemory(HistoryPtr, pSrcData, SrcSize);
MoveMemory(HistoryPtr, pSrcData, SrcSize);
xcrush->HistoryOffset += SrcSize;
if (SrcSize > 50)
@ -857,12 +921,12 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
return -1002;
OriginalData = *ppDstData;
OriginalDataSize = *pDstSize;
OriginalDataSize = SrcSize;
pDstData = xcrush->BlockBuffer;
DstSize = sizeof(xcrush->BlockBuffer);
CompressedDataSize = SrcSize;
status = xcrush_compress_l1(xcrush, pSrcData, SrcSize, &pDstData, &DstSize, &Level1ComprFlags);
status = xcrush_compress_l1(xcrush, pSrcData, SrcSize, &pDstData, &CompressedDataSize, &Level1ComprFlags);
if (status < 0)
return status;
@ -870,7 +934,6 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
if (Level1ComprFlags & L1_COMPRESSED)
{
CompressedData = pDstData;
CompressedDataSize = DstSize;
if (CompressedDataSize > SrcSize)
return -1003;
@ -878,18 +941,17 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
else
{
CompressedData = pSrcData;
CompressedDataSize = DstSize;
if (CompressedDataSize != SrcSize)
return -1004;
}
status = 1;
status = 0;
pDstData = OriginalData + 2;
pDstData = &OriginalData[2];
DstSize = OriginalDataSize - 2;
if (DstSize > 50)
if (CompressedDataSize > 50)
{
status = mppc_compress(xcrush->mppc, CompressedData, CompressedDataSize, &pDstData, &DstSize, &Level2ComprFlags);
}
@ -897,16 +959,18 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
if (status < 0)
return status;
if (!(Level2ComprFlags & PACKET_COMPRESSED) || (Level2ComprFlags & PACKET_FLUSHED))
if (!status || (Level2ComprFlags & PACKET_FLUSHED))
{
CompressedData = pDstData;
CompressedDataSize = DstSize;
if (CompressedDataSize > DstSize)
{
/* we should handle packet flushing here */
return -1005;
}
DstSize = CompressedDataSize;
CopyMemory(pDstData, CompressedData, CompressedDataSize);
MoveMemory(&OriginalData[2], CompressedData, CompressedDataSize);
}
if (Level2ComprFlags & PACKET_COMPRESSED)