diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index ac3acdc5a..6c703a3c7 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -80,41 +80,21 @@ const char* progressive_get_block_type_string(UINT16 blockType) #define UQ_GR (3) /* increase in kp after nonzero symbol in GR mode */ #define DQ_GR (3) /* decrease in kp after zero symbol in GR mode */ -/** - * __lzcnt16, __lzcnt, __lzcnt64: - * http://msdn.microsoft.com/en-us/library/bb384809/ - */ - -#ifndef _WIN32 - -INLINE UINT16 __lzcnt16(UINT16 value) -{ - return (UINT16) (__builtin_clz((UINT32) value) - 16); -} - -INLINE UINT32 __lzcnt(UINT32 value) -{ - return __builtin_clz(value); -} - -INLINE UINT64 __lzcnt64(UINT64 value) -{ - return __builtin_clzll(value); -} - -#endif - -int progressive_rfx_rlgr_decode(PROGRESSIVE_CONTEXT* progressive, BYTE* data, UINT16 length) +int rfx_rlgr1_decode(BYTE* pSrcData, UINT32 SrcSize, INT16* pDstData, UINT32 DstSize) { int vk; int run; + int cnt; + int size; + int nbits; + int offset; INT16 mag; int k, kp; int kr, krp; UINT16 code; UINT32 sign; + INT16* pOutput; wBitStream* bs; - UINT32 accumulator; k = 1; kp = k << LSGR; @@ -122,15 +102,24 @@ int progressive_rfx_rlgr_decode(PROGRESSIVE_CONTEXT* progressive, BYTE* data, UI kr = 1; krp = kr << LSGR; + if (!pSrcData) + return -2001; + + if (SrcSize < 1) + return -2002; + + pOutput = pDstData; + bs = BitStream_New(); - BitStream_Attach(bs, data, length); + if (!bs) + return -2003; + + BitStream_Attach(bs, pSrcData, SrcSize); BitStream_Fetch(bs); - while ((bs->length - bs->position) > 0) + while ((BitStream_GetRemainingLength(bs) > 0) && ((pOutput - pDstData) < DstSize)) { - accumulator = bs->accumulator; - if (k) { /* Run-Length (RL) Mode */ @@ -139,15 +128,38 @@ int progressive_rfx_rlgr_decode(PROGRESSIVE_CONTEXT* progressive, BYTE* data, UI /* count number of leading 0s */ - vk = __lzcnt(bs->accumulator); + cnt = __lzcnt(bs->accumulator); - while (vk && (vk % 32 == 0)) + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk = cnt; + + while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0)) { - BitStream_Shift(bs, vk); - vk += __lzcnt(bs->accumulator); + printf("__lzcnt loop: cnt: %d length: %d position: %d\n", + cnt, bs->length, bs->position); + + BitStream_Shift32(bs); + + cnt = __lzcnt(bs->accumulator); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk += cnt; } - BitStream_Shift(bs, ((vk % 32) + 1)); + BitStream_Shift(bs, (vk % 32)); + + if (BitStream_GetRemainingLength(bs) < 1) + break; + + BitStream_Shift(bs, 1); while (vk--) { @@ -167,25 +179,51 @@ int progressive_rfx_rlgr_decode(PROGRESSIVE_CONTEXT* progressive, BYTE* data, UI /* next k bits contain run length remainder */ + if (BitStream_GetRemainingLength(bs) < k) + break; + run += (bs->accumulator >> (32 - k)); BitStream_Shift(bs, k); /* read sign bit */ + if (BitStream_GetRemainingLength(bs) < 1) + break; + sign = (bs->accumulator & 0x80000000) ? 1 : 0; BitStream_Shift(bs, 1); /* count number of leading 1s */ - vk = __lzcnt(~(bs->accumulator)); + cnt = __lzcnt(~(bs->accumulator)); - while (vk && (vk % 32 == 0)) + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk = cnt; + + while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0)) { - BitStream_Shift(bs, vk); - vk += __lzcnt(~(bs->accumulator)); + BitStream_Shift32(bs); + + cnt = __lzcnt(~(bs->accumulator)); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk += cnt; } - BitStream_Shift(bs, ((vk % 32) + 1)); + BitStream_Shift(bs, (vk % 32)); + + if (BitStream_GetRemainingLength(bs) < 1) + break; + + BitStream_Shift(bs, 1); /* add (vk << kr) to code */ @@ -193,6 +231,9 @@ int progressive_rfx_rlgr_decode(PROGRESSIVE_CONTEXT* progressive, BYTE* data, UI /* next kr bits contain code remainder */ + if (BitStream_GetRemainingLength(bs) < kr) + break; + code += (bs->accumulator >> (32 - kr)); BitStream_Shift(bs, kr); @@ -243,8 +284,25 @@ int progressive_rfx_rlgr_decode(PROGRESSIVE_CONTEXT* progressive, BYTE* data, UI /* write to output stream */ - // WriteZeroes(run); - // WriteValue(mag); + offset = (int) (pOutput - pDstData); + size = run; + + if ((offset + size) > DstSize) + size = DstSize - offset; + + if (size) + { + ZeroMemory(pOutput, size * sizeof(INT16)); + pOutput += size; + } + + offset = (int) (pOutput - pDstData); + + if ((offset + 1) <= DstSize) + { + *pOutput = mag; + pOutput++; + } } else { @@ -252,15 +310,35 @@ int progressive_rfx_rlgr_decode(PROGRESSIVE_CONTEXT* progressive, BYTE* data, UI /* count number of leading 1s */ - vk = __lzcnt(~(bs->accumulator)); + cnt = __lzcnt(~(bs->accumulator)); - while (vk && (vk % 32 == 0)) + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk = cnt; + + while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0)) { - BitStream_Shift(bs, vk); - vk += __lzcnt(~(bs->accumulator)); + BitStream_Shift32(bs); + + cnt = __lzcnt(~(bs->accumulator)); + + nbits = BitStream_GetRemainingLength(bs); + + if (cnt > nbits) + cnt = nbits; + + vk += cnt; } - BitStream_Shift(bs, ((vk % 32) + 1)); + BitStream_Shift(bs, (vk % 32)); + + if (BitStream_GetRemainingLength(bs) < 1) + break; + + BitStream_Shift(bs, 1); /* add (vk << kr) to code */ @@ -268,6 +346,9 @@ int progressive_rfx_rlgr_decode(PROGRESSIVE_CONTEXT* progressive, BYTE* data, UI /* next kr bits contain code remainder */ + if (BitStream_GetRemainingLength(bs) < kr) + break; + code += (bs->accumulator >> (32 - kr)); BitStream_Shift(bs, kr); @@ -311,7 +392,7 @@ int progressive_rfx_rlgr_decode(PROGRESSIVE_CONTEXT* progressive, BYTE* data, UI k = kp >> LSGR; - // WriteValue(0); + mag = 0; } else { @@ -335,15 +416,21 @@ int progressive_rfx_rlgr_decode(PROGRESSIVE_CONTEXT* progressive, BYTE* data, UI mag = ((INT16) ((code + 1) >> 1)) * -1; else mag = (INT16) (mag >> 1); + } - // WriteValue(mag); + offset = (int) (pOutput - pDstData); + + if ((offset + 1) <= DstSize) + { + *pOutput = mag; + pOutput++; } } } BitStream_Free(bs); - return 1; + return (int) (pOutput - pDstData); } int progressive_decompress_tile_first(PROGRESSIVE_CONTEXT* progressive, RFX_PROGRESSIVE_TILE* tile) diff --git a/winpr/include/winpr/bitstream.h b/winpr/include/winpr/bitstream.h index b77a1dc97..092917322 100644 --- a/winpr/include/winpr/bitstream.h +++ b/winpr/include/winpr/bitstream.h @@ -29,9 +29,9 @@ struct _wBitStream { BYTE* buffer; BYTE* pointer; - DWORD position; - DWORD length; - DWORD capacity; + int position; + int length; + int capacity; UINT32 mask; UINT32 offset; UINT32 prefetch; @@ -83,28 +83,38 @@ extern "C" { } while(0) #define BitStream_Shift(_bs, _nbits) do { \ - _bs->accumulator <<= _nbits; \ - _bs->position += _nbits; \ - _bs->offset += _nbits; \ - if (_bs->offset < 32) { \ - _bs->mask = ((1 << _nbits) - 1); \ - _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ - _bs->prefetch <<= _nbits; \ - } else { \ - _bs->mask = ((1 << _nbits) - 1); \ - _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ - _bs->prefetch <<= _nbits; \ - _bs->offset -= 32; \ - _bs->pointer += 4; \ - BitStream_Prefetch(_bs); \ - if (_bs->offset) { \ - _bs->mask = ((1 << _bs->offset) - 1); \ - _bs->accumulator |= ((_bs->prefetch >> (32 - _bs->offset)) & _bs->mask); \ - _bs->prefetch <<= _bs->offset; \ + if (_nbits == 0) { \ + } else if ((_nbits > 0) && (_nbits < 32)) { \ + _bs->accumulator <<= _nbits; \ + _bs->position += _nbits; \ + _bs->offset += _nbits; \ + if (_bs->offset < 32) { \ + _bs->mask = ((1 << _nbits) - 1); \ + _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ + _bs->prefetch <<= _nbits; \ + } else { \ + _bs->mask = ((1 << _nbits) - 1); \ + _bs->accumulator |= ((_bs->prefetch >> (32 - _nbits)) & _bs->mask); \ + _bs->prefetch <<= _nbits; \ + _bs->offset -= 32; \ + _bs->pointer += 4; \ + BitStream_Prefetch(_bs); \ + if (_bs->offset) { \ + _bs->mask = ((1 << _bs->offset) - 1); \ + _bs->accumulator |= ((_bs->prefetch >> (32 - _bs->offset)) & _bs->mask); \ + _bs->prefetch <<= _bs->offset; \ + } \ } \ + } else { \ + fprintf(stderr, "warning: BitStream_Shift(%d)\n", _nbits); \ } \ } while(0) +#define BitStream_Shift32(_bs) do { \ + BitStream_Shift(_bs, 16); \ + BitStream_Shift(_bs, 16); \ +} while(0) + #define BitStream_Write_Bits(_bs, _bits, _nbits) do { \ _bs->position += _nbits; \ _bs->offset += _nbits; \ @@ -124,6 +134,9 @@ extern "C" { } \ } while(0) +#define BitStream_GetRemainingLength(_bs) \ + (_bs->length - _bs->position) + WINPR_API void BitDump(const BYTE* buffer, UINT32 length, UINT32 flags); WINPR_API UINT32 ReverseBits32(UINT32 bits, UINT32 nbits); diff --git a/winpr/include/winpr/crt.h b/winpr/include/winpr/crt.h index 6da3f4b16..ed136a2a0 100644 --- a/winpr/include/winpr/crt.h +++ b/winpr/include/winpr/crt.h @@ -82,6 +82,55 @@ static INLINE UINT64 _rotr64(UINT64 value, int shift) { #endif +/** + * __lzcnt16, __lzcnt, __lzcnt64: + * http://msdn.microsoft.com/en-us/library/bb384809/ + */ + +#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) + +/** + * __lzcnt16, __lzcnt, __lzcnt64: + * http://msdn.microsoft.com/en-us/library/bb384809/ + * + * Beware: the result of __builtin_clz(0) is undefined + */ + +static INLINE UINT32 __lzcnt(UINT32 _val32) { + return _val32 ? ((UINT32) __builtin_clz(_val32)) : 32; +} + +static INLINE UINT16 __lzcnt16(UINT16 _val16) { + return _val16 ? ((UINT16) (__builtin_clz((UINT32) _val16) - 16)) : 16; +} + +static INLINE UINT64 __lzcnt64(UINT64 _val64) { + return _val64 ? ((UINT64) __builtin_clzll(_val64)) : 64; +} + +#else + +static INLINE UINT32 __lzcnt(UINT32 x) { + unsigned y; + int n = 32; + y = x >> 16; if (y != 0) { n = n - 16; x = y; } + y = x >> 8; if (y != 0) { n = n - 8; x = y; } + y = x >> 4; if (y != 0) { n = n - 4; x = y; } + y = x >> 2; if (y != 0) { n = n - 2; x = y; } + y = x >> 1; if (y != 0) return n - 2; + return n - x; +} + +static INLINE UINT16 __lzcnt16(UINT16 x) { + return ((UINT16) __lzcnt((UINT32) x)); +} + +static INLINE UINT64 __lzcnt64(UINT64 x) { + return 0; /* TODO */ +} + +#endif + #endif #ifndef _WIN32 diff --git a/winpr/libwinpr/crt/test/CMakeLists.txt b/winpr/libwinpr/crt/test/CMakeLists.txt index 4f1f9d3fd..4bccde151 100644 --- a/winpr/libwinpr/crt/test/CMakeLists.txt +++ b/winpr/libwinpr/crt/test/CMakeLists.txt @@ -8,6 +8,7 @@ set(${MODULE_PREFIX}_TESTS TestTypes.c TestAlignment.c TestString.c + TestIntrinsics.c TestUnicodeConversion.c) create_test_sourcelist(${MODULE_PREFIX}_SRCS diff --git a/winpr/libwinpr/crt/test/TestIntrinsics.c b/winpr/libwinpr/crt/test/TestIntrinsics.c new file mode 100644 index 000000000..bb1f07b05 --- /dev/null +++ b/winpr/libwinpr/crt/test/TestIntrinsics.c @@ -0,0 +1,109 @@ + +#include +#include +#include + +int test_lzcnt() +{ + if (__lzcnt(0x0) != 32) { + fprintf(stderr, "__lzcnt(0x0) != 32\n"); + return -1; + } + + if (__lzcnt(0x1) != 31) { + fprintf(stderr, "__lzcnt(0x1) != 31\n"); + return -1; + } + + if (__lzcnt(0xFF) != 24) { + fprintf(stderr, "__lzcnt(0xFF) != 24\n"); + return -1; + } + + if (__lzcnt(0xFFFF) != 16) { + fprintf(stderr, "__lzcnt(0xFFFF) != 16\n"); + return -1; + } + + if (__lzcnt(0xFFFFFF) != 8) { + fprintf(stderr, "__lzcnt(0xFFFFFF) != 8\n"); + return -1; + } + + if (__lzcnt(0xFFFFFFFF) != 0) { + fprintf(stderr, "__lzcnt(0xFFFFFFFF) != 0\n"); + return -1; + } + + return 1; +} + +int test_lzcnt16() +{ + if (__lzcnt16(0x0) != 16) { + fprintf(stderr, "__lzcnt16(0x0) != 16\n"); + return -1; + } + + if (__lzcnt16(0x1) != 15) { + fprintf(stderr, "__lzcnt16(0x1) != 15\n"); + return -1; + } + + if (__lzcnt16(0xFF) != 8) { + fprintf(stderr, "__lzcnt16(0xFF) != 8\n"); + return -1; + } + + if (__lzcnt16(0xFFFF) != 0) { + fprintf(stderr, "__lzcnt16(0xFFFF) != 0\n"); + return -1; + } + + return 1; +} + +int test_lzcnt64() +{ + if (__lzcnt64(0x0) != 64) { + fprintf(stderr, "__lzcnt64(0x0) != 64\n"); + return -1; + } + + if (__lzcnt64(0x1) != 63) { + fprintf(stderr, "__lzcnt64(0x1) != 63\n"); + return -1; + } + + if (__lzcnt64(0xFF) != 56) { + fprintf(stderr, "__lzcnt64(0xFF) != 56\n"); + return -1; + } + + if (__lzcnt64(0xFFFF) != 48) { + fprintf(stderr, "__lzcnt64(0xFFFF) != 48\n"); + return -1; + } + + if (__lzcnt64(0xFFFFFF) != 40) { + fprintf(stderr, "__lzcnt64(0xFFFFFF) != 40\n"); + return -1; + } + + if (__lzcnt64(0xFFFFFFFF) != 32) { + fprintf(stderr, "__lzcnt64(0xFFFFFFFF) != 32\n"); + return -1; + } + + return 1; +} + +int TestIntrinsics(int argc, char* argv[]) +{ + test_lzcnt(); + test_lzcnt16(); + test_lzcnt64(); + + return 0; +} +