diff --git a/libfreerdp/codec/mppc.c b/libfreerdp/codec/mppc.c index d23447255..f26fdaeaa 100644 --- a/libfreerdp/codec/mppc.c +++ b/libfreerdp/codec/mppc.c @@ -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; diff --git a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c index b1e309bff..cfee4479a 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecMppc.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecMppc.c @@ -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; diff --git a/libfreerdp/codec/test/TestFreeRDPCodecXCrush.c b/libfreerdp/codec/test/TestFreeRDPCodecXCrush.c index 84b77b455..c0bce9a72 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecXCrush.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecXCrush.c @@ -3,8 +3,168 @@ #include +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; } diff --git a/libfreerdp/codec/xcrush.c b/libfreerdp/codec/xcrush.c index cc4d122eb..2cfefc3d0 100644 --- a/libfreerdp/codec/xcrush.c +++ b/libfreerdp/codec/xcrush.c @@ -27,6 +27,70 @@ #include +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)