Files
Vangers/lib/utils/xzip/treezip.cpp
Zhuravlev Uriy aka stalkerg 6730f30327 First version of public source.
2016-03-12 15:23:57 +03:00

707 lines
16 KiB
C++

#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<<extra_lbits[code]); n++){
length_code[length++] = (uchar)code;
}
}
length_code[length-1] = (uchar)code;
dist = 0;
for(code = 0 ; code < 16; code++){
base_dist[code] = dist;
for(n = 0; n < (1<<extra_dbits[code]); n++){
dist_code[dist++] = (uchar)code;
}
}
dist >>= 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
}