diff --git a/include/freerdp/codec/xcrush.h b/include/freerdp/codec/xcrush.h index 180b35aea..e8d73e63c 100644 --- a/include/freerdp/codec/xcrush.h +++ b/include/freerdp/codec/xcrush.h @@ -25,6 +25,13 @@ #include +struct _XCRUSH_SIGNATURE +{ + UINT16 seed; + UINT16 size; +}; +typedef struct _XCRUSH_SIGNATURE XCRUSH_SIGNATURE; + struct _RDP61_MATCH_DETAILS { UINT16 MatchLength; @@ -52,6 +59,10 @@ struct _XCRUSH_CONTEXT UINT32 HistoryBufferSize; BYTE HistoryBuffer[2000000]; BYTE BlockBuffer[16384]; + + UINT32 SignatureIndex; + UINT32 SignatureCount; + XCRUSH_SIGNATURE* Signatures; }; typedef struct _XCRUSH_CONTEXT XCRUSH_CONTEXT; diff --git a/libfreerdp/codec/xcrush.c b/libfreerdp/codec/xcrush.c index e36b01f01..d67ef0380 100644 --- a/libfreerdp/codec/xcrush.c +++ b/libfreerdp/codec/xcrush.c @@ -27,6 +27,126 @@ #include +#ifndef _rotl +INLINE UINT32 _rotl(UINT32 x, UINT32 r) { + return (x << r) | (x >> (32 - r)); +} +#endif + +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 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 > 0xFFFF) + return 0; + + if (size >= 15) + { + seed = xcrush_update_hash(&data[*beg], size); + xcrush->Signatures[xcrush->SignatureIndex].size = size; + xcrush->Signatures[xcrush->SignatureIndex].seed = seed; + xcrush->SignatureIndex++; + *beg = end; + } + + return 1; +} + +char xcrush_compute_chunks(XCRUSH_CONTEXT* xcrush, BYTE* data, UINT32 size, XCRUSH_SIGNATURE* Signatures, UINT32 SignatureCount, UINT32* pIndex) +{ + UINT32 i = 0; + UINT32 offset = 0; + UINT32 accumulator = 0; + + *pIndex = 0; + xcrush->SignatureIndex = 0; + + xcrush->Signatures = Signatures; + xcrush->SignatureCount = SignatureCount; + + if (size < 128) + return 0; + + for (i = 0; i < 32; i++) + { + accumulator = data[i] ^ _rotl(accumulator, 1); + } + + for (i = 0; i < size - 64; i++) + { + accumulator = data[i + 32] ^ data[i] ^ _rotl(accumulator, 1); + + if (!(accumulator & 0x7F)) + { + if (!xcrush_append_chunk(xcrush, data, &offset, i + 32)) + return 0; + } + i++; + + accumulator = data[i + 32] ^ data[i] ^ _rotl(accumulator, 1); + + if (!(accumulator & 0x7F)) + { + if (!xcrush_append_chunk(xcrush, data, &offset, i + 32)) + return 0; + } + i++; + + accumulator = data[i + 32] ^ data[i] ^ _rotl(accumulator, 1); + + if (!(accumulator & 0x7F)) + { + if (!xcrush_append_chunk(xcrush, data, &offset, i + 32)) + return 0; + } + i++; + + accumulator = data[i + 32] ^ data[i] ^ _rotl(accumulator, 1); + + 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; +} + int xcrush_copy_bytes(BYTE* dst, BYTE* src, int num) { int index; @@ -319,7 +439,8 @@ int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE void xcrush_context_reset(XCRUSH_CONTEXT* xcrush) { - + xcrush->SignatureIndex = 0; + xcrush->Signatures = NULL; } XCRUSH_CONTEXT* xcrush_context_new(BOOL Compressor)