#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

//		---------- EXTERN SECTION ----------
//	       ---------- PROTOTYPE SECTION ----------

int FlushMemory(void);
int FlushOutput(void);
void inflate(void);
int ReadMemoryByte(unsigned short* x);

//	       ---------- DEFINITION SECTION ----------

uchar* outbuf;
uchar* outptr;

uchar* slide;

int outcnt = 0;
int outpos = 0;
unsigned int bitbuf = 0;
int bits_left = 0;
char zipeof = 0;

unsigned short mask_bits[] = {
    0x0000,
    0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
    0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
};

static uchar* mem_i_buffer;
static uchar* mem_o_buffer;
static unsigned int mem_i_size,mem_i_offset;
static unsigned int mem_o_size,mem_o_offset;

unsigned int ZIP_GetExpandedSize(char* p)
{
	return *(unsigned int*)(p + 2);
}

void ZIP_expand(char* trg,unsigned int trgsize,char* src,unsigned int srcsize)
{
	unsigned short method;

	outbuf = new uchar[OUTBUFSIZ + 1];
	slide = new uchar[WSIZE];

	method = *(short*)(src);

	mem_i_buffer = (uchar*)src + 2 + 4;
	mem_i_size   = srcsize - 2 - 4;
	mem_i_offset = 0;

	mem_o_buffer = (uchar*)trg;
	mem_o_size   = trgsize;
	mem_o_offset = 0;

	bits_left = 0;
	bitbuf = 0L;
	outpos = 0L;
	outcnt = 0;
	outptr = outbuf;
	zipeof = 0;
	memset(outbuf,0xAA,OUTBUFSIZ);

	switch (method) {
		case STORE:
			memcpy(trg,src + 2 + 4,(unsigned)(srcsize - 2 - 4));
		break;
		case DEFLATE:
			inflate();
			FlushOutput();
			break;
		default:
			break;
	}

	delete outbuf;
	delete slide;
}

int FlushOutput(void)
{
	int rc = FlushMemory();
	outpos += outcnt;
	outcnt = 0;
	outptr = outbuf;
	return rc;
}

int ReadMemoryByte(unsigned short* x)
{
	if (mem_i_offset < mem_i_size) {
		*x = (unsigned short) mem_i_buffer[mem_i_offset++];
		return 8;
	} else
		return 0;
}

int FlushMemory(void)
{
	if(outcnt == 0)
		return 0;

	if(mem_o_offset + outcnt <= mem_o_size){
		memcpy((char*)(mem_o_buffer + mem_o_offset),(char*)outbuf,outcnt);
		mem_o_offset += outcnt;
		return 0;
	} else
		return 50;
}


#define NEXTBYTE	(ReadByte(&bytebuf), bytebuf)
#define NEEDBITS(n)	{while(k<(n)){b|=((unsigned int)NEXTBYTE)<<k;k+=8;}}
#define DUMPBITS(n)	{b>>=(n);k-=(n);}

#define BMAX		16
#define N_MAX		288

//		---------- EXTERN SECTION ----------

extern uchar* outptr;
extern int outcnt;

//	       ---------- PROTOTYPE SECTION ----------

int FlushOutput(void);
int ReadMemoryByte(unsigned short* x);

int huft_build(unsigned int* b,unsigned int n,unsigned int s,unsigned short* d,unsigned short* e,struct huft** t,int* m);
int huft_free(struct huft* t);
void flush(unsigned w);
int inflate_codes(struct huft* tl,struct huft* td,int bl,int bd);
int inflate_stored(void);
int inflate_fixed(void);
int inflate_dynamic(void);
int inflate_block(int* e);
int inflate_entry(void);
void inflate(void);
int ReadByte(unsigned short* x);

//	       ---------- DEFINITION SECTION ----------

struct huft {
	uchar e;
	uchar b;
	union {
		unsigned short n;
		struct huft *t;
	} v;
};

