/* ------------------------------------------------------------------------ */ /* */ /* Copyright (c) Microsoft Corporation, 2000-2001. All rights reserved. */ /* Copyright (c) Andrew Kadatch, 1991-2001. All rights reserved. */ /* */ /* Microsoft Confidential -- do not redistribute. */ /* */ /* ------------------------------------------------------------------------ */ #include "xprs.h" #define ALLOCATE_ON_STACK 1 #define MAGIC_DECODE 0x35DEC0DE typedef struct { struct { uchar *end, *beg, *careful, *stop, *last; } dst; struct { const uchar *end, *beg, *careful, *end_1, *end_tag, *end_bitmask2, *last; } src; int result; int eof; int magic; #if CODING & (CODING_HUFF_LEN | CODING_HUFF_PTR | CODING_HUFF_ALL) uint16 table[(1 << DECODE_BITS) + (HUFF_SIZE << 1)]; #endif } decode_info; #if CODING == CODING_BY_BIT static int bit_to_len_initialized = 0; static uchar bit_to_len1[1 << (9 - MIN_MATCH)]; static uchar bit_to_len2[1 << (9 - MIN_MATCH)]; static void bit_to_len_init (void) { int i, k; if (bit_to_len_initialized) return; bit_to_len1[0] = 0; bit_to_len2[0] = 9 - MIN_MATCH; for (k = 1, i = 1 << (8 - MIN_MATCH); i != 0; i >>= 1, ++k) { memset (bit_to_len1 + i, k, i); memset (bit_to_len2 + i, k - 1, i); } bit_to_len_initialized = 1; } #endif #if CODING & (CODING_HUFF_LEN | CODING_HUFF_PTR | CODING_HUFF_ALL) static int huffman_decode_create (uint16 *table, const uchar *length) { xint i, j, k, last, freq[16], sum[16]; /* calculate number of codewords */ memset (freq, 0, sizeof (freq)); i = HUFF_SIZE >> 1; do { k = length[--i]; ++freq[k & 0xf]; ++freq[k >> 4]; } while (i != 0); /* handle special case(s) -- 0 and 1 symbols in alphabet */ if (freq[0] == HUFF_SIZE) goto ok; if (freq[0] == HUFF_SIZE - 1) goto bad; #if 0 { if (freq[1] != 1) goto bad; i = -1; do ++i; while (length[i] == 0); k = i << 1; if (length[i] != 1) ++k; i = 1 << DECODE_BITS; do *table++ = (uint16) k; while (--i > 0); goto ok; } #endif /* save frequences */ memcpy (sum, freq, sizeof (sum)); /* check code correctness */ k = 0; i = 15; do { if ((k += freq[i]) & 1) goto bad; k >>= 1; } while (--i != 0); if (k != 1) goto bad; /* sort symbols */ k = 0; for (i = 1; i < 16; ++i) freq[i] = (k += freq[i]); last = freq[15]; /* preserve number of symbols in alphabet */ i = HUFF_SIZE << 4; do { i -= 1 << 4; k = length[i >> 5] >> 4; if (k != 0) table[--freq[k]] = (uint16) (k | i); i -= 1 << 4; k = length[i >> 5] & 0xf; if (k != 0) table[--freq[k]] = (uint16) (k | i); } while (i != 0); /* now create decoding table */ k = i = (1 << DECODE_BITS) + (HUFF_SIZE << 1); { xint n; for (n = 15; n > DECODE_BITS; --n) { j = i; while (k > j) table[--i] = (uint16) ((k -= 2) | 0x8000); for (k = sum[n]; --k >= 0;) table[--i] = table[--last]; k = j; } } j = i; i = 1 << DECODE_BITS; while (k > j) table[--i] = (uint16) ((k -= 2) | 0x8000); while (last > 0) { k = table[--last]; j = i - ((1 << DECODE_BITS) >> (k & 15)); do table[--i] = (uint16) k; while (i != j); } assert ((i | last) == 0); ok: return (1); bad: return (0); } #endif /* CODING */ #if DEBUG #define RET_OK do {printf ("OK @ %d\n", __LINE__); goto ret_ok;} while (0) #define RET_ERR do {printf ("ERR @ %d\n", __LINE__); goto ret_err;} while (0) #else #define RET_OK goto ret_ok #define RET_ERR goto ret_err #endif #define GET_UINT16(x,p) x = *(__unaligned uint16 *)(p); p += 2 #define COPY_8_BYTES(dst,src) \ dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2]; dst[3] = src[3]; \ dst[4] = src[4]; dst[5] = src[5]; dst[6] = src[6]; dst[7] = src[7] /* do not use "memcpy" -- it does not work properly if "dst" and "src" are close (overlap) */ #define COPY_BLOCK_SLOW(dst,src,len) \ if (len > 8) do \ { \ COPY_8_BYTES (dst, src); \ len -= 8; dst += 8; src += 8; \ } \ while (len > 8); \ do \ *dst++ = *src++, --len; \ while (len) #ifndef i386 #define COPY_BLOCK_FAST_8(dst,src) \ COPY_8_BYTES (dst, src) #else #if 0 #define COPY_BLOCK_FAST_8(dst,src) \ ((__unaligned uint32 *) dst)[0] = ((__unaligned uint32 *) src)[0]; \ ((__unaligned uint32 *) dst)[1] = ((__unaligned uint32 *) src)[1] #else #define COPY_BLOCK_FAST_8(dst,src) \ ((__unaligned __int64 *) dst)[0] = ((__unaligned __int64 *) src)[0] #endif #endif /* i386 */ #define BIORD(bits) \ (Mask >> (sizeof (Mask) * 8 - (bits))) #define CONCAT2(x,y) x##y #define CONCAT(x,y) CONCAT2(x,y) #define bits_t signed char #define BIORD_MORE0(bits) \ if ((Bits = (bits_t) (Bits - (bits))) < 0) \ { \ CAREFUL_ERR_IF (src >= info->src.end_1); \ Mask += ((ubitmask4) *(__unaligned ubitmask2 *)src) << (-Bits); \ src += sizeof (ubitmask2); \ Bits += (bits_t) (sizeof (ubitmask2) * 8); \ } #define BIORD_MORE(bits) \ Mask <<= (bits_t)(bits); \ BIORD_MORE0 (bits) #define BIORD_WORD(result,bits) \ result = 1 << (bits); \ if (bits) \ { \ result += BIORD (bits); \ BIORD_MORE (bits); \ } #define BIORD_DECODE(result,table) { \ bits_t __bits; \ result = ((int16 *)(table))[BIORD (DECODE_BITS)]; \ if (result < 0) \ { \ Mask <<= DECODE_BITS; \ do \ { \ result &= 0x7fff; \ if ((bitmask4) Mask < 0) ++result; \ result = ((int16 *)(table))[result]; \ Mask <<= 1; \ } \ while (result < 0); \ __bits = (bits_t)(result & 15); \ } \ else \ { \ __bits = (bits_t)(result & 15); \ Mask <<= __bits; \ } \ result >>= 4; \ Bits = (bits_t) (Bits - __bits); \ } \ if (Bits < 0) \ { \ CAREFUL_ERR_IF (src >= info->src.end_1); \ if (CODING == CODING_HUFF_ALL) \ {CAREFUL_IF (src >= info->src.careful, rdmore);} \ Mask += ((ubitmask4) *(__unaligned ubitmask2 *)src) << (-Bits); \ src += sizeof (ubitmask2); \ Bits += (bits_t) (sizeof (ubitmask2) * 8); \ } #ifdef _MSC_VER #ifdef _M_IX86 #pragma optimize ("aw", off) #else #pragma optimize ("w", off) #endif /* _M_IX86 */ #endif /* _MSC_VER */ #define CAREFUL 0 #include "xdecode.i" #define CAREFUL 1 #include "xdecode.i" #ifdef _MSC_VER #ifdef _M_IX86 #pragma optimize ("aw", on) #else #pragma optimize ("w", on) #endif /* _M_IX86 */ #endif int XPRESS_CALL XpressDecode ( XpressDecodeStream stream, void *orig, int orig_size, int decode_size, const void *comp, int comp_size ) { decode_info *info; const uchar *src; #if ALLOCATE_ON_STACK decode_info stack_info; info = &stack_info; info->src.beg = (void *) stream; #else if (stream == 0 || (info = (decode_info *) stream)->magic != MAGIC_DECODE) return (-1); #endif if (comp_size == orig_size) return (decode_size); if (orig_size < comp_size || comp_size < 0 || orig_size <= MIN_SIZE || comp_size < MIN_SIZE ) return (-1); if (orig_size > BUFF_SIZE || decode_size <= 0) return (decode_size); src = comp; info->dst.beg = orig; info->dst.end = (uchar *) orig + orig_size; info->dst.stop = (uchar *) orig + decode_size; info->src.end = src + comp_size; info->src.end_1 = info->src.end - 1; info->src.end_tag = info->src.end - (sizeof (tag_t) - 1); info->src.end_bitmask2 = info->src.end - (sizeof (bitmask2) - 1); // check bounds when we read new mask (at most 8 * sizeof (tag_t)) pointers // we may write at most 8 bytes without checks #define RESERVE_DST ((8 * 8 + 2) * sizeof (tag_t)) info->dst.careful = info->dst.beg; if (info->dst.stop - info->dst.beg > RESERVE_DST) info->dst.careful = info->dst.stop - RESERVE_DST; // we may read at most 7 bytes #define RESERVE_SRC ((7 * 8 + 2) * sizeof (tag_t)) info->src.careful = info->src.beg; if (info->src.end - info->src.beg > RESERVE_SRC) info->src.careful = info->src.end - RESERVE_SRC; #if CODING & (CODING_HUFF_LEN | CODING_HUFF_PTR | CODING_HUFF_ALL) if (!huffman_decode_create (info->table, src)) return (-1); src += HUFF_SIZE >> 1; #endif #if CODING == CODING_BY_BIT bit_to_len_init (); #endif info->src.beg = src; info->result = 0; info->eof = 0; do_decode (info); if (!info->result || info->dst.last > info->dst.stop || info->src.last > info->src.end || (info->dst.stop == info->dst.end && !info->eof) ) return (-1); return (decode_size); } XpressDecodeStream XPRESS_CALL XpressDecodeCreate ( void *context, // user-defined context info (will be passed to AllocFn) XpressAllocFn *AllocFn // memory allocation callback ) { #if ALLOCATE_ON_STACK #ifdef _M_IX86 return ((XpressDecodeStream) 1); #else return ((XpressDecodeStream) (__int64) 1); #endif #else decode_info *info; if (AllocFn == 0 || (info = AllocFn (context, sizeof (*info))) == 0) return (0); info->magic = MAGIC_DECODE; return ((XpressDecodeStream) info); #endif } void XPRESS_CALL XpressDecodeClose ( XpressDecodeStream stream, // encoder's workspace void *context, // user-defined context info (will be passed to FreeFn) XpressFreeFn *FreeFn // callback that releases the memory ) { #if ALLOCATE_ON_STACK /* do nothing */ #else if (FreeFn != 0 && stream != 0 && ((decode_info *) stream)->magic == MAGIC_DECODE) { ((decode_info *) stream)->magic = 0; FreeFn (context, stream); } #endif }