xref: /plan9-contrib/sys/src/libflate/deflate.c (revision f31039c4c0ea01ea4572406e0e1b29764109d0d2)
180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <flate.h>
480ee5cbfSDavid du Colombier 
580ee5cbfSDavid du Colombier typedef struct Chain	Chain;
680ee5cbfSDavid du Colombier typedef struct Chains	Chains;
780ee5cbfSDavid du Colombier typedef struct Dyncode	Dyncode;
880ee5cbfSDavid du Colombier typedef struct Huff	Huff;
980ee5cbfSDavid du Colombier typedef struct LZblock	LZblock;
1080ee5cbfSDavid du Colombier typedef struct LZstate	LZstate;
1180ee5cbfSDavid du Colombier 
1280ee5cbfSDavid du Colombier enum
1380ee5cbfSDavid du Colombier {
1480ee5cbfSDavid du Colombier 	/*
1580ee5cbfSDavid du Colombier 	 * deflate format paramaters
1680ee5cbfSDavid du Colombier 	 */
1780ee5cbfSDavid du Colombier 	DeflateUnc	= 0,			/* uncompressed block */
1880ee5cbfSDavid du Colombier 	DeflateFix	= 1,			/* fixed huffman codes */
1980ee5cbfSDavid du Colombier 	DeflateDyn	= 2,			/* dynamic huffman codes */
2080ee5cbfSDavid du Colombier 
2180ee5cbfSDavid du Colombier 	DeflateEob	= 256,			/* end of block code in lit/len book */
2280ee5cbfSDavid du Colombier 	DeflateMaxBlock	= 64*1024-1,		/* maximum size of uncompressed block */
2380ee5cbfSDavid du Colombier 
2480ee5cbfSDavid du Colombier 	DeflateMaxExp	= 10,			/* maximum expansion for a block */
2580ee5cbfSDavid du Colombier 
2680ee5cbfSDavid du Colombier 	LenStart	= 257,			/* start of length codes in litlen */
2780ee5cbfSDavid du Colombier 	Nlitlen		= 288,			/* number of litlen codes */
2880ee5cbfSDavid du Colombier 	Noff		= 30,			/* number of offset codes */
2980ee5cbfSDavid du Colombier 	Nclen		= 19,			/* number of codelen codes */
3080ee5cbfSDavid du Colombier 
3180ee5cbfSDavid du Colombier 	MaxOff		= 32*1024,
3280ee5cbfSDavid du Colombier 	MinMatch	= 3,			/* shortest match possible */
3380ee5cbfSDavid du Colombier 	MaxMatch	= 258,			/* longest match possible */
3480ee5cbfSDavid du Colombier 
3580ee5cbfSDavid du Colombier 	/*
3680ee5cbfSDavid du Colombier 	 * huffman code paramaters
3780ee5cbfSDavid du Colombier 	 */
3880ee5cbfSDavid du Colombier 	MaxLeaf		= Nlitlen,
3980ee5cbfSDavid du Colombier 	MaxHuffBits	= 16,			/* max bits in a huffman code */
4080ee5cbfSDavid du Colombier 	ChainMem	= 2 * (MaxHuffBits - 1) * MaxHuffBits,
4180ee5cbfSDavid du Colombier 
4280ee5cbfSDavid du Colombier 	/*
4380ee5cbfSDavid du Colombier 	 * coding of the lz parse
4480ee5cbfSDavid du Colombier 	 */
4580ee5cbfSDavid du Colombier 	LenFlag		= 1 << 3,
4680ee5cbfSDavid du Colombier 	LenShift	= 4,			/* leaves enough space for MinMatchMaxOff */
4780ee5cbfSDavid du Colombier 	MaxLitRun	= LenFlag - 1,
4880ee5cbfSDavid du Colombier 
4980ee5cbfSDavid du Colombier 	/*
5080ee5cbfSDavid du Colombier 	 * internal lz paramaters
5180ee5cbfSDavid du Colombier 	 */
5280ee5cbfSDavid du Colombier 	DeflateOut	= 4096,			/* output buffer size */
5380ee5cbfSDavid du Colombier 	BlockSize	= 8192,			/* attempted input read quanta */
5480ee5cbfSDavid du Colombier 	DeflateBlock	= DeflateMaxBlock & ~(BlockSize - 1),
5580ee5cbfSDavid du Colombier 	MinMatchMaxOff	= 4096,			/* max profitable offset for small match;
5680ee5cbfSDavid du Colombier 						 * assumes 8 bits for len, 5+10 for offset
5780ee5cbfSDavid du Colombier 						 * DONT CHANGE WITHOUT CHANGING LZPARSE CONSTANTS
5880ee5cbfSDavid du Colombier 						 */
59*f31039c4SDavid du Colombier 	HistSlop	= 512,			/* must be at least MaxMatch */
6080ee5cbfSDavid du Colombier 	HistBlock	= 64*1024,
6180ee5cbfSDavid du Colombier 	HistSize	= HistBlock + HistSlop,
6280ee5cbfSDavid du Colombier 
6380ee5cbfSDavid du Colombier 	HashLog		= 13,
6480ee5cbfSDavid du Colombier 	HashSize	= 1<<HashLog,
6580ee5cbfSDavid du Colombier 
6680ee5cbfSDavid du Colombier 	MaxOffCode	= 256,			/* biggest offset looked up in direct table */
6780ee5cbfSDavid du Colombier 
6880ee5cbfSDavid du Colombier 	EstLitBits	= 8,
6980ee5cbfSDavid du Colombier 	EstLenBits	= 4,
7080ee5cbfSDavid du Colombier 	EstOffBits	= 5,
7180ee5cbfSDavid du Colombier };
7280ee5cbfSDavid du Colombier 
7380ee5cbfSDavid du Colombier /*
7480ee5cbfSDavid du Colombier  * knuth vol. 3 multiplicative hashing
7580ee5cbfSDavid du Colombier  * each byte x chosen according to rules
7680ee5cbfSDavid du Colombier  * 1/4 < x < 3/10, 1/3 x < < 3/7, 4/7 < x < 2/3, 7/10 < x < 3/4
7780ee5cbfSDavid du Colombier  * with reasonable spread between the bytes & their complements
7880ee5cbfSDavid du Colombier  *
7980ee5cbfSDavid du Colombier  * the 3 byte value appears to be as almost good as the 4 byte value,
8080ee5cbfSDavid du Colombier  * and might be faster on some machines
8180ee5cbfSDavid du Colombier  */
8280ee5cbfSDavid du Colombier /*
8380ee5cbfSDavid du Colombier #define hashit(c)	(((ulong)(c) * 0x6b43a9) >> (24 - HashLog))
8480ee5cbfSDavid du Colombier */
8580ee5cbfSDavid du Colombier #define hashit(c)	((((ulong)(c) & 0xffffff) * 0x6b43a9b5) >> (32 - HashLog))
8680ee5cbfSDavid du Colombier 
8780ee5cbfSDavid du Colombier /*
8880ee5cbfSDavid du Colombier  * lempel-ziv style compression state
8980ee5cbfSDavid du Colombier  */
9080ee5cbfSDavid du Colombier struct LZstate
9180ee5cbfSDavid du Colombier {
9280ee5cbfSDavid du Colombier 	uchar	hist[HistSize];
9380ee5cbfSDavid du Colombier 	ulong	pos;				/* current location in history buffer */
9480ee5cbfSDavid du Colombier 	ulong	avail;				/* data available after pos */
9580ee5cbfSDavid du Colombier 	int	eof;
9680ee5cbfSDavid du Colombier 	ushort	hash[HashSize];			/* hash chains */
9780ee5cbfSDavid du Colombier 	ushort	nexts[MaxOff];
9880ee5cbfSDavid du Colombier 	int	now;				/* pos in hash chains */
9980ee5cbfSDavid du Colombier 	int	dot;				/* dawn of time in history */
10080ee5cbfSDavid du Colombier 	int	prevlen;			/* lazy matching state */
10180ee5cbfSDavid du Colombier 	int	prevoff;
10280ee5cbfSDavid du Colombier 	int	maxcheck;			/* compressor tuning */
10380ee5cbfSDavid du Colombier 
10480ee5cbfSDavid du Colombier 	uchar	obuf[DeflateOut];
10580ee5cbfSDavid du Colombier 	uchar	*out;				/* current position in the output buffer */
10680ee5cbfSDavid du Colombier 	uchar	*eout;
10780ee5cbfSDavid du Colombier 	ulong	bits;				/* bit shift register */
10880ee5cbfSDavid du Colombier 	int	nbits;
10980ee5cbfSDavid du Colombier 	int	rbad;				/* got an error reading the buffer */
11080ee5cbfSDavid du Colombier 	int	wbad;				/* got an error writing the buffer */
11180ee5cbfSDavid du Colombier 	int	(*w)(void*, void*, int);
11280ee5cbfSDavid du Colombier 	void	*wr;
11380ee5cbfSDavid du Colombier 
11480ee5cbfSDavid du Colombier 	ulong	totr;				/* total input size */
11580ee5cbfSDavid du Colombier 	ulong	totw;				/* total output size */
11680ee5cbfSDavid du Colombier 	int	debug;
11780ee5cbfSDavid du Colombier };
11880ee5cbfSDavid du Colombier 
11980ee5cbfSDavid du Colombier struct LZblock
12080ee5cbfSDavid du Colombier {
12180ee5cbfSDavid du Colombier 	ushort	parse[DeflateMaxBlock / 2 + 1];
12280ee5cbfSDavid du Colombier 	int	lastv;				/* value being constucted for parse */
12380ee5cbfSDavid du Colombier 	ulong	litlencount[Nlitlen];
12480ee5cbfSDavid du Colombier 	ulong	offcount[Noff];
12580ee5cbfSDavid du Colombier 	ushort	*eparse;			/* limit for parse table */
12680ee5cbfSDavid du Colombier 	int	bytes;				/* consumed from the input */
12780ee5cbfSDavid du Colombier 	int	excost;				/* cost of encoding extra len & off bits */
12880ee5cbfSDavid du Colombier };
12980ee5cbfSDavid du Colombier 
13080ee5cbfSDavid du Colombier /*
13180ee5cbfSDavid du Colombier  * huffman code table
13280ee5cbfSDavid du Colombier  */
13380ee5cbfSDavid du Colombier struct Huff
13480ee5cbfSDavid du Colombier {
13580ee5cbfSDavid du Colombier 	short	bits;				/* length of the code */
13680ee5cbfSDavid du Colombier 	ushort	encode;				/* the code */
13780ee5cbfSDavid du Colombier };
13880ee5cbfSDavid du Colombier 
13980ee5cbfSDavid du Colombier /*
14080ee5cbfSDavid du Colombier  * encoding of dynamic huffman trees
14180ee5cbfSDavid du Colombier  */
14280ee5cbfSDavid du Colombier struct Dyncode
14380ee5cbfSDavid du Colombier {
14480ee5cbfSDavid du Colombier 	int	nlit;
14580ee5cbfSDavid du Colombier 	int	noff;
14680ee5cbfSDavid du Colombier 	int	nclen;
14780ee5cbfSDavid du Colombier 	int	ncode;
14880ee5cbfSDavid du Colombier 	Huff	codetab[Nclen];
14980ee5cbfSDavid du Colombier 	uchar	codes[Nlitlen+Noff];
15080ee5cbfSDavid du Colombier 	uchar	codeaux[Nlitlen+Noff];
15180ee5cbfSDavid du Colombier };
15280ee5cbfSDavid du Colombier 
15380ee5cbfSDavid du Colombier static	int	deflateb(LZstate *lz, LZblock *lzb, void *rr, int (*r)(void*, void*, int));
15480ee5cbfSDavid du Colombier static	int	lzcomp(LZstate*, LZblock*, uchar*, ushort*, int finish);
15580ee5cbfSDavid du Colombier static	void	wrblock(LZstate*, int, ushort*, ushort*, Huff*, Huff*);
15680ee5cbfSDavid du Colombier static	int	bitcost(Huff*, ulong*, int);
15780ee5cbfSDavid du Colombier static	int	huffcodes(Dyncode*, Huff*, Huff*);
15880ee5cbfSDavid du Colombier static	void	wrdyncode(LZstate*, Dyncode*);
15980ee5cbfSDavid du Colombier static	void	lzput(LZstate*, ulong bits, int nbits);
16080ee5cbfSDavid du Colombier static	void	lzflushbits(LZstate*);
16180ee5cbfSDavid du Colombier static	void	lzflush(LZstate *lz);
16280ee5cbfSDavid du Colombier static	void	lzwrite(LZstate *lz, void *buf, int n);
16380ee5cbfSDavid du Colombier 
16480ee5cbfSDavid du Colombier static	int	hufftabinit(Huff*, int, ulong*, int);
16580ee5cbfSDavid du Colombier static	int	mkgzprecode(Huff*, ulong *, int, int);
16680ee5cbfSDavid du Colombier 
16780ee5cbfSDavid du Colombier static	int	mkprecode(Huff*, ulong *, int, int, ulong*);
16880ee5cbfSDavid du Colombier static	void	nextchain(Chains*, int);
16980ee5cbfSDavid du Colombier static	void	leafsort(ulong*, ushort*, int, int);
17080ee5cbfSDavid du Colombier 
17180ee5cbfSDavid du Colombier /* conversion from len to code word */
17280ee5cbfSDavid du Colombier static int lencode[MaxMatch];
17380ee5cbfSDavid du Colombier 
17480ee5cbfSDavid du Colombier /*
17580ee5cbfSDavid du Colombier  * conversion from off to code word
17680ee5cbfSDavid du Colombier  * off <= MaxOffCode ? offcode[off] : bigoffcode[off >> 7]
17780ee5cbfSDavid du Colombier */
17880ee5cbfSDavid du Colombier static int offcode[MaxOffCode];
17980ee5cbfSDavid du Colombier static int bigoffcode[256];
18080ee5cbfSDavid du Colombier 
18180ee5cbfSDavid du Colombier /* litlen code words LenStart-285 extra bits */
18280ee5cbfSDavid du Colombier static int litlenbase[Nlitlen-LenStart];
18380ee5cbfSDavid du Colombier static int litlenextra[Nlitlen-LenStart] =
18480ee5cbfSDavid du Colombier {
18580ee5cbfSDavid du Colombier /* 257 */	0, 0, 0,
18680ee5cbfSDavid du Colombier /* 260 */	0, 0, 0, 0, 0, 1, 1, 1, 1, 2,
18780ee5cbfSDavid du Colombier /* 270 */	2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
18880ee5cbfSDavid du Colombier /* 280 */	4, 5, 5, 5, 5, 0, 0, 0
18980ee5cbfSDavid du Colombier };
19080ee5cbfSDavid du Colombier 
19180ee5cbfSDavid du Colombier /* offset code word extra bits */
19280ee5cbfSDavid du Colombier static int offbase[Noff];
19380ee5cbfSDavid du Colombier static int offextra[] =
19480ee5cbfSDavid du Colombier {
19580ee5cbfSDavid du Colombier 	0,  0,  0,  0,  1,  1,  2,  2,  3,  3,
19680ee5cbfSDavid du Colombier 	4,  4,  5,  5,  6,  6,  7,  7,  8,  8,
19780ee5cbfSDavid du Colombier 	9,  9,  10, 10, 11, 11, 12, 12, 13, 13,
19880ee5cbfSDavid du Colombier 	0,  0,
19980ee5cbfSDavid du Colombier };
20080ee5cbfSDavid du Colombier 
20180ee5cbfSDavid du Colombier /* order code lengths */
20280ee5cbfSDavid du Colombier static int clenorder[Nclen] =
20380ee5cbfSDavid du Colombier {
20480ee5cbfSDavid du Colombier         16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
20580ee5cbfSDavid du Colombier };
20680ee5cbfSDavid du Colombier 
20780ee5cbfSDavid du Colombier /* static huffman tables */
20880ee5cbfSDavid du Colombier static	Huff	litlentab[Nlitlen];
20980ee5cbfSDavid du Colombier static	Huff	offtab[Noff];
21080ee5cbfSDavid du Colombier static	Huff	hofftab[Noff];
21180ee5cbfSDavid du Colombier 
21280ee5cbfSDavid du Colombier /* bit reversal for brain dead endian swap in huffman codes */
21380ee5cbfSDavid du Colombier static	uchar	revtab[256];
21480ee5cbfSDavid du Colombier static	ulong	nlits;
21580ee5cbfSDavid du Colombier static	ulong	nmatches;
21680ee5cbfSDavid du Colombier 
21780ee5cbfSDavid du Colombier int
deflateinit(void)21880ee5cbfSDavid du Colombier deflateinit(void)
21980ee5cbfSDavid du Colombier {
22080ee5cbfSDavid du Colombier 	ulong bitcount[MaxHuffBits];
22180ee5cbfSDavid du Colombier 	int i, j, ci, n;
22280ee5cbfSDavid du Colombier 
22380ee5cbfSDavid du Colombier 	/* byte reverse table */
22480ee5cbfSDavid du Colombier 	for(i=0; i<256; i++)
22580ee5cbfSDavid du Colombier 		for(j=0; j<8; j++)
22680ee5cbfSDavid du Colombier 			if(i & (1<<j))
22780ee5cbfSDavid du Colombier 				revtab[i] |= 0x80 >> j;
22880ee5cbfSDavid du Colombier 
22980ee5cbfSDavid du Colombier 	/* static Litlen bit lengths */
23080ee5cbfSDavid du Colombier 	for(i=0; i<144; i++)
23180ee5cbfSDavid du Colombier 		litlentab[i].bits = 8;
23280ee5cbfSDavid du Colombier 	for(i=144; i<256; i++)
23380ee5cbfSDavid du Colombier 		litlentab[i].bits = 9;
23480ee5cbfSDavid du Colombier 	for(i=256; i<280; i++)
23580ee5cbfSDavid du Colombier 		litlentab[i].bits = 7;
23680ee5cbfSDavid du Colombier 	for(i=280; i<Nlitlen; i++)
23780ee5cbfSDavid du Colombier 		litlentab[i].bits = 8;
23880ee5cbfSDavid du Colombier 
23980ee5cbfSDavid du Colombier 	memset(bitcount, 0, sizeof(bitcount));
24080ee5cbfSDavid du Colombier 	bitcount[8] += 144 - 0;
24180ee5cbfSDavid du Colombier 	bitcount[9] += 256 - 144;
24280ee5cbfSDavid du Colombier 	bitcount[7] += 280 - 256;
24380ee5cbfSDavid du Colombier 	bitcount[8] += Nlitlen - 280;
24480ee5cbfSDavid du Colombier 
24580ee5cbfSDavid du Colombier 	if(!hufftabinit(litlentab, Nlitlen, bitcount, 9))
24680ee5cbfSDavid du Colombier 		return FlateInternal;
24780ee5cbfSDavid du Colombier 
24880ee5cbfSDavid du Colombier 	/* static offset bit lengths */
24980ee5cbfSDavid du Colombier 	for(i = 0; i < Noff; i++)
25080ee5cbfSDavid du Colombier 		offtab[i].bits = 5;
25180ee5cbfSDavid du Colombier 
25280ee5cbfSDavid du Colombier 	memset(bitcount, 0, sizeof(bitcount));
25380ee5cbfSDavid du Colombier 	bitcount[5] = Noff;
25480ee5cbfSDavid du Colombier 
25580ee5cbfSDavid du Colombier 	if(!hufftabinit(offtab, Noff, bitcount, 5))
25680ee5cbfSDavid du Colombier 		return FlateInternal;
25780ee5cbfSDavid du Colombier 
25880ee5cbfSDavid du Colombier 	bitcount[0] = 0;
25980ee5cbfSDavid du Colombier 	bitcount[1] = 0;
26080ee5cbfSDavid du Colombier 	if(!mkgzprecode(hofftab, bitcount, 2, MaxHuffBits))
26180ee5cbfSDavid du Colombier 		return FlateInternal;
26280ee5cbfSDavid du Colombier 
26380ee5cbfSDavid du Colombier 	/* conversion tables for lens & offs to codes */
26480ee5cbfSDavid du Colombier 	ci = 0;
26580ee5cbfSDavid du Colombier 	for(i = LenStart; i < 286; i++){
26680ee5cbfSDavid du Colombier 		n = ci + (1 << litlenextra[i - LenStart]);
26780ee5cbfSDavid du Colombier 		litlenbase[i - LenStart] = ci;
26880ee5cbfSDavid du Colombier 		for(; ci < n; ci++)
26980ee5cbfSDavid du Colombier 			lencode[ci] = i;
27080ee5cbfSDavid du Colombier 	}
27180ee5cbfSDavid du Colombier 	/* patch up special case for len MaxMatch */
27280ee5cbfSDavid du Colombier 	lencode[MaxMatch-MinMatch] = 285;
27380ee5cbfSDavid du Colombier 	litlenbase[285-LenStart] = MaxMatch-MinMatch;
27480ee5cbfSDavid du Colombier 
27580ee5cbfSDavid du Colombier 	ci = 0;
27680ee5cbfSDavid du Colombier 	for(i = 0; i < 16; i++){
27780ee5cbfSDavid du Colombier 		n = ci + (1 << offextra[i]);
27880ee5cbfSDavid du Colombier 		offbase[i] = ci;
27980ee5cbfSDavid du Colombier 		for(; ci < n; ci++)
28080ee5cbfSDavid du Colombier 			offcode[ci] = i;
28180ee5cbfSDavid du Colombier 	}
28280ee5cbfSDavid du Colombier 
28380ee5cbfSDavid du Colombier 	ci = ci >> 7;
28480ee5cbfSDavid du Colombier 	for(; i < 30; i++){
28580ee5cbfSDavid du Colombier 		n = ci + (1 << (offextra[i] - 7));
28680ee5cbfSDavid du Colombier 		offbase[i] = ci << 7;
28780ee5cbfSDavid du Colombier 		for(; ci < n; ci++)
28880ee5cbfSDavid du Colombier 			bigoffcode[ci] = i;
28980ee5cbfSDavid du Colombier 	}
29080ee5cbfSDavid du Colombier 	return FlateOk;
29180ee5cbfSDavid du Colombier }
29280ee5cbfSDavid du Colombier 
29380ee5cbfSDavid du Colombier static void
deflatereset(LZstate * lz,int level,int debug)29480ee5cbfSDavid du Colombier deflatereset(LZstate *lz, int level, int debug)
29580ee5cbfSDavid du Colombier {
29680ee5cbfSDavid du Colombier 	memset(lz->nexts, 0, sizeof lz->nexts);
29780ee5cbfSDavid du Colombier 	memset(lz->hash, 0, sizeof lz->hash);
29880ee5cbfSDavid du Colombier 	lz->totr = 0;
29980ee5cbfSDavid du Colombier 	lz->totw = 0;
30080ee5cbfSDavid du Colombier 	lz->pos = 0;
30180ee5cbfSDavid du Colombier 	lz->avail = 0;
30280ee5cbfSDavid du Colombier 	lz->out = lz->obuf;
30380ee5cbfSDavid du Colombier 	lz->eout = &lz->obuf[DeflateOut];
30480ee5cbfSDavid du Colombier 	lz->prevlen = MinMatch - 1;
30580ee5cbfSDavid du Colombier 	lz->prevoff = 0;
30680ee5cbfSDavid du Colombier 	lz->now = MaxOff + 1;
30780ee5cbfSDavid du Colombier 	lz->dot = lz->now;
30880ee5cbfSDavid du Colombier 	lz->bits = 0;
30980ee5cbfSDavid du Colombier 	lz->nbits = 0;
31080ee5cbfSDavid du Colombier 	lz->maxcheck = (1 << level);
31180ee5cbfSDavid du Colombier 	lz->maxcheck -= lz->maxcheck >> 2;
31280ee5cbfSDavid du Colombier 	if(lz->maxcheck < 2)
31380ee5cbfSDavid du Colombier 		lz->maxcheck = 2;
31480ee5cbfSDavid du Colombier 	else if(lz->maxcheck > 1024)
31580ee5cbfSDavid du Colombier 		lz->maxcheck = 1024;
31680ee5cbfSDavid du Colombier 
31780ee5cbfSDavid du Colombier 	lz->debug = debug;
31880ee5cbfSDavid du Colombier }
31980ee5cbfSDavid du Colombier 
32080ee5cbfSDavid du Colombier int
deflate(void * wr,int (* w)(void *,void *,int),void * rr,int (* r)(void *,void *,int),int level,int debug)32180ee5cbfSDavid du Colombier deflate(void *wr, int (*w)(void*, void*, int), void *rr, int (*r)(void*, void*, int), int level, int debug)
32280ee5cbfSDavid du Colombier {
32380ee5cbfSDavid du Colombier 	LZstate *lz;
32480ee5cbfSDavid du Colombier 	LZblock *lzb;
32580ee5cbfSDavid du Colombier 	int ok;
32680ee5cbfSDavid du Colombier 
32780ee5cbfSDavid du Colombier 	lz = malloc(sizeof *lz + sizeof *lzb);
32880ee5cbfSDavid du Colombier 	if(lz == nil)
32980ee5cbfSDavid du Colombier 		return FlateNoMem;
33080ee5cbfSDavid du Colombier 	lzb = (LZblock*)&lz[1];
33180ee5cbfSDavid du Colombier 
33280ee5cbfSDavid du Colombier 	deflatereset(lz, level, debug);
33380ee5cbfSDavid du Colombier 	lz->w = w;
33480ee5cbfSDavid du Colombier 	lz->wr = wr;
33580ee5cbfSDavid du Colombier 	lz->wbad = 0;
33680ee5cbfSDavid du Colombier 	lz->rbad = 0;
33780ee5cbfSDavid du Colombier 	lz->eof = 0;
33880ee5cbfSDavid du Colombier 	ok = FlateOk;
33980ee5cbfSDavid du Colombier 	while(!lz->eof || lz->avail){
34080ee5cbfSDavid du Colombier 		ok = deflateb(lz, lzb, rr, r);
34180ee5cbfSDavid du Colombier 		if(ok != FlateOk)
34280ee5cbfSDavid du Colombier 			break;
34380ee5cbfSDavid du Colombier 	}
34480ee5cbfSDavid du Colombier 	if(ok == FlateOk && lz->rbad)
34580ee5cbfSDavid du Colombier 		ok = FlateInputFail;
34680ee5cbfSDavid du Colombier 	if(ok == FlateOk && lz->wbad)
34780ee5cbfSDavid du Colombier 		ok = FlateOutputFail;
34880ee5cbfSDavid du Colombier 	free(lz);
34980ee5cbfSDavid du Colombier 	return ok;
35080ee5cbfSDavid du Colombier }
35180ee5cbfSDavid du Colombier 
35280ee5cbfSDavid du Colombier static int
deflateb(LZstate * lz,LZblock * lzb,void * rr,int (* r)(void *,void *,int))35380ee5cbfSDavid du Colombier deflateb(LZstate *lz, LZblock *lzb, void *rr, int (*r)(void*, void*, int))
35480ee5cbfSDavid du Colombier {
35580ee5cbfSDavid du Colombier 	Dyncode dyncode, hdyncode;
35680ee5cbfSDavid du Colombier 	Huff dlitlentab[Nlitlen], dofftab[Noff], hlitlentab[Nlitlen];
35780ee5cbfSDavid du Colombier 	ulong litcount[Nlitlen];
35880ee5cbfSDavid du Colombier 	long nunc, ndyn, nfix, nhuff;
35980ee5cbfSDavid du Colombier 	uchar *slop, *hslop;
36080ee5cbfSDavid du Colombier 	ulong ep;
36180ee5cbfSDavid du Colombier 	int i, n, m, mm, nslop;
36280ee5cbfSDavid du Colombier 
36380ee5cbfSDavid du Colombier 	memset(lzb->litlencount, 0, sizeof lzb->litlencount);
36480ee5cbfSDavid du Colombier 	memset(lzb->offcount, 0, sizeof lzb->offcount);
36580ee5cbfSDavid du Colombier 	lzb->litlencount[DeflateEob]++;
36680ee5cbfSDavid du Colombier 
36780ee5cbfSDavid du Colombier 	lzb->bytes = 0;
36880ee5cbfSDavid du Colombier 	lzb->eparse = lzb->parse;
36980ee5cbfSDavid du Colombier 	lzb->lastv = 0;
37080ee5cbfSDavid du Colombier 	lzb->excost = 0;
37180ee5cbfSDavid du Colombier 
37280ee5cbfSDavid du Colombier 	slop = &lz->hist[lz->pos];
37380ee5cbfSDavid du Colombier 	n = lz->avail;
37480ee5cbfSDavid du Colombier 	while(n < DeflateBlock && (!lz->eof || lz->avail)){
37580ee5cbfSDavid du Colombier 		/*
37680ee5cbfSDavid du Colombier 		 * fill the buffer as much as possible,
37780ee5cbfSDavid du Colombier 		 * while leaving room for MaxOff history behind lz->pos,
37880ee5cbfSDavid du Colombier 		 * and not reading more than we can handle.
37980ee5cbfSDavid du Colombier 		 *
38080ee5cbfSDavid du Colombier 		 * make sure we read at least HistSlop bytes.
38180ee5cbfSDavid du Colombier 		 */
38280ee5cbfSDavid du Colombier 		if(!lz->eof){
38380ee5cbfSDavid du Colombier 			ep = lz->pos + lz->avail;
38480ee5cbfSDavid du Colombier 			if(ep >= HistBlock)
38580ee5cbfSDavid du Colombier 				ep -= HistBlock;
38680ee5cbfSDavid du Colombier 			m = HistBlock - MaxOff - lz->avail;
38780ee5cbfSDavid du Colombier 			if(m > HistBlock - n)
38880ee5cbfSDavid du Colombier 				m = HistBlock - n;
38980ee5cbfSDavid du Colombier 			if(m > (HistBlock + HistSlop) - ep)
39080ee5cbfSDavid du Colombier 				m = (HistBlock + HistSlop) - ep;
39180ee5cbfSDavid du Colombier 			if(m & ~(BlockSize - 1))
39280ee5cbfSDavid du Colombier 				m &= ~(BlockSize - 1);
39380ee5cbfSDavid du Colombier 
39480ee5cbfSDavid du Colombier 			/*
39580ee5cbfSDavid du Colombier 			 * be nice to the caller: stop reads that are too small.
39680ee5cbfSDavid du Colombier 			 * can only get here when we've already filled the buffer some
39780ee5cbfSDavid du Colombier 			 */
39880ee5cbfSDavid du Colombier 			if(m < HistSlop){
39980ee5cbfSDavid du Colombier 				if(!m || !lzb->bytes)
40080ee5cbfSDavid du Colombier 					return FlateInternal;
40180ee5cbfSDavid du Colombier 				break;
40280ee5cbfSDavid du Colombier 			}
40380ee5cbfSDavid du Colombier 
40480ee5cbfSDavid du Colombier 			mm = (*r)(rr, &lz->hist[ep], m);
40580ee5cbfSDavid du Colombier 			if(mm > 0){
40680ee5cbfSDavid du Colombier 				/*
40780ee5cbfSDavid du Colombier 				 * wrap data to end if we're read it from the beginning
40880ee5cbfSDavid du Colombier 				 * this way, we don't have to wrap searches.
40980ee5cbfSDavid du Colombier 				 *
41080ee5cbfSDavid du Colombier 				 * wrap reads past the end to the beginning.
41180ee5cbfSDavid du Colombier 				 * this way, we can guarantee minimum size reads.
41280ee5cbfSDavid du Colombier 				 */
41380ee5cbfSDavid du Colombier 				if(ep < HistSlop)
41480ee5cbfSDavid du Colombier 					memmove(&lz->hist[ep + HistBlock], &lz->hist[ep], HistSlop - ep);
41580ee5cbfSDavid du Colombier 				else if(ep + mm > HistBlock)
41680ee5cbfSDavid du Colombier 					memmove(&lz->hist[0], &lz->hist[HistBlock], ep + mm - HistBlock);
41780ee5cbfSDavid du Colombier 
41880ee5cbfSDavid du Colombier 				lz->totr += mm;
41980ee5cbfSDavid du Colombier 				n += mm;
42080ee5cbfSDavid du Colombier 				lz->avail += mm;
42180ee5cbfSDavid du Colombier 			}else{
42280ee5cbfSDavid du Colombier 				if(mm < 0)
42380ee5cbfSDavid du Colombier 					lz->rbad = 1;
42480ee5cbfSDavid du Colombier 				lz->eof = 1;
42580ee5cbfSDavid du Colombier 			}
42680ee5cbfSDavid du Colombier 		}
42780ee5cbfSDavid du Colombier 		ep = lz->pos + lz->avail;
42880ee5cbfSDavid du Colombier 		if(ep > HistSize)
42980ee5cbfSDavid du Colombier 			ep = HistSize;
43080ee5cbfSDavid du Colombier 		if(lzb->bytes + ep - lz->pos > DeflateMaxBlock)
43180ee5cbfSDavid du Colombier 			ep = lz->pos + DeflateMaxBlock - lzb->bytes;
43280ee5cbfSDavid du Colombier 		m = lzcomp(lz, lzb, &lz->hist[ep], lzb->eparse, lz->eof);
43380ee5cbfSDavid du Colombier 		lzb->bytes += m;
43480ee5cbfSDavid du Colombier 		lz->pos = (lz->pos + m) & (HistBlock - 1);
43580ee5cbfSDavid du Colombier 		lz->avail -= m;
43680ee5cbfSDavid du Colombier 	}
43780ee5cbfSDavid du Colombier 	if(lzb->lastv)
43880ee5cbfSDavid du Colombier 		*lzb->eparse++ = lzb->lastv;
43980ee5cbfSDavid du Colombier 	if(lzb->eparse > lzb->parse + nelem(lzb->parse))
44080ee5cbfSDavid du Colombier 		return FlateInternal;
44180ee5cbfSDavid du Colombier 	nunc = lzb->bytes;
44280ee5cbfSDavid du Colombier 
44380ee5cbfSDavid du Colombier 	if(!mkgzprecode(dlitlentab, lzb->litlencount, Nlitlen, MaxHuffBits)
44480ee5cbfSDavid du Colombier 	|| !mkgzprecode(dofftab, lzb->offcount, Noff, MaxHuffBits))
44580ee5cbfSDavid du Colombier 		return FlateInternal;
44680ee5cbfSDavid du Colombier 
44780ee5cbfSDavid du Colombier 	ndyn = huffcodes(&dyncode, dlitlentab, dofftab);
44880ee5cbfSDavid du Colombier 	if(ndyn < 0)
44980ee5cbfSDavid du Colombier 		return FlateInternal;
45080ee5cbfSDavid du Colombier 	ndyn += bitcost(dlitlentab, lzb->litlencount, Nlitlen)
45180ee5cbfSDavid du Colombier 		+ bitcost(dofftab, lzb->offcount, Noff)
45280ee5cbfSDavid du Colombier 		+ lzb->excost;
45380ee5cbfSDavid du Colombier 
45480ee5cbfSDavid du Colombier 	memset(litcount, 0, sizeof litcount);
45580ee5cbfSDavid du Colombier 
45680ee5cbfSDavid du Colombier 	nslop = nunc;
45780ee5cbfSDavid du Colombier 	if(nslop > &lz->hist[HistSize] - slop)
45880ee5cbfSDavid du Colombier 		nslop = &lz->hist[HistSize] - slop;
45980ee5cbfSDavid du Colombier 
46080ee5cbfSDavid du Colombier 	for(i = 0; i < nslop; i++)
46180ee5cbfSDavid du Colombier 		litcount[slop[i]]++;
46280ee5cbfSDavid du Colombier 	hslop = &lz->hist[HistSlop - nslop];
46380ee5cbfSDavid du Colombier 	for(; i < nunc; i++)
46480ee5cbfSDavid du Colombier 		litcount[hslop[i]]++;
46580ee5cbfSDavid du Colombier 	litcount[DeflateEob]++;
46680ee5cbfSDavid du Colombier 
46780ee5cbfSDavid du Colombier 	if(!mkgzprecode(hlitlentab, litcount, Nlitlen, MaxHuffBits))
46880ee5cbfSDavid du Colombier 		return FlateInternal;
46980ee5cbfSDavid du Colombier 	nhuff = huffcodes(&hdyncode, hlitlentab, hofftab);
47080ee5cbfSDavid du Colombier 	if(nhuff < 0)
47180ee5cbfSDavid du Colombier 		return FlateInternal;
47280ee5cbfSDavid du Colombier 	nhuff += bitcost(hlitlentab, litcount, Nlitlen);
47380ee5cbfSDavid du Colombier 
47480ee5cbfSDavid du Colombier 	nfix = bitcost(litlentab, lzb->litlencount, Nlitlen)
47580ee5cbfSDavid du Colombier 		+ bitcost(offtab, lzb->offcount, Noff)
47680ee5cbfSDavid du Colombier 		+ lzb->excost;
47780ee5cbfSDavid du Colombier 
47880ee5cbfSDavid du Colombier 	lzput(lz, lz->eof && !lz->avail, 1);
47980ee5cbfSDavid du Colombier 
48080ee5cbfSDavid du Colombier 	if(lz->debug){
48180ee5cbfSDavid du Colombier 		fprint(2, "block: bytes=%lud entries=%ld extra bits=%d\n\tuncompressed=%lud fixed=%lud dynamic=%lud huffman=%lud\n",
48280ee5cbfSDavid du Colombier 			nunc, lzb->eparse - lzb->parse, lzb->excost, (nunc + 4) * 8, nfix, ndyn, nhuff);
48380ee5cbfSDavid du Colombier 		fprint(2, "\tnlit=%lud matches=%lud eof=%d\n", nlits, nmatches, lz->eof && !lz->avail);
48480ee5cbfSDavid du Colombier 	}
48580ee5cbfSDavid du Colombier 
48680ee5cbfSDavid du Colombier 	if((nunc + 4) * 8 < ndyn && (nunc + 4) * 8 < nfix && (nunc + 4) * 8 < nhuff){
48780ee5cbfSDavid du Colombier 		lzput(lz, DeflateUnc, 2);
48880ee5cbfSDavid du Colombier 		lzflushbits(lz);
48980ee5cbfSDavid du Colombier 
49080ee5cbfSDavid du Colombier 		lzput(lz, nunc & 0xff, 8);
49180ee5cbfSDavid du Colombier 		lzput(lz, (nunc >> 8) & 0xff, 8);
49280ee5cbfSDavid du Colombier 		lzput(lz, ~nunc & 0xff, 8);
49380ee5cbfSDavid du Colombier 		lzput(lz, (~nunc >> 8) & 0xff, 8);
49480ee5cbfSDavid du Colombier 		lzflush(lz);
49580ee5cbfSDavid du Colombier 
49680ee5cbfSDavid du Colombier 		lzwrite(lz, slop, nslop);
49780ee5cbfSDavid du Colombier 		lzwrite(lz, &lz->hist[HistSlop], nunc - nslop);
49880ee5cbfSDavid du Colombier 	}else if(ndyn < nfix && ndyn < nhuff){
49980ee5cbfSDavid du Colombier 		lzput(lz, DeflateDyn, 2);
50080ee5cbfSDavid du Colombier 
50180ee5cbfSDavid du Colombier 		wrdyncode(lz, &dyncode);
50280ee5cbfSDavid du Colombier 		wrblock(lz, slop - lz->hist, lzb->parse, lzb->eparse, dlitlentab, dofftab);
50380ee5cbfSDavid du Colombier 		lzput(lz, dlitlentab[DeflateEob].encode, dlitlentab[DeflateEob].bits);
50480ee5cbfSDavid du Colombier 	}else if(nhuff < nfix){
50580ee5cbfSDavid du Colombier 		lzput(lz, DeflateDyn, 2);
50680ee5cbfSDavid du Colombier 
50780ee5cbfSDavid du Colombier 		wrdyncode(lz, &hdyncode);
50880ee5cbfSDavid du Colombier 
50980ee5cbfSDavid du Colombier 		m = 0;
51080ee5cbfSDavid du Colombier 		for(i = nunc; i > MaxLitRun; i -= MaxLitRun)
51180ee5cbfSDavid du Colombier 			lzb->parse[m++] = MaxLitRun;
51280ee5cbfSDavid du Colombier 		lzb->parse[m++] = i;
51380ee5cbfSDavid du Colombier 
51480ee5cbfSDavid du Colombier 		wrblock(lz, slop - lz->hist, lzb->parse, lzb->parse + m, hlitlentab, hofftab);
51580ee5cbfSDavid du Colombier 		lzput(lz, hlitlentab[DeflateEob].encode, hlitlentab[DeflateEob].bits);
51680ee5cbfSDavid du Colombier 	}else{
51780ee5cbfSDavid du Colombier 		lzput(lz, DeflateFix, 2);
51880ee5cbfSDavid du Colombier 
51980ee5cbfSDavid du Colombier 		wrblock(lz, slop - lz->hist, lzb->parse, lzb->eparse, litlentab, offtab);
52080ee5cbfSDavid du Colombier 		lzput(lz, litlentab[DeflateEob].encode, litlentab[DeflateEob].bits);
52180ee5cbfSDavid du Colombier 	}
52280ee5cbfSDavid du Colombier 
52380ee5cbfSDavid du Colombier 	if(lz->eof && !lz->avail){
52480ee5cbfSDavid du Colombier 		lzflushbits(lz);
52580ee5cbfSDavid du Colombier 		lzflush(lz);
52680ee5cbfSDavid du Colombier 	}
52780ee5cbfSDavid du Colombier 	return FlateOk;
52880ee5cbfSDavid du Colombier }
52980ee5cbfSDavid du Colombier 
53080ee5cbfSDavid du Colombier static void
lzwrite(LZstate * lz,void * buf,int n)53180ee5cbfSDavid du Colombier lzwrite(LZstate *lz, void *buf, int n)
53280ee5cbfSDavid du Colombier {
53380ee5cbfSDavid du Colombier 	int nw;
53480ee5cbfSDavid du Colombier 
53580ee5cbfSDavid du Colombier 	if(n && lz->w){
53680ee5cbfSDavid du Colombier 		nw = (*lz->w)(lz->wr, buf, n);
53780ee5cbfSDavid du Colombier 		if(nw != n){
53880ee5cbfSDavid du Colombier 			lz->w = nil;
53980ee5cbfSDavid du Colombier 			lz->wbad = 1;
54080ee5cbfSDavid du Colombier 		}else
54180ee5cbfSDavid du Colombier 			lz->totw += n;
54280ee5cbfSDavid du Colombier 	}
54380ee5cbfSDavid du Colombier }
54480ee5cbfSDavid du Colombier 
54580ee5cbfSDavid du Colombier static void
lzflush(LZstate * lz)54680ee5cbfSDavid du Colombier lzflush(LZstate *lz)
54780ee5cbfSDavid du Colombier {
54880ee5cbfSDavid du Colombier 	lzwrite(lz, lz->obuf, lz->out - lz->obuf);
54980ee5cbfSDavid du Colombier 	lz->out = lz->obuf;
55080ee5cbfSDavid du Colombier }
55180ee5cbfSDavid du Colombier 
55280ee5cbfSDavid du Colombier static void
lzput(LZstate * lz,ulong bits,int nbits)55380ee5cbfSDavid du Colombier lzput(LZstate *lz, ulong bits, int nbits)
55480ee5cbfSDavid du Colombier {
55580ee5cbfSDavid du Colombier 	bits = (bits << lz->nbits) | lz->bits;
55680ee5cbfSDavid du Colombier 	for(nbits += lz->nbits; nbits >= 8; nbits -= 8){
55780ee5cbfSDavid du Colombier 		*lz->out++ = bits;
55880ee5cbfSDavid du Colombier 		if(lz->out == lz->eout)
55980ee5cbfSDavid du Colombier 			lzflush(lz);
56080ee5cbfSDavid du Colombier 		bits >>= 8;
56180ee5cbfSDavid du Colombier 	}
56280ee5cbfSDavid du Colombier 	lz->bits = bits;
56380ee5cbfSDavid du Colombier 	lz->nbits = nbits;
56480ee5cbfSDavid du Colombier }
56580ee5cbfSDavid du Colombier 
56680ee5cbfSDavid du Colombier static void
lzflushbits(LZstate * lz)56780ee5cbfSDavid du Colombier lzflushbits(LZstate *lz)
56880ee5cbfSDavid du Colombier {
56980ee5cbfSDavid du Colombier 	if(lz->nbits)
57080ee5cbfSDavid du Colombier 		lzput(lz, 0, 8 - (lz->nbits & 7));
57180ee5cbfSDavid du Colombier }
57280ee5cbfSDavid du Colombier 
57380ee5cbfSDavid du Colombier /*
57480ee5cbfSDavid du Colombier  * write out a block of n samples,
57580ee5cbfSDavid du Colombier  * given lz encoding and counts for huffman tables
57680ee5cbfSDavid du Colombier  */
57780ee5cbfSDavid du Colombier static void
wrblock(LZstate * out,int litoff,ushort * soff,ushort * eoff,Huff * litlentab,Huff * offtab)57880ee5cbfSDavid du Colombier wrblock(LZstate *out, int litoff, ushort *soff, ushort *eoff, Huff *litlentab, Huff *offtab)
57980ee5cbfSDavid du Colombier {
58080ee5cbfSDavid du Colombier 	ushort *off;
58180ee5cbfSDavid du Colombier 	int i, run, offset, lit, len, c;
58280ee5cbfSDavid du Colombier 
58380ee5cbfSDavid du Colombier 	if(out->debug > 2){
58480ee5cbfSDavid du Colombier 		for(off = soff; off < eoff; ){
58580ee5cbfSDavid du Colombier 			offset = *off++;
58680ee5cbfSDavid du Colombier 			run = offset & MaxLitRun;
58780ee5cbfSDavid du Colombier 			if(run){
58880ee5cbfSDavid du Colombier 				for(i = 0; i < run; i++){
58980ee5cbfSDavid du Colombier 					lit = out->hist[litoff & (HistBlock - 1)];
59080ee5cbfSDavid du Colombier 					litoff++;
59180ee5cbfSDavid du Colombier 					fprint(2, "\tlit %.2ux %c\n", lit, lit);
59280ee5cbfSDavid du Colombier 				}
59380ee5cbfSDavid du Colombier 				if(!(offset & LenFlag))
59480ee5cbfSDavid du Colombier 					continue;
59580ee5cbfSDavid du Colombier 				len = offset >> LenShift;
59680ee5cbfSDavid du Colombier 				offset = *off++;
59780ee5cbfSDavid du Colombier 			}else if(offset & LenFlag){
59880ee5cbfSDavid du Colombier 				len = offset >> LenShift;
59980ee5cbfSDavid du Colombier 				offset = *off++;
60080ee5cbfSDavid du Colombier 			}else{
60180ee5cbfSDavid du Colombier 				len = 0;
60280ee5cbfSDavid du Colombier 				offset >>= LenShift;
60380ee5cbfSDavid du Colombier 			}
60480ee5cbfSDavid du Colombier 			litoff += len + MinMatch;
60580ee5cbfSDavid du Colombier 			fprint(2, "\t<%d, %d>\n", offset + 1, len + MinMatch);
60680ee5cbfSDavid du Colombier 		}
60780ee5cbfSDavid du Colombier 	}
60880ee5cbfSDavid du Colombier 
60980ee5cbfSDavid du Colombier 	for(off = soff; off < eoff; ){
61080ee5cbfSDavid du Colombier 		offset = *off++;
61180ee5cbfSDavid du Colombier 		run = offset & MaxLitRun;
61280ee5cbfSDavid du Colombier 		if(run){
61380ee5cbfSDavid du Colombier 			for(i = 0; i < run; i++){
61480ee5cbfSDavid du Colombier 				lit = out->hist[litoff & (HistBlock - 1)];
61580ee5cbfSDavid du Colombier 				litoff++;
61680ee5cbfSDavid du Colombier 				lzput(out, litlentab[lit].encode, litlentab[lit].bits);
61780ee5cbfSDavid du Colombier 			}
61880ee5cbfSDavid du Colombier 			if(!(offset & LenFlag))
61980ee5cbfSDavid du Colombier 				continue;
62080ee5cbfSDavid du Colombier 			len = offset >> LenShift;
62180ee5cbfSDavid du Colombier 			offset = *off++;
62280ee5cbfSDavid du Colombier 		}else if(offset & LenFlag){
62380ee5cbfSDavid du Colombier 			len = offset >> LenShift;
62480ee5cbfSDavid du Colombier 			offset = *off++;
62580ee5cbfSDavid du Colombier 		}else{
62680ee5cbfSDavid du Colombier 			len = 0;
62780ee5cbfSDavid du Colombier 			offset >>= LenShift;
62880ee5cbfSDavid du Colombier 		}
62980ee5cbfSDavid du Colombier 		litoff += len + MinMatch;
63080ee5cbfSDavid du Colombier 		c = lencode[len];
63180ee5cbfSDavid du Colombier 		lzput(out, litlentab[c].encode, litlentab[c].bits);
63280ee5cbfSDavid du Colombier 		c -= LenStart;
63380ee5cbfSDavid du Colombier 		if(litlenextra[c])
63480ee5cbfSDavid du Colombier 			lzput(out, len - litlenbase[c], litlenextra[c]);
63580ee5cbfSDavid du Colombier 
63680ee5cbfSDavid du Colombier 		if(offset < MaxOffCode)
63780ee5cbfSDavid du Colombier 			c = offcode[offset];
63880ee5cbfSDavid du Colombier 		else
63980ee5cbfSDavid du Colombier 			c = bigoffcode[offset >> 7];
64080ee5cbfSDavid du Colombier 		lzput(out, offtab[c].encode, offtab[c].bits);
64180ee5cbfSDavid du Colombier 		if(offextra[c])
64280ee5cbfSDavid du Colombier 			lzput(out, offset - offbase[c], offextra[c]);
64380ee5cbfSDavid du Colombier 	}
64480ee5cbfSDavid du Colombier }
64580ee5cbfSDavid du Colombier 
64680ee5cbfSDavid du Colombier /*
64780ee5cbfSDavid du Colombier  * look for the longest, closest string which matches
64880ee5cbfSDavid du Colombier  * the next prefix.  the clever part here is looking for
64980ee5cbfSDavid du Colombier  * a string 1 longer than the previous best match.
65080ee5cbfSDavid du Colombier  *
65180ee5cbfSDavid du Colombier  * follows the recommendation of limiting number of chains
65280ee5cbfSDavid du Colombier  * which are checked.  this appears to be the best heuristic.
65380ee5cbfSDavid du Colombier  */
65480ee5cbfSDavid du Colombier static int
lzmatch(int now,int then,uchar * p,uchar * es,ushort * nexts,uchar * hist,int runlen,int check,int * m)65580ee5cbfSDavid du Colombier lzmatch(int now, int then, uchar *p, uchar *es, ushort *nexts, uchar *hist, int runlen, int check, int *m)
65680ee5cbfSDavid du Colombier {
65780ee5cbfSDavid du Colombier 	uchar *s, *t;
65880ee5cbfSDavid du Colombier 	int ml, off, last;
65980ee5cbfSDavid du Colombier 
66080ee5cbfSDavid du Colombier 	ml = check;
66180ee5cbfSDavid du Colombier 	if(runlen >= 8)
66280ee5cbfSDavid du Colombier 		check >>= 2;
66380ee5cbfSDavid du Colombier 	*m = 0;
66480ee5cbfSDavid du Colombier 	if(p + runlen >= es)
66580ee5cbfSDavid du Colombier 		return runlen;
66680ee5cbfSDavid du Colombier 	last = 0;
66780ee5cbfSDavid du Colombier 	for(; check-- > 0; then = nexts[then & (MaxOff-1)]){
66880ee5cbfSDavid du Colombier 		off = (ushort)(now - then);
66980ee5cbfSDavid du Colombier 		if(off <= last || off > MaxOff)
67080ee5cbfSDavid du Colombier 			break;
67180ee5cbfSDavid du Colombier 		s = p + runlen;
67280ee5cbfSDavid du Colombier 		t = hist + (((p - hist) - off) & (HistBlock-1));
67380ee5cbfSDavid du Colombier 		t += runlen;
67480ee5cbfSDavid du Colombier 		for(; s >= p; s--){
67580ee5cbfSDavid du Colombier 			if(*s != *t)
67680ee5cbfSDavid du Colombier 				goto matchloop;
67780ee5cbfSDavid du Colombier 			t--;
67880ee5cbfSDavid du Colombier 		}
67980ee5cbfSDavid du Colombier 
68080ee5cbfSDavid du Colombier 		/*
68180ee5cbfSDavid du Colombier 		 * we have a new best match.
68280ee5cbfSDavid du Colombier 		 * extend it to it's maximum length
68380ee5cbfSDavid du Colombier 		 */
68480ee5cbfSDavid du Colombier 		t += runlen + 2;
68580ee5cbfSDavid du Colombier 		s += runlen + 2;
68680ee5cbfSDavid du Colombier 		for(; s < es; s++){
68780ee5cbfSDavid du Colombier 			if(*s != *t)
68880ee5cbfSDavid du Colombier 				break;
68980ee5cbfSDavid du Colombier 			t++;
69080ee5cbfSDavid du Colombier 		}
69180ee5cbfSDavid du Colombier 		runlen = s - p;
69280ee5cbfSDavid du Colombier 		*m = off - 1;
69380ee5cbfSDavid du Colombier 		if(s == es || runlen > ml)
69480ee5cbfSDavid du Colombier 			break;
69580ee5cbfSDavid du Colombier matchloop:;
69680ee5cbfSDavid du Colombier 		last = off;
69780ee5cbfSDavid du Colombier 	}
69880ee5cbfSDavid du Colombier 	return runlen;
69980ee5cbfSDavid du Colombier }
70080ee5cbfSDavid du Colombier 
70180ee5cbfSDavid du Colombier static int
lzcomp(LZstate * lz,LZblock * lzb,uchar * ep,ushort * parse,int finish)70280ee5cbfSDavid du Colombier lzcomp(LZstate *lz, LZblock *lzb, uchar *ep, ushort *parse, int finish)
70380ee5cbfSDavid du Colombier {
70480ee5cbfSDavid du Colombier 	ulong cont, excost, *litlencount, *offcount;
70580ee5cbfSDavid du Colombier 	uchar *p, *q, *s, *es;
70680ee5cbfSDavid du Colombier 	ushort *nexts, *hash;
70780ee5cbfSDavid du Colombier 	int v, i, h, runlen, n, now, then, m, prevlen, prevoff, maxdefer;
70880ee5cbfSDavid du Colombier 
70980ee5cbfSDavid du Colombier 	litlencount = lzb->litlencount;
71080ee5cbfSDavid du Colombier 	offcount = lzb->offcount;
71180ee5cbfSDavid du Colombier 	nexts = lz->nexts;
71280ee5cbfSDavid du Colombier 	hash = lz->hash;
71380ee5cbfSDavid du Colombier 	now = lz->now;
71480ee5cbfSDavid du Colombier 
71580ee5cbfSDavid du Colombier 	p = &lz->hist[lz->pos];
71680ee5cbfSDavid du Colombier 	if(lz->prevlen != MinMatch - 1)
71780ee5cbfSDavid du Colombier 		p++;
71880ee5cbfSDavid du Colombier 
71980ee5cbfSDavid du Colombier 	/*
72080ee5cbfSDavid du Colombier 	 * hash in the links for any hanging link positions,
72180ee5cbfSDavid du Colombier 	 * and calculate the hash for the current position.
72280ee5cbfSDavid du Colombier 	 */
72380ee5cbfSDavid du Colombier 	n = MinMatch;
72480ee5cbfSDavid du Colombier 	if(n > ep - p)
72580ee5cbfSDavid du Colombier 		n = ep - p;
72680ee5cbfSDavid du Colombier 	cont = 0;
72780ee5cbfSDavid du Colombier 	for(i = 0; i < n - 1; i++){
72880ee5cbfSDavid du Colombier 		m = now - ((MinMatch-1) - i);
72980ee5cbfSDavid du Colombier 		if(m < lz->dot)
73080ee5cbfSDavid du Colombier 			continue;
73180ee5cbfSDavid du Colombier 		s = lz->hist + (((p - lz->hist) - (now - m)) & (HistBlock-1));
73280ee5cbfSDavid du Colombier 
73380ee5cbfSDavid du Colombier 		cont = (s[0] << 16) | (s[1] << 8) | s[2];
73480ee5cbfSDavid du Colombier 		h = hashit(cont);
73580ee5cbfSDavid du Colombier 		prevoff = 0;
73680ee5cbfSDavid du Colombier 		for(then = hash[h]; ; then = nexts[then & (MaxOff-1)]){
73780ee5cbfSDavid du Colombier 			v = (ushort)(now - then);
73880ee5cbfSDavid du Colombier 			if(v <= prevoff || v >= (MinMatch-1) - i)
73980ee5cbfSDavid du Colombier 				break;
74080ee5cbfSDavid du Colombier 			prevoff = v;
74180ee5cbfSDavid du Colombier 		}
74280ee5cbfSDavid du Colombier 		if(then == (ushort)m)
74380ee5cbfSDavid du Colombier 			continue;
74480ee5cbfSDavid du Colombier 		nexts[m & (MaxOff-1)] = hash[h];
74580ee5cbfSDavid du Colombier 		hash[h] = m;
74680ee5cbfSDavid du Colombier 	}
74780ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++)
74880ee5cbfSDavid du Colombier 		cont = (cont << 8) | p[i];
74980ee5cbfSDavid du Colombier 
75080ee5cbfSDavid du Colombier 	/*
75180ee5cbfSDavid du Colombier 	 * now must point to the index in the nexts array
75280ee5cbfSDavid du Colombier 	 * corresponding to p's position in the history
75380ee5cbfSDavid du Colombier 	 */
75480ee5cbfSDavid du Colombier 	prevlen = lz->prevlen;
75580ee5cbfSDavid du Colombier 	prevoff = lz->prevoff;
75680ee5cbfSDavid du Colombier 	maxdefer = lz->maxcheck >> 2;
75780ee5cbfSDavid du Colombier 	excost = 0;
75880ee5cbfSDavid du Colombier 	v = lzb->lastv;
75980ee5cbfSDavid du Colombier 	for(;;){
76080ee5cbfSDavid du Colombier 		es = p + MaxMatch;
76180ee5cbfSDavid du Colombier 		if(es > ep){
76280ee5cbfSDavid du Colombier 			if(!finish || p >= ep)
76380ee5cbfSDavid du Colombier 				break;
76480ee5cbfSDavid du Colombier 			es = ep;
76580ee5cbfSDavid du Colombier 		}
76680ee5cbfSDavid du Colombier 
76780ee5cbfSDavid du Colombier 		h = hashit(cont);
76880ee5cbfSDavid du Colombier 		runlen = lzmatch(now, hash[h], p, es, nexts, lz->hist, prevlen, lz->maxcheck, &m);
76980ee5cbfSDavid du Colombier 
77080ee5cbfSDavid du Colombier 		/*
77180ee5cbfSDavid du Colombier 		 * back out of small matches too far in the past
77280ee5cbfSDavid du Colombier 		 */
77380ee5cbfSDavid du Colombier 		if(runlen == MinMatch && m >= MinMatchMaxOff){
77480ee5cbfSDavid du Colombier 			runlen = MinMatch - 1;
77580ee5cbfSDavid du Colombier 			m = 0;
77680ee5cbfSDavid du Colombier 		}
77780ee5cbfSDavid du Colombier 
77880ee5cbfSDavid du Colombier 		/*
77980ee5cbfSDavid du Colombier 		 * record the encoding and increment counts for huffman trees
78080ee5cbfSDavid du Colombier 		 * if we get a match, defer selecting it until we check for
78180ee5cbfSDavid du Colombier 		 * a longer match at the next position.
78280ee5cbfSDavid du Colombier 		 */
78380ee5cbfSDavid du Colombier 		if(prevlen >= runlen && prevlen != MinMatch - 1){
78480ee5cbfSDavid du Colombier 			/*
78580ee5cbfSDavid du Colombier 			 * old match at least as good; use that one
78680ee5cbfSDavid du Colombier 			 */
78780ee5cbfSDavid du Colombier 			n = prevlen - MinMatch;
78880ee5cbfSDavid du Colombier 			if(v || n){
78980ee5cbfSDavid du Colombier 				*parse++ = v | LenFlag | (n << LenShift);
79080ee5cbfSDavid du Colombier 				*parse++ = prevoff;
79180ee5cbfSDavid du Colombier 			}else
79280ee5cbfSDavid du Colombier 				*parse++ = prevoff << LenShift;
79380ee5cbfSDavid du Colombier 			v = 0;
79480ee5cbfSDavid du Colombier 
79580ee5cbfSDavid du Colombier 			n = lencode[n];
79680ee5cbfSDavid du Colombier 			litlencount[n]++;
79780ee5cbfSDavid du Colombier 			excost += litlenextra[n - LenStart];
79880ee5cbfSDavid du Colombier 
79980ee5cbfSDavid du Colombier 			if(prevoff < MaxOffCode)
80080ee5cbfSDavid du Colombier 				n = offcode[prevoff];
80180ee5cbfSDavid du Colombier 			else
80280ee5cbfSDavid du Colombier 				n = bigoffcode[prevoff >> 7];
80380ee5cbfSDavid du Colombier 			offcount[n]++;
80480ee5cbfSDavid du Colombier 			excost += offextra[n];
80580ee5cbfSDavid du Colombier 
80680ee5cbfSDavid du Colombier 			runlen = prevlen - 1;
80780ee5cbfSDavid du Colombier 			prevlen = MinMatch - 1;
80880ee5cbfSDavid du Colombier 			nmatches++;
80980ee5cbfSDavid du Colombier 		}else if(runlen == MinMatch - 1){
81080ee5cbfSDavid du Colombier 			/*
81180ee5cbfSDavid du Colombier 			 * no match; just put out the literal
81280ee5cbfSDavid du Colombier 			 */
81380ee5cbfSDavid du Colombier 			if(++v == MaxLitRun){
81480ee5cbfSDavid du Colombier 				*parse++ = v;
81580ee5cbfSDavid du Colombier 				v = 0;
81680ee5cbfSDavid du Colombier 			}
81780ee5cbfSDavid du Colombier 			litlencount[*p]++;
81880ee5cbfSDavid du Colombier 			nlits++;
81980ee5cbfSDavid du Colombier 			runlen = 1;
82080ee5cbfSDavid du Colombier 		}else{
82180ee5cbfSDavid du Colombier 			if(prevlen != MinMatch - 1){
82280ee5cbfSDavid du Colombier 				/*
82380ee5cbfSDavid du Colombier 				 * longer match now. output previous literal,
82480ee5cbfSDavid du Colombier 				 * update current match, and try again
82580ee5cbfSDavid du Colombier 				 */
82680ee5cbfSDavid du Colombier 				if(++v == MaxLitRun){
82780ee5cbfSDavid du Colombier 					*parse++ = v;
82880ee5cbfSDavid du Colombier 					v = 0;
82980ee5cbfSDavid du Colombier 				}
83080ee5cbfSDavid du Colombier 				litlencount[p[-1]]++;
83180ee5cbfSDavid du Colombier 				nlits++;
83280ee5cbfSDavid du Colombier 			}
83380ee5cbfSDavid du Colombier 
83480ee5cbfSDavid du Colombier 			prevoff = m;
83580ee5cbfSDavid du Colombier 
83680ee5cbfSDavid du Colombier 			if(runlen < maxdefer){
83780ee5cbfSDavid du Colombier 				prevlen = runlen;
83880ee5cbfSDavid du Colombier 				runlen = 1;
83980ee5cbfSDavid du Colombier 			}else{
84080ee5cbfSDavid du Colombier 				n = runlen - MinMatch;
84180ee5cbfSDavid du Colombier 				if(v || n){
84280ee5cbfSDavid du Colombier 					*parse++ = v | LenFlag | (n << LenShift);
84380ee5cbfSDavid du Colombier 					*parse++ = prevoff;
84480ee5cbfSDavid du Colombier 				}else
84580ee5cbfSDavid du Colombier 					*parse++ = prevoff << LenShift;
84680ee5cbfSDavid du Colombier 				v = 0;
84780ee5cbfSDavid du Colombier 
84880ee5cbfSDavid du Colombier 				n = lencode[n];
84980ee5cbfSDavid du Colombier 				litlencount[n]++;
85080ee5cbfSDavid du Colombier 				excost += litlenextra[n - LenStart];
85180ee5cbfSDavid du Colombier 
85280ee5cbfSDavid du Colombier 				if(prevoff < MaxOffCode)
85380ee5cbfSDavid du Colombier 					n = offcode[prevoff];
85480ee5cbfSDavid du Colombier 				else
85580ee5cbfSDavid du Colombier 					n = bigoffcode[prevoff >> 7];
85680ee5cbfSDavid du Colombier 				offcount[n]++;
85780ee5cbfSDavid du Colombier 				excost += offextra[n];
85880ee5cbfSDavid du Colombier 
85980ee5cbfSDavid du Colombier 				prevlen = MinMatch - 1;
86080ee5cbfSDavid du Colombier 				nmatches++;
86180ee5cbfSDavid du Colombier 			}
86280ee5cbfSDavid du Colombier 		}
86380ee5cbfSDavid du Colombier 
86480ee5cbfSDavid du Colombier 		/*
86580ee5cbfSDavid du Colombier 		 * update the hash for the newly matched data
86680ee5cbfSDavid du Colombier 		 * this is constructed so the link for the old
86780ee5cbfSDavid du Colombier 		 * match in this position must be at the end of a chain,
86880ee5cbfSDavid du Colombier 		 * and will expire when this match is added, ie it will
86980ee5cbfSDavid du Colombier 		 * never be examined by the match loop.
87080ee5cbfSDavid du Colombier 		 * add to the hash chain only if we have the real hash data.
87180ee5cbfSDavid du Colombier 		 */
87280ee5cbfSDavid du Colombier 		for(q = p + runlen; p != q; p++){
87380ee5cbfSDavid du Colombier 			if(p + MinMatch <= ep){
87480ee5cbfSDavid du Colombier 				h = hashit(cont);
87580ee5cbfSDavid du Colombier 				nexts[now & (MaxOff-1)] = hash[h];
87680ee5cbfSDavid du Colombier 				hash[h] = now;
87780ee5cbfSDavid du Colombier 				if(p + MinMatch < ep)
87880ee5cbfSDavid du Colombier 					cont = (cont << 8) | p[MinMatch];
87980ee5cbfSDavid du Colombier 			}
88080ee5cbfSDavid du Colombier 			now++;
88180ee5cbfSDavid du Colombier 		}
88280ee5cbfSDavid du Colombier 	}
88380ee5cbfSDavid du Colombier 
88480ee5cbfSDavid du Colombier 	/*
88580ee5cbfSDavid du Colombier 	 * we can just store away the lazy state and
88680ee5cbfSDavid du Colombier 	 * pick it up next time.  the last block will have finish set
88780ee5cbfSDavid du Colombier 	 * so we won't have any pending matches
88880ee5cbfSDavid du Colombier 	 * however, we need to correct for how much we've encoded
88980ee5cbfSDavid du Colombier 	 */
89080ee5cbfSDavid du Colombier 	if(prevlen != MinMatch - 1)
89180ee5cbfSDavid du Colombier 		p--;
89280ee5cbfSDavid du Colombier 
89380ee5cbfSDavid du Colombier 	lzb->excost += excost;
89480ee5cbfSDavid du Colombier 	lzb->eparse = parse;
89580ee5cbfSDavid du Colombier 	lzb->lastv = v;
89680ee5cbfSDavid du Colombier 
89780ee5cbfSDavid du Colombier 	lz->now = now;
89880ee5cbfSDavid du Colombier 	lz->prevlen = prevlen;
89980ee5cbfSDavid du Colombier 	lz->prevoff = prevoff;
90080ee5cbfSDavid du Colombier 
90180ee5cbfSDavid du Colombier 	return p - &lz->hist[lz->pos];
90280ee5cbfSDavid du Colombier }
90380ee5cbfSDavid du Colombier 
90480ee5cbfSDavid du Colombier /*
90580ee5cbfSDavid du Colombier  * make up the dynamic code tables, and return the number of bits
90680ee5cbfSDavid du Colombier  * needed to transmit them.
90780ee5cbfSDavid du Colombier  */
90880ee5cbfSDavid du Colombier static int
huffcodes(Dyncode * dc,Huff * littab,Huff * offtab)90980ee5cbfSDavid du Colombier huffcodes(Dyncode *dc, Huff *littab, Huff *offtab)
91080ee5cbfSDavid du Colombier {
91180ee5cbfSDavid du Colombier 	Huff *codetab;
91280ee5cbfSDavid du Colombier 	uchar *codes, *codeaux;
91380ee5cbfSDavid du Colombier 	ulong codecount[Nclen], excost;
91480ee5cbfSDavid du Colombier 	int i, n, m, v, c, nlit, noff, ncode, nclen;
91580ee5cbfSDavid du Colombier 
91680ee5cbfSDavid du Colombier 	codetab = dc->codetab;
91780ee5cbfSDavid du Colombier 	codes = dc->codes;
91880ee5cbfSDavid du Colombier 	codeaux = dc->codeaux;
91980ee5cbfSDavid du Colombier 
92080ee5cbfSDavid du Colombier 	/*
92180ee5cbfSDavid du Colombier 	 * trim the sizes of the tables
92280ee5cbfSDavid du Colombier 	 */
92380ee5cbfSDavid du Colombier 	for(nlit = Nlitlen; nlit > 257 && littab[nlit-1].bits == 0; nlit--)
92480ee5cbfSDavid du Colombier 		;
92580ee5cbfSDavid du Colombier 	for(noff = Noff; noff > 1 && offtab[noff-1].bits == 0; noff--)
92680ee5cbfSDavid du Colombier 		;
92780ee5cbfSDavid du Colombier 
92880ee5cbfSDavid du Colombier 	/*
92980ee5cbfSDavid du Colombier 	 * make the code-length code
93080ee5cbfSDavid du Colombier 	 */
93180ee5cbfSDavid du Colombier 	for(i = 0; i < nlit; i++)
93280ee5cbfSDavid du Colombier 		codes[i] = littab[i].bits;
93380ee5cbfSDavid du Colombier 	for(i = 0; i < noff; i++)
93480ee5cbfSDavid du Colombier 		codes[i + nlit] = offtab[i].bits;
93580ee5cbfSDavid du Colombier 
93680ee5cbfSDavid du Colombier 	/*
93780ee5cbfSDavid du Colombier 	 * run-length compress the code-length code
93880ee5cbfSDavid du Colombier 	 */
93980ee5cbfSDavid du Colombier 	excost = 0;
94080ee5cbfSDavid du Colombier 	c = 0;
94180ee5cbfSDavid du Colombier 	ncode = nlit+noff;
94280ee5cbfSDavid du Colombier 	for(i = 0; i < ncode; ){
94380ee5cbfSDavid du Colombier 		n = i + 1;
94480ee5cbfSDavid du Colombier 		v = codes[i];
94580ee5cbfSDavid du Colombier 		while(n < ncode && v == codes[n])
94680ee5cbfSDavid du Colombier 			n++;
94780ee5cbfSDavid du Colombier 		n -= i;
94880ee5cbfSDavid du Colombier 		i += n;
94980ee5cbfSDavid du Colombier 		if(v == 0){
95080ee5cbfSDavid du Colombier 			while(n >= 11){
95180ee5cbfSDavid du Colombier 				m = n;
95280ee5cbfSDavid du Colombier 				if(m > 138)
95380ee5cbfSDavid du Colombier 					m = 138;
95480ee5cbfSDavid du Colombier 				codes[c] = 18;
95580ee5cbfSDavid du Colombier 				codeaux[c++] = m - 11;
95680ee5cbfSDavid du Colombier 				n -= m;
95780ee5cbfSDavid du Colombier 				excost += 7;
95880ee5cbfSDavid du Colombier 			}
95980ee5cbfSDavid du Colombier 			if(n >= 3){
96080ee5cbfSDavid du Colombier 				codes[c] = 17;
96180ee5cbfSDavid du Colombier 				codeaux[c++] = n - 3;
96280ee5cbfSDavid du Colombier 				n = 0;
96380ee5cbfSDavid du Colombier 				excost += 3;
96480ee5cbfSDavid du Colombier 			}
96580ee5cbfSDavid du Colombier 		}
96680ee5cbfSDavid du Colombier 		while(n--){
96780ee5cbfSDavid du Colombier 			codes[c++] = v;
96880ee5cbfSDavid du Colombier 			while(n >= 3){
96980ee5cbfSDavid du Colombier 				m = n;
97080ee5cbfSDavid du Colombier 				if(m > 6)
97180ee5cbfSDavid du Colombier 					m = 6;
97280ee5cbfSDavid du Colombier 				codes[c] = 16;
97380ee5cbfSDavid du Colombier 				codeaux[c++] = m - 3;
97480ee5cbfSDavid du Colombier 				n -= m;
97580ee5cbfSDavid du Colombier 				excost += 3;
97680ee5cbfSDavid du Colombier 			}
97780ee5cbfSDavid du Colombier 		}
97880ee5cbfSDavid du Colombier 	}
97980ee5cbfSDavid du Colombier 
98080ee5cbfSDavid du Colombier 	memset(codecount, 0, sizeof codecount);
98180ee5cbfSDavid du Colombier 	for(i = 0; i < c; i++)
98280ee5cbfSDavid du Colombier 		codecount[codes[i]]++;
98380ee5cbfSDavid du Colombier 	if(!mkgzprecode(codetab, codecount, Nclen, 8))
98480ee5cbfSDavid du Colombier 		return -1;
98580ee5cbfSDavid du Colombier 
98680ee5cbfSDavid du Colombier 	for(nclen = Nclen; nclen > 4 && codetab[clenorder[nclen-1]].bits == 0; nclen--)
98780ee5cbfSDavid du Colombier 		;
98880ee5cbfSDavid du Colombier 
98980ee5cbfSDavid du Colombier 	dc->nlit = nlit;
99080ee5cbfSDavid du Colombier 	dc->noff = noff;
99180ee5cbfSDavid du Colombier 	dc->nclen = nclen;
99280ee5cbfSDavid du Colombier 	dc->ncode = c;
99380ee5cbfSDavid du Colombier 
99480ee5cbfSDavid du Colombier 	return 5 + 5 + 4 + nclen * 3 + bitcost(codetab, codecount, Nclen) + excost;
99580ee5cbfSDavid du Colombier }
99680ee5cbfSDavid du Colombier 
99780ee5cbfSDavid du Colombier static void
wrdyncode(LZstate * out,Dyncode * dc)99880ee5cbfSDavid du Colombier wrdyncode(LZstate *out, Dyncode *dc)
99980ee5cbfSDavid du Colombier {
100080ee5cbfSDavid du Colombier 	Huff *codetab;
100180ee5cbfSDavid du Colombier 	uchar *codes, *codeaux;
100280ee5cbfSDavid du Colombier 	int i, v, c;
100380ee5cbfSDavid du Colombier 
100480ee5cbfSDavid du Colombier 	/*
100580ee5cbfSDavid du Colombier 	 * write out header, then code length code lengths,
100680ee5cbfSDavid du Colombier 	 * and code lengths
100780ee5cbfSDavid du Colombier 	 */
100880ee5cbfSDavid du Colombier 	lzput(out, dc->nlit-257, 5);
100980ee5cbfSDavid du Colombier 	lzput(out, dc->noff-1, 5);
101080ee5cbfSDavid du Colombier 	lzput(out, dc->nclen-4, 4);
101180ee5cbfSDavid du Colombier 
101280ee5cbfSDavid du Colombier 	codetab = dc->codetab;
101380ee5cbfSDavid du Colombier 	for(i = 0; i < dc->nclen; i++)
101480ee5cbfSDavid du Colombier 		lzput(out, codetab[clenorder[i]].bits, 3);
101580ee5cbfSDavid du Colombier 
101680ee5cbfSDavid du Colombier 	codes = dc->codes;
101780ee5cbfSDavid du Colombier 	codeaux = dc->codeaux;
101880ee5cbfSDavid du Colombier 	c = dc->ncode;
101980ee5cbfSDavid du Colombier 	for(i = 0; i < c; i++){
102080ee5cbfSDavid du Colombier 		v = codes[i];
102180ee5cbfSDavid du Colombier 		lzput(out, codetab[v].encode, codetab[v].bits);
102280ee5cbfSDavid du Colombier 		if(v >= 16){
102380ee5cbfSDavid du Colombier 			if(v == 16)
102480ee5cbfSDavid du Colombier 				lzput(out, codeaux[i], 2);
102580ee5cbfSDavid du Colombier 			else if(v == 17)
102680ee5cbfSDavid du Colombier 				lzput(out, codeaux[i], 3);
102780ee5cbfSDavid du Colombier 			else /* v == 18 */
102880ee5cbfSDavid du Colombier 				lzput(out, codeaux[i], 7);
102980ee5cbfSDavid du Colombier 		}
103080ee5cbfSDavid du Colombier 	}
103180ee5cbfSDavid du Colombier }
103280ee5cbfSDavid du Colombier 
103380ee5cbfSDavid du Colombier static int
bitcost(Huff * tab,ulong * count,int n)103480ee5cbfSDavid du Colombier bitcost(Huff *tab, ulong *count, int n)
103580ee5cbfSDavid du Colombier {
103680ee5cbfSDavid du Colombier 	ulong tot;
103780ee5cbfSDavid du Colombier 	int i;
103880ee5cbfSDavid du Colombier 
103980ee5cbfSDavid du Colombier 	tot = 0;
104080ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++)
104180ee5cbfSDavid du Colombier 		tot += count[i] * tab[i].bits;
104280ee5cbfSDavid du Colombier 	return tot;
104380ee5cbfSDavid du Colombier }
104480ee5cbfSDavid du Colombier 
104580ee5cbfSDavid du Colombier static int
mkgzprecode(Huff * tab,ulong * count,int n,int maxbits)104680ee5cbfSDavid du Colombier mkgzprecode(Huff *tab, ulong *count, int n, int maxbits)
104780ee5cbfSDavid du Colombier {
104880ee5cbfSDavid du Colombier 	ulong bitcount[MaxHuffBits];
104980ee5cbfSDavid du Colombier 	int i, nbits;
105080ee5cbfSDavid du Colombier 
105180ee5cbfSDavid du Colombier 	nbits = mkprecode(tab, count, n, maxbits, bitcount);
105280ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++){
105380ee5cbfSDavid du Colombier 		if(tab[i].bits == -1)
105480ee5cbfSDavid du Colombier 			tab[i].bits = 0;
105580ee5cbfSDavid du Colombier 		else if(tab[i].bits == 0){
105680ee5cbfSDavid du Colombier 			if(nbits != 0 || bitcount[0] != 1)
105780ee5cbfSDavid du Colombier 				return 0;
105880ee5cbfSDavid du Colombier 			bitcount[1] = 1;
105980ee5cbfSDavid du Colombier 			bitcount[0] = 0;
106080ee5cbfSDavid du Colombier 			nbits = 1;
106180ee5cbfSDavid du Colombier 			tab[i].bits = 1;
106280ee5cbfSDavid du Colombier 		}
106380ee5cbfSDavid du Colombier 	}
106480ee5cbfSDavid du Colombier 	if(bitcount[0] != 0)
106580ee5cbfSDavid du Colombier 		return 0;
106680ee5cbfSDavid du Colombier 	return hufftabinit(tab, n, bitcount, nbits);
106780ee5cbfSDavid du Colombier }
106880ee5cbfSDavid du Colombier 
106980ee5cbfSDavid du Colombier static int
hufftabinit(Huff * tab,int n,ulong * bitcount,int nbits)107080ee5cbfSDavid du Colombier hufftabinit(Huff *tab, int n, ulong *bitcount, int nbits)
107180ee5cbfSDavid du Colombier {
107280ee5cbfSDavid du Colombier 	ulong code, nc[MaxHuffBits];
107380ee5cbfSDavid du Colombier 	int i, bits;
107480ee5cbfSDavid du Colombier 
107580ee5cbfSDavid du Colombier 	code = 0;
107680ee5cbfSDavid du Colombier 	for(bits = 1; bits <= nbits; bits++){
107780ee5cbfSDavid du Colombier 		code = (code + bitcount[bits-1]) << 1;
107880ee5cbfSDavid du Colombier 		nc[bits] = code;
107980ee5cbfSDavid du Colombier 	}
108080ee5cbfSDavid du Colombier 
108180ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++){
108280ee5cbfSDavid du Colombier 		bits = tab[i].bits;
108380ee5cbfSDavid du Colombier 		if(bits){
108480ee5cbfSDavid du Colombier 			code = nc[bits]++ << (16 - bits);
108580ee5cbfSDavid du Colombier 			if(code & ~0xffff)
108680ee5cbfSDavid du Colombier 				return 0;
108780ee5cbfSDavid du Colombier 			tab[i].encode = revtab[code >> 8] | (revtab[code & 0xff] << 8);
108880ee5cbfSDavid du Colombier 		}
108980ee5cbfSDavid du Colombier 	}
109080ee5cbfSDavid du Colombier 	return 1;
109180ee5cbfSDavid du Colombier }
109280ee5cbfSDavid du Colombier 
109380ee5cbfSDavid du Colombier 
109480ee5cbfSDavid du Colombier /*
109580ee5cbfSDavid du Colombier  * this should be in a library
109680ee5cbfSDavid du Colombier  */
109780ee5cbfSDavid du Colombier struct Chain
109880ee5cbfSDavid du Colombier {
109980ee5cbfSDavid du Colombier 	ulong	count;				/* occurances of everything in the chain */
110080ee5cbfSDavid du Colombier 	ushort	leaf;				/* leaves to the left of chain, or leaf value */
110180ee5cbfSDavid du Colombier 	char	col;				/* ref count for collecting unused chains */
110280ee5cbfSDavid du Colombier 	char	gen;				/* need to generate chains for next lower level */
110380ee5cbfSDavid du Colombier 	Chain	*up;				/* Chain up in the lists */
110480ee5cbfSDavid du Colombier };
110580ee5cbfSDavid du Colombier 
110680ee5cbfSDavid du Colombier struct Chains
110780ee5cbfSDavid du Colombier {
110880ee5cbfSDavid du Colombier 	Chain	*lists[(MaxHuffBits - 1) * 2];
110980ee5cbfSDavid du Colombier 	ulong	leafcount[MaxLeaf];		/* sorted list of leaf counts */
111080ee5cbfSDavid du Colombier 	ushort	leafmap[MaxLeaf];		/* map to actual leaf number */
111180ee5cbfSDavid du Colombier 	int	nleaf;				/* number of leaves */
111280ee5cbfSDavid du Colombier 	Chain	chains[ChainMem];
111380ee5cbfSDavid du Colombier 	Chain	*echains;
111480ee5cbfSDavid du Colombier 	Chain	*free;
111580ee5cbfSDavid du Colombier 	char	col;
111680ee5cbfSDavid du Colombier 	int	nlists;
111780ee5cbfSDavid du Colombier };
111880ee5cbfSDavid du Colombier 
111980ee5cbfSDavid du Colombier /*
112080ee5cbfSDavid du Colombier  * fast, low space overhead algorithm for max depth huffman type codes
112180ee5cbfSDavid du Colombier  *
112280ee5cbfSDavid du Colombier  * J. Katajainen, A. Moffat and A. Turpin, "A fast and space-economical
112380ee5cbfSDavid du Colombier  * algorithm for length-limited coding," Proc. Intl. Symp. on Algorithms
112480ee5cbfSDavid du Colombier  * and Computation, Cairns, Australia, Dec. 1995, Lecture Notes in Computer
112580ee5cbfSDavid du Colombier  * Science, Vol 1004, J. Staples, P. Eades, N. Katoh, and A. Moffat, eds.,
112680ee5cbfSDavid du Colombier  * pp 12-21, Springer Verlag, New York, 1995.
112780ee5cbfSDavid du Colombier  */
112880ee5cbfSDavid du Colombier static int
mkprecode(Huff * tab,ulong * count,int n,int maxbits,ulong * bitcount)112980ee5cbfSDavid du Colombier mkprecode(Huff *tab, ulong *count, int n, int maxbits, ulong *bitcount)
113080ee5cbfSDavid du Colombier {
113180ee5cbfSDavid du Colombier 	Chains cs;
113280ee5cbfSDavid du Colombier 	Chain *c;
113380ee5cbfSDavid du Colombier 	int i, m, em, bits;
113480ee5cbfSDavid du Colombier 
113580ee5cbfSDavid du Colombier 	/*
113680ee5cbfSDavid du Colombier 	 * set up the sorted list of leaves
113780ee5cbfSDavid du Colombier 	 */
113880ee5cbfSDavid du Colombier 	m = 0;
113980ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++){
114080ee5cbfSDavid du Colombier 		tab[i].bits = -1;
114180ee5cbfSDavid du Colombier 		tab[i].encode = 0;
114280ee5cbfSDavid du Colombier 		if(count[i] != 0){
114380ee5cbfSDavid du Colombier 			cs.leafcount[m] = count[i];
114480ee5cbfSDavid du Colombier 			cs.leafmap[m] = i;
114580ee5cbfSDavid du Colombier 			m++;
114680ee5cbfSDavid du Colombier 		}
114780ee5cbfSDavid du Colombier 	}
114880ee5cbfSDavid du Colombier 	if(m < 2){
114980ee5cbfSDavid du Colombier 		if(m != 0){
115080ee5cbfSDavid du Colombier 			tab[cs.leafmap[0]].bits = 0;
115180ee5cbfSDavid du Colombier 			bitcount[0] = 1;
115280ee5cbfSDavid du Colombier 		}else
115380ee5cbfSDavid du Colombier 			bitcount[0] = 0;
115480ee5cbfSDavid du Colombier 		return 0;
115580ee5cbfSDavid du Colombier 	}
115680ee5cbfSDavid du Colombier 	cs.nleaf = m;
115780ee5cbfSDavid du Colombier 	leafsort(cs.leafcount, cs.leafmap, 0, m);
115880ee5cbfSDavid du Colombier 
115980ee5cbfSDavid du Colombier 	for(i = 0; i < m; i++)
116080ee5cbfSDavid du Colombier 		cs.leafcount[i] = count[cs.leafmap[i]];
116180ee5cbfSDavid du Colombier 
116280ee5cbfSDavid du Colombier 	/*
116380ee5cbfSDavid du Colombier 	 * set up free list
116480ee5cbfSDavid du Colombier 	 */
116580ee5cbfSDavid du Colombier 	cs.free = &cs.chains[2];
116680ee5cbfSDavid du Colombier 	cs.echains = &cs.chains[ChainMem];
116780ee5cbfSDavid du Colombier 	cs.col = 1;
116880ee5cbfSDavid du Colombier 
116980ee5cbfSDavid du Colombier 	/*
117080ee5cbfSDavid du Colombier 	 * initialize chains for each list
117180ee5cbfSDavid du Colombier 	 */
117280ee5cbfSDavid du Colombier 	c = &cs.chains[0];
117380ee5cbfSDavid du Colombier 	c->count = cs.leafcount[0];
117480ee5cbfSDavid du Colombier 	c->leaf = 1;
117580ee5cbfSDavid du Colombier 	c->col = cs.col;
117680ee5cbfSDavid du Colombier 	c->up = nil;
117780ee5cbfSDavid du Colombier 	c->gen = 0;
117880ee5cbfSDavid du Colombier 	cs.chains[1] = cs.chains[0];
117980ee5cbfSDavid du Colombier 	cs.chains[1].leaf = 2;
118080ee5cbfSDavid du Colombier 	cs.chains[1].count = cs.leafcount[1];
118180ee5cbfSDavid du Colombier 	for(i = 0; i < maxbits-1; i++){
118280ee5cbfSDavid du Colombier 		cs.lists[i * 2] = &cs.chains[0];
118380ee5cbfSDavid du Colombier 		cs.lists[i * 2 + 1] = &cs.chains[1];
118480ee5cbfSDavid du Colombier 	}
118580ee5cbfSDavid du Colombier 
118680ee5cbfSDavid du Colombier 	cs.nlists = 2 * (maxbits - 1);
118780ee5cbfSDavid du Colombier 	m = 2 * m - 2;
118880ee5cbfSDavid du Colombier 	for(i = 2; i < m; i++)
118980ee5cbfSDavid du Colombier 		nextchain(&cs, cs.nlists - 2);
119080ee5cbfSDavid du Colombier 
119180ee5cbfSDavid du Colombier 	bits = 0;
119280ee5cbfSDavid du Colombier 	bitcount[0] = cs.nleaf;
119380ee5cbfSDavid du Colombier 	for(c = cs.lists[cs.nlists - 1]; c != nil; c = c->up){
119480ee5cbfSDavid du Colombier 		m = c->leaf;
119580ee5cbfSDavid du Colombier 		bitcount[bits++] -= m;
119680ee5cbfSDavid du Colombier 		bitcount[bits] = m;
119780ee5cbfSDavid du Colombier 	}
119880ee5cbfSDavid du Colombier 	m = 0;
119980ee5cbfSDavid du Colombier 	for(i = bits; i >= 0; i--)
120080ee5cbfSDavid du Colombier 		for(em = m + bitcount[i]; m < em; m++)
120180ee5cbfSDavid du Colombier 			tab[cs.leafmap[m]].bits = i;
120280ee5cbfSDavid du Colombier 
120380ee5cbfSDavid du Colombier 	return bits;
120480ee5cbfSDavid du Colombier }
120580ee5cbfSDavid du Colombier 
120680ee5cbfSDavid du Colombier /*
120780ee5cbfSDavid du Colombier  * calculate the next chain on the list
120880ee5cbfSDavid du Colombier  * we can always toss out the old chain
120980ee5cbfSDavid du Colombier  */
121080ee5cbfSDavid du Colombier static void
nextchain(Chains * cs,int list)121180ee5cbfSDavid du Colombier nextchain(Chains *cs, int list)
121280ee5cbfSDavid du Colombier {
121380ee5cbfSDavid du Colombier 	Chain *c, *oc;
121480ee5cbfSDavid du Colombier 	int i, nleaf, sumc;
121580ee5cbfSDavid du Colombier 
121680ee5cbfSDavid du Colombier 	oc = cs->lists[list + 1];
121780ee5cbfSDavid du Colombier 	cs->lists[list] = oc;
121880ee5cbfSDavid du Colombier 	if(oc == nil)
121980ee5cbfSDavid du Colombier 		return;
122080ee5cbfSDavid du Colombier 
122180ee5cbfSDavid du Colombier 	/*
122280ee5cbfSDavid du Colombier 	 * make sure we have all chains needed to make sumc
122380ee5cbfSDavid du Colombier 	 * note it is possible to generate only one of these,
122480ee5cbfSDavid du Colombier 	 * use twice that value for sumc, and then generate
122580ee5cbfSDavid du Colombier 	 * the second if that preliminary sumc would be chosen.
122680ee5cbfSDavid du Colombier 	 * however, this appears to be slower on current tests
122780ee5cbfSDavid du Colombier 	 */
122880ee5cbfSDavid du Colombier 	if(oc->gen){
122980ee5cbfSDavid du Colombier 		nextchain(cs, list - 2);
123080ee5cbfSDavid du Colombier 		nextchain(cs, list - 2);
123180ee5cbfSDavid du Colombier 		oc->gen = 0;
123280ee5cbfSDavid du Colombier 	}
123380ee5cbfSDavid du Colombier 
123480ee5cbfSDavid du Colombier 	/*
123580ee5cbfSDavid du Colombier 	 * pick up the chain we're going to add;
123680ee5cbfSDavid du Colombier 	 * collect unused chains no free ones are left
123780ee5cbfSDavid du Colombier 	 */
123880ee5cbfSDavid du Colombier 	for(c = cs->free; ; c++){
123980ee5cbfSDavid du Colombier 		if(c >= cs->echains){
124080ee5cbfSDavid du Colombier 			cs->col++;
124180ee5cbfSDavid du Colombier 			for(i = 0; i < cs->nlists; i++)
124280ee5cbfSDavid du Colombier 				for(c = cs->lists[i]; c != nil; c = c->up)
124380ee5cbfSDavid du Colombier 					c->col = cs->col;
124480ee5cbfSDavid du Colombier 			c = cs->chains;
124580ee5cbfSDavid du Colombier 		}
124680ee5cbfSDavid du Colombier 		if(c->col != cs->col)
124780ee5cbfSDavid du Colombier 			break;
124880ee5cbfSDavid du Colombier 	}
124980ee5cbfSDavid du Colombier 
125080ee5cbfSDavid du Colombier 	/*
125180ee5cbfSDavid du Colombier 	 * pick the cheapest of
125280ee5cbfSDavid du Colombier 	 * 1) the next package from the previous list
125380ee5cbfSDavid du Colombier 	 * 2) the next leaf
125480ee5cbfSDavid du Colombier 	 */
125580ee5cbfSDavid du Colombier 	nleaf = oc->leaf;
125680ee5cbfSDavid du Colombier 	sumc = 0;
125780ee5cbfSDavid du Colombier 	if(list > 0 && cs->lists[list-1] != nil)
125880ee5cbfSDavid du Colombier 		sumc = cs->lists[list-2]->count + cs->lists[list-1]->count;
125980ee5cbfSDavid du Colombier 	if(sumc != 0 && (nleaf >= cs->nleaf || cs->leafcount[nleaf] > sumc)){
126080ee5cbfSDavid du Colombier 		c->count = sumc;
126180ee5cbfSDavid du Colombier 		c->leaf = oc->leaf;
126280ee5cbfSDavid du Colombier 		c->up = cs->lists[list-1];
126380ee5cbfSDavid du Colombier 		c->gen = 1;
126480ee5cbfSDavid du Colombier 	}else if(nleaf >= cs->nleaf){
126580ee5cbfSDavid du Colombier 		cs->lists[list + 1] = nil;
126680ee5cbfSDavid du Colombier 		return;
126780ee5cbfSDavid du Colombier 	}else{
126880ee5cbfSDavid du Colombier 		c->leaf = nleaf + 1;
126980ee5cbfSDavid du Colombier 		c->count = cs->leafcount[nleaf];
127080ee5cbfSDavid du Colombier 		c->up = oc->up;
127180ee5cbfSDavid du Colombier 		c->gen = 0;
127280ee5cbfSDavid du Colombier 	}
127380ee5cbfSDavid du Colombier 	cs->free = c + 1;
127480ee5cbfSDavid du Colombier 
127580ee5cbfSDavid du Colombier 	cs->lists[list + 1] = c;
127680ee5cbfSDavid du Colombier 	c->col = cs->col;
127780ee5cbfSDavid du Colombier }
127880ee5cbfSDavid du Colombier 
127980ee5cbfSDavid du Colombier static int
pivot(ulong * c,int a,int n)128080ee5cbfSDavid du Colombier pivot(ulong *c, int a, int n)
128180ee5cbfSDavid du Colombier {
128280ee5cbfSDavid du Colombier 	int j, pi, pj, pk;
128380ee5cbfSDavid du Colombier 
128480ee5cbfSDavid du Colombier 	j = n/6;
128580ee5cbfSDavid du Colombier 	pi = a + j;	/* 1/6 */
128680ee5cbfSDavid du Colombier 	j += j;
128780ee5cbfSDavid du Colombier 	pj = pi + j;	/* 1/2 */
128880ee5cbfSDavid du Colombier 	pk = pj + j;	/* 5/6 */
128980ee5cbfSDavid du Colombier 	if(c[pi] < c[pj]){
129080ee5cbfSDavid du Colombier 		if(c[pi] < c[pk]){
129180ee5cbfSDavid du Colombier 			if(c[pj] < c[pk])
129280ee5cbfSDavid du Colombier 				return pj;
129380ee5cbfSDavid du Colombier 			return pk;
129480ee5cbfSDavid du Colombier 		}
129580ee5cbfSDavid du Colombier 		return pi;
129680ee5cbfSDavid du Colombier 	}
129780ee5cbfSDavid du Colombier 	if(c[pj] < c[pk]){
129880ee5cbfSDavid du Colombier 		if(c[pi] < c[pk])
129980ee5cbfSDavid du Colombier 			return pi;
130080ee5cbfSDavid du Colombier 		return pk;
130180ee5cbfSDavid du Colombier 	}
130280ee5cbfSDavid du Colombier 	return pj;
130380ee5cbfSDavid du Colombier }
130480ee5cbfSDavid du Colombier 
130580ee5cbfSDavid du Colombier static	void
leafsort(ulong * leafcount,ushort * leafmap,int a,int n)130680ee5cbfSDavid du Colombier leafsort(ulong *leafcount, ushort *leafmap, int a, int n)
130780ee5cbfSDavid du Colombier {
130880ee5cbfSDavid du Colombier 	ulong t;
130980ee5cbfSDavid du Colombier 	int j, pi, pj, pn;
131080ee5cbfSDavid du Colombier 
131180ee5cbfSDavid du Colombier 	while(n > 1){
131280ee5cbfSDavid du Colombier 		if(n > 10){
131380ee5cbfSDavid du Colombier 			pi = pivot(leafcount, a, n);
131480ee5cbfSDavid du Colombier 		}else
131580ee5cbfSDavid du Colombier 			pi = a + (n>>1);
131680ee5cbfSDavid du Colombier 
131780ee5cbfSDavid du Colombier 		t = leafcount[pi];
131880ee5cbfSDavid du Colombier 		leafcount[pi] = leafcount[a];
131980ee5cbfSDavid du Colombier 		leafcount[a] = t;
132080ee5cbfSDavid du Colombier 		t = leafmap[pi];
132180ee5cbfSDavid du Colombier 		leafmap[pi] = leafmap[a];
132280ee5cbfSDavid du Colombier 		leafmap[a] = t;
132380ee5cbfSDavid du Colombier 		pi = a;
132480ee5cbfSDavid du Colombier 		pn = a + n;
132580ee5cbfSDavid du Colombier 		pj = pn;
132680ee5cbfSDavid du Colombier 		for(;;){
132780ee5cbfSDavid du Colombier 			do
132880ee5cbfSDavid du Colombier 				pi++;
132980ee5cbfSDavid du Colombier 			while(pi < pn && (leafcount[pi] < leafcount[a] || leafcount[pi] == leafcount[a] && leafmap[pi] > leafmap[a]));
133080ee5cbfSDavid du Colombier 			do
133180ee5cbfSDavid du Colombier 				pj--;
133280ee5cbfSDavid du Colombier 			while(pj > a && (leafcount[pj] > leafcount[a] || leafcount[pj] == leafcount[a] && leafmap[pj] < leafmap[a]));
133380ee5cbfSDavid du Colombier 			if(pj < pi)
133480ee5cbfSDavid du Colombier 				break;
133580ee5cbfSDavid du Colombier 			t = leafcount[pi];
133680ee5cbfSDavid du Colombier 			leafcount[pi] = leafcount[pj];
133780ee5cbfSDavid du Colombier 			leafcount[pj] = t;
133880ee5cbfSDavid du Colombier 			t = leafmap[pi];
133980ee5cbfSDavid du Colombier 			leafmap[pi] = leafmap[pj];
134080ee5cbfSDavid du Colombier 			leafmap[pj] = t;
134180ee5cbfSDavid du Colombier 		}
134280ee5cbfSDavid du Colombier 		t = leafcount[a];
134380ee5cbfSDavid du Colombier 		leafcount[a] = leafcount[pj];
134480ee5cbfSDavid du Colombier 		leafcount[pj] = t;
134580ee5cbfSDavid du Colombier 		t = leafmap[a];
134680ee5cbfSDavid du Colombier 		leafmap[a] = leafmap[pj];
134780ee5cbfSDavid du Colombier 		leafmap[pj] = t;
134880ee5cbfSDavid du Colombier 		j = pj - a;
134980ee5cbfSDavid du Colombier 
135080ee5cbfSDavid du Colombier 		n = n-j-1;
135180ee5cbfSDavid du Colombier 		if(j >= n){
135280ee5cbfSDavid du Colombier 			leafsort(leafcount, leafmap, a, j);
135380ee5cbfSDavid du Colombier 			a += j+1;
135480ee5cbfSDavid du Colombier 		}else{
135580ee5cbfSDavid du Colombier 			leafsort(leafcount, leafmap, a + (j+1), n);
135680ee5cbfSDavid du Colombier 			n = j;
135780ee5cbfSDavid du Colombier 		}
135880ee5cbfSDavid du Colombier 	}
135980ee5cbfSDavid du Colombier }
1360