#include "xzip.h" typedef unsigned char uchar; //typedef unsigned short ushort; //typedef unsigned long ulong; extern char* IErrMsg; #ifdef _LARGE_MODEL_ #define WSIZE 0x4000U #define OUTBUFSIZ 0x800U #else #define WSIZE 0x8000U #define OUTBUFSIZ 0x1000U #endif #define MIN_MATCH 3 #define MAX_MATCH 258 #define DYN_ALLOC #define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) #define MAX_DIST (WSIZE-MIN_LOOKAHEAD) #define UNKNOWN (-1) #define BINARY 0 #define ASCII 1 #define STORE 0 #define DEFLATE 8 #define MAX_BITS 15 #define MAX_BL_BITS 7 #define LENGTH_CODES 29 #define LITERALS 256 #define END_BLOCK 256 #define L_CODES (LITERALS+1+LENGTH_CODES) #define D_CODES 30 #define BL_CODES 19 #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 #define LIT_BUFSIZE 0x4000 #define DIST_BUFSIZE LIT_BUFSIZE #define REP_3_6 16 #define REPZ_3_10 17 #define REPZ_11_138 18 typedef struct ct_data { union { unsigned short freq; unsigned short code; } fc; union { unsigned short dad; unsigned short len; } dl; } ct_data; typedef struct tree_desc { ct_data* dyn_tree; ct_data* static_tree; int* extra_bits; int extra_base; int elems; int max_length; int max_code; } tree_desc; #define Freq fc.freq #define Code fc.code #define Dad dl.dad #define Len dl.len #define HEAP_SIZE (2 * L_CODES + 1) // ---------- EXTERN SECTION ---------- extern int verbose; extern int level; // ---------- PROTOTYPE SECTION ---------- void ct_init(unsigned short* attr,int* method); unsigned int flush_block(char* buf,unsigned int stored_len,int eof); int ct_tally(int dist,int lc); void copy_block(char* buf,unsigned len,int header); void bi_windup(void); unsigned bi_reverse(unsigned code,int len); void send_bits(int value,int length); void free_data(void); void lm_free(void); static void init_block(void); static void pqdownheap(ct_data* tree, int k); static void gen_bitlen(tree_desc* desc); static void gen_codes(ct_data* tree, int max_code); static void build_tree(tree_desc* desc); static void scan_tree(ct_data* tree, int max_code); static void send_tree(ct_data* tree, int max_code); static int build_bl_tree(void); static void send_all_trees(int lcodes, int dcodes, int blcodes); static void compress_block(ct_data* ltree, ct_data* dtree); static void set_file_type(void); // ---------- DEFINITION SECTION ---------- static int extra_lbits[LENGTH_CODES] = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; static int extra_dbits[D_CODES] = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; static int extra_blbits[BL_CODES] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; static ct_data dyn_ltree[HEAP_SIZE]; static ct_data dyn_dtree[2*D_CODES+1]; static ct_data static_ltree[L_CODES+2]; static ct_data static_dtree[D_CODES]; static ct_data bl_tree[2*BL_CODES+1]; static tree_desc l_desc = {dyn_ltree, static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS, 0}; static tree_desc d_desc = {dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0}; static tree_desc bl_desc = {bl_tree, NULL, extra_blbits, 0, BL_CODES, MAX_BL_BITS, 0}; static unsigned short bl_count[MAX_BITS + 1]; static uchar bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; static int heap[2 * L_CODES + 1]; static int heap_len; static int heap_max; static uchar depth[2 * L_CODES + 1]; static uchar length_code[MAX_MATCH - MIN_MATCH + 1]; static uchar dist_code[512]; static int base_length[LENGTH_CODES]; static int base_dist[D_CODES]; #ifndef DYN_ALLOC static uchar l_buf[LIT_BUFSIZE]; static unsigned short d_buf[DIST_BUFSIZE]; #else static uchar* l_buf; static unsigned short* d_buf; #endif static uchar flag_buf[(LIT_BUFSIZE/8)]; static unsigned last_lit; static unsigned last_dist; static unsigned last_flags; static uchar flags; static uchar flag_bit; static unsigned int opt_len; static unsigned int static_len; static unsigned int compressed_len; static unsigned int input_len; unsigned short *file_type; int *file_method; extern int block_start; extern unsigned strstart; # define send_code(c, tree) \ { if(verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(tree[c].Code, tree[c].Len); } #define d_code(dist) \ ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) #define MAX(a,b) (a >= b ? a : b) void ct_init(unsigned short* attr,int* method) { int n; int bits; int length; int code; int dist; file_type = attr; file_method = method; compressed_len = input_len = 0L; #ifdef DYN_ALLOC d_buf = new unsigned short[DIST_BUFSIZE]; l_buf = new uchar[LIT_BUFSIZE]; #endif length = 0; for(code = 0; code < LENGTH_CODES-1; code++){ base_length[code] = length; for(n = 0; n < (1<>= 7; for( ; code < D_CODES; code++){ base_dist[code] = dist << 7; for(n = 0; n < (1<<(extra_dbits[code]-7)); n++){ dist_code[256 + dist++] = (uchar)code; } } for(bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; n = 0; while(n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; while(n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; while(n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; while(n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; gen_codes((ct_data*)static_ltree, L_CODES+1); for(n = 0; n < D_CODES; n++){ static_dtree[n].Len = 5; static_dtree[n].Code = bi_reverse(n, 5); } init_block(); } static void init_block(void) { int n; for(n = 0; n < L_CODES; n++) dyn_ltree[n].Freq = 0; for(n = 0; n < D_CODES; n++) dyn_dtree[n].Freq = 0; for(n = 0; n < BL_CODES; n++) bl_tree[n].Freq = 0; dyn_ltree[END_BLOCK].Freq = 1; opt_len = static_len = 0L; last_lit = last_dist = last_flags = 0; flags = 0; flag_bit = 1; } #define SMALLEST 1 #define pqremove(tree, top) \ {\ top = heap[SMALLEST]; \ heap[SMALLEST] = heap[heap_len--]; \ pqdownheap(tree,SMALLEST); \ } #define smaller(tree, n, m) \ (tree[n].Freq < tree[m].Freq || \ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) static void pqdownheap(ct_data* tree,int k) { int v = heap[k]; int j = k << 1; int htemp; while(j <= heap_len){ if(j < heap_len && smaller(tree, heap[j+1], heap[j])) j++; htemp = heap[j]; if(smaller(tree, v, htemp)) break; heap[k] = htemp; k = j; j <<= 1; } heap[k] = v; } static void gen_bitlen(tree_desc* desc) { ct_data* tree = desc->dyn_tree; int* extra = desc->extra_bits; int base = desc->extra_base; int max_code = desc->max_code; int max_length = desc->max_length; ct_data* stree = desc->static_tree; int h; int n, m; int bits; int xbits; unsigned short f; int overflow = 0; for(bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; tree[heap[heap_max]].Len = 0; for(h = heap_max+1; h < HEAP_SIZE; h++){ n = heap[h]; bits = tree[tree[n].Dad].Len + 1; if(bits > max_length) bits = max_length, overflow++; tree[n].Len = bits; if(n > max_code) continue; bl_count[bits]++; xbits = 0; if(n >= base) xbits = extra[n-base]; f = tree[n].Freq; opt_len += (unsigned int)f * (bits + xbits); if(stree) static_len += (unsigned int)f * (stree[n].Len + xbits); } if(overflow == 0) return; do { bits = max_length-1; while(bl_count[bits] == 0) bits--; bl_count[bits]--; bl_count[bits+1] += 2; bl_count[max_length]--; overflow -= 2; } while(overflow > 0); for(bits = max_length; bits != 0; bits--){ n = bl_count[bits]; while(n != 0){ m = heap[--h]; if(m > max_code) continue; if(tree[m].Len != (unsigned) bits){ opt_len += ((int)bits-(int)tree[m].Len)*(int)tree[m].Freq; tree[m].Len = bits; } n--; } } } static void gen_codes (ct_data* tree,int max_code) { unsigned short next_code[MAX_BITS+1]; unsigned short code = 0; int bits; int n; for(bits = 1; bits <= MAX_BITS; bits++){ next_code[bits] = code = (code + bl_count[bits-1]) << 1; } for(n = 0; n <= max_code; n++){ int len = tree[n].Len; if(len == 0) continue; tree[n].Code = bi_reverse(next_code[len]++, len); } } static void build_tree(tree_desc* desc) { ct_data* tree = desc->dyn_tree; ct_data* stree = desc->static_tree; int elems = desc->elems; int n, m; int max_code = -1; int node = elems; heap_len = 0, heap_max = HEAP_SIZE; for(n = 0; n < elems; n++){ if(tree[n].Freq != 0){ heap[++heap_len] = max_code = n; depth[n] = 0; } else { tree[n].Len = 0; } } while(heap_len < 2){ int new_ = heap[++heap_len] = (max_code < 2 ? ++max_code : 0); tree[new_].Freq = 1; depth[new_] = 0; opt_len--; if(stree) static_len -= stree[new_].Len; } desc->max_code = max_code; for(n = heap_len/2; n >= 1; n--) pqdownheap(tree, n); do { pqremove(tree, n); m = heap[SMALLEST]; heap[--heap_max] = n; heap[--heap_max] = m; tree[node].Freq = tree[n].Freq + tree[m].Freq; depth[node] = (uchar) (MAX(depth[n], depth[m]) + 1); tree[n].Dad = tree[m].Dad = node; heap[SMALLEST] = node++; pqdownheap(tree, SMALLEST); } while(heap_len >= 2); heap[--heap_max] = heap[SMALLEST]; gen_bitlen((tree_desc*)desc); gen_codes ((ct_data*)tree, max_code); } static void scan_tree (ct_data* tree,int max_code) { int n; int prevlen = -1; int curlen; int nextlen = tree[0].Len; int count = 0; int max_count = 7; int min_count = 4; if(nextlen == 0) max_count = 138, min_count = 3; tree[max_code+1].Len = (unsigned short)-1; for(n = 0; n <= max_code; n++){ curlen = nextlen; nextlen = tree[n+1].Len; if(++count < max_count && curlen == nextlen){ continue; } else if(count < min_count){ bl_tree[curlen].Freq += count; } else if(curlen != 0){ if(curlen != prevlen) bl_tree[curlen].Freq++; bl_tree[REP_3_6].Freq++; } else if(count <= 10){ bl_tree[REPZ_3_10].Freq++; } else { bl_tree[REPZ_11_138].Freq++; } count = 0; prevlen = curlen; if(nextlen == 0){ max_count = 138, min_count = 3; } else if(curlen == nextlen){ max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } static void send_tree (ct_data* tree,int max_code) { int n; int prevlen = -1; int curlen; int nextlen = tree[0].Len; int count = 0; int max_count = 7; int min_count = 4; if(nextlen == 0) max_count = 138, min_count = 3; for(n = 0; n <= max_code; n++){ curlen = nextlen; nextlen = tree[n+1].Len; if(++count < max_count && curlen == nextlen){ continue; } else if(count < min_count){ do { send_code(curlen, bl_tree); } while(--count != 0); } else if(curlen != 0){ if(curlen != prevlen){ send_code(curlen, bl_tree); count--; } send_code(REP_3_6, bl_tree); send_bits(count-3, 2); } else if(count <= 10){ send_code(REPZ_3_10, bl_tree); send_bits(count-3, 3); } else { send_code(REPZ_11_138, bl_tree); send_bits(count-11, 7); } count = 0; prevlen = curlen; if(nextlen == 0){ max_count = 138, min_count = 3; } else if(curlen == nextlen){ max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } static int build_bl_tree() { int max_blindex; scan_tree((ct_data*)dyn_ltree, l_desc.max_code); scan_tree((ct_data*)dyn_dtree, d_desc.max_code); build_tree((tree_desc*)(&bl_desc)); for(max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--){ if(bl_tree[bl_order[max_blindex]].Len != 0) break; } opt_len += 3*(max_blindex+1) + 5+5+4; return max_blindex; } static void send_all_trees(int lcodes,int dcodes,int blcodes) { int rank; send_bits(lcodes-257, 5); send_bits(dcodes-1, 5); send_bits(blcodes-4, 4); for(rank = 0; rank < blcodes; rank++){ send_bits(bl_tree[bl_order[rank]].Len, 3); } send_tree((ct_data*)dyn_ltree, lcodes-1); send_tree((ct_data*)dyn_dtree, dcodes-1); } unsigned int flush_block(char* buf,unsigned int stored_len,int eof) { unsigned int opt_lenb, static_lenb; int max_blindex; flag_buf[last_flags] = flags; if(*file_type == (unsigned short)UNKNOWN) set_file_type(); build_tree((tree_desc*)(&l_desc)); build_tree((tree_desc*)(&d_desc)); max_blindex = build_bl_tree(); opt_lenb = (opt_len+3+7)>>3; static_lenb = (static_len+3+7)>>3; input_len += stored_len; if(static_lenb <= opt_lenb) opt_lenb = static_lenb; if(stored_len <= opt_lenb && eof && compressed_len == 0L){ //if(buf == NULL) ErrH.Abort(IErrMsg); copy_block(buf,(unsigned)stored_len,0); compressed_len = stored_len << 3; *file_method = STORE; } else if(stored_len+4 <= opt_lenb && buf != (char*)NULL){ send_bits((STORED_BLOCK<<1)+eof, 3); compressed_len = (compressed_len + 3 + 7) & ~7L; compressed_len += (stored_len + 4) << 3; copy_block(buf, (unsigned)stored_len, 1); } else if(static_lenb == opt_lenb){ send_bits((STATIC_TREES<<1)+eof, 3); compress_block((ct_data*)static_ltree, (ct_data*)static_dtree); compressed_len += 3 + static_len; } else { send_bits((DYN_TREES<<1)+eof, 3); send_all_trees(l_desc.max_code+1, d_desc.max_code+1, max_blindex+1); compress_block((ct_data*)dyn_ltree, (ct_data*)dyn_dtree); compressed_len += 3 + opt_len; } init_block(); if(eof){ #ifdef DYN_ALLOC extern uchar *window; #else extern uchar window[]; #endif memset(window, 0, (unsigned)(2*WSIZE-1)); bi_windup(); compressed_len += 7; } return compressed_len >> 3; } int ct_tally(int dist,int lc) { l_buf[last_lit++] = (uchar)lc; if(dist == 0){ dyn_ltree[lc].Freq++; } else { dist--; dyn_ltree[length_code[lc]+LITERALS+1].Freq++; dyn_dtree[d_code(dist)].Freq++; d_buf[last_dist++] = dist; flags |= flag_bit; } flag_bit <<= 1; if((last_lit & 7) == 0){ flag_buf[last_flags++] = flags; flags = 0, flag_bit = 1; } if(level > 2 && (last_lit & 0xfff) == 0){ unsigned int out_length = (unsigned int)last_lit*8L; unsigned int in_length = (unsigned int)strstart-block_start; int dcode; for(dcode = 0; dcode < D_CODES; dcode++){ out_length += (unsigned int)dyn_dtree[dcode].Freq*(5L+extra_dbits[dcode]); } out_length >>= 3; if(last_dist < last_lit/2 && out_length < in_length/2) return 1; } return (last_lit == LIT_BUFSIZE-1 || last_dist == DIST_BUFSIZE); } static void compress_block(ct_data* ltree,ct_data* dtree) { unsigned dist; int lc; unsigned lx = 0; unsigned dx = 0; unsigned fx = 0; uchar flag = 0; unsigned code; int extra; if(last_lit != 0) do { if((lx & 7) == 0) flag = flag_buf[fx++]; lc = l_buf[lx++]; if((flag & 1) == 0){ send_code(lc, ltree); } else { code = length_code[lc]; send_code(code+LITERALS+1, ltree); extra = extra_lbits[code]; if(extra != 0){ lc -= base_length[code]; send_bits(lc, extra); } dist = d_buf[dx++]; code = d_code(dist); send_code(code, dtree); extra = extra_dbits[code]; if(extra != 0){ dist -= base_dist[code]; send_bits(dist, extra); } } flag >>= 1; } while(lx < last_lit); send_code(END_BLOCK, ltree); } static void set_file_type() { int n = 0; unsigned ascii_freq = 0; unsigned bin_freq = 0; while(n < 7) bin_freq += dyn_ltree[n++].Freq; while(n < 128) ascii_freq += dyn_ltree[n++].Freq; while(n < LITERALS) bin_freq += dyn_ltree[n++].Freq; *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII; } void free_data(void) { #ifdef DYN_ALLOC delete l_buf; delete d_buf; lm_free(); #endif }