Merge pull request #1863 from awakecoding/master
RDP6.1 XCrush Bulk Compression
This commit is contained in:
commit
f0317d6b22
@ -48,7 +48,9 @@ FREERDP_API int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize
|
||||
FREERDP_API int mppc_decompress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
|
||||
|
||||
FREERDP_API void mppc_set_compression_level(MPPC_CONTEXT* mppc, DWORD CompressionLevel);
|
||||
|
||||
FREERDP_API void mppc_context_reset(MPPC_CONTEXT* mppc);
|
||||
FREERDP_API void mppc_context_flush(MPPC_CONTEXT* mppc);
|
||||
|
||||
FREERDP_API MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor);
|
||||
FREERDP_API void mppc_context_free(MPPC_CONTEXT* mppc);
|
||||
|
@ -25,6 +25,30 @@
|
||||
|
||||
#include <freerdp/codec/mppc.h>
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
struct _XCRUSH_MATCH_INFO
|
||||
{
|
||||
UINT32 MatchOffset;
|
||||
UINT32 ChunkOffset;
|
||||
UINT32 MatchLength;
|
||||
};
|
||||
typedef struct _XCRUSH_MATCH_INFO XCRUSH_MATCH_INFO;
|
||||
|
||||
struct _XCRUSH_CHUNK
|
||||
{
|
||||
UINT32 offset;
|
||||
UINT32 next;
|
||||
};
|
||||
typedef struct _XCRUSH_CHUNK XCRUSH_CHUNK;
|
||||
|
||||
struct _XCRUSH_SIGNATURE
|
||||
{
|
||||
UINT16 seed;
|
||||
UINT16 size;
|
||||
};
|
||||
typedef struct _XCRUSH_SIGNATURE XCRUSH_SIGNATURE;
|
||||
|
||||
struct _RDP61_MATCH_DETAILS
|
||||
{
|
||||
UINT16 MatchLength;
|
||||
@ -43,6 +67,8 @@ struct _RDP61_COMPRESSED_DATA
|
||||
};
|
||||
typedef struct _RDP61_COMPRESSED_DATA RDP61_COMPRESSED_DATA;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
struct _XCRUSH_CONTEXT
|
||||
{
|
||||
BOOL Compressor;
|
||||
@ -52,6 +78,21 @@ struct _XCRUSH_CONTEXT
|
||||
UINT32 HistoryBufferSize;
|
||||
BYTE HistoryBuffer[2000000];
|
||||
BYTE BlockBuffer[16384];
|
||||
UINT32 CompressionFlags;
|
||||
|
||||
UINT32 SignatureIndex;
|
||||
UINT32 SignatureCount;
|
||||
XCRUSH_SIGNATURE Signatures[1000];
|
||||
|
||||
UINT32 ChunkHead;
|
||||
UINT32 ChunkTail;
|
||||
XCRUSH_CHUNK Chunks[65534];
|
||||
UINT16 NextChunks[65536];
|
||||
|
||||
UINT32 OriginalMatchCount;
|
||||
UINT32 OptimizedMatchCount;
|
||||
XCRUSH_MATCH_INFO OriginalMatches[1000];
|
||||
XCRUSH_MATCH_INFO OptimizedMatches[1000];
|
||||
};
|
||||
typedef struct _XCRUSH_CONTEXT XCRUSH_CONTEXT;
|
||||
|
||||
@ -63,6 +104,7 @@ FREERDP_API int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 S
|
||||
FREERDP_API int xcrush_decompress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
|
||||
|
||||
FREERDP_API void xcrush_context_reset(XCRUSH_CONTEXT* xcrush);
|
||||
FREERDP_API void xcrush_context_flush(XCRUSH_CONTEXT* xcrush);
|
||||
|
||||
FREERDP_API XCRUSH_CONTEXT* xcrush_context_new(BOOL Compressor);
|
||||
FREERDP_API void xcrush_context_free(XCRUSH_CONTEXT* xcrush);
|
||||
|
@ -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,12 +510,10 @@ 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;
|
||||
if (*pDstSize > SrcSize)
|
||||
DstSize = SrcSize;
|
||||
else
|
||||
DstSize = *pDstSize;
|
||||
|
||||
BitStream_Attach(bs, pDstData, DstSize);
|
||||
|
||||
@ -546,9 +544,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD
|
||||
{
|
||||
if (((bs->position / 8) + 2) > (DstSize - 1))
|
||||
{
|
||||
ZeroMemory(HistoryBuffer, HistoryBufferSize);
|
||||
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
|
||||
mppc->HistoryOffset = HistoryBufferSize + 1;
|
||||
mppc_context_flush(mppc);
|
||||
*pFlags |= PACKET_FLUSHED;
|
||||
*pFlags |= CompressionLevel;
|
||||
*ppDstData = pSrcData;
|
||||
@ -600,9 +596,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD
|
||||
|
||||
if (((bs->position / 8) + 7) > (DstSize - 1))
|
||||
{
|
||||
ZeroMemory(HistoryBuffer, HistoryBufferSize);
|
||||
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
|
||||
mppc->HistoryOffset = HistoryBufferSize + 1;
|
||||
mppc_context_flush(mppc);
|
||||
*pFlags |= PACKET_FLUSHED;
|
||||
*pFlags |= CompressionLevel;
|
||||
*ppDstData = pSrcData;
|
||||
@ -759,9 +753,7 @@ int mppc_compress(MPPC_CONTEXT* mppc, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppD
|
||||
{
|
||||
if (((bs->position / 8) + 2) > (DstSize - 1))
|
||||
{
|
||||
ZeroMemory(HistoryBuffer, HistoryBufferSize);
|
||||
ZeroMemory(mppc->MatchBuffer, sizeof(mppc->MatchBuffer));
|
||||
mppc->HistoryOffset = HistoryBufferSize + 1;
|
||||
mppc_context_flush(mppc);
|
||||
*pFlags |= PACKET_FLUSHED;
|
||||
*pFlags |= CompressionLevel;
|
||||
*ppDstData = pSrcData;
|
||||
@ -836,6 +828,12 @@ void mppc_context_reset(MPPC_CONTEXT* mppc)
|
||||
mppc->HistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryOffset]);
|
||||
}
|
||||
|
||||
void mppc_context_flush(MPPC_CONTEXT* mppc)
|
||||
{
|
||||
mppc_context_reset(mppc);
|
||||
mppc->HistoryOffset = mppc->HistoryBufferSize + 1;
|
||||
}
|
||||
|
||||
MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor)
|
||||
{
|
||||
MPPC_CONTEXT* mppc;
|
||||
@ -859,11 +857,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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,647 @@
|
||||
|
||||
#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;
|
||||
UINT32 seed = 5381; /* same value as in djb2 */
|
||||
|
||||
if (size > 32)
|
||||
{
|
||||
size = 32;
|
||||
seed = 5413;
|
||||
}
|
||||
|
||||
end = &data[size - 4];
|
||||
|
||||
while (data < end)
|
||||
{
|
||||
seed += (data[3] ^ data[0]) + (data[1] << 8);
|
||||
data += 4;
|
||||
}
|
||||
|
||||
return (UINT16) seed;
|
||||
}
|
||||
|
||||
int xcrush_append_chunk(XCRUSH_CONTEXT* xcrush, BYTE* data, UINT32* beg, UINT32 end)
|
||||
{
|
||||
UINT16 seed;
|
||||
UINT32 size;
|
||||
|
||||
if (xcrush->SignatureIndex >= xcrush->SignatureCount)
|
||||
return 0;
|
||||
|
||||
size = end - *beg;
|
||||
|
||||
if (size > 65535)
|
||||
return 0;
|
||||
|
||||
if (size >= 15)
|
||||
{
|
||||
seed = xcrush_update_hash(&data[*beg], (UINT16) size);
|
||||
xcrush->Signatures[xcrush->SignatureIndex].size = size;
|
||||
xcrush->Signatures[xcrush->SignatureIndex].seed = seed;
|
||||
xcrush->SignatureIndex++;
|
||||
*beg = end;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xcrush_compute_chunks(XCRUSH_CONTEXT* xcrush, BYTE* data, UINT32 size, UINT32* pIndex)
|
||||
{
|
||||
UINT32 i = 0;
|
||||
UINT32 offset = 0;
|
||||
UINT32 rotation = 0;
|
||||
UINT32 accumulator = 0;
|
||||
|
||||
*pIndex = 0;
|
||||
xcrush->SignatureIndex = 0;
|
||||
|
||||
if (size < 128)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
rotation = _rotl(accumulator, 1);
|
||||
accumulator = data[i] ^ rotation;
|
||||
}
|
||||
|
||||
for (i = 0; i < size - 64; i++)
|
||||
{
|
||||
rotation = _rotl(accumulator, 1);
|
||||
accumulator = data[i + 32] ^ data[i] ^ rotation;
|
||||
|
||||
if (!(accumulator & 0x7F))
|
||||
{
|
||||
if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
|
||||
rotation = _rotl(accumulator, 1);
|
||||
accumulator = data[i + 32] ^ data[i] ^ rotation;
|
||||
|
||||
if (!(accumulator & 0x7F))
|
||||
{
|
||||
if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
|
||||
rotation = _rotl(accumulator, 1);
|
||||
accumulator = data[i + 32] ^ data[i] ^ rotation;
|
||||
|
||||
if (!(accumulator & 0x7F))
|
||||
{
|
||||
if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
|
||||
return 0;
|
||||
}
|
||||
i++;
|
||||
|
||||
rotation = _rotl(accumulator, 1);
|
||||
accumulator = data[i + 32] ^ data[i] ^ rotation;
|
||||
|
||||
if (!(accumulator & 0x7F))
|
||||
{
|
||||
if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((size == offset) || xcrush_append_chunk(xcrush, data, &offset, size))
|
||||
{
|
||||
*pIndex = xcrush->SignatureIndex;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT32 xcrush_compute_signatures(XCRUSH_CONTEXT* xcrush, BYTE* data, UINT32 size)
|
||||
{
|
||||
UINT32 index = 0;
|
||||
|
||||
if (xcrush_compute_chunks(xcrush, data, size, &index))
|
||||
return index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xcrush_clear_hash_table_range(XCRUSH_CONTEXT* xcrush, UINT32 beg, UINT32 end)
|
||||
{
|
||||
UINT32 index;
|
||||
|
||||
for (index = 0; index < 65536; index++)
|
||||
{
|
||||
if (xcrush->NextChunks[index] >= beg)
|
||||
{
|
||||
if (xcrush->NextChunks[index] <= end)
|
||||
{
|
||||
xcrush->NextChunks[index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (index = 0; index < 65534; index++)
|
||||
{
|
||||
if (xcrush->Chunks[index].next >= beg )
|
||||
{
|
||||
if (xcrush->Chunks[index].next <= end)
|
||||
{
|
||||
xcrush->Chunks[index].next = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int xcrush_find_next_matching_chunk(XCRUSH_CONTEXT* xcrush, XCRUSH_CHUNK* chunk, XCRUSH_CHUNK** pNextChunk)
|
||||
{
|
||||
UINT32 index;
|
||||
XCRUSH_CHUNK* next = NULL;
|
||||
|
||||
if (!chunk)
|
||||
return -4001; /* error */
|
||||
|
||||
if (chunk->next)
|
||||
{
|
||||
index = (chunk - xcrush->Chunks) / sizeof(XCRUSH_CHUNK);
|
||||
|
||||
if (index >= 65534)
|
||||
return -4002; /* error */
|
||||
|
||||
if ((index < xcrush->ChunkHead) || (chunk->next >= xcrush->ChunkHead))
|
||||
{
|
||||
if (chunk->next >= 65534)
|
||||
return -4003; /* error */
|
||||
|
||||
next = &xcrush->Chunks[chunk->next];
|
||||
}
|
||||
}
|
||||
|
||||
*pNextChunk = next;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xcrush_insert_chunk(XCRUSH_CONTEXT* xcrush, XCRUSH_SIGNATURE* signature, UINT32 offset, XCRUSH_CHUNK** pPrevChunk)
|
||||
{
|
||||
UINT32 seed;
|
||||
UINT32 index;
|
||||
|
||||
if (xcrush->ChunkHead >= 65530)
|
||||
{
|
||||
xcrush->ChunkHead = 1;
|
||||
xcrush->ChunkTail = 1;
|
||||
}
|
||||
|
||||
if (xcrush->ChunkHead >= xcrush->ChunkTail)
|
||||
{
|
||||
xcrush_clear_hash_table_range(xcrush, xcrush->ChunkTail, xcrush->ChunkTail + 10000);
|
||||
xcrush->ChunkTail += 10000;
|
||||
}
|
||||
|
||||
index = xcrush->ChunkHead++;
|
||||
|
||||
if (xcrush->ChunkHead >= 65534)
|
||||
return -3001; /* error */
|
||||
|
||||
xcrush->Chunks[index].offset = offset;
|
||||
|
||||
seed = signature->seed;
|
||||
|
||||
if (seed >= 65536)
|
||||
return -3002; /* error */
|
||||
|
||||
if (xcrush->NextChunks[seed])
|
||||
{
|
||||
if (xcrush->NextChunks[seed] >= 65534)
|
||||
return -3003; /* error */
|
||||
|
||||
*pPrevChunk = &xcrush->Chunks[xcrush->NextChunks[seed]];
|
||||
}
|
||||
|
||||
xcrush->Chunks[index].next = xcrush->NextChunks[seed] & 0xFFFF;
|
||||
xcrush->NextChunks[seed] = index;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xcrush_find_match_length(XCRUSH_CONTEXT* xcrush, UINT32 MatchOffset, UINT32 ChunkOffset, UINT32 HistoryOffset, UINT32 SrcSize, UINT32 MaxMatchLength, XCRUSH_MATCH_INFO* MatchInfo)
|
||||
{
|
||||
UINT32 MatchSymbol;
|
||||
UINT32 ChunkSymbol;
|
||||
BYTE* ChunkBuffer;
|
||||
BYTE* MatchBuffer;
|
||||
BYTE* MatchStartPtr;
|
||||
BYTE* ForwardChunkPtr;
|
||||
BYTE* ReverseChunkPtr;
|
||||
BYTE* ForwardMatchPtr;
|
||||
BYTE* ReverseMatchPtr;
|
||||
BYTE* HistoryBufferEnd;
|
||||
UINT32 ReverseMatchLength;
|
||||
UINT32 ForwardMatchLength;
|
||||
UINT32 TotalMatchLength;
|
||||
BYTE* HistoryBuffer;
|
||||
UINT32 HistoryBufferSize;
|
||||
|
||||
ForwardMatchLength = 0;
|
||||
ReverseMatchLength = 0;
|
||||
|
||||
HistoryBuffer = xcrush->HistoryBuffer;
|
||||
HistoryBufferSize = xcrush->HistoryBufferSize;
|
||||
HistoryBufferEnd = &HistoryBuffer[HistoryOffset + SrcSize];
|
||||
|
||||
if (MatchOffset > HistoryBufferSize)
|
||||
return -2001; /* error */
|
||||
|
||||
MatchBuffer = &HistoryBuffer[MatchOffset];
|
||||
|
||||
if (ChunkOffset > HistoryBufferSize)
|
||||
return -2002; /* error */
|
||||
|
||||
ChunkBuffer = &HistoryBuffer[ChunkOffset];
|
||||
|
||||
if (MatchOffset == ChunkOffset)
|
||||
return -2003; /* error */
|
||||
|
||||
if (MatchBuffer < HistoryBuffer)
|
||||
return -2004; /* error */
|
||||
|
||||
if (ChunkBuffer < HistoryBuffer)
|
||||
return -2005; /* error */
|
||||
|
||||
ForwardMatchPtr = &HistoryBuffer[MatchOffset];
|
||||
ForwardChunkPtr = &HistoryBuffer[ChunkOffset];
|
||||
|
||||
if ((&MatchBuffer[MaxMatchLength + 1] < HistoryBufferEnd)
|
||||
&& (MatchBuffer[MaxMatchLength + 1] != ChunkBuffer[MaxMatchLength + 1]))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
MatchSymbol = *ForwardMatchPtr++;
|
||||
ChunkSymbol = *ForwardChunkPtr++;
|
||||
|
||||
if (MatchSymbol != ChunkSymbol)
|
||||
break;
|
||||
|
||||
if (ForwardMatchPtr > HistoryBufferEnd)
|
||||
break;
|
||||
|
||||
ForwardMatchLength++;
|
||||
}
|
||||
|
||||
ReverseMatchPtr = MatchBuffer - 1;
|
||||
ReverseChunkPtr = ChunkBuffer - 1;
|
||||
|
||||
while((ReverseMatchPtr > &HistoryBuffer[HistoryOffset])
|
||||
&& (ReverseChunkPtr > HistoryBuffer)
|
||||
&& (*ReverseMatchPtr == *ReverseChunkPtr))
|
||||
{
|
||||
ReverseMatchLength++;
|
||||
ReverseMatchPtr--;
|
||||
ReverseChunkPtr--;
|
||||
}
|
||||
|
||||
MatchStartPtr = MatchBuffer - ReverseMatchLength;
|
||||
TotalMatchLength = ReverseMatchLength + ForwardMatchLength;
|
||||
|
||||
if (TotalMatchLength < 11)
|
||||
return 0;
|
||||
|
||||
if (MatchStartPtr < HistoryBuffer)
|
||||
return -2006; /* error */
|
||||
|
||||
MatchInfo->MatchOffset = MatchStartPtr - HistoryBuffer;
|
||||
MatchInfo->ChunkOffset = ChunkBuffer - ReverseMatchLength - HistoryBuffer;
|
||||
MatchInfo->MatchLength = TotalMatchLength;
|
||||
|
||||
return (int) TotalMatchLength;
|
||||
}
|
||||
|
||||
int xcrush_find_all_matches(XCRUSH_CONTEXT* xcrush, UINT32 SignatureIndex, UINT32 HistoryOffset, UINT32 SrcOffset, UINT32 SrcSize)
|
||||
{
|
||||
UINT32 i = 0;
|
||||
UINT32 j = 0;
|
||||
int status = 0;
|
||||
UINT32 offset = 0;
|
||||
UINT32 ChunkIndex = 0;
|
||||
UINT32 ChunkCount = 0;
|
||||
XCRUSH_CHUNK* chunk = NULL;
|
||||
UINT32 MatchLength = 0;
|
||||
UINT32 MaxMatchLength = 0;
|
||||
UINT32 PrevMatchEnd = 0;
|
||||
XCRUSH_MATCH_INFO MatchInfo = { 0 };
|
||||
XCRUSH_MATCH_INFO MaxMatchInfo = { 0 };
|
||||
XCRUSH_SIGNATURE* Signatures = NULL;
|
||||
|
||||
Signatures = xcrush->Signatures;
|
||||
|
||||
for (i = 0; i < SignatureIndex; i++)
|
||||
{
|
||||
offset = SrcOffset + HistoryOffset;
|
||||
|
||||
if (!Signatures[i].size)
|
||||
return -1001; /* error */
|
||||
|
||||
status = xcrush_insert_chunk(xcrush, &Signatures[i], offset, &chunk);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (chunk && (SrcOffset + HistoryOffset + Signatures[i].size >= PrevMatchEnd))
|
||||
{
|
||||
ChunkCount = 0;
|
||||
MaxMatchLength = 0;
|
||||
ZeroMemory(&MaxMatchInfo, sizeof(XCRUSH_MATCH_INFO));
|
||||
|
||||
while (chunk)
|
||||
{
|
||||
if ((chunk->offset < HistoryOffset) || (chunk->offset < offset)
|
||||
|| (chunk->offset > SrcSize + HistoryOffset))
|
||||
{
|
||||
status = xcrush_find_match_length(xcrush, offset, chunk->offset,
|
||||
HistoryOffset, SrcSize, MaxMatchLength, &MatchInfo);
|
||||
|
||||
if (status < 0)
|
||||
return status; /* error */
|
||||
|
||||
MatchLength = (UINT32) status;
|
||||
|
||||
if (MatchLength > MaxMatchLength)
|
||||
{
|
||||
MaxMatchLength = MatchLength;
|
||||
MaxMatchInfo.MatchOffset = MatchInfo.MatchOffset;
|
||||
MaxMatchInfo.ChunkOffset = MatchInfo.ChunkOffset;
|
||||
MaxMatchInfo.MatchLength = MatchInfo.MatchLength;
|
||||
|
||||
if (MatchLength > 256)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ChunkIndex = ChunkCount++;
|
||||
|
||||
if (ChunkIndex > 4)
|
||||
break;
|
||||
|
||||
status = xcrush_find_next_matching_chunk(xcrush, chunk, &chunk);
|
||||
|
||||
if (status < 0)
|
||||
return status; /* error */
|
||||
}
|
||||
|
||||
if (MaxMatchLength)
|
||||
{
|
||||
xcrush->OriginalMatches[j].MatchOffset = MaxMatchInfo.MatchOffset;
|
||||
xcrush->OriginalMatches[j].ChunkOffset = MaxMatchInfo.ChunkOffset;
|
||||
xcrush->OriginalMatches[j].MatchLength = MaxMatchInfo.MatchLength;
|
||||
|
||||
if (xcrush->OriginalMatches[j].MatchOffset < HistoryOffset)
|
||||
return -1002; /* error */
|
||||
|
||||
PrevMatchEnd = xcrush->OriginalMatches[j].MatchLength + xcrush->OriginalMatches[j].MatchOffset;
|
||||
|
||||
j++;
|
||||
|
||||
if (j >= 1000)
|
||||
return -1003; /* error */
|
||||
}
|
||||
}
|
||||
|
||||
SrcOffset += Signatures[i].size;
|
||||
|
||||
if (SrcOffset > SrcSize)
|
||||
return -1004; /* error */
|
||||
}
|
||||
|
||||
if (SrcOffset > SrcSize)
|
||||
return -1005; /* error */
|
||||
|
||||
return (int) j;
|
||||
}
|
||||
|
||||
int xcrush_optimize_matches(XCRUSH_CONTEXT* xcrush)
|
||||
{
|
||||
UINT32 i, j;
|
||||
UINT32 MatchDiff;
|
||||
UINT32 PrevMatchEnd;
|
||||
UINT32 TotalMatchLength;
|
||||
UINT32 OriginalMatchCount;
|
||||
UINT32 OptimizedMatchCount;
|
||||
XCRUSH_MATCH_INFO* OriginalMatch;
|
||||
XCRUSH_MATCH_INFO* OptimizedMatch;
|
||||
XCRUSH_MATCH_INFO* OriginalMatches;
|
||||
XCRUSH_MATCH_INFO* OptimizedMatches;
|
||||
|
||||
i = j = 0;
|
||||
PrevMatchEnd = 0;
|
||||
TotalMatchLength = 0;
|
||||
|
||||
OriginalMatches = xcrush->OriginalMatches;
|
||||
OriginalMatchCount = xcrush->OriginalMatchCount;
|
||||
|
||||
OptimizedMatches = xcrush->OptimizedMatches;
|
||||
OptimizedMatchCount = xcrush->OptimizedMatchCount;
|
||||
|
||||
for (i = 0; i < OriginalMatchCount; i++)
|
||||
{
|
||||
if (OriginalMatches[i].MatchOffset <= PrevMatchEnd)
|
||||
{
|
||||
if ((OriginalMatches[i].MatchOffset < PrevMatchEnd)
|
||||
&& (OriginalMatches[i].MatchLength + OriginalMatches[i].MatchOffset > PrevMatchEnd + 6))
|
||||
{
|
||||
MatchDiff = PrevMatchEnd - OriginalMatches[i].MatchOffset;
|
||||
|
||||
OriginalMatch = &OriginalMatches[i];
|
||||
OptimizedMatch = &OptimizedMatches[j];
|
||||
|
||||
OptimizedMatch->MatchOffset = OriginalMatch->MatchOffset;
|
||||
OptimizedMatch->ChunkOffset = OriginalMatch->ChunkOffset;
|
||||
OptimizedMatch->MatchLength = OriginalMatch->MatchLength;
|
||||
|
||||
if (OptimizedMatches[j].MatchLength <= MatchDiff)
|
||||
return -5001; /* error */
|
||||
|
||||
if (MatchDiff >= 20000)
|
||||
return -5002; /* error */
|
||||
|
||||
OptimizedMatches[j].MatchLength -= MatchDiff;
|
||||
OptimizedMatches[j].MatchOffset += MatchDiff;
|
||||
OptimizedMatches[j].ChunkOffset += MatchDiff;
|
||||
|
||||
PrevMatchEnd = OptimizedMatches[j].MatchLength + OptimizedMatches[j].MatchOffset;
|
||||
TotalMatchLength += OptimizedMatches[j].MatchLength;
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OriginalMatch = &OriginalMatches[i];
|
||||
OptimizedMatch = &OptimizedMatches[j];
|
||||
|
||||
OptimizedMatch->MatchOffset = OriginalMatch->MatchOffset;
|
||||
OptimizedMatch->ChunkOffset = OriginalMatch->ChunkOffset;
|
||||
OptimizedMatch->MatchLength = OriginalMatch->MatchLength;
|
||||
|
||||
PrevMatchEnd = OptimizedMatches[j].MatchLength + OptimizedMatches[j].MatchOffset;
|
||||
TotalMatchLength += OptimizedMatches[j].MatchLength;
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
OptimizedMatchCount = j;
|
||||
xcrush->OptimizedMatchCount = OptimizedMatchCount;
|
||||
|
||||
return (int) TotalMatchLength;
|
||||
}
|
||||
|
||||
int xcrush_generate_output(XCRUSH_CONTEXT* xcrush, BYTE* OutputBuffer, UINT32 OutputSize, UINT32 HistoryOffset, UINT32* pDstSize)
|
||||
{
|
||||
BYTE* Literals;
|
||||
BYTE* OutputEnd;
|
||||
UINT32 MatchIndex;
|
||||
UINT32 MatchOffset;
|
||||
UINT16 MatchLength;
|
||||
UINT32 MatchCount;
|
||||
UINT32 CurrentOffset;
|
||||
UINT32 MatchOffsetDiff;
|
||||
UINT32 HistoryOffsetDiff;
|
||||
RDP61_MATCH_DETAILS* MatchDetails;
|
||||
|
||||
MatchCount = xcrush->OptimizedMatchCount;
|
||||
|
||||
OutputEnd = &OutputBuffer[OutputSize];
|
||||
|
||||
if (&OutputBuffer[2] >= &OutputBuffer[OutputSize])
|
||||
return -6001; /* error */
|
||||
|
||||
*((UINT16*) OutputBuffer) = MatchCount;
|
||||
|
||||
MatchDetails = (RDP61_MATCH_DETAILS*) &OutputBuffer[2];
|
||||
Literals = (BYTE*) &MatchDetails[MatchCount];
|
||||
|
||||
if (Literals > OutputEnd)
|
||||
return -6002; /* error */
|
||||
|
||||
for (MatchIndex = 0; MatchIndex < MatchCount; MatchIndex++)
|
||||
{
|
||||
MatchDetails[MatchIndex].MatchLength = (UINT16) (xcrush->OptimizedMatches[MatchIndex].MatchLength);
|
||||
MatchDetails[MatchIndex].MatchOutputOffset = (UINT16) (xcrush->OptimizedMatches[MatchIndex].MatchOffset - HistoryOffset);
|
||||
MatchDetails[MatchIndex].MatchHistoryOffset = xcrush->OptimizedMatches[MatchIndex].ChunkOffset;
|
||||
}
|
||||
|
||||
CurrentOffset = HistoryOffset;
|
||||
|
||||
for (MatchIndex = 0; MatchIndex < MatchCount; MatchIndex++)
|
||||
{
|
||||
MatchLength = (UINT16) (xcrush->OptimizedMatches[MatchIndex].MatchLength);
|
||||
MatchOffset = xcrush->OptimizedMatches[MatchIndex].MatchOffset;
|
||||
|
||||
if (MatchOffset <= CurrentOffset)
|
||||
{
|
||||
if (MatchOffset != CurrentOffset)
|
||||
return -6003; /* error */
|
||||
|
||||
CurrentOffset = MatchOffset + MatchLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
MatchOffsetDiff = MatchOffset - CurrentOffset;
|
||||
|
||||
if (Literals + MatchOffset - CurrentOffset >= OutputEnd)
|
||||
return -6004; /* error */
|
||||
|
||||
CopyMemory(Literals, &xcrush->HistoryBuffer[CurrentOffset], MatchOffsetDiff);
|
||||
|
||||
if (Literals >= OutputEnd)
|
||||
return -6005; /* error */
|
||||
|
||||
Literals += MatchOffsetDiff;
|
||||
CurrentOffset = MatchOffset + MatchLength;
|
||||
}
|
||||
}
|
||||
|
||||
HistoryOffsetDiff = xcrush->HistoryOffset - CurrentOffset;
|
||||
|
||||
if (Literals + HistoryOffsetDiff >= OutputEnd)
|
||||
return -6006; /* error */
|
||||
|
||||
CopyMemory(Literals, &xcrush->HistoryBuffer[CurrentOffset], HistoryOffsetDiff);
|
||||
*pDstSize = Literals + HistoryOffsetDiff - OutputBuffer;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xcrush_copy_bytes(BYTE* dst, BYTE* src, int num)
|
||||
{
|
||||
int index;
|
||||
@ -192,25 +833,67 @@ int xcrush_decompress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BY
|
||||
|
||||
int xcrush_compress_l1(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
|
||||
{
|
||||
int status = 0;
|
||||
UINT32 Flags = 0;
|
||||
UINT32 HistoryOffset = 0;
|
||||
BYTE* HistoryPtr = NULL;
|
||||
BYTE* HistoryBuffer = NULL;
|
||||
UINT32 SignatureIndex = 0;
|
||||
|
||||
if (xcrush->HistoryOffset + SrcSize + 8 > xcrush->HistoryBufferSize)
|
||||
{
|
||||
xcrush->HistoryOffset = 0;
|
||||
Flags |= L1_PACKET_AT_FRONT;
|
||||
}
|
||||
|
||||
HistoryOffset = xcrush->HistoryOffset;
|
||||
HistoryBuffer = xcrush->HistoryBuffer;
|
||||
HistoryPtr = &HistoryBuffer[HistoryOffset];
|
||||
|
||||
CopyMemory(HistoryPtr, pSrcData, SrcSize);
|
||||
MoveMemory(HistoryPtr, pSrcData, SrcSize);
|
||||
xcrush->HistoryOffset += SrcSize;
|
||||
|
||||
if (SrcSize <= 50)
|
||||
if (SrcSize > 50)
|
||||
{
|
||||
SignatureIndex = xcrush_compute_signatures(xcrush, pSrcData, SrcSize);
|
||||
|
||||
if (SignatureIndex)
|
||||
{
|
||||
status = xcrush_find_all_matches(xcrush,
|
||||
SignatureIndex, HistoryOffset, 0, SrcSize);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
xcrush->OriginalMatchCount = (UINT32) status;
|
||||
|
||||
xcrush->OptimizedMatchCount = 0;
|
||||
|
||||
if (xcrush->OriginalMatchCount)
|
||||
{
|
||||
status = xcrush_optimize_matches(xcrush);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
}
|
||||
|
||||
if (xcrush->OptimizedMatchCount)
|
||||
{
|
||||
status = xcrush_generate_output(xcrush, *ppDstData, SrcSize, HistoryOffset, pDstSize);
|
||||
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
if (status > 0)
|
||||
Flags |= L1_COMPRESSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(Flags & L1_COMPRESSED))
|
||||
{
|
||||
Flags |= L1_NO_COMPRESSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
*pDstSize = SrcSize;
|
||||
}
|
||||
|
||||
*pFlags = Flags;
|
||||
@ -232,18 +915,18 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
||||
UINT32 CompressionLevel = 3;
|
||||
|
||||
if (SrcSize > 16384)
|
||||
return -1;
|
||||
return -1001;
|
||||
|
||||
if ((SrcSize + 2) > *pDstSize)
|
||||
return -1;
|
||||
return -1002;
|
||||
|
||||
OriginalData = pDstData;
|
||||
OriginalDataSize = *pDstSize;
|
||||
OriginalData = *ppDstData;
|
||||
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;
|
||||
@ -251,26 +934,24 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
||||
if (Level1ComprFlags & L1_COMPRESSED)
|
||||
{
|
||||
CompressedData = pDstData;
|
||||
CompressedDataSize = DstSize;
|
||||
|
||||
if (CompressedDataSize > SrcSize)
|
||||
return -1;
|
||||
return -1003;
|
||||
}
|
||||
else
|
||||
{
|
||||
CompressedData = pSrcData;
|
||||
CompressedDataSize = DstSize;
|
||||
|
||||
if (CompressedDataSize != SrcSize)
|
||||
return -1;
|
||||
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);
|
||||
}
|
||||
@ -278,29 +959,29 @@ 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))
|
||||
{
|
||||
if (CompressedDataSize > DstSize)
|
||||
return -1;
|
||||
{
|
||||
xcrush_context_flush(xcrush);
|
||||
*ppDstData = pSrcData;
|
||||
*pDstSize = SrcSize;
|
||||
*pFlags = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
DstSize = CompressedDataSize;
|
||||
CopyMemory(pDstData, CompressedData, CompressedDataSize);
|
||||
CopyMemory(&OriginalData[2], CompressedData, CompressedDataSize);
|
||||
}
|
||||
|
||||
if (Level2ComprFlags & PACKET_COMPRESSED)
|
||||
{
|
||||
|
||||
Level2ComprFlags |= xcrush->CompressionFlags;
|
||||
xcrush->CompressionFlags = 0;
|
||||
}
|
||||
else
|
||||
else if (Level2ComprFlags & PACKET_FLUSHED)
|
||||
{
|
||||
if (Level2ComprFlags & PACKET_FLUSHED)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
xcrush->CompressionFlags = PACKET_FLUSHED;
|
||||
}
|
||||
|
||||
Level1ComprFlags |= L1_INNER_COMPRESSION;
|
||||
@ -308,8 +989,14 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
||||
OriginalData[0] = (BYTE) Level1ComprFlags;
|
||||
OriginalData[1] = (BYTE) Level2ComprFlags;
|
||||
|
||||
#if 0
|
||||
printf("XCrushCompress: Level1ComprFlags: %s Level2ComprFlags: %s\n",
|
||||
xcrush_get_level_1_compression_flags_string(Level1ComprFlags),
|
||||
xcrush_get_level_2_compression_flags_string(Level2ComprFlags));
|
||||
#endif
|
||||
|
||||
if (*pDstSize < (DstSize + 2))
|
||||
return -1;
|
||||
return -1006;
|
||||
|
||||
*pDstSize = DstSize + 2;
|
||||
*pFlags = PACKET_COMPRESSED | CompressionLevel;
|
||||
@ -319,7 +1006,28 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE
|
||||
|
||||
void xcrush_context_reset(XCRUSH_CONTEXT* xcrush)
|
||||
{
|
||||
xcrush->SignatureIndex = 0;
|
||||
xcrush->SignatureCount = 1000;
|
||||
ZeroMemory(&(xcrush->Signatures), sizeof(XCRUSH_SIGNATURE) * xcrush->SignatureCount);
|
||||
|
||||
xcrush->CompressionFlags = 0;
|
||||
|
||||
xcrush->ChunkHead = xcrush->ChunkTail = 1;
|
||||
ZeroMemory(&(xcrush->Chunks), sizeof(xcrush->Chunks));
|
||||
ZeroMemory(&(xcrush->NextChunks), sizeof(xcrush->NextChunks));
|
||||
|
||||
ZeroMemory(&(xcrush->OriginalMatches), sizeof(xcrush->OriginalMatches));
|
||||
ZeroMemory(&(xcrush->OptimizedMatches), sizeof(xcrush->OptimizedMatches));
|
||||
|
||||
mppc_context_reset(xcrush->mppc);
|
||||
}
|
||||
|
||||
void xcrush_context_flush(XCRUSH_CONTEXT* xcrush)
|
||||
{
|
||||
xcrush_context_reset(xcrush);
|
||||
xcrush->HistoryOffset = xcrush->HistoryBufferSize + 1;
|
||||
|
||||
mppc_context_flush(xcrush->mppc);
|
||||
}
|
||||
|
||||
XCRUSH_CONTEXT* xcrush_context_new(BOOL Compressor)
|
||||
|
@ -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)
|
||||
{
|
||||
@ -52,14 +52,19 @@ const char* bulk_get_compression_flags_string(UINT32 flags)
|
||||
UINT32 bulk_compression_level(rdpBulk* bulk)
|
||||
{
|
||||
rdpSettings* settings = bulk->context->settings;
|
||||
bulk->CompressionLevel = (settings->CompressionLevel >= 2) ? 2 : settings->CompressionLevel;
|
||||
|
||||
bulk->CompressionLevel = (settings->CompressionLevel >= PACKET_COMPR_TYPE_RDP61) ?
|
||||
PACKET_COMPR_TYPE_RDP61 : settings->CompressionLevel;
|
||||
|
||||
return bulk->CompressionLevel;
|
||||
}
|
||||
|
||||
UINT32 bulk_compression_max_size(rdpBulk* bulk)
|
||||
{
|
||||
bulk_compression_level(bulk);
|
||||
bulk->CompressionMaxSize = (bulk->CompressionLevel < 1) ? 8192 : 65536;
|
||||
|
||||
bulk->CompressionMaxSize = (bulk->CompressionLevel < PACKET_COMPR_TYPE_64K) ? 8192 : 65536;
|
||||
|
||||
return bulk->CompressionMaxSize;
|
||||
}
|
||||
|
||||
@ -202,16 +207,25 @@ int bulk_compress(rdpBulk* bulk, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstDat
|
||||
bulk_compression_level(bulk);
|
||||
bulk_compression_max_size(bulk);
|
||||
|
||||
if (bulk->CompressionLevel < PACKET_COMPR_TYPE_RDP6)
|
||||
if ((bulk->CompressionLevel == PACKET_COMPR_TYPE_8K) ||
|
||||
(bulk->CompressionLevel == PACKET_COMPR_TYPE_64K))
|
||||
{
|
||||
mppc_set_compression_level(bulk->mppcSend, bulk->CompressionLevel);
|
||||
status = mppc_compress(bulk->mppcSend, pSrcData, SrcSize, ppDstData, pDstSize, pFlags);
|
||||
}
|
||||
else
|
||||
else if (bulk->CompressionLevel == PACKET_COMPR_TYPE_RDP6)
|
||||
{
|
||||
status = ncrush_compress(bulk->ncrushSend, pSrcData, SrcSize, ppDstData, pDstSize, pFlags);
|
||||
}
|
||||
|
||||
else if (bulk->CompressionLevel == PACKET_COMPR_TYPE_RDP61)
|
||||
{
|
||||
status = xcrush_compress(bulk->xcrushSend, pSrcData, SrcSize, ppDstData, pDstSize, pFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = -1;
|
||||
}
|
||||
|
||||
if (status >= 0)
|
||||
{
|
||||
CompressedBytes = *pDstSize;
|
||||
|
@ -257,9 +257,9 @@ rdpSettings* freerdp_settings_new(DWORD flags)
|
||||
settings->CompressionEnabled = TRUE;
|
||||
|
||||
if (settings->ServerMode)
|
||||
settings->CompressionLevel = PACKET_COMPR_TYPE_64K;
|
||||
settings->CompressionLevel = PACKET_COMPR_TYPE_RDP61;
|
||||
else
|
||||
settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
|
||||
settings->CompressionLevel = PACKET_COMPR_TYPE_RDP61;
|
||||
|
||||
settings->Authentication = TRUE;
|
||||
settings->AuthenticationOnly = FALSE;
|
||||
|
2
libfreerdp/utils/test/.gitignore
vendored
2
libfreerdp/utils/test/.gitignore
vendored
@ -1 +1 @@
|
||||
TestFreeRDPutils.c
|
||||
TestFreeRDPUtils.c
|
||||
|
@ -533,7 +533,8 @@ BOOL tf_peer_activate(freerdp_peer* client)
|
||||
|
||||
//client->settings->CompressionLevel = PACKET_COMPR_TYPE_8K;
|
||||
//client->settings->CompressionLevel = PACKET_COMPR_TYPE_64K;
|
||||
client->settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
|
||||
//client->settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
|
||||
client->settings->CompressionLevel = PACKET_COMPR_TYPE_RDP61;
|
||||
|
||||
if (test_pcap_file != NULL)
|
||||
{
|
||||
|
@ -32,6 +32,22 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
static INLINE UINT32 _rotl(UINT32 value, int shift) {
|
||||
return (value << shift) | (value >> (32 - shift));
|
||||
}
|
||||
|
||||
static INLINE UINT64 _rotl64(UINT64 value, int shift) {
|
||||
return (value << shift) | (value >> (64 - shift));
|
||||
}
|
||||
|
||||
static INLINE UINT32 _rotr(UINT32 value, int shift) {
|
||||
return (value >> shift) | (value << (32 - shift));
|
||||
}
|
||||
|
||||
static INLINE UINT64 _rotr64(UINT64 value, int shift) {
|
||||
return (value >> shift) | (value << (64 - shift));
|
||||
}
|
||||
|
||||
#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2))
|
||||
|
||||
#define _byteswap_ushort(_val) __builtin_bswap16(_val)
|
||||
|
Loading…
Reference in New Issue
Block a user