Files
Vangers/lib/utils/xzip/inzip.cpp

568 lines
12 KiB
C++
Raw Normal View History

2016-03-12 15:23:57 +03:00
#include "xzip.h"
typedef unsigned char uchar;
typedef unsigned short ushort;
//typedef unsigned long ulong;
struct huft;
#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 Buf_size (8 * 2 * sizeof(char))
#define PUTSHORT(w) \
{ if(out_offset < out_size-1){ \
out_buf[out_offset++] = (char)((w) & 0xFF); \
out_buf[out_offset++] = (char)((ushort)(w) >> 8); \
} else { \
flush_outbuf((w),2); \
} \
}
#define PUTBYTE(b) \
{ if(out_offset < out_size){ \
out_buf[out_offset++] = (char)(b); \
} else { \
flush_outbuf((b),1); \
} \
}
// ---------- EXTERN SECTION ----------
extern unsigned int window_size;
// ---------- PROTOTYPE SECTION ----------
unsigned int deflate(void);
void lm_init(int pack_level,ushort* flags);
void bi_init(void);
void bi_windup(void);
unsigned bi_reverse(unsigned code,int len);
void ct_init(ushort* attr,int* method);
void send_bits(int value,int length);
void flush_outbuf(unsigned w,unsigned bytes);
int mem_read(char* b,unsigned bsize);
void copy_block(char* buf,unsigned len,int header);
void free_data(void);
// ---------- DEFINITION SECTION ----------
unsigned short bi_buf;
char IErrMsg[] = "ZIP Internal Error";
int level = 6;
int verbose = 0;
int bi_valid;
char* in_buf;
char* out_buf;
unsigned in_offset;
unsigned out_offset;
unsigned in_size;
unsigned out_size;
int (*read_buf)(char* buf,unsigned size);
unsigned int ZIP_compress(char* trg,unsigned int trgsize,char* src,unsigned int srcsize)
{
ushort att = (ushort)UNKNOWN;
ushort flags = 0;
int method = DEFLATE;
read_buf = mem_read;
in_buf = src;
in_size = (unsigned)srcsize;
in_offset = 0;
out_buf = trg;
out_size = (unsigned)trgsize;
out_offset = 2 + 4;
window_size = 0L;
if(out_size <= 6) return 0;
bi_init();
ct_init(&att,&method);
lm_init((level != 0 ? level : 1),&flags);
deflate();
free_data();
window_size = 0L;
trg[0] = (char)(method & 0xFF);
trg[1] = (char)((method >> 8) & 0xFF);
*(unsigned int*)(trg + 2) = (unsigned int)srcsize;
return (unsigned int)out_offset;
}
void bi_init(void)
{
bi_buf = 0;
bi_valid = 0;
}
void send_bits(int value,int length)
{
if(bi_valid > (int)Buf_size - length){
bi_buf |= (value << bi_valid);
PUTSHORT(bi_buf);
bi_buf = (ushort)value >> (Buf_size - bi_valid);
bi_valid += length - Buf_size;
}
else {
bi_buf |= value << bi_valid;
bi_valid += length;
}
}
unsigned bi_reverse(unsigned code,int len)
{
register unsigned res = 0;
do {
res |= code & 1;
code >>= 1, res <<= 1;
} while (--len > 0);
return res >> 1;
}
void flush_outbuf(unsigned w,unsigned bytes)
{
//ErrH.Abort(IErrMsg);
}
void bi_windup(void)
{
if(bi_valid > 8){
PUTSHORT(bi_buf);
}
else
if(bi_valid > 0){
PUTBYTE(bi_buf);
}
bi_buf = 0;
bi_valid = 0;
}
void copy_block(char* buf,unsigned len,int header)
{
bi_windup();
if(header){
PUTSHORT((ushort)len);
PUTSHORT((ushort)~len);
}
if(out_offset + len > out_size){
//ErrH.Abort(IErrMsg);
}
else {
memcpy(out_buf + out_offset, buf, len);
out_offset += len;
}
}
int mem_read(char* b,unsigned bsize)
{
if(in_offset < in_size){
unsigned int block_size = in_size - in_offset;
if (block_size > (unsigned int)bsize) block_size = (unsigned int)bsize;
memcpy(b, in_buf + in_offset, (unsigned)block_size);
in_offset += (unsigned)block_size;
return (int)block_size;
}
else {
return 0;
}
}
#ifdef _LARGE_MODEL_
#define HASH_BITS 14
#else
#define HASH_BITS 15
#endif
#define HASH_SIZE (unsigned short)(1<<HASH_BITS)
#define HASH_MASK (HASH_SIZE-1)
#define WMASK (WSIZE-1)
#define NIL 0
#define FAST 4
#define SLOW 2
#ifndef TOO_FAR
# define TOO_FAR 4096
#endif
typedef ushort Pos;
typedef unsigned IPos;
#define H_SHIFT ((HASH_BITS+MIN_MATCH-1)/MIN_MATCH)
// ---------- EXTERN SECTION ----------
extern int (*read_buf)(char* buf,unsigned size);
extern int verbose;
extern int level;
// ---------- PROTOTYPE SECTION ----------
void fill_window(void);
unsigned int deflate_fast(void);
int longest_match(IPos cur_match);
void lm_init(int pack_level,ushort* flags);
void lm_free(void);
unsigned int deflate(void);
unsigned int flush_block(char* buf,unsigned int stored_len,int eof);
int ct_tally(int dist,int lc);
// ---------- DEFINITION SECTION ----------
#ifndef DYN_ALLOC
uchar window[2L*WSIZE];
Pos prev[WSIZE];
Pos head[HASH_SIZE];
#else
uchar* window = NULL;
Pos* prev = NULL;
Pos* head;
#endif
unsigned int window_size;
int block_start;
static int sliding;
static unsigned ins_h;
unsigned int prev_length;
unsigned strstart;
unsigned match_start;
static int eofile;
static unsigned lookahead;
unsigned max_chain_length;
static unsigned int max_lazy_match;
#define max_insert_length max_lazy_match
unsigned good_match;
typedef struct config {
ushort good_length;
ushort max_lazy;
ushort nice_length;
ushort max_chain;
} config;
int nice_match;
static config configuration_table[10] = {
/* 0 */ {0, 0, 0, 0},
/* 1 */ {4, 4, 8, 4},
/* 2 */ {4, 5, 16, 8},
/* 3 */ {4, 6, 32, 32},
/* 4 */ {4, 4, 16, 16},
/* 5 */ {8, 16, 32, 32},
/* 6 */ {8, 16, 128, 128},
/* 7 */ {8, 32, 128, 256},
/* 8 */ {32, 128, 258, 1024},
/* 9 */ {32, 258, 258, 4096}};
#define EQUAL 0
#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)
#define INSERT_STRING(s, match_head) \
(UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \
prev[(s) & WMASK] = match_head = head[ins_h], \
head[ins_h] = (s))
void lm_init(int pack_level,ushort* flags)
{
register unsigned j;
//if(pack_level < 1 || pack_level > 9) ErrH.Abort(IErrMsg);
sliding = 0;
if(window_size == 0L){
sliding = 1;
window_size = (unsigned int)2L*WSIZE;
}
#ifdef DYN_ALLOC
if(window == NULL)
window = new uchar[WSIZE * 2];
if(prev == NULL){
prev = new Pos[WSIZE];
head = new Pos[HASH_SIZE];
}
#endif
head[HASH_SIZE-1] = NIL;
memset((char*)head,NIL,(unsigned)(HASH_SIZE - 1) * sizeof(*head));
max_lazy_match = configuration_table[pack_level].max_lazy;
good_match = configuration_table[pack_level].good_length;
nice_match = configuration_table[pack_level].nice_length;
max_chain_length = configuration_table[pack_level].max_chain;
if(pack_level == 1){
*flags |= FAST;
} else
if(pack_level == 9){
*flags |= SLOW;
}
strstart = 0;
block_start = 0L;
j = WSIZE;
if(sizeof(int) > 2)
j <<= 1;
lookahead = (*read_buf)((char*)window, j);
if(lookahead == 0 || lookahead == (unsigned)EOF){
eofile = 1, lookahead = 0;
return;
}
eofile = 0;
while(lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
ins_h = 0;
for(j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(ins_h, window[j]);
}
void lm_free(void)
{
#ifdef DYN_ALLOC
if(window != NULL){
// free(window);
delete window;
window = NULL;
}
if(prev != NULL){
/*
free((unsigned char*)prev);
free((unsigned char*)head);
*/
delete prev;
delete head;
prev = head = NULL;
}
#endif
}
int longest_match(IPos cur_match)
{
unsigned chain_length = max_chain_length;
register uchar *scan = window + strstart;
register uchar *match;
register int len;
int best_len = prev_length;
IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL;
register uchar *strend = window + strstart + MAX_MATCH;
register uchar scan_end1 = scan[best_len-1];
register uchar scan_end = scan[best_len];
if(prev_length >= good_match){
chain_length >>= 2;
}
do {
match = window + cur_match;
if(match[best_len] != scan_end ||
match[best_len-1] != scan_end1 ||
*match != *scan ||
*++match != scan[1]) continue;
scan += 2, match++;
do {
} while(*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
*++scan == *++match && *++scan == *++match &&
scan < strend);
len = MAX_MATCH - (int)(strend - scan);
scan = strend - MAX_MATCH;
if(len > best_len){
match_start = cur_match;
best_len = len;
if(len >= nice_match) break;
scan_end1 = scan[best_len-1];
scan_end = scan[best_len];
}
} while((cur_match = prev[cur_match & WMASK]) > limit && --chain_length != 0);
return best_len;
}
#define check_match(start, match, length)
void fill_window(void)
{
register unsigned n, m;
unsigned more = (unsigned)(window_size - (unsigned int)lookahead - (unsigned int)strstart);
if(more == (unsigned)EOF){
more--;
} else
if(strstart >= WSIZE+MAX_DIST && sliding){
memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
match_start -= WSIZE;
strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
block_start -= (int) WSIZE;
for(n = 0; n < HASH_SIZE; n++){
m = head[n];
head[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
}
for(n = 0; n < WSIZE; n++){
m = prev[n];
prev[n] = (Pos)(m >= WSIZE ? m-WSIZE : NIL);
}
more += WSIZE;
if(verbose) putc('.', stderr);
}
if(!eofile){
n = (*read_buf)((char*)window+strstart+lookahead, more);
if(n == 0 || n == (unsigned)EOF){
eofile = 1;
}
else {
lookahead += n;
}
}
}
#define FLUSH_BLOCK(eof) \
flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
(char*)NULL,(int)strstart - block_start,(eof))
unsigned int deflate_fast(void)
{
IPos hash_head;
int flush;
unsigned match_length = 0;
prev_length = MIN_MATCH-1;
while(lookahead != 0){
INSERT_STRING(strstart, hash_head);
if(hash_head != NIL && strstart - hash_head <= MAX_DIST){
match_length = longest_match (hash_head);
if(match_length > lookahead) match_length = lookahead;
}
if(match_length >= MIN_MATCH){
check_match(strstart, match_start, match_length);
flush = ct_tally(strstart-match_start, match_length - MIN_MATCH);
lookahead -= match_length;
if(match_length <= max_insert_length){
match_length--;
do {
strstart++;
INSERT_STRING(strstart, hash_head);
} while(--match_length != 0);
strstart++;
}
else {
strstart += match_length;
match_length = 0;
ins_h = window[strstart];
UPDATE_HASH(ins_h, window[strstart+1]);
}
}
else {
flush = ct_tally (0, window[strstart]);
lookahead--;
strstart++;
}
if(flush) FLUSH_BLOCK(0), block_start = strstart;
while(lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
}
return FLUSH_BLOCK(1);
}
unsigned int deflate(void)
{
IPos hash_head;
IPos prev_match;
int flush;
int match_available = 0;
register unsigned match_length = MIN_MATCH - 1;
if(level <= 3) return deflate_fast();
while(lookahead != 0){
INSERT_STRING(strstart, hash_head);
prev_length = match_length, prev_match = match_start;
match_length = MIN_MATCH-1;
if(hash_head != NIL && prev_length < max_lazy_match && strstart - hash_head <= MAX_DIST){
match_length = longest_match (hash_head);
if(match_length > lookahead) match_length = lookahead;
if(match_length == MIN_MATCH && strstart-match_start > TOO_FAR){
match_length--;
}
}
if(prev_length >= MIN_MATCH && match_length <= prev_length){
check_match(strstart-1, prev_match, prev_length);
flush = ct_tally(strstart-1-prev_match, prev_length - MIN_MATCH);
lookahead -= prev_length-1;
prev_length -= 2;
do {
strstart++;
INSERT_STRING(strstart, hash_head);
} while(--prev_length != 0);
match_available = 0;
match_length = MIN_MATCH-1;
strstart++;
if(flush) FLUSH_BLOCK(0), block_start = strstart;
}
else
if(match_available){
if(ct_tally (0, window[strstart-1])){
FLUSH_BLOCK(0), block_start = strstart;
}
strstart++;
lookahead--;
}
else {
match_available = 1;
strstart++;
lookahead--;
}
while(lookahead < MIN_LOOKAHEAD && !eofile) fill_window();
}
if(match_available) ct_tally(0, window[strstart-1]);
return FLUSH_BLOCK(1);
}