|
|
/* ------------------------------------------------------------------------ */ /* */ /* Copyright (c) Microsoft Corporation, 2000-2002. All rights reserved. */ /* Copyright (c) Andrew Kadatch, 1991-2002. All rights reserved. */ /* */ /* Microsoft Confidential -- do not redistribute. */ /* */ /* ------------------------------------------------------------------------ */
#include "xprs.h"
#define MAX_CHAIN 9
#define FILL_NULL 0 // fill q_hash buffer with NULLs or with &orig[0]
// Zobrist hashing
#define Z_HASH_SIZE_LOG (BUFF_SIZE_LOG - 1)
#define Z_HASH_SIZE (1 << Z_HASH_SIZE_LOG)
#define Z_HASH_SUM(b) (z_hash_map[0][b[0]] ^ z_hash_map[1][b[1]] ^ z_hash_map[2][b[2]])
// quick hashing
#define Q_HASH_SH1 3
#define Q_HASH_SH2 (Q_HASH_SH1 >> 1)
#define Q_HASH_SUM3(c1,c2,c3) (((c1) << Q_HASH_SH1) + ((c2) << Q_HASH_SH2) + (c3))
#define Q_HASH_SUM(b) Q_HASH_SUM3 (b[0], b[1], b[2])
#define Q_HASH_SIZE (Q_HASH_SUM3 (255, 255, 255) + 1)
#define z_hash_t uint16
#define z_index_t uint16
#if CODING & (CODING_HUFF_LEN | CODING_HUFF_PTR | CODING_HUFF_ALL)
typedef struct huff_node_t huff_node;
struct huff_node_t { huff_node *son[2]; uxint freq; uint16 ch; uint16 bits; };
typedef struct { huff_node buff[2 * HUFF_SIZE], *head[256], **link[256]; } huff_info; #endif
typedef struct { struct { #if CODING == CODING_BY_BIT
xint bits; uchar *ptr; #elif CODING & (CODING_DIRECT | CODING_DIRECT2)
uchar *ptr; #elif CODING & (CODING_HUFF_LEN | CODING_HUFF_PTR | CODING_HUFF_ALL)
uxint freq[HUFF_SIZE]; uxint mask[HUFF_SIZE]; uchar bits[HUFF_SIZE]; huff_info info; uxint pointers; uxint extra; uxint masks; #endif /* CODING */
} stat; xint chain; xint max_size; struct { uchar *beg; uchar *ptr; } comp; struct { uchar *beg; uchar *ptr; uchar *tag_ptr; tag_t tag_mask; xint chain; } temp; struct { xint len; xint pos; } match; struct { xint pos; xint size; xint stop; xint progress; const uchar *ptr; const uchar *end; const uchar *end_16; const uchar *end_3; const uchar *ptr_stop; } orig; } context;
#define v p[-1].c
typedef struct { union { z_index_t z_hash[Z_HASH_SIZE]; z_index_t z_next[16]; const uchar *q_last[16]; } x;
context c; } prs;
#define MAGIC_ENCODE 0x53E7C0DE
typedef struct { int magic; void *memory; prs *p; uchar *temp; unsigned max_size; int chain; int max_chain; } xpress_info;
#if MAX_CHAIN >= 1
static z_hash_t z_hash_map[MIN_MATCH][256]; static int z_hash_map_initialized = 0;
static void z_hash_map_init (void) { long v1, v2; z_hash_t *m;
if (z_hash_map_initialized) return;
v1 = 0x13579bdfL; v2 = 0x87654321L; for (m = z_hash_map[0]; m < z_hash_map[0] + sizeof (z_hash_map) / sizeof (z_hash_map[0][0]); ++m) { long vv1 = v2, vv2 = v1, d = 0; xint i = 32; do { d += 0x9e3779b9L; vv1 += d; vv2 += d; v1 += ((v2<<3) + vv1) ^ (v2 + d) ^ ((v2>>5) + vv2); v2 += ((v1<<3) + vv2) ^ (v1 + d) ^ ((v1>>5) + vv1); --i; } while (i); *m = (z_hash_t) ((v1 += v2) & (Z_HASH_SIZE - 1)); }
z_hash_map_initialized = 1; }
static void z_hash_insert (prs *p) { const uchar *b, *e; xint n, h;
e = v.orig.end - (MIN_MATCH-1); b = v.orig.ptr; n = 0; for (; b < e; ++b, ++n) { h = Z_HASH_SUM (b); p->x.z_next[n] = p[-1].x.z_hash[h]; p[-1].x.z_hash[h] = (z_index_t) n; } e += MIN_MATCH-1; for (; b < e; ++b, ++n) p->x.z_next[n] = 0; } #endif
#if CODING != CODING_BY_BIT
static void tag_write_start (prs *p) { v.temp.tag_ptr = v.temp.ptr; v.temp.ptr += sizeof (v.temp.tag_mask); v.temp.tag_mask = 1; }
#if CODING == CODING_HUFF_ALL
#define INC_MASKS ++v.stat.masks
#else
#define INC_MASKS
#endif
#define tag_write(p,ptr,n) \
{ \ tag_t __n = n | (v.temp.tag_mask << 1); \ if (v.temp.tag_mask < 0) \ { \ *(__unaligned tag_t *) v.temp.tag_ptr = __n; \ v.temp.tag_ptr = ptr; \ ptr += sizeof (v.temp.tag_mask); \ INC_MASKS; \ __n = 1; \ } \ v.temp.tag_mask = __n; \ }
static void tag_write_finish (prs *p) { uchar *ptr = v.temp.ptr; do { tag_write (p, ptr, 1); } while (ptr == v.temp.ptr); }
#elif CODING == CODING_BY_BIT
static void tag_write_start (prs *p) { v.temp.tag_ptr = (uchar *) &v.temp.tag_mask; v.temp.tag_mask = 0; v.stat.bits = 0; }
#define tag_write(p,ptr,n) do { \
if (--v.stat.bits < 0) \ { \ *(__unaligned tag_t *)v.temp.tag_ptr = v.temp.tag_mask; \ v.temp.tag_mask = n; \ v.stat.bits = 8 * sizeof (v.temp.tag_mask) - 1; \ v.temp.tag_ptr = ptr; \ ptr += sizeof (v.temp.tag_mask); \ } \ v.temp.tag_mask = (v.temp.tag_mask << 1) + (n); \ } while (0)
#define tag_write_mask(p,ptr,n,b) do { \
if ((v.stat.bits -= (b)) < 0) \ { \ *(__unaligned tag_t *)v.temp.tag_ptr = (v.temp.tag_mask << ((b) + v.stat.bits)) \ + ((n) >> (-v.stat.bits)); \ v.stat.bits += 8 * sizeof (v.temp.tag_mask); \ v.temp.tag_mask = (n); \ v.temp.tag_ptr = ptr; \ ptr += sizeof (v.temp.tag_mask); \ } \ else \ v.temp.tag_mask = (v.temp.tag_mask << (b)) + (n); \ } while (0);
static void tag_write_finish (prs *p) { do tag_write (p, v.temp.ptr, 1); while (v.stat.bits != 0); *(__unaligned tag_t *)v.temp.tag_ptr = v.temp.tag_mask; }
#define write_lit(p,ptr,ch) do { \
tag_write (p, ptr, 0); \ *ptr++ = (ch); \ } while (0)
INLINE uchar *write_ptr (prs *p, uchar *ptr, xint offset, xint length) { uxint k;
--offset;
k = 2; if (offset > 255) k = 3; tag_write_mask (p, ptr, k, 2); *ptr++ = (uchar) offset; if (offset > 255) *ptr++ = (uchar) (offset >>= 8);
if (length <= 8) { length -= MIN_MATCH - 1; tag_write_mask (p, ptr, 1, length); } else { tag_write_mask (p, ptr, 0, (9 - MIN_MATCH)); if ((length -= 9) < 15) { if (v.stat.ptr == 0) { v.stat.ptr = ptr; *ptr++ = (uchar) length; } else { v.stat.ptr[0] |= length << 4; v.stat.ptr = 0; } } else { length -= 15; if (v.stat.ptr == 0) { v.stat.ptr = ptr; *ptr++ = 15; } else { v.stat.ptr[0] += 0xf0; v.stat.ptr = 0; } *ptr++ = (uchar) length; if (length >= 255) { ptr[-1] = 255; ptr[0] = (uchar) length; ptr[1] = (uchar) (length >>= 8); ptr += 2; } } }
return (ptr); }
#endif
#if CODING & (CODING_DIRECT | CODING_DIRECT2)
#define write_lit(p,ptr,ch) do { \
*ptr++ = (ch); \ tag_write (p, ptr, 0); \ } while (0)
#ifndef i386
INLINE uchar *write_ptr (prs *p, uchar *ptr, int offset, int length) { length -= MIN_MATCH; --offset;
#if CODING == CODING_DIRECT2
offset <<= DIRECT2_LEN_LOG; if (length < DIRECT2_MAX_LEN) { offset |= length; ptr[0] = (uchar) offset; ptr[1] = (uchar) (offset >>= 8); ptr += 2; } else { offset |= DIRECT2_MAX_LEN; length -= DIRECT2_MAX_LEN; ptr[0] = (uchar) offset; ptr[1] = (uchar) (offset >>= 8); ptr += 2; if (v.stat.ptr == 0) { v.stat.ptr = ptr; *ptr++ = (uchar) (length < 15 ? length : 15); } else { v.stat.ptr[0] |= (uchar) ((length < 15 ? length : 15) << 4); v.stat.ptr = 0; } if ((length -= 15) >= 0) { *ptr++ = (uchar) length; if (length >= 255) { ptr[-1] = 255; length += DIRECT2_MAX_LEN + 15; ptr[0] = (uchar) length; ptr[1] = (uchar) (length >>= 8); ptr += 2; } } } #elif CODING == CODING_DIRECT
if (v.stat.ptr == 0) { if (length < 7) { length <<= 5; v.stat.ptr = ptr; short_len: ptr[0] = (uchar) length; ptr[1] = (uchar) offset; ptr += 2; if (offset > 255) { ptr[0] = (uchar) (offset >>= 8); ptr[-2] = (uchar) (length += 16); ptr += 1; } } else if (length < 15 + 7) { length += (14 << 4) - 7; goto short_len; } else { if (offset > 255) ptr[0] = 0xff; else ptr[0] = 0xef; long_len: ptr[1] = (uchar) (length -= (7 + 15)); ptr += 2; if (length >= 255) { length += 7 + 15; ptr[-1] = 255; ptr[0] = (uchar) (length); ptr[1] = (uchar) (length >>= 8); ptr += 2; } *ptr++ = (uchar) offset; if (offset > 255) *ptr++ = (uchar) (offset >>= 8); } } else { if (length < 7) { length |= v.stat.ptr[0]; *ptr++ = (uchar) offset; if (offset > 255) { *ptr++ = (uchar) (offset >>= 8); length |= 8; } v.stat.ptr[0] = (uchar) length; v.stat.ptr = 0; } else if (length < 15 + 7) { length -= 7; ptr[1] = (uchar) offset; ptr[0] = (uchar) (length <<= 4); if (offset > 255) { v.stat.ptr[0] |= 15; v.stat.ptr = ptr; ptr[2] = (uchar) (offset >>= 8); ptr += 3; } else { v.stat.ptr[0] |= 7; v.stat.ptr = ptr; ptr += 2; } } else { if (offset > 255) v.stat.ptr[0] |= 15; else v.stat.ptr[0] |= 7; v.stat.ptr = ptr; ptr[0] = 15 << 4; goto long_len; } } #endif /* CODING */
tag_write (p, ptr, 1);
return (ptr); } #endif /* i386 */
#elif CODING & (CODING_HUFF_LEN | CODING_HUFF_PTR | CODING_HUFF_ALL)
#if CODING == CODING_HUFF_ALL
#define write_lit(p,ptr,ch) do { \
++v.stat.freq[*ptr++ = (ch)]; \ tag_write (p, ptr, 0); \ } while (0) #else
#define write_lit(p,ptr,ch) do { \
*ptr++ = (ch); \ tag_write (p, ptr, 0); \ } while (0) #endif
#define BIOWR(mask,bits) { \
assert (((mask) >> (bits)) == 0); \ if ((Bits -= (bits)) < 0) \ { \ *(__unaligned bitmask2 *)Ptr1 = (bitmask2) ((Mask << (Bits + (bits))) \ + ((mask) >> (-Bits))); \ Mask = (mask); \ Bits += sizeof (ubitmask2) * 8; \ Ptr1 = Ptr2; \ Ptr2 = (ubitmask2 *) ptr; \ ptr += sizeof (ubitmask2); \ } \ else \ Mask = (Mask << (bits)) + (mask); \ }
#if CODING == CODING_HUFF_LEN
INLINE uchar *write_ptr (prs *p, uchar *ptr, int offset, int length) { xint k;
++v.stat.pointers;
length -= MIN_MATCH; --offset;
k = 0; if (offset > 255) k = 1;
if (length < MAX_LENGTH - 1) ++v.stat.freq[*ptr++ = (uchar) (k |= length << 1)]; else { length -= MAX_LENGTH - 1; ++v.stat.freq[ptr[0] = (uchar) (k |= (MAX_LENGTH - 1) << 1)]; ptr[1] = (uchar) length; ptr += 2; if (length >= 255) { ptr[-1] = 255; length += MAX_LENGTH - 1; ptr[0] = (uchar) length; ptr[1] = (uchar) (length >>= 8); ptr += 2; } }
*ptr++ = (uchar) offset; if (offset > 255) *ptr++ = (uchar) (offset >>= 8);
tag_write (p, ptr, 1);
return (ptr); }
static void encode_pass2 (prs *p) { xint Bits; ubitmask4 Mask; ubitmask2 *Ptr1, *Ptr2; tag_t bmask; uchar *src = v.temp.beg; uchar *ptr = v.comp.ptr; uxint k;
Ptr1 = (ubitmask2 *) ptr; ptr += sizeof (ubitmask2); Ptr2 = (ubitmask2 *) ptr; ptr += sizeof (ubitmask2); Mask = 0; Bits = 8 * sizeof (ubitmask2); bmask = 0; goto start;
next: if (bmask >= 0) { bmask <<= 1; copy_byte: *ptr++ = *src++; goto next; }
if ((bmask <<= 1) == 0) { start: *(__unaligned tag_t *)ptr = bmask = *(__unaligned tag_t *)src; src += sizeof (tag_t); ptr += sizeof (tag_t); if (bmask >= 0) { bmask = (bmask << 1) + 1; goto copy_byte; } bmask = (bmask << 1) + 1; }
if (src >= v.temp.ptr) goto done;
k = *src++; assert (k < HUFF_SIZE); BIOWR (v.stat.mask[k], v.stat.bits[k]);
if (k >= ((MAX_LENGTH - 1) << 1)) { if ((*ptr++ = *src++) == 255) { ptr[0] = src[0]; ptr[1] = src[1]; src += 2; ptr += 2; } }
*ptr++ = *src++; if (k & 1) *ptr++ = *src++; goto next;
done: *Ptr1 = (ubitmask2) (Mask <<= Bits); *Ptr2 = 0; v.comp.ptr = ptr; assert (src == v.temp.ptr); }
#elif CODING & (CODING_HUFF_PTR | CODING_HUFF_ALL)
#if CODING == CODING_HUFF_ALL
#define CODING_ADJUST(n) (256 + (n))
#else
#define CODING_ADJUST(n) (n)
#endif
#if !defined (i386) || CODING != CODING_HUFF_ALL
#define MAX_BITNO_LOG 8
#define MAX_BITNO (1 << MAX_BITNO_LOG)
static uchar bitno_table[MAX_BITNO]; static int bitno_table_initialized = 0;
static void bitno_init (void) { int i, k, n; if (bitno_table_initialized) return; bitno_table[0] = 255; for (i = 0; i < MAX_BITNO_LOG; ++i) { for (n = (k = 1<<i) << 1; k < n; ++k) bitno_table[k] = (uchar) i; } bitno_table_initialized = 1; }
static int bitno (uxint n) { assert (n != 0 && (n >> (MAX_BITNO_LOG*2)) == 0); if (n >= MAX_BITNO) return (bitno_table[n >> MAX_BITNO_LOG] + MAX_BITNO_LOG); return (bitno_table[n]); }
INLINE uchar *write_ptr (prs *p, uchar *ptr, int offset, int length) { xint k;
k = bitno (offset); length -= MIN_MATCH; offset ^= 1 << k;
v.stat.pointers += 2; v.stat.extra += k;
k <<= MAX_LENGTH_LOG; if (length < MAX_LENGTH - 1) { k |= length; *ptr++ = (uchar) k; ++v.stat.freq[CODING_ADJUST (k)]; } else { k |= MAX_LENGTH - 1; length -= MAX_LENGTH - 1; ptr[0] = (uchar) k; ++v.stat.freq[CODING_ADJUST (k)]; ptr[1] = (uchar) length; ptr += 2; if (length >= 255) { length += MAX_LENGTH - 1; ptr[-1] = 255; ptr[0] = (uchar) length; ptr[1] = (uchar) (length >>= 8); ptr += 2; } }
*ptr++ = (uchar) offset; if (k >= (9 << MAX_LENGTH_LOG)) { v.stat.pointers += 1; *ptr++ = (uchar) (offset >>= 8); }
tag_write (p, ptr, 1);
return (ptr); }
static void encode_pass2 (prs *p) { xint Bits; uxint Mask; ubitmask2 *Ptr1, *Ptr2; tag_t bmask; uchar *src = v.temp.beg; uchar *ptr = v.comp.ptr; uxint k;
Ptr1 = (ubitmask2 *) ptr; ptr += sizeof (ubitmask2); Ptr2 = (ubitmask2 *) ptr; ptr += sizeof (ubitmask2); Mask = 0; Bits = 8 * sizeof (ubitmask2); bmask = 0; goto start;
next: if (bmask >= 0) { bmask <<= 1; copy_byte: #if CODING == CODING_HUFF_ALL
k = *src++; BIOWR (v.stat.mask[k], v.stat.bits[k]); #elif CODING == CODING_HUFF_PTR
*ptr++ = *src++; #endif
goto next; }
if ((bmask <<= 1) == 0) { start: bmask = *(__unaligned tag_t *)src; src += sizeof (tag_t); #if CODING == CODING_HUFF_PTR
*(__unaligned tag_t *)ptr = bmask; ptr += sizeof (tag_t); #endif
if (bmask >= 0) { bmask = (bmask << 1) + 1; goto copy_byte; } bmask = (bmask << 1) + 1; }
if (src >= v.temp.ptr) goto done;
k = *src++; assert (k < HUFF_SIZE); BIOWR (v.stat.mask[CODING_ADJUST (k)], v.stat.bits[CODING_ADJUST (k)]);
if ((k & (MAX_LENGTH - 1)) == MAX_LENGTH - 1) { if ((*ptr++ = *src++) == 255) { ptr[0] = src[0]; ptr[1] = src[1]; src += 2; ptr += 2; } }
k >>= MAX_LENGTH_LOG; { uxint m = *src++; if (k > 8) m += *src++ << 8; BIOWR (m, k); } goto next;
done: #if CODING == CODING_HUFF_ALL
BIOWR (v.stat.mask[CODING_ADJUST(0)], v.stat.bits[CODING_ADJUST(0)]); #endif
*(__unaligned bitmask2 *)Ptr1 = (ubitmask2) (Mask <<= Bits); *(__unaligned bitmask2 *)Ptr2 = 0; v.comp.ptr = ptr; assert (src == v.temp.ptr); }
#else /* !defined (i386) || CODING != CODING_HUFF_ALL */
#define TEMP eax
#define TEMPB al
#define PRS ebx
#define V [PRS - SIZE prs] prs.c
#define TAG edx
#define TAGW dx
#define TAGB dl
#define PTR1 edi
#define SRC esi
#define MASK ebp
#define MASKW bp
#define PTR esp
#define PTR2 esp + 4
#define TAGS esp + 8
static void encode_pass2 (prs *PrsPtr) { __asm { push ebp sub esp, 12
/*
uchar *src = v.temp.beg; uchar *ptr = v.comp.ptr; Ptr1 = (ubitmask2 *) ptr; ptr += sizeof (ubitmask2); Ptr2 = (ubitmask2 *) ptr; ptr += sizeof (ubitmask2); */ mov PRS, PrsPtr mov PTR1, V.comp.ptr mov SRC, V.temp.beg lea TEMP, [PTR1 + 2] mov [PTR2], TEMP add TEMP, 2 mov [PTR], TEMP
/*
Mask = 0; Bits = 8 * sizeof (ubitmask2); bmask = 0; */ xor MASK, MASK mov ch, 16 xor TAG, TAG jmp ReloadTag
Literal: /*
k = *src++; BIOWR (v.stat.mask[k], v.stat.bits[k]); */ mov TEMP, V.stat.mask[TEMP*4] shl MASK, cl inc SRC add MASK, TEMP sub ch, cl jge BiowrDone_Literal
mov cl, ch add ch, 16 mov TEMP, [PTR] rol MASK, cl // attention! 286+ masks shift cound mod 32
mov [PTR1], MASKW mov PTR1, [PTR2] ror MASK, cl mov [PTR2], TEMP add TEMP, 2 mov [PTR], TEMP
BiowrDone_Literal:
movzx TEMP, byte ptr [SRC] add TAG, TAG mov cl, V.stat.bits[TEMP] jnc Literal jz ReloadTag
Pointer: /*
if (src >= v.temp.ptr) goto done; */ mov cl, V.stat.bits[TEMP + 256] mov [TAGS], TAG
cmp SRC, V.temp.ptr jae Done
/*
k = *src++; assert (k < HUFF_SIZE); BIOWR (v.stat.mask[CODING_ADJUST (k)], v.stat.bits[CODING_ADJUST (k)]); */
shl MASK, cl mov TAGB, TEMPB add MASK, V.stat.mask[TEMP*4 + 256*4] mov TEMP, [PTR] sub ch, cl jge BiowrDone_Pointer
mov cl, ch add ch, 16 rol MASK, cl // attention! 286+ masks shift cound mod 32
mov [PTR1], MASKW mov PTR1, [PTR2] ror MASK, cl mov [PTR2], TEMP add TEMP, 2
BiowrDone_Pointer:
mov cl, TAGB // release TEMP for LongLength
and TAGB, MAX_LENGTH-1 shr cl, MAX_LENGTH_LOG
/*
if ((k & (MAX_LENGTH - 1)) == MAX_LENGTH - 1) { if ((*ptr++ = *src++) == 255) { ptr[0] = src[0]; ptr[1] = src[1]; src += 2; ptr += 2; } } */ cmp TAGB, MAX_LENGTH-1 je LongLength LengthWritten:
/*
k >>= MAX_LENGTH_LOG; { uxint m = src[1]; if (k > 8) { m += src[2] << 8; ++src; } BIOWR (m, k); } src += 2; */ movzx TAG, byte ptr [SRC + 1] shl MASK, cl cmp cl, 8 jbe GotOffset movzx TAG, word ptr [SRC + 1] inc SRC GotOffset:
add MASK, TAG sub ch, cl jge BiowrDone_Offset
mov cl, ch add ch, 16 rol MASK, cl // attention! 286+ masks shift cound mod 32
mov [PTR1], MASKW mov PTR1, [PTR2] ror MASK, cl mov [PTR2], TEMP add TEMP, 2
BiowrDone_Offset:
mov TAG, [TAGS] add SRC, 2 mov [PTR], TEMP
movzx TEMP, byte ptr [SRC] add TAG, TAG mov cl, V.stat.bits[TEMP] jnc Literal jnz Pointer jmp ReloadTag
align 16 ReloadTag: mov TAG, [SRC] movzx TEMP, byte ptr [SRC + 4] add SRC, 4 test TAG, TAG mov cl, V.stat.bits[TEMP] lea TAG, [TAG*2 + 1] jge Literal jmp Pointer
/*
if ((*ptr++ = *++src) == 255) { ptr[0] = src[1]; ptr[1] = src[2]; src += 2; ptr += 2; } */
#if _MSC_VER >= 1300
align 16 // workaround bug in VC 6.0 back end (incorrect jump offset generation)
#endif /* _MSC_VER >= 1300 */
LongLength: mov TAGB, [SRC + 1] inc SRC mov [TEMP], TAGB inc TEMP cmp TAGB, 255 jne LengthWritten mov TAGW, [SRC + 1] add TEMP, 2 add SRC, 2 mov [TEMP-2], TAGW jmp LengthWritten
Done: /*
BIOWR (v.stat.mask[CODING_ADJUST(0)], v.stat.bits[CODING_ADJUST(0)]); */ mov cl, V.stat.bits[256] mov TEMP, [PTR] shl MASK, cl mov TAG, [PTR2] add MASK, V.stat.mask[256*4] sub ch, cl jge LastMaskWritten
mov cl, ch neg cl add ch, 16 ror MASK, cl mov [PTR1], MASKW mov PTR1, TAG rol MASK, cl mov TAG, TEMP add TEMP, 2 /*
*(__unaligned bitmask2 *)Ptr1 = (ubitmask2) (Mask <<= Bits); *(__unaligned bitmask2 *)Ptr2 = 0; v.comp.ptr = ptr; */ LastMaskWritten: mov cl, ch shl MASK, cl mov word ptr [PTR1], MASKW mov word ptr [TAG], 0 mov V.comp.ptr, TEMP
#if DEBUG
/*
assert (src == v.temp.ptr); */ cmp V.temp.ptr, SRC je RetOK int 3 RetOK: #endif
add esp, 12 pop ebp } /* __asm */ }
#undef TEMP
#undef PRS
#undef V
#undef TAG
#undef TAGW
#undef TAGB
#undef PTR1
#undef SRC
#undef MASK
#undef MASKW
#undef PTR
#undef PTR2
#undef TAGS
#endif /* !defined (i386) || CODING != CODING_HUFF_ALL */
#endif /* CODING & (CODING_HUFF_PTR | CODING_HUFF_ALL) */
/* ------------------ Create canonical Huffman code ------------------- */ /* ----------------------------- */
#define MAX_ALPHABET HUFF_SIZE
static void huffman_create_codes (huff_info *info, uxint *freq, xint n, uxint *mask, uchar *length, uxint maxbits, uchar *encoded, uxint *total) { huff_node *p, *q, *r, *first_sorted, *first_free; xint i, k;
assert ((uxint) (n-1) <= (MAX_ALPHABET-1));
/* honestly it is easy enough to create Huffman code in-place */ /* but the use of explicit data structures makes code simpler */
/* clean everything up */ memset (length, 0, sizeof (length[0]) * n); memset (encoded, 0, (n + 1) >> 1);
if (mask != 0 && mask != freq) memset (mask, 0, sizeof (mask[0]) * n);
/* store frequencies */ p = info->buff; for (i = 0; i < n; ++i) { if ((p->freq = freq[i]) != 0) { p->son[0] = p+1; p->son[1] = 0; p->ch = (uint16) i; ++p; } }
/* handle simple case */ *total = 0; if (p <= info->buff + 1) { if (p == info->buff) /* if no symbols do nothing */ return; i = p[-1].ch; /* single symbol code */ mask[i] = 0; encoded[i >> 1] = 0x11; /* two symbols has 1-bit length */ return; }
first_free = p; /* store location of first unused node */
p[-1].son[0] = 0; /* terminate the list */ /* radix sort the list by frequency */ p = info->buff; /* head of the list */ /* initialize */ for (n = 0; n < 256; ++n) *(info->link[n] = info->head + n) = 0; for (i = 0; i < (BUFF_SIZE_LOG <= 16 ? 16 : 32); i += 8) { /* link node to the end of respective bucket */ do { n = (p->freq >> i) & 0xff; info->link[n][0] = p; info->link[n] = p->son; } while ((p = p->son[0]) != 0);
/* merge buckets into single list */ n = 0; while (info->head[n] == 0) ++n; p = info->head[n]; info->head[k = n] = 0; while (++n < 256) { if (info->head[n] == 0) continue; info->link[k][0] = info->head[n]; info->link[k] = info->head + k; info->head[n] = 0; k = n; } info->link[k][0] = 0; info->link[k] = info->head + k; } first_sorted = p; /* store head of sorted symbol's list */
restart: assert (p == first_sorted); q = first_free; r = q - 1; while (p != 0 || q != r) { ++r;
/* select left subtree */ assert (q <= r && (p != 0 || q != r)); if (p == 0 || (q != r && p->freq > q->freq)) { r->son[0] = q; r->freq = q->freq; ++q; } else { r->son[0] = p; r->freq = p->freq; p = p->son[0]; }
/* select right subtree */ assert (q <= r && (p != 0 || q != r)); if (p == 0 || (q != r && p->freq > q->freq)) { r->son[1] = q; r->freq += q->freq; ++q; } else { r->son[1] = p; r->freq += p->freq; p = p->son[0]; } }
/* evaluate codewords' length */ i = -1; /* stack pointer */ n = 0; /* current tree depth */ p = r; /* current subtree root */ for (;;) { while (p->son[1] != 0) { /* put right son into stack and set up its depth */ (info->head[++i] = p->son[1])->bits = (uint16) (++n); (p = p->son[0])->bits = (uint16) n; } length[p->ch] = (uchar) n;
if (i < 0) break; /* nothing's in stack */ n = (p = info->head[i--])->bits; }
p = first_sorted; #if DEBUG
for (q = p; (r = q->son[0]) != 0; q = r) assert (q->bits >= r->bits); #endif
if (p->bits > maxbits) { assert (p == first_sorted); q = p; do q->freq = (q->freq + 1) >> 1; while ((q = q->son[0]) != 0); goto restart; }
/* now sort symbols in a stable way by increasing codeword length */ /* initialize */ memset (info->head, 0, sizeof (info->head[0]) * 32); for (n = 0; n < 32; ++n) info->link[n] = info->head + n;
/* link node to the end of respective bucket */ p = info->buff; do { n = p->bits; info->link[n][0] = p; info->link[n] = p->son; } while (++p != first_free);
/* merge buckets into single list */ n = 0; while (info->head[n] == 0) ++n; p = info->head[n]; k = n; while (++n < 32) { if (info->head[n] == 0) continue; info->link[k][0] = info->head[n]; k = n; } info->link[k][0] = 0;
#if DEBUG
for (q = p; (r = q->son[0]) != 0; q = r) assert (r->bits > q->bits || (r->bits == q->bits && r->ch > q->ch)); #endif
/* set up code masks */ if (mask == freq) memset (mask, 0, sizeof (mask[0]) * n);
n = 0; /* mask */ i = 1; /* bit length */ k = 1; /* first index */ do { /* sum a[i] * b[i] may be evaluated without multiplications */ /* using O(B) memory and O(N+B) time if 0 <= b[i] < B */ *total += freq[p->ch] * p->bits; encoded[p->ch >> 1] |= p->bits << (p->ch & 1 ? 4 : 0); mask[p->ch] = (n <<= p->bits - i); i = p->bits; ++n; } while ((p = p->son[0]) != 0); }
#endif /* CODING */
#define CHAIN 0
#define encode_pass1 encode0_pass1
#include "xencode.i"
#if MAX_CHAIN >= 1
#define CHAIN 1
#define encode_pass1 encode1_pass1
#define find_match find_match1
#include "xencode.i"
#endif
#if MAX_CHAIN >= 2
#define CHAIN 2
#define encode_pass1 encode2_pass1
#define find_match find_match2
#include "xencode.i"
#endif
#if MAX_CHAIN >= 3
#define CHAIN 3
#define encode_pass1 encodeN_pass1
#define find_match find_matchN
#include "xencode.i"
#endif
typedef void encode_pass1_proc (prs *p);
static void encode_pass1_progress ( prs *p, encode_pass1_proc *encode_pass1, XpressProgressFn *ProgressFn, // NULL or progress callback
void *ProgressContext, // user-defined context that will be passed to ProgressFn
int ProgressSize // call ProgressFn each time ProgressSize bytes processed
) { xint stop;
if (ProgressFn == 0) { encode_pass1 (p); return; }
stop = v.orig.stop; for (;;) { if (v.orig.pos - v.orig.progress >= ProgressSize) { #if CODING & (CODING_HUFF_LEN | CODING_HUFF_PTR | CODING_HUFF_ALL)
ProgressFn (ProgressContext, v.orig.pos); #else
ProgressFn (ProgressContext, (v.orig.pos * 15) >> 4); #endif
v.orig.progress = v.orig.pos; }
v.orig.stop = stop; if (v.orig.pos >= stop) break;
if (stop - v.orig.progress > ProgressSize) v.orig.stop = v.orig.progress + ProgressSize; assert (v.orig.stop > v.orig.pos);
v.orig.ptr_stop = v.orig.stop + v.orig.ptr; encode_pass1 (p); } }
#if !FILL_NULL
static void MemoryFillPtr ( const void **p, const void *d, int n ) { const void **e; while (n & 7) { *p++ = d; if (--n == 0) return; } e = p + n; do { p[0] = d; p[1] = d; p[2] = d; p[3] = d; p[4] = d; p[5] = d; p[6] = d; p[7] = d; p += 8; } while (p != e); } #endif /* !FILL_NULL */
XPRESS_EXPORT int XPRESS_CALL XpressEncodeEx ( XpressEncodeStream stream, void *comp, int comp_size, const void *orig, int orig_size, XpressProgressFn *ProgressFn, // NULL or progress callback
void *ProgressContext, // user-defined context that will be passed to ProgressFn
int ProgressSize, // call ProgressFn each time ProgressSize bytes processed
int CompressionLevel ) { #if CODING & (CODING_HUFF_LEN | CODING_HUFF_PTR | CODING_HUFF_ALL)
uchar huff_buff [HUFF_SIZE >> 1]; uxint huff_total; #endif
uxint c_size; prs *p; xpress_info *info = (xpress_info *) stream; encode_pass1_proc *encode_pass1;
if (info == 0 || info->magic != MAGIC_ENCODE) return (0);
if ((unsigned) (orig_size-1) > info->max_size || orig_size <= MIN_SIZE || comp_size < MIN_SIZE || comp == 0 || orig == 0) { return (orig_size); }
p = info->p; memset (&v, 0, sizeof (v));
if (CompressionLevel < 0) CompressionLevel = 0; else if (CompressionLevel > info->max_chain) CompressionLevel = info->max_chain; v.chain = CompressionLevel;
v.orig.end = (v.orig.ptr = orig) + (v.orig.size = v.orig.stop = orig_size); v.orig.end_16 = v.orig.end - 16; v.orig.end_3 = v.orig.end - MIN_MATCH; v.comp.ptr = v.comp.beg = comp; v.orig.pos = 0; v.temp.beg = v.temp.ptr = info->temp;
#if CODING & (CODING_HUFF_PTR | CODING_HUFF_ALL) && !defined (i386)
// check initialization of static tables (in case somebody messed up with DLLs)
if (!bitno_table_initialized) bitno_init (); #endif
encode_pass1 = encode0_pass1; if (v.chain <= 0) { #if FILL_NULL
memset ((void *) (&p->x.q_last[0]), 0, Q_HASH_SIZE * sizeof (p->x.q_last[0])); #else
MemoryFillPtr ((const void **) (&p->x.q_last[0]), orig, Q_HASH_SIZE); #endif /* FILL_NULL */
} #if MAX_CHAIN >= 1
else { // check initialization of static tables (in case somebody messed up with DLLs)
if (!z_hash_map_initialized) z_hash_map_init ();
if (v.chain == 1) { encode_pass1 = encode1_pass1; memset ((void *) (&p->x.z_next[0]), 0, Z_HASH_SIZE * sizeof (p->x.z_next[0])); } #if MAX_CHAIN >= 2
else { encode_pass1 = encode2_pass1; #if MAX_CHAIN >= 3
if (v.chain >= 3) encode_pass1 = encodeN_pass1; #endif /* MAX_CHAIN >= 3 */
memset (p[-1].x.z_hash, 0, sizeof (p[-1].x.z_hash)); z_hash_insert (p);
#if 0
{ int n = 0x1653; int i, k; i = 0; k = n; do { k = p->x.z_next[k]; printf ("%2d: 0x%04x 0x%04x\n", i, k, n - k); ++i; } while (k != 0); } #endif
} #endif /* MAX_CHAIN >= 2 */
} #endif /* MAX_CHAIN >= 1 */
if (ProgressSize <= 0 || ProgressSize > orig_size) ProgressSize = orig_size;
if (ProgressFn != 0) ProgressFn (ProgressContext, v.orig.progress = 0);
#if CODING & (CODING_DIRECT | CODING_DIRECT2 | CODING_BY_BIT)
v.temp.beg = v.temp.ptr = v.comp.ptr; tag_write_start (p); for (;;) { xint rest = comp_size - (xint) (v.temp.ptr - v.comp.beg) - 2 * sizeof (tag_t); rest -= (rest + 7) >> 3; if (rest <= (xint) (2 * sizeof (tag_t) + 8)) goto no_compression; if (v.orig.pos >= v.orig.size) break; v.orig.stop = v.orig.pos + rest; if (v.orig.stop > v.orig.size - 8) { v.orig.stop = v.orig.size - 8; if (v.orig.pos >= v.orig.stop) break; } encode_pass1_progress (p, encode_pass1, ProgressFn, ProgressContext, ProgressSize); } #else
v.orig.stop -= 7; tag_write_start (p); encode_pass1_progress (p, encode_pass1, ProgressFn, ProgressContext, ProgressSize); #endif
while (v.orig.pos < v.orig.size) { write_lit (p, v.temp.ptr, v.orig.ptr[v.orig.pos]); ++v.orig.pos; } tag_write_finish (p);
#if CODING & (CODING_DIRECT | CODING_DIRECT2 | CODING_BY_BIT)
c_size = (xint) (v.temp.ptr - v.temp.beg); #elif CODING & (CODING_HUFF_LEN | CODING_HUFF_PTR | CODING_HUFF_ALL)
if (v.stat.pointers == 0) goto no_compression; #if CODING == CODING_HUFF_ALL
++v.stat.freq[CODING_ADJUST(0)]; #endif
huffman_create_codes ( &v.stat.info, v.stat.freq, HUFF_SIZE, v.stat.mask, v.stat.bits, 15, huff_buff, &huff_total );
c_size = huff_total; #if CODING & (CODING_HUFF_PTR | CODING_HUFF_ALL)
c_size += v.stat.extra; #endif
if (c_size == 0) c_size = 1; c_size = (((c_size - 1) & ~(sizeof (bitmask2) * 8 - 1)) >> 3); c_size += (int) (v.temp.ptr - v.temp.beg) - v.stat.pointers + 4 + sizeof (huff_buff); #if CODING == CODING_HUFF_ALL
for (huff_total = 0; huff_total < 256; ++huff_total) c_size -= v.stat.freq[huff_total]; c_size -= v.stat.masks * sizeof (tag_t); #endif
#endif /* CODING */
if (c_size >= (uxint) comp_size) { no_compression: comp_size = orig_size; } else { #if CODING & (CODING_HUFF_LEN | CODING_HUFF_PTR | CODING_HUFF_ALL)
memcpy (v.comp.ptr, huff_buff, sizeof (huff_buff)); v.comp.ptr += sizeof (huff_buff);
#if 0
printf ("c_size = %d, temp_size = %d\n", c_size, v.temp.ptr - v.temp.beg); { FILE *fd = fopen ( #ifdef i386
"a.bad" #else
"c.bad" #endif
, "wb"); if (fd != 0) { fwrite (v.temp.beg, v.temp.ptr - v.temp.beg, 1, fd); fclose (fd); } } #endif
encode_pass2 (p); #elif CODING & (CODING_BY_BIT | CODING_DIRECT | CODING_DIRECT2)
v.comp.ptr += c_size; #else
#error Unknown CODING
#endif
comp_size = (int) (v.comp.ptr - v.comp.beg);
#if DEBUG
if (c_size != (uxint) comp_size) printf ("error: c_size = %d, comp_size = %d\n", c_size, comp_size); #endif
}
if (ProgressFn != 0) ProgressFn (ProgressContext, orig_size);
return (comp_size); }
XPRESS_EXPORT int XPRESS_CALL XpressEncode ( XpressEncodeStream stream, void *comp, int comp_size, const void *orig, int orig_size, XpressProgressFn *ProgressFn, // NULL or progress callback
void *ProgressContext, // user-defined context that will be passed to ProgressFn
int ProgressSize // call ProgressFn each time ProgressSize bytes processed
) { xpress_info *info = (xpress_info *) stream; if (info == 0 || info->magic != MAGIC_ENCODE) return (0); return (XpressEncodeEx ( stream, comp, comp_size, orig, orig_size, ProgressFn, ProgressContext, ProgressSize, info->chain )); }
#define MEM_ALIGN 256
XPRESS_EXPORT XpressEncodeStream XPRESS_CALL XpressEncodeCreate ( int max_orig_size, void *context, XpressAllocFn *AllocFn, int chain ) { xpress_info *info; prs *p; uchar *b; int temp_size; int alloc_size; int max_chain;
if (AllocFn == 0 || (unsigned) (max_orig_size-1) > (BUFF_SIZE-1)) return (0);
#if CODING & (CODING_DIRECT | CODING_DIRECT2 | CODING_BY_BIT)
temp_size = 0; #else
temp_size = max_orig_size + ((max_orig_size + 7) >> 3); #endif
alloc_size = sizeof (p->x.q_last[0]) * Q_HASH_SIZE; #if MAX_CHAIN <= 0
max_chain = chain = 0; #else
if (chain > MAX_CHAIN) chain = MAX_CHAIN; max_chain = chain; if (chain >= 1) { alloc_size = sizeof (p->x.z_next[0]) * Z_HASH_SIZE; #if MAX_CHAIN >= 2
if (chain >= 2) { // data structures for (chain >= 2) are the same, enable deeper search
max_chain = MAX_CHAIN; alloc_size = sizeof (p->x.z_next[0]) * max_orig_size; if (temp_size < sizeof (p[-1].x.z_hash[0]) * Z_HASH_SIZE) temp_size = sizeof (p[-1].x.z_hash[0]) * Z_HASH_SIZE; } #endif
} #endif
temp_size = (temp_size + 256 + MEM_ALIGN-1 + sizeof (*p) - sizeof (p->x)) & ~(MEM_ALIGN-1); alloc_size += temp_size + sizeof (*info) + MEM_ALIGN;
b = AllocFn (context, alloc_size); if (b == 0) return (0);
info = (xpress_info *) b; info->max_size = max_orig_size - 1; info->max_chain = max_chain; info->chain = chain; info->magic = MAGIC_ENCODE; info->memory = b;
b = (uchar *) (info + 1); b += MEM_ALIGN - (((__int64) b) & (MEM_ALIGN-1)); info->p = p = ((prs *) (b + temp_size)); info->temp = b;
#if MAX_CHAIN >= 1
if (!z_hash_map_initialized) z_hash_map_init (); #endif
#if CODING & (CODING_HUFF_PTR | CODING_HUFF_ALL) && !defined (i386)
if (!bitno_table_initialized) bitno_init (); #endif
return ((XpressEncodeStream) info); }
XPRESS_EXPORT void XPRESS_CALL XpressEncodeClose ( XpressEncodeStream stream, void *context, XpressFreeFn *FreeFn ) { xpress_info *info = (xpress_info *) stream; if (info != 0 && FreeFn != 0 && info->magic == MAGIC_ENCODE) { info->magic = 0; FreeFn (context, info->memory); } }
// returns MaxCompressionLevel or (-1) if stream was not initialized properly
XPRESS_EXPORT int XPRESS_CALL XpressEncodeGetMaxCompressionLevel ( XpressEncodeStream EncodeStream // encoder's workspace
) { xpress_info *info = (xpress_info *) EncodeStream; if (info != 0 && info->magic == MAGIC_ENCODE) return (info->max_chain); return (-1); }
|