static unsigned border[] = {
	16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
static unsigned short cplens[] = {
	3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
	35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
static unsigned short cplext[] = {
	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, 99, 99};
static unsigned short cpdist[] = {
	1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
	257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
	8193, 12289, 16385, 24577};
static unsigned short cpdext[] = {
	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};

unsigned wp;
unsigned int bb;
unsigned bk;
unsigned short bytebuf;

int lbits = 9;
int dbits = 6;

unsigned hufts;

int huft_build(unsigned int* b,unsigned int n,unsigned int s,unsigned short* d,unsigned short* e,struct huft** t,int* m)
{
	unsigned a;
	unsigned c[BMAX+1];
	unsigned f;
	int g;
	int h;
	unsigned i;
	unsigned j;
	int k;
	int l;
	unsigned *p;
	struct huft *q;
	struct huft r;
	struct huft *u[BMAX];
	unsigned v[N_MAX];
	int w;
	unsigned x[BMAX+1];
	unsigned *xp;
	int y;
	unsigned z;

	memset(c, 0,sizeof(c));
	p = b;	i = n;
	do {
		c[*p++]++;
	} while(--i);
	if(c[0] == n)
		return 2;

	l = *m;
	for(j = 1; j <= BMAX; j++)
		if(c[j])
			break;
		k = j;
		if((unsigned)l < j)
			l = j;
		for(i = BMAX; i; i--)
			if(c[i])
				break;
		g = i;
		if((unsigned)l > i)
			l = i;
		*m = l;

		for(y = 1 << j; j < i; j++,y <<= 1)
			if((y -= c[j]) < 0)
				return 2;
		if((y -= c[i]) < 0)
			return 2;
		c[i] += y;

	x[1] = j = 0;
	p = c + 1;  xp = x + 2;
	while(--i){
		*xp++ = (j += *p++);
	}

	p = b;	i = 0;
	do {
		if((j = *p++) != 0)
			v[x[j]++] = i;
	} while(++i < n);

	x[0] = i = 0;
	p = v;
	h = -1;
	w = -l;
	u[0] = (struct huft*)NULL;
	q = (struct huft*)NULL;
	z = 0;

	for(; k <= g; k++){
		a = c[k];
		while(a--){
			while(k > w + l){
				h++;
				w += l;
				z = (z = g - w) > (unsigned)l ? l : z;
				if((f = 1 << (j = k - w)) > a + 1)
				{
					f -= a + 1;
					xp = c + k;
					while(++j < z)
					{
						if((f <<= 1) <= *++xp)
							break;
						f -= *xp;
					}
				}
				z = 1 << j;
				q = new huft[z + 1];
				hufts += z + 1;
				*t = q + 1;
				*(t = &(q->v.t)) = (struct huft*)NULL;
				u[h] = ++q;

				if(h){
					x[h] = i;
					r.b = (uchar)l;
					r.e = (uchar)(16 + j);
					r.v.t = q;
					j = i >> (w - l);
					u[h-1][j] = r;
				}
			}

			r.b = (uchar)(k - w);
			if(p >= v + n)
				r.e = 99;
			else
				if(*p < s){
					r.e = (uchar)(*p < 256 ? 16 : 15);
					r.v.n = *p++;
				}
			else {
				r.e = (uchar)e[*p - s];  /* non-simple--look up in lists */
				r.v.n = d[*p++ - s];
			}

			f = 1 << (k - w);
			for(j = i >> w; j < z; j += f)
				q[j] = r;

			for(j = 1 << (k - 1); i & j; j >>= 1)
				i ^= j;
			i ^= j;

			while((i & ((1 << w) - 1)) != x[h]){
				h--;
				w -= l;
			}
		}
	}
	return y != 0 && n != 1;
}

int huft_free(struct huft* t)
{
	struct huft *p,*q;
	p = t;
	while(p != (struct huft*)NULL){
		q = (--p)->v.t;
//		  free(p);
		delete p;
		p = q;
	}
	return 0;
}

void flush(unsigned w)
{
	unsigned n;
	uchar *p;

	p = slide;
	while(w){
		n = (n = OUTBUFSIZ - outcnt) < w ? n : w;
		memcpy(outptr,p,n);
		outptr += n;
		if((outcnt += n) == OUTBUFSIZ)
			FlushOutput();
		p += n;
		w -= n;
	}
}

int inflate_codes(struct huft* tl,struct huft* td,int bl,int bd)
{
	unsigned e;
	unsigned n,d;
	unsigned w;
	struct huft *t;
	unsigned ml,md;
	unsigned int b;
	unsigned k;

	b = bb;
	k = bk;
	w = wp;

	ml = mask_bits[bl];
	md = mask_bits[bd];
	while(1){
		NEEDBITS((unsigned)bl)
		if((e = (t = tl + ((unsigned)b & ml))->e) > 16)
			do {
				if(e == 99)
					return 1;
				DUMPBITS(t->b)
				e -= 16;
				NEEDBITS(e)
			} while((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
			DUMPBITS(t->b)
			if(e == 16){
				slide[w++] = (uchar)t->v.n;
				if(w == WSIZE){
					flush(w);
					w = 0;
				}
			}
			else {
				if(e == 15)
					break;
				NEEDBITS(e)
				n = t->v.n + ((unsigned)b & mask_bits[e]);
				DUMPBITS(e);
				NEEDBITS((unsigned)bd)
				if((e = (t = td + ((unsigned)b & md))->e) > 16)
					do {
						if(e == 99)
							return 1;
						DUMPBITS(t->b)
						e -= 16;
						NEEDBITS(e)
					} while((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
				DUMPBITS(t->b)
				NEEDBITS(e)
				d = w - t->v.n - ((unsigned)b & mask_bits[e]);
				DUMPBITS(e)
				do {
					n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
					if(w - d >= e){
						memcpy(slide + w,slide + d,e);
						w += e;
						d += e;
					}
					else
						do {
							slide[w++] = slide[d++];
						} while(--e);
					if(w == WSIZE){
						flush(w);
						w = 0;
					}
				} while(n);
			}
		}
	wp = w;
	bb = b;
	bk = k;
	return 0;
}

int inflate_stored(void)
{
	unsigned n;
	unsigned w;
	unsigned int b;
	unsigned k;

	b = bb;
	k = bk;
	w = wp;
	n = k & 7;
	DUMPBITS(n);

	NEEDBITS(16)
	n = ((unsigned)b & 0xffff);
	DUMPBITS(16)
	NEEDBITS(16)
	if(n != (unsigned)((~b) & 0xffff))
		return 1;
	DUMPBITS(16)

	while(n--){
		NEEDBITS(8)
		slide[w++] = (uchar)b;
		if(w == WSIZE){
			flush(w);
			w = 0;
		}
		DUMPBITS(8)
	}

	wp = w;
	bb = b;
	bk = k;
	return 0;
}

int inflate_fixed(void)
{
	int i;
	struct huft *tl;
	struct huft *td;
	int bl;
	int bd;
	unsigned l[288];

	for(i = 0; i < 144; i++)
		l[i] = 8;
	for(; i < 256; i++)
		l[i] = 9;
	for(; i < 280; i++)
		l[i] = 7;
	for(; i < 288; i++)
		l[i] = 8;
	bl = 7;
	if((i = huft_build(l,288,257,cplens,cplext,&tl,&bl)) != 0)
		return i;

	for(i = 0; i < 30; i++)
		l[i] = 5;
	bd = 5;
	if((i = huft_build(l,30,0,cpdist,cpdext,&td,&bd)) > 1){
		huft_free(tl);
		return i;
	}

	if(inflate_codes(tl,td,bl,bd))
		return 1;

	huft_free(tl);
	huft_free(td);
	return 0;
}

int inflate_dynamic(void)
{
	int i;
	unsigned j;
	unsigned l;
	unsigned m;
	unsigned n;
	struct huft *tl;
	struct huft *td;
	int bl;
	int bd;
	unsigned nb;
	unsigned nl;
	unsigned nd;
	unsigned ll[286+30];
	unsigned int b;
	unsigned k;

	b = bb;
	k = bk;

	NEEDBITS(5)
	nl = 257 + ((unsigned)b & 0x1f);
	DUMPBITS(5)
	NEEDBITS(5)
	nd = 1 + ((unsigned)b & 0x1f);
	DUMPBITS(5)
	NEEDBITS(4)
	nb = 4 + ((unsigned)b & 0xf);
	DUMPBITS(4)
	if(nl > 286 || nd > 30)
		return 1;
	for(j = 0; j < nb; j++){
		NEEDBITS(3)
		ll[border[j]] = (unsigned)b & 7;
		DUMPBITS(3)
	}
	for(; j < 19; j++)
		ll[border[j]] = 0;
	bl = 7;
	if((i = huft_build(ll,19,19,NULL,NULL,&tl,&bl)) != 0){
		if(i == 1)
			huft_free(tl);
		return i;
	}
	n = nl + nd;
	m = mask_bits[bl];
	i = l = 0;
	while((unsigned)i < n){
		NEEDBITS((unsigned)bl)
		j = (td = tl + ((unsigned)b & m))->b;
		DUMPBITS(j)
		j = td->v.n;
		if(j < 16)
			ll[i++] = l = j;
		else
			if(j == 16){
				NEEDBITS(2)
				j = 3 + ((unsigned)b & 3);
				DUMPBITS(2)
				if((unsigned)i + j > n)
					return 1;
				while(j--)
					ll[i++] = l;
			}
			else
				if(j == 17){
					NEEDBITS(3)
					j = 3 + ((unsigned)b & 7);
					DUMPBITS(3)
					if((unsigned)i + j > n)
						return 1;
					while(j--)
						ll[i++] = 0;
					l = 0;
				}
				else {
					NEEDBITS(7)
					j = 11 + ((unsigned)b & 0x7f);
					DUMPBITS(7)
					if((unsigned)i + j > n)
						return 1;
					while(j--)
						ll[i++] = 0;
					l = 0;
				}
	}
	huft_free(tl);

	bb = b;
	bk = k;
	bl = lbits;
	if((i = huft_build(ll,nl,257,cplens,cplext,&tl,&bl)) != 0){
		if(i == 1)
		huft_free(tl);
		return i;
	}
	bd = dbits;
	if((i = huft_build(ll + nl,nd,0,cpdist,cpdext,&td,&bd)) != 0){
		if(i == 1)
			huft_free(td);
		huft_free(tl);
		return i;
	}
	if(inflate_codes(tl,td,bl,bd))
		return 1;
	huft_free(tl);
	huft_free(td);
	return 0;
}

int inflate_block(int* e)
{
	unsigned t;
	unsigned int b;
	unsigned k;

	b = bb;
	k = bk;

	NEEDBITS(1)
	*e = (int)b & 1;
	DUMPBITS(1)

	NEEDBITS(2)
	t = (unsigned)b & 3;
	DUMPBITS(2)

	bb = b;
	bk = k;

	if(t == 2)
		return inflate_dynamic();
	if(t == 0)
		return inflate_stored();
	if(t == 1)
		return inflate_fixed();
	return 2;
}

int inflate_entry(void)
{
	int e;
	int r;
	unsigned h;

	wp = 0;
	bk = 0;
	bb = 0;

	h = 0;
	do {
		hufts = 0;
		if((r = inflate_block(&e)) != 0)
			return r;
		if(hufts > h)
			h = hufts;
	} while(!e);

	flush(wp);
	return 0;
}

void inflate(void)
{
	inflate_entry();
}

int ReadByte(unsigned short* x)
{
	return ReadMemoryByte(x);
}

