xref: /plan9/sys/src/libflate/deflate.c (revision 80ee5cbfe36716af62da8896207e9763b8e3d760)
1*80ee5cbfSDavid du Colombier #include <u.h>
2*80ee5cbfSDavid du Colombier #include <libc.h>
3*80ee5cbfSDavid du Colombier #include <flate.h>
4*80ee5cbfSDavid du Colombier 
5*80ee5cbfSDavid du Colombier typedef struct Chain	Chain;
6*80ee5cbfSDavid du Colombier typedef struct Chains	Chains;
7*80ee5cbfSDavid du Colombier typedef struct Dyncode	Dyncode;
8*80ee5cbfSDavid du Colombier typedef struct Huff	Huff;
9*80ee5cbfSDavid du Colombier typedef struct LZblock	LZblock;
10*80ee5cbfSDavid du Colombier typedef struct LZstate	LZstate;
11*80ee5cbfSDavid du Colombier 
12*80ee5cbfSDavid du Colombier enum
13*80ee5cbfSDavid du Colombier {
14*80ee5cbfSDavid du Colombier 	/*
15*80ee5cbfSDavid du Colombier 	 * deflate format paramaters
16*80ee5cbfSDavid du Colombier 	 */
17*80ee5cbfSDavid du Colombier 	DeflateUnc	= 0,			/* uncompressed block */
18*80ee5cbfSDavid du Colombier 	DeflateFix	= 1,			/* fixed huffman codes */
19*80ee5cbfSDavid du Colombier 	DeflateDyn	= 2,			/* dynamic huffman codes */
20*80ee5cbfSDavid du Colombier 
21*80ee5cbfSDavid du Colombier 	DeflateEob	= 256,			/* end of block code in lit/len book */
22*80ee5cbfSDavid du Colombier 	DeflateMaxBlock	= 64*1024-1,		/* maximum size of uncompressed block */
23*80ee5cbfSDavid du Colombier 
24*80ee5cbfSDavid du Colombier 	DeflateMaxExp	= 10,			/* maximum expansion for a block */
25*80ee5cbfSDavid du Colombier 
26*80ee5cbfSDavid du Colombier 	LenStart	= 257,			/* start of length codes in litlen */
27*80ee5cbfSDavid du Colombier 	Nlitlen		= 288,			/* number of litlen codes */
28*80ee5cbfSDavid du Colombier 	Noff		= 30,			/* number of offset codes */
29*80ee5cbfSDavid du Colombier 	Nclen		= 19,			/* number of codelen codes */
30*80ee5cbfSDavid du Colombier 
31*80ee5cbfSDavid du Colombier 	MaxOff		= 32*1024,
32*80ee5cbfSDavid du Colombier 	MinMatch	= 3,			/* shortest match possible */
33*80ee5cbfSDavid du Colombier 	MaxMatch	= 258,			/* longest match possible */
34*80ee5cbfSDavid du Colombier 
35*80ee5cbfSDavid du Colombier 	/*
36*80ee5cbfSDavid du Colombier 	 * huffman code paramaters
37*80ee5cbfSDavid du Colombier 	 */
38*80ee5cbfSDavid du Colombier 	MaxLeaf		= Nlitlen,
39*80ee5cbfSDavid du Colombier 	MaxHuffBits	= 16,			/* max bits in a huffman code */
40*80ee5cbfSDavid du Colombier 	ChainMem	= 2 * (MaxHuffBits - 1) * MaxHuffBits,
41*80ee5cbfSDavid du Colombier 
42*80ee5cbfSDavid du Colombier 	/*
43*80ee5cbfSDavid du Colombier 	 * coding of the lz parse
44*80ee5cbfSDavid du Colombier 	 */
45*80ee5cbfSDavid du Colombier 	LenFlag		= 1 << 3,
46*80ee5cbfSDavid du Colombier 	LenShift	= 4,			/* leaves enough space for MinMatchMaxOff */
47*80ee5cbfSDavid du Colombier 	MaxLitRun	= LenFlag - 1,
48*80ee5cbfSDavid du Colombier 
49*80ee5cbfSDavid du Colombier 	/*
50*80ee5cbfSDavid du Colombier 	 * internal lz paramaters
51*80ee5cbfSDavid du Colombier 	 */
52*80ee5cbfSDavid du Colombier 	DeflateOut	= 4096,			/* output buffer size */
53*80ee5cbfSDavid du Colombier 	BlockSize	= 8192,			/* attempted input read quanta */
54*80ee5cbfSDavid du Colombier 	DeflateBlock	= DeflateMaxBlock & ~(BlockSize - 1),
55*80ee5cbfSDavid du Colombier 	MinMatchMaxOff	= 4096,			/* max profitable offset for small match;
56*80ee5cbfSDavid du Colombier 						 * assumes 8 bits for len, 5+10 for offset
57*80ee5cbfSDavid du Colombier 						 * DONT CHANGE WITHOUT CHANGING LZPARSE CONSTANTS
58*80ee5cbfSDavid du Colombier 						 */
59*80ee5cbfSDavid du Colombier 	HistSlop	= 512,			/* must be at lead MaxMatch */
60*80ee5cbfSDavid du Colombier 	HistBlock	= 64*1024,
61*80ee5cbfSDavid du Colombier 	HistSize	= HistBlock + HistSlop,
62*80ee5cbfSDavid du Colombier 
63*80ee5cbfSDavid du Colombier 	HashLog		= 13,
64*80ee5cbfSDavid du Colombier 	HashSize	= 1<<HashLog,
65*80ee5cbfSDavid du Colombier 
66*80ee5cbfSDavid du Colombier 	MaxOffCode	= 256,			/* biggest offset looked up in direct table */
67*80ee5cbfSDavid du Colombier 
68*80ee5cbfSDavid du Colombier 	EstLitBits	= 8,
69*80ee5cbfSDavid du Colombier 	EstLenBits	= 4,
70*80ee5cbfSDavid du Colombier 	EstOffBits	= 5,
71*80ee5cbfSDavid du Colombier };
72*80ee5cbfSDavid du Colombier 
73*80ee5cbfSDavid du Colombier /*
74*80ee5cbfSDavid du Colombier  * knuth vol. 3 multiplicative hashing
75*80ee5cbfSDavid du Colombier  * each byte x chosen according to rules
76*80ee5cbfSDavid du Colombier  * 1/4 < x < 3/10, 1/3 x < < 3/7, 4/7 < x < 2/3, 7/10 < x < 3/4
77*80ee5cbfSDavid du Colombier  * with reasonable spread between the bytes & their complements
78*80ee5cbfSDavid du Colombier  *
79*80ee5cbfSDavid du Colombier  * the 3 byte value appears to be as almost good as the 4 byte value,
80*80ee5cbfSDavid du Colombier  * and might be faster on some machines
81*80ee5cbfSDavid du Colombier  */
82*80ee5cbfSDavid du Colombier /*
83*80ee5cbfSDavid du Colombier #define hashit(c)	(((ulong)(c) * 0x6b43a9) >> (24 - HashLog))
84*80ee5cbfSDavid du Colombier */
85*80ee5cbfSDavid du Colombier #define hashit(c)	((((ulong)(c) & 0xffffff) * 0x6b43a9b5) >> (32 - HashLog))
86*80ee5cbfSDavid du Colombier 
87*80ee5cbfSDavid du Colombier /*
88*80ee5cbfSDavid du Colombier  * lempel-ziv style compression state
89*80ee5cbfSDavid du Colombier  */
90*80ee5cbfSDavid du Colombier struct LZstate
91*80ee5cbfSDavid du Colombier {
92*80ee5cbfSDavid du Colombier 	uchar	hist[HistSize];
93*80ee5cbfSDavid du Colombier 	ulong	pos;				/* current location in history buffer */
94*80ee5cbfSDavid du Colombier 	ulong	avail;				/* data available after pos */
95*80ee5cbfSDavid du Colombier 	int	eof;
96*80ee5cbfSDavid du Colombier 	ushort	hash[HashSize];			/* hash chains */
97*80ee5cbfSDavid du Colombier 	ushort	nexts[MaxOff];
98*80ee5cbfSDavid du Colombier 	int	now;				/* pos in hash chains */
99*80ee5cbfSDavid du Colombier 	int	dot;				/* dawn of time in history */
100*80ee5cbfSDavid du Colombier 	int	prevlen;			/* lazy matching state */
101*80ee5cbfSDavid du Colombier 	int	prevoff;
102*80ee5cbfSDavid du Colombier 	int	maxcheck;			/* compressor tuning */
103*80ee5cbfSDavid du Colombier 
104*80ee5cbfSDavid du Colombier 	uchar	obuf[DeflateOut];
105*80ee5cbfSDavid du Colombier 	uchar	*out;				/* current position in the output buffer */
106*80ee5cbfSDavid du Colombier 	uchar	*eout;
107*80ee5cbfSDavid du Colombier 	ulong	bits;				/* bit shift register */
108*80ee5cbfSDavid du Colombier 	int	nbits;
109*80ee5cbfSDavid du Colombier 	int	rbad;				/* got an error reading the buffer */
110*80ee5cbfSDavid du Colombier 	int	wbad;				/* got an error writing the buffer */
111*80ee5cbfSDavid du Colombier 	int	(*w)(void*, void*, int);
112*80ee5cbfSDavid du Colombier 	void	*wr;
113*80ee5cbfSDavid du Colombier 
114*80ee5cbfSDavid du Colombier 	ulong	totr;				/* total input size */
115*80ee5cbfSDavid du Colombier 	ulong	totw;				/* total output size */
116*80ee5cbfSDavid du Colombier 	int	debug;
117*80ee5cbfSDavid du Colombier };
118*80ee5cbfSDavid du Colombier 
119*80ee5cbfSDavid du Colombier struct LZblock
120*80ee5cbfSDavid du Colombier {
121*80ee5cbfSDavid du Colombier 	ushort	parse[DeflateMaxBlock / 2 + 1];
122*80ee5cbfSDavid du Colombier 	int	lastv;				/* value being constucted for parse */
123*80ee5cbfSDavid du Colombier 	ulong	litlencount[Nlitlen];
124*80ee5cbfSDavid du Colombier 	ulong	offcount[Noff];
125*80ee5cbfSDavid du Colombier 	ushort	*eparse;			/* limit for parse table */
126*80ee5cbfSDavid du Colombier 	int	bytes;				/* consumed from the input */
127*80ee5cbfSDavid du Colombier 	int	excost;				/* cost of encoding extra len & off bits */
128*80ee5cbfSDavid du Colombier };
129*80ee5cbfSDavid du Colombier 
130*80ee5cbfSDavid du Colombier /*
131*80ee5cbfSDavid du Colombier  * huffman code table
132*80ee5cbfSDavid du Colombier  */
133*80ee5cbfSDavid du Colombier struct Huff
134*80ee5cbfSDavid du Colombier {
135*80ee5cbfSDavid du Colombier 	short	bits;				/* length of the code */
136*80ee5cbfSDavid du Colombier 	ushort	encode;				/* the code */
137*80ee5cbfSDavid du Colombier };
138*80ee5cbfSDavid du Colombier 
139*80ee5cbfSDavid du Colombier /*
140*80ee5cbfSDavid du Colombier  * encoding of dynamic huffman trees
141*80ee5cbfSDavid du Colombier  */
142*80ee5cbfSDavid du Colombier struct Dyncode
143*80ee5cbfSDavid du Colombier {
144*80ee5cbfSDavid du Colombier 	int	nlit;
145*80ee5cbfSDavid du Colombier 	int	noff;
146*80ee5cbfSDavid du Colombier 	int	nclen;
147*80ee5cbfSDavid du Colombier 	int	ncode;
148*80ee5cbfSDavid du Colombier 	Huff	codetab[Nclen];
149*80ee5cbfSDavid du Colombier 	uchar	codes[Nlitlen+Noff];
150*80ee5cbfSDavid du Colombier 	uchar	codeaux[Nlitlen+Noff];
151*80ee5cbfSDavid du Colombier };
152*80ee5cbfSDavid du Colombier 
153*80ee5cbfSDavid du Colombier static	int	deflateb(LZstate *lz, LZblock *lzb, void *rr, int (*r)(void*, void*, int));
154*80ee5cbfSDavid du Colombier static	int	lzcomp(LZstate*, LZblock*, uchar*, ushort*, int finish);
155*80ee5cbfSDavid du Colombier static	void	wrblock(LZstate*, int, ushort*, ushort*, Huff*, Huff*);
156*80ee5cbfSDavid du Colombier static	int	bitcost(Huff*, ulong*, int);
157*80ee5cbfSDavid du Colombier static	int	huffcodes(Dyncode*, Huff*, Huff*);
158*80ee5cbfSDavid du Colombier static	void	wrdyncode(LZstate*, Dyncode*);
159*80ee5cbfSDavid du Colombier static	void	lzput(LZstate*, ulong bits, int nbits);
160*80ee5cbfSDavid du Colombier static	void	lzflushbits(LZstate*);
161*80ee5cbfSDavid du Colombier static	void	lzflush(LZstate *lz);
162*80ee5cbfSDavid du Colombier static	void	lzwrite(LZstate *lz, void *buf, int n);
163*80ee5cbfSDavid du Colombier 
164*80ee5cbfSDavid du Colombier static	int	hufftabinit(Huff*, int, ulong*, int);
165*80ee5cbfSDavid du Colombier static	int	mkgzprecode(Huff*, ulong *, int, int);
166*80ee5cbfSDavid du Colombier 
167*80ee5cbfSDavid du Colombier static	int	mkprecode(Huff*, ulong *, int, int, ulong*);
168*80ee5cbfSDavid du Colombier static	void	nextchain(Chains*, int);
169*80ee5cbfSDavid du Colombier static	void	leafsort(ulong*, ushort*, int, int);
170*80ee5cbfSDavid du Colombier 
171*80ee5cbfSDavid du Colombier /* conversion from len to code word */
172*80ee5cbfSDavid du Colombier static int lencode[MaxMatch];
173*80ee5cbfSDavid du Colombier 
174*80ee5cbfSDavid du Colombier /*
175*80ee5cbfSDavid du Colombier  * conversion from off to code word
176*80ee5cbfSDavid du Colombier  * off <= MaxOffCode ? offcode[off] : bigoffcode[off >> 7]
177*80ee5cbfSDavid du Colombier */
178*80ee5cbfSDavid du Colombier static int offcode[MaxOffCode];
179*80ee5cbfSDavid du Colombier static int bigoffcode[256];
180*80ee5cbfSDavid du Colombier 
181*80ee5cbfSDavid du Colombier /* litlen code words LenStart-285 extra bits */
182*80ee5cbfSDavid du Colombier static int litlenbase[Nlitlen-LenStart];
183*80ee5cbfSDavid du Colombier static int litlenextra[Nlitlen-LenStart] =
184*80ee5cbfSDavid du Colombier {
185*80ee5cbfSDavid du Colombier /* 257 */	0, 0, 0,
186*80ee5cbfSDavid du Colombier /* 260 */	0, 0, 0, 0, 0, 1, 1, 1, 1, 2,
187*80ee5cbfSDavid du Colombier /* 270 */	2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
188*80ee5cbfSDavid du Colombier /* 280 */	4, 5, 5, 5, 5, 0, 0, 0
189*80ee5cbfSDavid du Colombier };
190*80ee5cbfSDavid du Colombier 
191*80ee5cbfSDavid du Colombier /* offset code word extra bits */
192*80ee5cbfSDavid du Colombier static int offbase[Noff];
193*80ee5cbfSDavid du Colombier static int offextra[] =
194*80ee5cbfSDavid du Colombier {
195*80ee5cbfSDavid du Colombier 	0,  0,  0,  0,  1,  1,  2,  2,  3,  3,
196*80ee5cbfSDavid du Colombier 	4,  4,  5,  5,  6,  6,  7,  7,  8,  8,
197*80ee5cbfSDavid du Colombier 	9,  9,  10, 10, 11, 11, 12, 12, 13, 13,
198*80ee5cbfSDavid du Colombier 	0,  0,
199*80ee5cbfSDavid du Colombier };
200*80ee5cbfSDavid du Colombier 
201*80ee5cbfSDavid du Colombier /* order code lengths */
202*80ee5cbfSDavid du Colombier static int clenorder[Nclen] =
203*80ee5cbfSDavid du Colombier {
204*80ee5cbfSDavid du Colombier         16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
205*80ee5cbfSDavid du Colombier };
206*80ee5cbfSDavid du Colombier 
207*80ee5cbfSDavid du Colombier /* static huffman tables */
208*80ee5cbfSDavid du Colombier static	Huff	litlentab[Nlitlen];
209*80ee5cbfSDavid du Colombier static	Huff	offtab[Noff];
210*80ee5cbfSDavid du Colombier static	Huff	hofftab[Noff];
211*80ee5cbfSDavid du Colombier 
212*80ee5cbfSDavid du Colombier /* bit reversal for brain dead endian swap in huffman codes */
213*80ee5cbfSDavid du Colombier static	uchar	revtab[256];
214*80ee5cbfSDavid du Colombier static	ulong	nlits;
215*80ee5cbfSDavid du Colombier static	ulong	nmatches;
216*80ee5cbfSDavid du Colombier 
217*80ee5cbfSDavid du Colombier int
deflateinit(void)218*80ee5cbfSDavid du Colombier deflateinit(void)
219*80ee5cbfSDavid du Colombier {
220*80ee5cbfSDavid du Colombier 	ulong bitcount[MaxHuffBits];
221*80ee5cbfSDavid du Colombier 	int i, j, ci, n;
222*80ee5cbfSDavid du Colombier 
223*80ee5cbfSDavid du Colombier 	/* byte reverse table */
224*80ee5cbfSDavid du Colombier 	for(i=0; i<256; i++)
225*80ee5cbfSDavid du Colombier 		for(j=0; j<8; j++)
226*80ee5cbfSDavid du Colombier 			if(i & (1<<j))
227*80ee5cbfSDavid du Colombier 				revtab[i] |= 0x80 >> j;
228*80ee5cbfSDavid du Colombier 
229*80ee5cbfSDavid du Colombier 	/* static Litlen bit lengths */
230*80ee5cbfSDavid du Colombier 	for(i=0; i<144; i++)
231*80ee5cbfSDavid du Colombier 		litlentab[i].bits = 8;
232*80ee5cbfSDavid du Colombier 	for(i=144; i<256; i++)
233*80ee5cbfSDavid du Colombier 		litlentab[i].bits = 9;
234*80ee5cbfSDavid du Colombier 	for(i=256; i<280; i++)
235*80ee5cbfSDavid du Colombier 		litlentab[i].bits = 7;
236*80ee5cbfSDavid du Colombier 	for(i=280; i<Nlitlen; i++)
237*80ee5cbfSDavid du Colombier 		litlentab[i].bits = 8;
238*80ee5cbfSDavid du Colombier 
239*80ee5cbfSDavid du Colombier 	memset(bitcount, 0, sizeof(bitcount));
240*80ee5cbfSDavid du Colombier 	bitcount[8] += 144 - 0;
241*80ee5cbfSDavid du Colombier 	bitcount[9] += 256 - 144;
242*80ee5cbfSDavid du Colombier 	bitcount[7] += 280 - 256;
243*80ee5cbfSDavid du Colombier 	bitcount[8] += Nlitlen - 280;
244*80ee5cbfSDavid du Colombier 
245*80ee5cbfSDavid du Colombier 	if(!hufftabinit(litlentab, Nlitlen, bitcount, 9))
246*80ee5cbfSDavid du Colombier 		return FlateInternal;
247*80ee5cbfSDavid du Colombier 
248*80ee5cbfSDavid du Colombier 	/* static offset bit lengths */
249*80ee5cbfSDavid du Colombier 	for(i = 0; i < Noff; i++)
250*80ee5cbfSDavid du Colombier 		offtab[i].bits = 5;
251*80ee5cbfSDavid du Colombier 
252*80ee5cbfSDavid du Colombier 	memset(bitcount, 0, sizeof(bitcount));
253*80ee5cbfSDavid du Colombier 	bitcount[5] = Noff;
254*80ee5cbfSDavid du Colombier 
255*80ee5cbfSDavid du Colombier 	if(!hufftabinit(offtab, Noff, bitcount, 5))
256*80ee5cbfSDavid du Colombier 		return FlateInternal;
257*80ee5cbfSDavid du Colombier 
258*80ee5cbfSDavid du Colombier 	bitcount[0] = 0;
259*80ee5cbfSDavid du Colombier 	bitcount[1] = 0;
260*80ee5cbfSDavid du Colombier 	if(!mkgzprecode(hofftab, bitcount, 2, MaxHuffBits))
261*80ee5cbfSDavid du Colombier 		return FlateInternal;
262*80ee5cbfSDavid du Colombier 
263*80ee5cbfSDavid du Colombier 	/* conversion tables for lens & offs to codes */
264*80ee5cbfSDavid du Colombier 	ci = 0;
265*80ee5cbfSDavid du Colombier 	for(i = LenStart; i < 286; i++){
266*80ee5cbfSDavid du Colombier 		n = ci + (1 << litlenextra[i - LenStart]);
267*80ee5cbfSDavid du Colombier 		litlenbase[i - LenStart] = ci;
268*80ee5cbfSDavid du Colombier 		for(; ci < n; ci++)
269*80ee5cbfSDavid du Colombier 			lencode[ci] = i;
270*80ee5cbfSDavid du Colombier 	}
271*80ee5cbfSDavid du Colombier 	/* patch up special case for len MaxMatch */
272*80ee5cbfSDavid du Colombier 	lencode[MaxMatch-MinMatch] = 285;
273*80ee5cbfSDavid du Colombier 	litlenbase[285-LenStart] = MaxMatch-MinMatch;
274*80ee5cbfSDavid du Colombier 
275*80ee5cbfSDavid du Colombier 	ci = 0;
276*80ee5cbfSDavid du Colombier 	for(i = 0; i < 16; i++){
277*80ee5cbfSDavid du Colombier 		n = ci + (1 << offextra[i]);
278*80ee5cbfSDavid du Colombier 		offbase[i] = ci;
279*80ee5cbfSDavid du Colombier 		for(; ci < n; ci++)
280*80ee5cbfSDavid du Colombier 			offcode[ci] = i;
281*80ee5cbfSDavid du Colombier 	}
282*80ee5cbfSDavid du Colombier 
283*80ee5cbfSDavid du Colombier 	ci = ci >> 7;
284*80ee5cbfSDavid du Colombier 	for(; i < 30; i++){
285*80ee5cbfSDavid du Colombier 		n = ci + (1 << (offextra[i] - 7));
286*80ee5cbfSDavid du Colombier 		offbase[i] = ci << 7;
287*80ee5cbfSDavid du Colombier 		for(; ci < n; ci++)
288*80ee5cbfSDavid du Colombier 			bigoffcode[ci] = i;
289*80ee5cbfSDavid du Colombier 	}
290*80ee5cbfSDavid du Colombier 	return FlateOk;
291*80ee5cbfSDavid du Colombier }
292*80ee5cbfSDavid du Colombier 
293*80ee5cbfSDavid du Colombier static void
deflatereset(LZstate * lz,int level,int debug)294*80ee5cbfSDavid du Colombier deflatereset(LZstate *lz, int level, int debug)
295*80ee5cbfSDavid du Colombier {
296*80ee5cbfSDavid du Colombier 	memset(lz->nexts, 0, sizeof lz->nexts);
297*80ee5cbfSDavid du Colombier 	memset(lz->hash, 0, sizeof lz->hash);
298*80ee5cbfSDavid du Colombier 	lz->totr = 0;
299*80ee5cbfSDavid du Colombier 	lz->totw = 0;
300*80ee5cbfSDavid du Colombier 	lz->pos = 0;
301*80ee5cbfSDavid du Colombier 	lz->avail = 0;
302*80ee5cbfSDavid du Colombier 	lz->out = lz->obuf;
303*80ee5cbfSDavid du Colombier 	lz->eout = &lz->obuf[DeflateOut];
304*80ee5cbfSDavid du Colombier 	lz->prevlen = MinMatch - 1;
305*80ee5cbfSDavid du Colombier 	lz->prevoff = 0;
306*80ee5cbfSDavid du Colombier 	lz->now = MaxOff + 1;
307*80ee5cbfSDavid du Colombier 	lz->dot = lz->now;
308*80ee5cbfSDavid du Colombier 	lz->bits = 0;
309*80ee5cbfSDavid du Colombier 	lz->nbits = 0;
310*80ee5cbfSDavid du Colombier 	lz->maxcheck = (1 << level);
311*80ee5cbfSDavid du Colombier 	lz->maxcheck -= lz->maxcheck >> 2;
312*80ee5cbfSDavid du Colombier 	if(lz->maxcheck < 2)
313*80ee5cbfSDavid du Colombier 		lz->maxcheck = 2;
314*80ee5cbfSDavid du Colombier 	else if(lz->maxcheck > 1024)
315*80ee5cbfSDavid du Colombier 		lz->maxcheck = 1024;
316*80ee5cbfSDavid du Colombier 
317*80ee5cbfSDavid du Colombier 	lz->debug = debug;
318*80ee5cbfSDavid du Colombier }
319*80ee5cbfSDavid du Colombier 
320*80ee5cbfSDavid du Colombier int
deflate(void * wr,int (* w)(void *,void *,int),void * rr,int (* r)(void *,void *,int),int level,int debug)321*80ee5cbfSDavid du Colombier deflate(void *wr, int (*w)(void*, void*, int), void *rr, int (*r)(void*, void*, int), int level, int debug)
322*80ee5cbfSDavid du Colombier {
323*80ee5cbfSDavid du Colombier 	LZstate *lz;
324*80ee5cbfSDavid du Colombier 	LZblock *lzb;
325*80ee5cbfSDavid du Colombier 	int ok;
326*80ee5cbfSDavid du Colombier 
327*80ee5cbfSDavid du Colombier 	lz = malloc(sizeof *lz + sizeof *lzb);
328*80ee5cbfSDavid du Colombier 	if(lz == nil)
329*80ee5cbfSDavid du Colombier 		return FlateNoMem;
330*80ee5cbfSDavid du Colombier 	lzb = (LZblock*)&lz[1];
331*80ee5cbfSDavid du Colombier 
332*80ee5cbfSDavid du Colombier 	deflatereset(lz, level, debug);
333*80ee5cbfSDavid du Colombier 	lz->w = w;
334*80ee5cbfSDavid du Colombier 	lz->wr = wr;
335*80ee5cbfSDavid du Colombier 	lz->wbad = 0;
336*80ee5cbfSDavid du Colombier 	lz->rbad = 0;
337*80ee5cbfSDavid du Colombier 	lz->eof = 0;
338*80ee5cbfSDavid du Colombier 	ok = FlateOk;
339*80ee5cbfSDavid du Colombier 	while(!lz->eof || lz->avail){
340*80ee5cbfSDavid du Colombier 		ok = deflateb(lz, lzb, rr, r);
341*80ee5cbfSDavid du Colombier 		if(ok != FlateOk)
342*80ee5cbfSDavid du Colombier 			break;
343*80ee5cbfSDavid du Colombier 	}
344*80ee5cbfSDavid du Colombier 	if(ok == FlateOk && lz->rbad)
345*80ee5cbfSDavid du Colombier 		ok = FlateInputFail;
346*80ee5cbfSDavid du Colombier 	if(ok == FlateOk && lz->wbad)
347*80ee5cbfSDavid du Colombier 		ok = FlateOutputFail;
348*80ee5cbfSDavid du Colombier 	free(lz);
349*80ee5cbfSDavid du Colombier 	return ok;
350*80ee5cbfSDavid du Colombier }
351*80ee5cbfSDavid du Colombier 
352*80ee5cbfSDavid du Colombier static int
deflateb(LZstate * lz,LZblock * lzb,void * rr,int (* r)(void *,void *,int))353*80ee5cbfSDavid du Colombier deflateb(LZstate *lz, LZblock *lzb, void *rr, int (*r)(void*, void*, int))
354*80ee5cbfSDavid du Colombier {
355*80ee5cbfSDavid du Colombier 	Dyncode dyncode, hdyncode;
356*80ee5cbfSDavid du Colombier 	Huff dlitlentab[Nlitlen], dofftab[Noff], hlitlentab[Nlitlen];
357*80ee5cbfSDavid du Colombier 	ulong litcount[Nlitlen];
358*80ee5cbfSDavid du Colombier 	long nunc, ndyn, nfix, nhuff;
359*80ee5cbfSDavid du Colombier 	uchar *slop, *hslop;
360*80ee5cbfSDavid du Colombier 	ulong ep;
361*80ee5cbfSDavid du Colombier 	int i, n, m, mm, nslop;
362*80ee5cbfSDavid du Colombier 
363*80ee5cbfSDavid du Colombier 	memset(lzb->litlencount, 0, sizeof lzb->litlencount);
364*80ee5cbfSDavid du Colombier 	memset(lzb->offcount, 0, sizeof lzb->offcount);
365*80ee5cbfSDavid du Colombier 	lzb->litlencount[DeflateEob]++;
366*80ee5cbfSDavid du Colombier 
367*80ee5cbfSDavid du Colombier 	lzb->bytes = 0;
368*80ee5cbfSDavid du Colombier 	lzb->eparse = lzb->parse;
369*80ee5cbfSDavid du Colombier 	lzb->lastv = 0;
370*80ee5cbfSDavid du Colombier 	lzb->excost = 0;
371*80ee5cbfSDavid du Colombier 
372*80ee5cbfSDavid du Colombier 	slop = &lz->hist[lz->pos];
373*80ee5cbfSDavid du Colombier 	n = lz->avail;
374*80ee5cbfSDavid du Colombier 	while(n < DeflateBlock && (!lz->eof || lz->avail)){
375*80ee5cbfSDavid du Colombier 		/*
376*80ee5cbfSDavid du Colombier 		 * fill the buffer as much as possible,
377*80ee5cbfSDavid du Colombier 		 * while leaving room for MaxOff history behind lz->pos,
378*80ee5cbfSDavid du Colombier 		 * and not reading more than we can handle.
379*80ee5cbfSDavid du Colombier 		 *
380*80ee5cbfSDavid du Colombier 		 * make sure we read at least HistSlop bytes.
381*80ee5cbfSDavid du Colombier 		 */
382*80ee5cbfSDavid du Colombier 		if(!lz->eof){
383*80ee5cbfSDavid du Colombier 			ep = lz->pos + lz->avail;
384*80ee5cbfSDavid du Colombier 			if(ep >= HistBlock)
385*80ee5cbfSDavid du Colombier 				ep -= HistBlock;
386*80ee5cbfSDavid du Colombier 			m = HistBlock - MaxOff - lz->avail;
387*80ee5cbfSDavid du Colombier 			if(m > HistBlock - n)
388*80ee5cbfSDavid du Colombier 				m = HistBlock - n;
389*80ee5cbfSDavid du Colombier 			if(m > (HistBlock + HistSlop) - ep)
390*80ee5cbfSDavid du Colombier 				m = (HistBlock + HistSlop) - ep;
391*80ee5cbfSDavid du Colombier 			if(m & ~(BlockSize - 1))
392*80ee5cbfSDavid du Colombier 				m &= ~(BlockSize - 1);
393*80ee5cbfSDavid du Colombier 
394*80ee5cbfSDavid du Colombier 			/*
395*80ee5cbfSDavid du Colombier 			 * be nice to the caller: stop reads that are too small.
396*80ee5cbfSDavid du Colombier 			 * can only get here when we've already filled the buffer some
397*80ee5cbfSDavid du Colombier 			 */
398*80ee5cbfSDavid du Colombier 			if(m < HistSlop){
399*80ee5cbfSDavid du Colombier 				if(!m || !lzb->bytes)
400*80ee5cbfSDavid du Colombier 					return FlateInternal;
401*80ee5cbfSDavid du Colombier 				break;
402*80ee5cbfSDavid du Colombier 			}
403*80ee5cbfSDavid du Colombier 
404*80ee5cbfSDavid du Colombier 			mm = (*r)(rr, &lz->hist[ep], m);
405*80ee5cbfSDavid du Colombier 			if(mm > 0){
406*80ee5cbfSDavid du Colombier 				/*
407*80ee5cbfSDavid du Colombier 				 * wrap data to end if we're read it from the beginning
408*80ee5cbfSDavid du Colombier 				 * this way, we don't have to wrap searches.
409*80ee5cbfSDavid du Colombier 				 *
410*80ee5cbfSDavid du Colombier 				 * wrap reads past the end to the beginning.
411*80ee5cbfSDavid du Colombier 				 * this way, we can guarantee minimum size reads.
412*80ee5cbfSDavid du Colombier 				 */
413*80ee5cbfSDavid du Colombier 				if(ep < HistSlop)
414*80ee5cbfSDavid du Colombier 					memmove(&lz->hist[ep + HistBlock], &lz->hist[ep], HistSlop - ep);
415*80ee5cbfSDavid du Colombier 				else if(ep + mm > HistBlock)
416*80ee5cbfSDavid du Colombier 					memmove(&lz->hist[0], &lz->hist[HistBlock], ep + mm - HistBlock);
417*80ee5cbfSDavid du Colombier 
418*80ee5cbfSDavid du Colombier 				lz->totr += mm;
419*80ee5cbfSDavid du Colombier 				n += mm;
420*80ee5cbfSDavid du Colombier 				lz->avail += mm;
421*80ee5cbfSDavid du Colombier 			}else{
422*80ee5cbfSDavid du Colombier 				if(mm < 0)
423*80ee5cbfSDavid du Colombier 					lz->rbad = 1;
424*80ee5cbfSDavid du Colombier 				lz->eof = 1;
425*80ee5cbfSDavid du Colombier 			}
426*80ee5cbfSDavid du Colombier 		}
427*80ee5cbfSDavid du Colombier 		ep = lz->pos + lz->avail;
428*80ee5cbfSDavid du Colombier 		if(ep > HistSize)
429*80ee5cbfSDavid du Colombier 			ep = HistSize;
430*80ee5cbfSDavid du Colombier 		if(lzb->bytes + ep - lz->pos > DeflateMaxBlock)
431*80ee5cbfSDavid du Colombier 			ep = lz->pos + DeflateMaxBlock - lzb->bytes;
432*80ee5cbfSDavid du Colombier 		m = lzcomp(lz, lzb, &lz->hist[ep], lzb->eparse, lz->eof);
433*80ee5cbfSDavid du Colombier 		lzb->bytes += m;
434*80ee5cbfSDavid du Colombier 		lz->pos = (lz->pos + m) & (HistBlock - 1);
435*80ee5cbfSDavid du Colombier 		lz->avail -= m;
436*80ee5cbfSDavid du Colombier 	}
437*80ee5cbfSDavid du Colombier 	if(lzb->lastv)
438*80ee5cbfSDavid du Colombier 		*lzb->eparse++ = lzb->lastv;
439*80ee5cbfSDavid du Colombier 	if(lzb->eparse > lzb->parse + nelem(lzb->parse))
440*80ee5cbfSDavid du Colombier 		return FlateInternal;
441*80ee5cbfSDavid du Colombier 	nunc = lzb->bytes;
442*80ee5cbfSDavid du Colombier 
443*80ee5cbfSDavid du Colombier 	if(!mkgzprecode(dlitlentab, lzb->litlencount, Nlitlen, MaxHuffBits)
444*80ee5cbfSDavid du Colombier 	|| !mkgzprecode(dofftab, lzb->offcount, Noff, MaxHuffBits))
445*80ee5cbfSDavid du Colombier 		return FlateInternal;
446*80ee5cbfSDavid du Colombier 
447*80ee5cbfSDavid du Colombier 	ndyn = huffcodes(&dyncode, dlitlentab, dofftab);
448*80ee5cbfSDavid du Colombier 	if(ndyn < 0)
449*80ee5cbfSDavid du Colombier 		return FlateInternal;
450*80ee5cbfSDavid du Colombier 	ndyn += bitcost(dlitlentab, lzb->litlencount, Nlitlen)
451*80ee5cbfSDavid du Colombier 		+ bitcost(dofftab, lzb->offcount, Noff)
452*80ee5cbfSDavid du Colombier 		+ lzb->excost;
453*80ee5cbfSDavid du Colombier 
454*80ee5cbfSDavid du Colombier 	memset(litcount, 0, sizeof litcount);
455*80ee5cbfSDavid du Colombier 
456*80ee5cbfSDavid du Colombier 	nslop = nunc;
457*80ee5cbfSDavid du Colombier 	if(nslop > &lz->hist[HistSize] - slop)
458*80ee5cbfSDavid du Colombier 		nslop = &lz->hist[HistSize] - slop;
459*80ee5cbfSDavid du Colombier 
460*80ee5cbfSDavid du Colombier 	for(i = 0; i < nslop; i++)
461*80ee5cbfSDavid du Colombier 		litcount[slop[i]]++;
462*80ee5cbfSDavid du Colombier 	hslop = &lz->hist[HistSlop - nslop];
463*80ee5cbfSDavid du Colombier 	for(; i < nunc; i++)
464*80ee5cbfSDavid du Colombier 		litcount[hslop[i]]++;
465*80ee5cbfSDavid du Colombier 	litcount[DeflateEob]++;
466*80ee5cbfSDavid du Colombier 
467*80ee5cbfSDavid du Colombier 	if(!mkgzprecode(hlitlentab, litcount, Nlitlen, MaxHuffBits))
468*80ee5cbfSDavid du Colombier 		return FlateInternal;
469*80ee5cbfSDavid du Colombier 	nhuff = huffcodes(&hdyncode, hlitlentab, hofftab);
470*80ee5cbfSDavid du Colombier 	if(nhuff < 0)
471*80ee5cbfSDavid du Colombier 		return FlateInternal;
472*80ee5cbfSDavid du Colombier 	nhuff += bitcost(hlitlentab, litcount, Nlitlen);
473*80ee5cbfSDavid du Colombier 
474*80ee5cbfSDavid du Colombier 	nfix = bitcost(litlentab, lzb->litlencount, Nlitlen)
475*80ee5cbfSDavid du Colombier 		+ bitcost(offtab, lzb->offcount, Noff)
476*80ee5cbfSDavid du Colombier 		+ lzb->excost;
477*80ee5cbfSDavid du Colombier 
478*80ee5cbfSDavid du Colombier 	lzput(lz, lz->eof && !lz->avail, 1);
479*80ee5cbfSDavid du Colombier 
480*80ee5cbfSDavid du Colombier 	if(lz->debug){
481*80ee5cbfSDavid du Colombier 		fprint(2, "block: bytes=%lud entries=%ld extra bits=%d\n\tuncompressed=%lud fixed=%lud dynamic=%lud huffman=%lud\n",
482*80ee5cbfSDavid du Colombier 			nunc, lzb->eparse - lzb->parse, lzb->excost, (nunc + 4) * 8, nfix, ndyn, nhuff);
483*80ee5cbfSDavid du Colombier 		fprint(2, "\tnlit=%lud matches=%lud eof=%d\n", nlits, nmatches, lz->eof && !lz->avail);
484*80ee5cbfSDavid du Colombier 	}
485*80ee5cbfSDavid du Colombier 
486*80ee5cbfSDavid du Colombier 	if((nunc + 4) * 8 < ndyn && (nunc + 4) * 8 < nfix && (nunc + 4) * 8 < nhuff){
487*80ee5cbfSDavid du Colombier 		lzput(lz, DeflateUnc, 2);
488*80ee5cbfSDavid du Colombier 		lzflushbits(lz);
489*80ee5cbfSDavid du Colombier 
490*80ee5cbfSDavid du Colombier 		lzput(lz, nunc & 0xff, 8);
491*80ee5cbfSDavid du Colombier 		lzput(lz, (nunc >> 8) & 0xff, 8);
492*80ee5cbfSDavid du Colombier 		lzput(lz, ~nunc & 0xff, 8);
493*80ee5cbfSDavid du Colombier 		lzput(lz, (~nunc >> 8) & 0xff, 8);
494*80ee5cbfSDavid du Colombier 		lzflush(lz);
495*80ee5cbfSDavid du Colombier 
496*80ee5cbfSDavid du Colombier 		lzwrite(lz, slop, nslop);
497*80ee5cbfSDavid du Colombier 		lzwrite(lz, &lz->hist[HistSlop], nunc - nslop);
498*80ee5cbfSDavid du Colombier 	}else if(ndyn < nfix && ndyn < nhuff){
499*80ee5cbfSDavid du Colombier 		lzput(lz, DeflateDyn, 2);
500*80ee5cbfSDavid du Colombier 
501*80ee5cbfSDavid du Colombier 		wrdyncode(lz, &dyncode);
502*80ee5cbfSDavid du Colombier 		wrblock(lz, slop - lz->hist, lzb->parse, lzb->eparse, dlitlentab, dofftab);
503*80ee5cbfSDavid du Colombier 		lzput(lz, dlitlentab[DeflateEob].encode, dlitlentab[DeflateEob].bits);
504*80ee5cbfSDavid du Colombier 	}else if(nhuff < nfix){
505*80ee5cbfSDavid du Colombier 		lzput(lz, DeflateDyn, 2);
506*80ee5cbfSDavid du Colombier 
507*80ee5cbfSDavid du Colombier 		wrdyncode(lz, &hdyncode);
508*80ee5cbfSDavid du Colombier 
509*80ee5cbfSDavid du Colombier 		m = 0;
510*80ee5cbfSDavid du Colombier 		for(i = nunc; i > MaxLitRun; i -= MaxLitRun)
511*80ee5cbfSDavid du Colombier 			lzb->parse[m++] = MaxLitRun;
512*80ee5cbfSDavid du Colombier 		lzb->parse[m++] = i;
513*80ee5cbfSDavid du Colombier 
514*80ee5cbfSDavid du Colombier 		wrblock(lz, slop - lz->hist, lzb->parse, lzb->parse + m, hlitlentab, hofftab);
515*80ee5cbfSDavid du Colombier 		lzput(lz, hlitlentab[DeflateEob].encode, hlitlentab[DeflateEob].bits);
516*80ee5cbfSDavid du Colombier 	}else{
517*80ee5cbfSDavid du Colombier 		lzput(lz, DeflateFix, 2);
518*80ee5cbfSDavid du Colombier 
519*80ee5cbfSDavid du Colombier 		wrblock(lz, slop - lz->hist, lzb->parse, lzb->eparse, litlentab, offtab);
520*80ee5cbfSDavid du Colombier 		lzput(lz, litlentab[DeflateEob].encode, litlentab[DeflateEob].bits);
521*80ee5cbfSDavid du Colombier 	}
522*80ee5cbfSDavid du Colombier 
523*80ee5cbfSDavid du Colombier 	if(lz->eof && !lz->avail){
524*80ee5cbfSDavid du Colombier 		lzflushbits(lz);
525*80ee5cbfSDavid du Colombier 		lzflush(lz);
526*80ee5cbfSDavid du Colombier 	}
527*80ee5cbfSDavid du Colombier 	return FlateOk;
528*80ee5cbfSDavid du Colombier }
529*80ee5cbfSDavid du Colombier 
530*80ee5cbfSDavid du Colombier static void
lzwrite(LZstate * lz,void * buf,int n)531*80ee5cbfSDavid du Colombier lzwrite(LZstate *lz, void *buf, int n)
532*80ee5cbfSDavid du Colombier {
533*80ee5cbfSDavid du Colombier 	int nw;
534*80ee5cbfSDavid du Colombier 
535*80ee5cbfSDavid du Colombier 	if(n && lz->w){
536*80ee5cbfSDavid du Colombier 		nw = (*lz->w)(lz->wr, buf, n);
537*80ee5cbfSDavid du Colombier 		if(nw != n){
538*80ee5cbfSDavid du Colombier 			lz->w = nil;
539*80ee5cbfSDavid du Colombier 			lz->wbad = 1;
540*80ee5cbfSDavid du Colombier 		}else
541*80ee5cbfSDavid du Colombier 			lz->totw += n;
542*80ee5cbfSDavid du Colombier 	}
543*80ee5cbfSDavid du Colombier }
544*80ee5cbfSDavid du Colombier 
545*80ee5cbfSDavid du Colombier static void
lzflush(LZstate * lz)546*80ee5cbfSDavid du Colombier lzflush(LZstate *lz)
547*80ee5cbfSDavid du Colombier {
548*80ee5cbfSDavid du Colombier 	lzwrite(lz, lz->obuf, lz->out - lz->obuf);
549*80ee5cbfSDavid du Colombier 	lz->out = lz->obuf;
550*80ee5cbfSDavid du Colombier }
551*80ee5cbfSDavid du Colombier 
552*80ee5cbfSDavid du Colombier static void
lzput(LZstate * lz,ulong bits,int nbits)553*80ee5cbfSDavid du Colombier lzput(LZstate *lz, ulong bits, int nbits)
554*80ee5cbfSDavid du Colombier {
555*80ee5cbfSDavid du Colombier 	bits = (bits << lz->nbits) | lz->bits;
556*80ee5cbfSDavid du Colombier 	for(nbits += lz->nbits; nbits >= 8; nbits -= 8){
557*80ee5cbfSDavid du Colombier 		*lz->out++ = bits;
558*80ee5cbfSDavid du Colombier 		if(lz->out == lz->eout)
559*80ee5cbfSDavid du Colombier 			lzflush(lz);
560*80ee5cbfSDavid du Colombier 		bits >>= 8;
561*80ee5cbfSDavid du Colombier 	}
562*80ee5cbfSDavid du Colombier 	lz->bits = bits;
563*80ee5cbfSDavid du Colombier 	lz->nbits = nbits;
564*80ee5cbfSDavid du Colombier }
565*80ee5cbfSDavid du Colombier 
566*80ee5cbfSDavid du Colombier static void
lzflushbits(LZstate * lz)567*80ee5cbfSDavid du Colombier lzflushbits(LZstate *lz)
568*80ee5cbfSDavid du Colombier {
569*80ee5cbfSDavid du Colombier 	if(lz->nbits)
570*80ee5cbfSDavid du Colombier 		lzput(lz, 0, 8 - (lz->nbits & 7));
571*80ee5cbfSDavid du Colombier }
572*80ee5cbfSDavid du Colombier 
573*80ee5cbfSDavid du Colombier /*
574*80ee5cbfSDavid du Colombier  * write out a block of n samples,
575*80ee5cbfSDavid du Colombier  * given lz encoding and counts for huffman tables
576*80ee5cbfSDavid du Colombier  */
577*80ee5cbfSDavid du Colombier static void
wrblock(LZstate * out,int litoff,ushort * soff,ushort * eoff,Huff * litlentab,Huff * offtab)578*80ee5cbfSDavid du Colombier wrblock(LZstate *out, int litoff, ushort *soff, ushort *eoff, Huff *litlentab, Huff *offtab)
579*80ee5cbfSDavid du Colombier {
580*80ee5cbfSDavid du Colombier 	ushort *off;
581*80ee5cbfSDavid du Colombier 	int i, run, offset, lit, len, c;
582*80ee5cbfSDavid du Colombier 
583*80ee5cbfSDavid du Colombier 	if(out->debug > 2){
584*80ee5cbfSDavid du Colombier 		for(off = soff; off < eoff; ){
585*80ee5cbfSDavid du Colombier 			offset = *off++;
586*80ee5cbfSDavid du Colombier 			run = offset & MaxLitRun;
587*80ee5cbfSDavid du Colombier 			if(run){
588*80ee5cbfSDavid du Colombier 				for(i = 0; i < run; i++){
589*80ee5cbfSDavid du Colombier 					lit = out->hist[litoff & (HistBlock - 1)];
590*80ee5cbfSDavid du Colombier 					litoff++;
591*80ee5cbfSDavid du Colombier 					fprint(2, "\tlit %.2ux %c\n", lit, lit);
592*80ee5cbfSDavid du Colombier 				}
593*80ee5cbfSDavid du Colombier 				if(!(offset & LenFlag))
594*80ee5cbfSDavid du Colombier 					continue;
595*80ee5cbfSDavid du Colombier 				len = offset >> LenShift;
596*80ee5cbfSDavid du Colombier 				offset = *off++;
597*80ee5cbfSDavid du Colombier 			}else if(offset & LenFlag){
598*80ee5cbfSDavid du Colombier 				len = offset >> LenShift;
599*80ee5cbfSDavid du Colombier 				offset = *off++;
600*80ee5cbfSDavid du Colombier 			}else{
601*80ee5cbfSDavid du Colombier 				len = 0;
602*80ee5cbfSDavid du Colombier 				offset >>= LenShift;
603*80ee5cbfSDavid du Colombier 			}
604*80ee5cbfSDavid du Colombier 			litoff += len + MinMatch;
605*80ee5cbfSDavid du Colombier 			fprint(2, "\t<%d, %d>\n", offset + 1, len + MinMatch);
606*80ee5cbfSDavid du Colombier 		}
607*80ee5cbfSDavid du Colombier 	}
608*80ee5cbfSDavid du Colombier 
609*80ee5cbfSDavid du Colombier 	for(off = soff; off < eoff; ){
610*80ee5cbfSDavid du Colombier 		offset = *off++;
611*80ee5cbfSDavid du Colombier 		run = offset & MaxLitRun;
612*80ee5cbfSDavid du Colombier 		if(run){
613*80ee5cbfSDavid du Colombier 			for(i = 0; i < run; i++){
614*80ee5cbfSDavid du Colombier 				lit = out->hist[litoff & (HistBlock - 1)];
615*80ee5cbfSDavid du Colombier 				litoff++;
616*80ee5cbfSDavid du Colombier 				lzput(out, litlentab[lit].encode, litlentab[lit].bits);
617*80ee5cbfSDavid du Colombier 			}
618*80ee5cbfSDavid du Colombier 			if(!(offset & LenFlag))
619*80ee5cbfSDavid du Colombier 				continue;
620*80ee5cbfSDavid du Colombier 			len = offset >> LenShift;
621*80ee5cbfSDavid du Colombier 			offset = *off++;
622*80ee5cbfSDavid du Colombier 		}else if(offset & LenFlag){
623*80ee5cbfSDavid du Colombier 			len = offset >> LenShift;
624*80ee5cbfSDavid du Colombier 			offset = *off++;
625*80ee5cbfSDavid du Colombier 		}else{
626*80ee5cbfSDavid du Colombier 			len = 0;
627*80ee5cbfSDavid du Colombier 			offset >>= LenShift;
628*80ee5cbfSDavid du Colombier 		}
629*80ee5cbfSDavid du Colombier 		litoff += len + MinMatch;
630*80ee5cbfSDavid du Colombier 		c = lencode[len];
631*80ee5cbfSDavid du Colombier 		lzput(out, litlentab[c].encode, litlentab[c].bits);
632*80ee5cbfSDavid du Colombier 		c -= LenStart;
633*80ee5cbfSDavid du Colombier 		if(litlenextra[c])
634*80ee5cbfSDavid du Colombier 			lzput(out, len - litlenbase[c], litlenextra[c]);
635*80ee5cbfSDavid du Colombier 
636*80ee5cbfSDavid du Colombier 		if(offset < MaxOffCode)
637*80ee5cbfSDavid du Colombier 			c = offcode[offset];
638*80ee5cbfSDavid du Colombier 		else
639*80ee5cbfSDavid du Colombier 			c = bigoffcode[offset >> 7];
640*80ee5cbfSDavid du Colombier 		lzput(out, offtab[c].encode, offtab[c].bits);
641*80ee5cbfSDavid du Colombier 		if(offextra[c])
642*80ee5cbfSDavid du Colombier 			lzput(out, offset - offbase[c], offextra[c]);
643*80ee5cbfSDavid du Colombier 	}
644*80ee5cbfSDavid du Colombier }
645*80ee5cbfSDavid du Colombier 
646*80ee5cbfSDavid du Colombier /*
647*80ee5cbfSDavid du Colombier  * look for the longest, closest string which matches
648*80ee5cbfSDavid du Colombier  * the next prefix.  the clever part here is looking for
649*80ee5cbfSDavid du Colombier  * a string 1 longer than the previous best match.
650*80ee5cbfSDavid du Colombier  *
651*80ee5cbfSDavid du Colombier  * follows the recommendation of limiting number of chains
652*80ee5cbfSDavid du Colombier  * which are checked.  this appears to be the best heuristic.
653*80ee5cbfSDavid du Colombier  */
654*80ee5cbfSDavid du Colombier static int
lzmatch(int now,int then,uchar * p,uchar * es,ushort * nexts,uchar * hist,int runlen,int check,int * m)655*80ee5cbfSDavid du Colombier lzmatch(int now, int then, uchar *p, uchar *es, ushort *nexts, uchar *hist, int runlen, int check, int *m)
656*80ee5cbfSDavid du Colombier {
657*80ee5cbfSDavid du Colombier 	uchar *s, *t;
658*80ee5cbfSDavid du Colombier 	int ml, off, last;
659*80ee5cbfSDavid du Colombier 
660*80ee5cbfSDavid du Colombier 	ml = check;
661*80ee5cbfSDavid du Colombier 	if(runlen >= 8)
662*80ee5cbfSDavid du Colombier 		check >>= 2;
663*80ee5cbfSDavid du Colombier 	*m = 0;
664*80ee5cbfSDavid du Colombier 	if(p + runlen >= es)
665*80ee5cbfSDavid du Colombier 		return runlen;
666*80ee5cbfSDavid du Colombier 	last = 0;
667*80ee5cbfSDavid du Colombier 	for(; check-- > 0; then = nexts[then & (MaxOff-1)]){
668*80ee5cbfSDavid du Colombier 		off = (ushort)(now - then);
669*80ee5cbfSDavid du Colombier 		if(off <= last || off > MaxOff)
670*80ee5cbfSDavid du Colombier 			break;
671*80ee5cbfSDavid du Colombier 		s = p + runlen;
672*80ee5cbfSDavid du Colombier 		t = hist + (((p - hist) - off) & (HistBlock-1));
673*80ee5cbfSDavid du Colombier 		t += runlen;
674*80ee5cbfSDavid du Colombier 		for(; s >= p; s--){
675*80ee5cbfSDavid du Colombier 			if(*s != *t)
676*80ee5cbfSDavid du Colombier 				goto matchloop;
677*80ee5cbfSDavid du Colombier 			t--;
678*80ee5cbfSDavid du Colombier 		}
679*80ee5cbfSDavid du Colombier 
680*80ee5cbfSDavid du Colombier 		/*
681*80ee5cbfSDavid du Colombier 		 * we have a new best match.
682*80ee5cbfSDavid du Colombier 		 * extend it to it's maximum length
683*80ee5cbfSDavid du Colombier 		 */
684*80ee5cbfSDavid du Colombier 		t += runlen + 2;
685*80ee5cbfSDavid du Colombier 		s += runlen + 2;
686*80ee5cbfSDavid du Colombier 		for(; s < es; s++){
687*80ee5cbfSDavid du Colombier 			if(*s != *t)
688*80ee5cbfSDavid du Colombier 				break;
689*80ee5cbfSDavid du Colombier 			t++;
690*80ee5cbfSDavid du Colombier 		}
691*80ee5cbfSDavid du Colombier 		runlen = s - p;
692*80ee5cbfSDavid du Colombier 		*m = off - 1;
693*80ee5cbfSDavid du Colombier 		if(s == es || runlen > ml)
694*80ee5cbfSDavid du Colombier 			break;
695*80ee5cbfSDavid du Colombier matchloop:;
696*80ee5cbfSDavid du Colombier 		last = off;
697*80ee5cbfSDavid du Colombier 	}
698*80ee5cbfSDavid du Colombier 	return runlen;
699*80ee5cbfSDavid du Colombier }
700*80ee5cbfSDavid du Colombier 
701*80ee5cbfSDavid du Colombier static int
lzcomp(LZstate * lz,LZblock * lzb,uchar * ep,ushort * parse,int finish)702*80ee5cbfSDavid du Colombier lzcomp(LZstate *lz, LZblock *lzb, uchar *ep, ushort *parse, int finish)
703*80ee5cbfSDavid du Colombier {
704*80ee5cbfSDavid du Colombier 	ulong cont, excost, *litlencount, *offcount;
705*80ee5cbfSDavid du Colombier 	uchar *p, *q, *s, *es;
706*80ee5cbfSDavid du Colombier 	ushort *nexts, *hash;
707*80ee5cbfSDavid du Colombier 	int v, i, h, runlen, n, now, then, m, prevlen, prevoff, maxdefer;
708*80ee5cbfSDavid du Colombier 
709*80ee5cbfSDavid du Colombier 	litlencount = lzb->litlencount;
710*80ee5cbfSDavid du Colombier 	offcount = lzb->offcount;
711*80ee5cbfSDavid du Colombier 	nexts = lz->nexts;
712*80ee5cbfSDavid du Colombier 	hash = lz->hash;
713*80ee5cbfSDavid du Colombier 	now = lz->now;
714*80ee5cbfSDavid du Colombier 
715*80ee5cbfSDavid du Colombier 	p = &lz->hist[lz->pos];
716*80ee5cbfSDavid du Colombier 	if(lz->prevlen != MinMatch - 1)
717*80ee5cbfSDavid du Colombier 		p++;
718*80ee5cbfSDavid du Colombier 
719*80ee5cbfSDavid du Colombier 	/*
720*80ee5cbfSDavid du Colombier 	 * hash in the links for any hanging link positions,
721*80ee5cbfSDavid du Colombier 	 * and calculate the hash for the current position.
722*80ee5cbfSDavid du Colombier 	 */
723*80ee5cbfSDavid du Colombier 	n = MinMatch;
724*80ee5cbfSDavid du Colombier 	if(n > ep - p)
725*80ee5cbfSDavid du Colombier 		n = ep - p;
726*80ee5cbfSDavid du Colombier 	cont = 0;
727*80ee5cbfSDavid du Colombier 	for(i = 0; i < n - 1; i++){
728*80ee5cbfSDavid du Colombier 		m = now - ((MinMatch-1) - i);
729*80ee5cbfSDavid du Colombier 		if(m < lz->dot)
730*80ee5cbfSDavid du Colombier 			continue;
731*80ee5cbfSDavid du Colombier 		s = lz->hist + (((p - lz->hist) - (now - m)) & (HistBlock-1));
732*80ee5cbfSDavid du Colombier 
733*80ee5cbfSDavid du Colombier 		cont = (s[0] << 16) | (s[1] << 8) | s[2];
734*80ee5cbfSDavid du Colombier 		h = hashit(cont);
735*80ee5cbfSDavid du Colombier 		prevoff = 0;
736*80ee5cbfSDavid du Colombier 		for(then = hash[h]; ; then = nexts[then & (MaxOff-1)]){
737*80ee5cbfSDavid du Colombier 			v = (ushort)(now - then);
738*80ee5cbfSDavid du Colombier 			if(v <= prevoff || v >= (MinMatch-1) - i)
739*80ee5cbfSDavid du Colombier 				break;
740*80ee5cbfSDavid du Colombier 			prevoff = v;
741*80ee5cbfSDavid du Colombier 		}
742*80ee5cbfSDavid du Colombier 		if(then == (ushort)m)
743*80ee5cbfSDavid du Colombier 			continue;
744*80ee5cbfSDavid du Colombier 		nexts[m & (MaxOff-1)] = hash[h];
745*80ee5cbfSDavid du Colombier 		hash[h] = m;
746*80ee5cbfSDavid du Colombier 	}
747*80ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++)
748*80ee5cbfSDavid du Colombier 		cont = (cont << 8) | p[i];
749*80ee5cbfSDavid du Colombier 
750*80ee5cbfSDavid du Colombier 	/*
751*80ee5cbfSDavid du Colombier 	 * now must point to the index in the nexts array
752*80ee5cbfSDavid du Colombier 	 * corresponding to p's position in the history
753*80ee5cbfSDavid du Colombier 	 */
754*80ee5cbfSDavid du Colombier 	prevlen = lz->prevlen;
755*80ee5cbfSDavid du Colombier 	prevoff = lz->prevoff;
756*80ee5cbfSDavid du Colombier 	maxdefer = lz->maxcheck >> 2;
757*80ee5cbfSDavid du Colombier 	excost = 0;
758*80ee5cbfSDavid du Colombier 	v = lzb->lastv;
759*80ee5cbfSDavid du Colombier 	for(;;){
760*80ee5cbfSDavid du Colombier 		es = p + MaxMatch;
761*80ee5cbfSDavid du Colombier 		if(es > ep){
762*80ee5cbfSDavid du Colombier 			if(!finish || p >= ep)
763*80ee5cbfSDavid du Colombier 				break;
764*80ee5cbfSDavid du Colombier 			es = ep;
765*80ee5cbfSDavid du Colombier 		}
766*80ee5cbfSDavid du Colombier 
767*80ee5cbfSDavid du Colombier 		h = hashit(cont);
768*80ee5cbfSDavid du Colombier 		runlen = lzmatch(now, hash[h], p, es, nexts, lz->hist, prevlen, lz->maxcheck, &m);
769*80ee5cbfSDavid du Colombier 
770*80ee5cbfSDavid du Colombier 		/*
771*80ee5cbfSDavid du Colombier 		 * back out of small matches too far in the past
772*80ee5cbfSDavid du Colombier 		 */
773*80ee5cbfSDavid du Colombier 		if(runlen == MinMatch && m >= MinMatchMaxOff){
774*80ee5cbfSDavid du Colombier 			runlen = MinMatch - 1;
775*80ee5cbfSDavid du Colombier 			m = 0;
776*80ee5cbfSDavid du Colombier 		}
777*80ee5cbfSDavid du Colombier 
778*80ee5cbfSDavid du Colombier 		/*
779*80ee5cbfSDavid du Colombier 		 * record the encoding and increment counts for huffman trees
780*80ee5cbfSDavid du Colombier 		 * if we get a match, defer selecting it until we check for
781*80ee5cbfSDavid du Colombier 		 * a longer match at the next position.
782*80ee5cbfSDavid du Colombier 		 */
783*80ee5cbfSDavid du Colombier 		if(prevlen >= runlen && prevlen != MinMatch - 1){
784*80ee5cbfSDavid du Colombier 			/*
785*80ee5cbfSDavid du Colombier 			 * old match at least as good; use that one
786*80ee5cbfSDavid du Colombier 			 */
787*80ee5cbfSDavid du Colombier 			n = prevlen - MinMatch;
788*80ee5cbfSDavid du Colombier 			if(v || n){
789*80ee5cbfSDavid du Colombier 				*parse++ = v | LenFlag | (n << LenShift);
790*80ee5cbfSDavid du Colombier 				*parse++ = prevoff;
791*80ee5cbfSDavid du Colombier 			}else
792*80ee5cbfSDavid du Colombier 				*parse++ = prevoff << LenShift;
793*80ee5cbfSDavid du Colombier 			v = 0;
794*80ee5cbfSDavid du Colombier 
795*80ee5cbfSDavid du Colombier 			n = lencode[n];
796*80ee5cbfSDavid du Colombier 			litlencount[n]++;
797*80ee5cbfSDavid du Colombier 			excost += litlenextra[n - LenStart];
798*80ee5cbfSDavid du Colombier 
799*80ee5cbfSDavid du Colombier 			if(prevoff < MaxOffCode)
800*80ee5cbfSDavid du Colombier 				n = offcode[prevoff];
801*80ee5cbfSDavid du Colombier 			else
802*80ee5cbfSDavid du Colombier 				n = bigoffcode[prevoff >> 7];
803*80ee5cbfSDavid du Colombier 			offcount[n]++;
804*80ee5cbfSDavid du Colombier 			excost += offextra[n];
805*80ee5cbfSDavid du Colombier 
806*80ee5cbfSDavid du Colombier 			runlen = prevlen - 1;
807*80ee5cbfSDavid du Colombier 			prevlen = MinMatch - 1;
808*80ee5cbfSDavid du Colombier 			nmatches++;
809*80ee5cbfSDavid du Colombier 		}else if(runlen == MinMatch - 1){
810*80ee5cbfSDavid du Colombier 			/*
811*80ee5cbfSDavid du Colombier 			 * no match; just put out the literal
812*80ee5cbfSDavid du Colombier 			 */
813*80ee5cbfSDavid du Colombier 			if(++v == MaxLitRun){
814*80ee5cbfSDavid du Colombier 				*parse++ = v;
815*80ee5cbfSDavid du Colombier 				v = 0;
816*80ee5cbfSDavid du Colombier 			}
817*80ee5cbfSDavid du Colombier 			litlencount[*p]++;
818*80ee5cbfSDavid du Colombier 			nlits++;
819*80ee5cbfSDavid du Colombier 			runlen = 1;
820*80ee5cbfSDavid du Colombier 		}else{
821*80ee5cbfSDavid du Colombier 			if(prevlen != MinMatch - 1){
822*80ee5cbfSDavid du Colombier 				/*
823*80ee5cbfSDavid du Colombier 				 * longer match now. output previous literal,
824*80ee5cbfSDavid du Colombier 				 * update current match, and try again
825*80ee5cbfSDavid du Colombier 				 */
826*80ee5cbfSDavid du Colombier 				if(++v == MaxLitRun){
827*80ee5cbfSDavid du Colombier 					*parse++ = v;
828*80ee5cbfSDavid du Colombier 					v = 0;
829*80ee5cbfSDavid du Colombier 				}
830*80ee5cbfSDavid du Colombier 				litlencount[p[-1]]++;
831*80ee5cbfSDavid du Colombier 				nlits++;
832*80ee5cbfSDavid du Colombier 			}
833*80ee5cbfSDavid du Colombier 
834*80ee5cbfSDavid du Colombier 			prevoff = m;
835*80ee5cbfSDavid du Colombier 
836*80ee5cbfSDavid du Colombier 			if(runlen < maxdefer){
837*80ee5cbfSDavid du Colombier 				prevlen = runlen;
838*80ee5cbfSDavid du Colombier 				runlen = 1;
839*80ee5cbfSDavid du Colombier 			}else{
840*80ee5cbfSDavid du Colombier 				n = runlen - MinMatch;
841*80ee5cbfSDavid du Colombier 				if(v || n){
842*80ee5cbfSDavid du Colombier 					*parse++ = v | LenFlag | (n << LenShift);
843*80ee5cbfSDavid du Colombier 					*parse++ = prevoff;
844*80ee5cbfSDavid du Colombier 				}else
845*80ee5cbfSDavid du Colombier 					*parse++ = prevoff << LenShift;
846*80ee5cbfSDavid du Colombier 				v = 0;
847*80ee5cbfSDavid du Colombier 
848*80ee5cbfSDavid du Colombier 				n = lencode[n];
849*80ee5cbfSDavid du Colombier 				litlencount[n]++;
850*80ee5cbfSDavid du Colombier 				excost += litlenextra[n - LenStart];
851*80ee5cbfSDavid du Colombier 
852*80ee5cbfSDavid du Colombier 				if(prevoff < MaxOffCode)
853*80ee5cbfSDavid du Colombier 					n = offcode[prevoff];
854*80ee5cbfSDavid du Colombier 				else
855*80ee5cbfSDavid du Colombier 					n = bigoffcode[prevoff >> 7];
856*80ee5cbfSDavid du Colombier 				offcount[n]++;
857*80ee5cbfSDavid du Colombier 				excost += offextra[n];
858*80ee5cbfSDavid du Colombier 
859*80ee5cbfSDavid du Colombier 				prevlen = MinMatch - 1;
860*80ee5cbfSDavid du Colombier 				nmatches++;
861*80ee5cbfSDavid du Colombier 			}
862*80ee5cbfSDavid du Colombier 		}
863*80ee5cbfSDavid du Colombier 
864*80ee5cbfSDavid du Colombier 		/*
865*80ee5cbfSDavid du Colombier 		 * update the hash for the newly matched data
866*80ee5cbfSDavid du Colombier 		 * this is constructed so the link for the old
867*80ee5cbfSDavid du Colombier 		 * match in this position must be at the end of a chain,
868*80ee5cbfSDavid du Colombier 		 * and will expire when this match is added, ie it will
869*80ee5cbfSDavid du Colombier 		 * never be examined by the match loop.
870*80ee5cbfSDavid du Colombier 		 * add to the hash chain only if we have the real hash data.
871*80ee5cbfSDavid du Colombier 		 */
872*80ee5cbfSDavid du Colombier 		for(q = p + runlen; p != q; p++){
873*80ee5cbfSDavid du Colombier 			if(p + MinMatch <= ep){
874*80ee5cbfSDavid du Colombier 				h = hashit(cont);
875*80ee5cbfSDavid du Colombier 				nexts[now & (MaxOff-1)] = hash[h];
876*80ee5cbfSDavid du Colombier 				hash[h] = now;
877*80ee5cbfSDavid du Colombier 				if(p + MinMatch < ep)
878*80ee5cbfSDavid du Colombier 					cont = (cont << 8) | p[MinMatch];
879*80ee5cbfSDavid du Colombier 			}
880*80ee5cbfSDavid du Colombier 			now++;
881*80ee5cbfSDavid du Colombier 		}
882*80ee5cbfSDavid du Colombier 	}
883*80ee5cbfSDavid du Colombier 
884*80ee5cbfSDavid du Colombier 	/*
885*80ee5cbfSDavid du Colombier 	 * we can just store away the lazy state and
886*80ee5cbfSDavid du Colombier 	 * pick it up next time.  the last block will have finish set
887*80ee5cbfSDavid du Colombier 	 * so we won't have any pending matches
888*80ee5cbfSDavid du Colombier 	 * however, we need to correct for how much we've encoded
889*80ee5cbfSDavid du Colombier 	 */
890*80ee5cbfSDavid du Colombier 	if(prevlen != MinMatch - 1)
891*80ee5cbfSDavid du Colombier 		p--;
892*80ee5cbfSDavid du Colombier 
893*80ee5cbfSDavid du Colombier 	lzb->excost += excost;
894*80ee5cbfSDavid du Colombier 	lzb->eparse = parse;
895*80ee5cbfSDavid du Colombier 	lzb->lastv = v;
896*80ee5cbfSDavid du Colombier 
897*80ee5cbfSDavid du Colombier 	lz->now = now;
898*80ee5cbfSDavid du Colombier 	lz->prevlen = prevlen;
899*80ee5cbfSDavid du Colombier 	lz->prevoff = prevoff;
900*80ee5cbfSDavid du Colombier 
901*80ee5cbfSDavid du Colombier 	return p - &lz->hist[lz->pos];
902*80ee5cbfSDavid du Colombier }
903*80ee5cbfSDavid du Colombier 
904*80ee5cbfSDavid du Colombier /*
905*80ee5cbfSDavid du Colombier  * make up the dynamic code tables, and return the number of bits
906*80ee5cbfSDavid du Colombier  * needed to transmit them.
907*80ee5cbfSDavid du Colombier  */
908*80ee5cbfSDavid du Colombier static int
huffcodes(Dyncode * dc,Huff * littab,Huff * offtab)909*80ee5cbfSDavid du Colombier huffcodes(Dyncode *dc, Huff *littab, Huff *offtab)
910*80ee5cbfSDavid du Colombier {
911*80ee5cbfSDavid du Colombier 	Huff *codetab;
912*80ee5cbfSDavid du Colombier 	uchar *codes, *codeaux;
913*80ee5cbfSDavid du Colombier 	ulong codecount[Nclen], excost;
914*80ee5cbfSDavid du Colombier 	int i, n, m, v, c, nlit, noff, ncode, nclen;
915*80ee5cbfSDavid du Colombier 
916*80ee5cbfSDavid du Colombier 	codetab = dc->codetab;
917*80ee5cbfSDavid du Colombier 	codes = dc->codes;
918*80ee5cbfSDavid du Colombier 	codeaux = dc->codeaux;
919*80ee5cbfSDavid du Colombier 
920*80ee5cbfSDavid du Colombier 	/*
921*80ee5cbfSDavid du Colombier 	 * trim the sizes of the tables
922*80ee5cbfSDavid du Colombier 	 */
923*80ee5cbfSDavid du Colombier 	for(nlit = Nlitlen; nlit > 257 && littab[nlit-1].bits == 0; nlit--)
924*80ee5cbfSDavid du Colombier 		;
925*80ee5cbfSDavid du Colombier 	for(noff = Noff; noff > 1 && offtab[noff-1].bits == 0; noff--)
926*80ee5cbfSDavid du Colombier 		;
927*80ee5cbfSDavid du Colombier 
928*80ee5cbfSDavid du Colombier 	/*
929*80ee5cbfSDavid du Colombier 	 * make the code-length code
930*80ee5cbfSDavid du Colombier 	 */
931*80ee5cbfSDavid du Colombier 	for(i = 0; i < nlit; i++)
932*80ee5cbfSDavid du Colombier 		codes[i] = littab[i].bits;
933*80ee5cbfSDavid du Colombier 	for(i = 0; i < noff; i++)
934*80ee5cbfSDavid du Colombier 		codes[i + nlit] = offtab[i].bits;
935*80ee5cbfSDavid du Colombier 
936*80ee5cbfSDavid du Colombier 	/*
937*80ee5cbfSDavid du Colombier 	 * run-length compress the code-length code
938*80ee5cbfSDavid du Colombier 	 */
939*80ee5cbfSDavid du Colombier 	excost = 0;
940*80ee5cbfSDavid du Colombier 	c = 0;
941*80ee5cbfSDavid du Colombier 	ncode = nlit+noff;
942*80ee5cbfSDavid du Colombier 	for(i = 0; i < ncode; ){
943*80ee5cbfSDavid du Colombier 		n = i + 1;
944*80ee5cbfSDavid du Colombier 		v = codes[i];
945*80ee5cbfSDavid du Colombier 		while(n < ncode && v == codes[n])
946*80ee5cbfSDavid du Colombier 			n++;
947*80ee5cbfSDavid du Colombier 		n -= i;
948*80ee5cbfSDavid du Colombier 		i += n;
949*80ee5cbfSDavid du Colombier 		if(v == 0){
950*80ee5cbfSDavid du Colombier 			while(n >= 11){
951*80ee5cbfSDavid du Colombier 				m = n;
952*80ee5cbfSDavid du Colombier 				if(m > 138)
953*80ee5cbfSDavid du Colombier 					m = 138;
954*80ee5cbfSDavid du Colombier 				codes[c] = 18;
955*80ee5cbfSDavid du Colombier 				codeaux[c++] = m - 11;
956*80ee5cbfSDavid du Colombier 				n -= m;
957*80ee5cbfSDavid du Colombier 				excost += 7;
958*80ee5cbfSDavid du Colombier 			}
959*80ee5cbfSDavid du Colombier 			if(n >= 3){
960*80ee5cbfSDavid du Colombier 				codes[c] = 17;
961*80ee5cbfSDavid du Colombier 				codeaux[c++] = n - 3;
962*80ee5cbfSDavid du Colombier 				n = 0;
963*80ee5cbfSDavid du Colombier 				excost += 3;
964*80ee5cbfSDavid du Colombier 			}
965*80ee5cbfSDavid du Colombier 		}
966*80ee5cbfSDavid du Colombier 		while(n--){
967*80ee5cbfSDavid du Colombier 			codes[c++] = v;
968*80ee5cbfSDavid du Colombier 			while(n >= 3){
969*80ee5cbfSDavid du Colombier 				m = n;
970*80ee5cbfSDavid du Colombier 				if(m > 6)
971*80ee5cbfSDavid du Colombier 					m = 6;
972*80ee5cbfSDavid du Colombier 				codes[c] = 16;
973*80ee5cbfSDavid du Colombier 				codeaux[c++] = m - 3;
974*80ee5cbfSDavid du Colombier 				n -= m;
975*80ee5cbfSDavid du Colombier 				excost += 3;
976*80ee5cbfSDavid du Colombier 			}
977*80ee5cbfSDavid du Colombier 		}
978*80ee5cbfSDavid du Colombier 	}
979*80ee5cbfSDavid du Colombier 
980*80ee5cbfSDavid du Colombier 	memset(codecount, 0, sizeof codecount);
981*80ee5cbfSDavid du Colombier 	for(i = 0; i < c; i++)
982*80ee5cbfSDavid du Colombier 		codecount[codes[i]]++;
983*80ee5cbfSDavid du Colombier 	if(!mkgzprecode(codetab, codecount, Nclen, 8))
984*80ee5cbfSDavid du Colombier 		return -1;
985*80ee5cbfSDavid du Colombier 
986*80ee5cbfSDavid du Colombier 	for(nclen = Nclen; nclen > 4 && codetab[clenorder[nclen-1]].bits == 0; nclen--)
987*80ee5cbfSDavid du Colombier 		;
988*80ee5cbfSDavid du Colombier 
989*80ee5cbfSDavid du Colombier 	dc->nlit = nlit;
990*80ee5cbfSDavid du Colombier 	dc->noff = noff;
991*80ee5cbfSDavid du Colombier 	dc->nclen = nclen;
992*80ee5cbfSDavid du Colombier 	dc->ncode = c;
993*80ee5cbfSDavid du Colombier 
994*80ee5cbfSDavid du Colombier 	return 5 + 5 + 4 + nclen * 3 + bitcost(codetab, codecount, Nclen) + excost;
995*80ee5cbfSDavid du Colombier }
996*80ee5cbfSDavid du Colombier 
997*80ee5cbfSDavid du Colombier static void
wrdyncode(LZstate * out,Dyncode * dc)998*80ee5cbfSDavid du Colombier wrdyncode(LZstate *out, Dyncode *dc)
999*80ee5cbfSDavid du Colombier {
1000*80ee5cbfSDavid du Colombier 	Huff *codetab;
1001*80ee5cbfSDavid du Colombier 	uchar *codes, *codeaux;
1002*80ee5cbfSDavid du Colombier 	int i, v, c;
1003*80ee5cbfSDavid du Colombier 
1004*80ee5cbfSDavid du Colombier 	/*
1005*80ee5cbfSDavid du Colombier 	 * write out header, then code length code lengths,
1006*80ee5cbfSDavid du Colombier 	 * and code lengths
1007*80ee5cbfSDavid du Colombier 	 */
1008*80ee5cbfSDavid du Colombier 	lzput(out, dc->nlit-257, 5);
1009*80ee5cbfSDavid du Colombier 	lzput(out, dc->noff-1, 5);
1010*80ee5cbfSDavid du Colombier 	lzput(out, dc->nclen-4, 4);
1011*80ee5cbfSDavid du Colombier 
1012*80ee5cbfSDavid du Colombier 	codetab = dc->codetab;
1013*80ee5cbfSDavid du Colombier 	for(i = 0; i < dc->nclen; i++)
1014*80ee5cbfSDavid du Colombier 		lzput(out, codetab[clenorder[i]].bits, 3);
1015*80ee5cbfSDavid du Colombier 
1016*80ee5cbfSDavid du Colombier 	codes = dc->codes;
1017*80ee5cbfSDavid du Colombier 	codeaux = dc->codeaux;
1018*80ee5cbfSDavid du Colombier 	c = dc->ncode;
1019*80ee5cbfSDavid du Colombier 	for(i = 0; i < c; i++){
1020*80ee5cbfSDavid du Colombier 		v = codes[i];
1021*80ee5cbfSDavid du Colombier 		lzput(out, codetab[v].encode, codetab[v].bits);
1022*80ee5cbfSDavid du Colombier 		if(v >= 16){
1023*80ee5cbfSDavid du Colombier 			if(v == 16)
1024*80ee5cbfSDavid du Colombier 				lzput(out, codeaux[i], 2);
1025*80ee5cbfSDavid du Colombier 			else if(v == 17)
1026*80ee5cbfSDavid du Colombier 				lzput(out, codeaux[i], 3);
1027*80ee5cbfSDavid du Colombier 			else /* v == 18 */
1028*80ee5cbfSDavid du Colombier 				lzput(out, codeaux[i], 7);
1029*80ee5cbfSDavid du Colombier 		}
1030*80ee5cbfSDavid du Colombier 	}
1031*80ee5cbfSDavid du Colombier }
1032*80ee5cbfSDavid du Colombier 
1033*80ee5cbfSDavid du Colombier static int
bitcost(Huff * tab,ulong * count,int n)1034*80ee5cbfSDavid du Colombier bitcost(Huff *tab, ulong *count, int n)
1035*80ee5cbfSDavid du Colombier {
1036*80ee5cbfSDavid du Colombier 	ulong tot;
1037*80ee5cbfSDavid du Colombier 	int i;
1038*80ee5cbfSDavid du Colombier 
1039*80ee5cbfSDavid du Colombier 	tot = 0;
1040*80ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++)
1041*80ee5cbfSDavid du Colombier 		tot += count[i] * tab[i].bits;
1042*80ee5cbfSDavid du Colombier 	return tot;
1043*80ee5cbfSDavid du Colombier }
1044*80ee5cbfSDavid du Colombier 
1045*80ee5cbfSDavid du Colombier static int
mkgzprecode(Huff * tab,ulong * count,int n,int maxbits)1046*80ee5cbfSDavid du Colombier mkgzprecode(Huff *tab, ulong *count, int n, int maxbits)
1047*80ee5cbfSDavid du Colombier {
1048*80ee5cbfSDavid du Colombier 	ulong bitcount[MaxHuffBits];
1049*80ee5cbfSDavid du Colombier 	int i, nbits;
1050*80ee5cbfSDavid du Colombier 
1051*80ee5cbfSDavid du Colombier 	nbits = mkprecode(tab, count, n, maxbits, bitcount);
1052*80ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++){
1053*80ee5cbfSDavid du Colombier 		if(tab[i].bits == -1)
1054*80ee5cbfSDavid du Colombier 			tab[i].bits = 0;
1055*80ee5cbfSDavid du Colombier 		else if(tab[i].bits == 0){
1056*80ee5cbfSDavid du Colombier 			if(nbits != 0 || bitcount[0] != 1)
1057*80ee5cbfSDavid du Colombier 				return 0;
1058*80ee5cbfSDavid du Colombier 			bitcount[1] = 1;
1059*80ee5cbfSDavid du Colombier 			bitcount[0] = 0;
1060*80ee5cbfSDavid du Colombier 			nbits = 1;
1061*80ee5cbfSDavid du Colombier 			tab[i].bits = 1;
1062*80ee5cbfSDavid du Colombier 		}
1063*80ee5cbfSDavid du Colombier 	}
1064*80ee5cbfSDavid du Colombier 	if(bitcount[0] != 0)
1065*80ee5cbfSDavid du Colombier 		return 0;
1066*80ee5cbfSDavid du Colombier 	return hufftabinit(tab, n, bitcount, nbits);
1067*80ee5cbfSDavid du Colombier }
1068*80ee5cbfSDavid du Colombier 
1069*80ee5cbfSDavid du Colombier static int
hufftabinit(Huff * tab,int n,ulong * bitcount,int nbits)1070*80ee5cbfSDavid du Colombier hufftabinit(Huff *tab, int n, ulong *bitcount, int nbits)
1071*80ee5cbfSDavid du Colombier {
1072*80ee5cbfSDavid du Colombier 	ulong code, nc[MaxHuffBits];
1073*80ee5cbfSDavid du Colombier 	int i, bits;
1074*80ee5cbfSDavid du Colombier 
1075*80ee5cbfSDavid du Colombier 	code = 0;
1076*80ee5cbfSDavid du Colombier 	for(bits = 1; bits <= nbits; bits++){
1077*80ee5cbfSDavid du Colombier 		code = (code + bitcount[bits-1]) << 1;
1078*80ee5cbfSDavid du Colombier 		nc[bits] = code;
1079*80ee5cbfSDavid du Colombier 	}
1080*80ee5cbfSDavid du Colombier 
1081*80ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++){
1082*80ee5cbfSDavid du Colombier 		bits = tab[i].bits;
1083*80ee5cbfSDavid du Colombier 		if(bits){
1084*80ee5cbfSDavid du Colombier 			code = nc[bits]++ << (16 - bits);
1085*80ee5cbfSDavid du Colombier 			if(code & ~0xffff)
1086*80ee5cbfSDavid du Colombier 				return 0;
1087*80ee5cbfSDavid du Colombier 			tab[i].encode = revtab[code >> 8] | (revtab[code & 0xff] << 8);
1088*80ee5cbfSDavid du Colombier 		}
1089*80ee5cbfSDavid du Colombier 	}
1090*80ee5cbfSDavid du Colombier 	return 1;
1091*80ee5cbfSDavid du Colombier }
1092*80ee5cbfSDavid du Colombier 
1093*80ee5cbfSDavid du Colombier 
1094*80ee5cbfSDavid du Colombier /*
1095*80ee5cbfSDavid du Colombier  * this should be in a library
1096*80ee5cbfSDavid du Colombier  */
1097*80ee5cbfSDavid du Colombier struct Chain
1098*80ee5cbfSDavid du Colombier {
1099*80ee5cbfSDavid du Colombier 	ulong	count;				/* occurances of everything in the chain */
1100*80ee5cbfSDavid du Colombier 	ushort	leaf;				/* leaves to the left of chain, or leaf value */
1101*80ee5cbfSDavid du Colombier 	char	col;				/* ref count for collecting unused chains */
1102*80ee5cbfSDavid du Colombier 	char	gen;				/* need to generate chains for next lower level */
1103*80ee5cbfSDavid du Colombier 	Chain	*up;				/* Chain up in the lists */
1104*80ee5cbfSDavid du Colombier };
1105*80ee5cbfSDavid du Colombier 
1106*80ee5cbfSDavid du Colombier struct Chains
1107*80ee5cbfSDavid du Colombier {
1108*80ee5cbfSDavid du Colombier 	Chain	*lists[(MaxHuffBits - 1) * 2];
1109*80ee5cbfSDavid du Colombier 	ulong	leafcount[MaxLeaf];		/* sorted list of leaf counts */
1110*80ee5cbfSDavid du Colombier 	ushort	leafmap[MaxLeaf];		/* map to actual leaf number */
1111*80ee5cbfSDavid du Colombier 	int	nleaf;				/* number of leaves */
1112*80ee5cbfSDavid du Colombier 	Chain	chains[ChainMem];
1113*80ee5cbfSDavid du Colombier 	Chain	*echains;
1114*80ee5cbfSDavid du Colombier 	Chain	*free;
1115*80ee5cbfSDavid du Colombier 	char	col;
1116*80ee5cbfSDavid du Colombier 	int	nlists;
1117*80ee5cbfSDavid du Colombier };
1118*80ee5cbfSDavid du Colombier 
1119*80ee5cbfSDavid du Colombier /*
1120*80ee5cbfSDavid du Colombier  * fast, low space overhead algorithm for max depth huffman type codes
1121*80ee5cbfSDavid du Colombier  *
1122*80ee5cbfSDavid du Colombier  * J. Katajainen, A. Moffat and A. Turpin, "A fast and space-economical
1123*80ee5cbfSDavid du Colombier  * algorithm for length-limited coding," Proc. Intl. Symp. on Algorithms
1124*80ee5cbfSDavid du Colombier  * and Computation, Cairns, Australia, Dec. 1995, Lecture Notes in Computer
1125*80ee5cbfSDavid du Colombier  * Science, Vol 1004, J. Staples, P. Eades, N. Katoh, and A. Moffat, eds.,
1126*80ee5cbfSDavid du Colombier  * pp 12-21, Springer Verlag, New York, 1995.
1127*80ee5cbfSDavid du Colombier  */
1128*80ee5cbfSDavid du Colombier static int
mkprecode(Huff * tab,ulong * count,int n,int maxbits,ulong * bitcount)1129*80ee5cbfSDavid du Colombier mkprecode(Huff *tab, ulong *count, int n, int maxbits, ulong *bitcount)
1130*80ee5cbfSDavid du Colombier {
1131*80ee5cbfSDavid du Colombier 	Chains cs;
1132*80ee5cbfSDavid du Colombier 	Chain *c;
1133*80ee5cbfSDavid du Colombier 	int i, m, em, bits;
1134*80ee5cbfSDavid du Colombier 
1135*80ee5cbfSDavid du Colombier 	/*
1136*80ee5cbfSDavid du Colombier 	 * set up the sorted list of leaves
1137*80ee5cbfSDavid du Colombier 	 */
1138*80ee5cbfSDavid du Colombier 	m = 0;
1139*80ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++){
1140*80ee5cbfSDavid du Colombier 		tab[i].bits = -1;
1141*80ee5cbfSDavid du Colombier 		tab[i].encode = 0;
1142*80ee5cbfSDavid du Colombier 		if(count[i] != 0){
1143*80ee5cbfSDavid du Colombier 			cs.leafcount[m] = count[i];
1144*80ee5cbfSDavid du Colombier 			cs.leafmap[m] = i;
1145*80ee5cbfSDavid du Colombier 			m++;
1146*80ee5cbfSDavid du Colombier 		}
1147*80ee5cbfSDavid du Colombier 	}
1148*80ee5cbfSDavid du Colombier 	if(m < 2){
1149*80ee5cbfSDavid du Colombier 		if(m != 0){
1150*80ee5cbfSDavid du Colombier 			tab[cs.leafmap[0]].bits = 0;
1151*80ee5cbfSDavid du Colombier 			bitcount[0] = 1;
1152*80ee5cbfSDavid du Colombier 		}else
1153*80ee5cbfSDavid du Colombier 			bitcount[0] = 0;
1154*80ee5cbfSDavid du Colombier 		return 0;
1155*80ee5cbfSDavid du Colombier 	}
1156*80ee5cbfSDavid du Colombier 	cs.nleaf = m;
1157*80ee5cbfSDavid du Colombier 	leafsort(cs.leafcount, cs.leafmap, 0, m);
1158*80ee5cbfSDavid du Colombier 
1159*80ee5cbfSDavid du Colombier 	for(i = 0; i < m; i++)
1160*80ee5cbfSDavid du Colombier 		cs.leafcount[i] = count[cs.leafmap[i]];
1161*80ee5cbfSDavid du Colombier 
1162*80ee5cbfSDavid du Colombier 	/*
1163*80ee5cbfSDavid du Colombier 	 * set up free list
1164*80ee5cbfSDavid du Colombier 	 */
1165*80ee5cbfSDavid du Colombier 	cs.free = &cs.chains[2];
1166*80ee5cbfSDavid du Colombier 	cs.echains = &cs.chains[ChainMem];
1167*80ee5cbfSDavid du Colombier 	cs.col = 1;
1168*80ee5cbfSDavid du Colombier 
1169*80ee5cbfSDavid du Colombier 	/*
1170*80ee5cbfSDavid du Colombier 	 * initialize chains for each list
1171*80ee5cbfSDavid du Colombier 	 */
1172*80ee5cbfSDavid du Colombier 	c = &cs.chains[0];
1173*80ee5cbfSDavid du Colombier 	c->count = cs.leafcount[0];
1174*80ee5cbfSDavid du Colombier 	c->leaf = 1;
1175*80ee5cbfSDavid du Colombier 	c->col = cs.col;
1176*80ee5cbfSDavid du Colombier 	c->up = nil;
1177*80ee5cbfSDavid du Colombier 	c->gen = 0;
1178*80ee5cbfSDavid du Colombier 	cs.chains[1] = cs.chains[0];
1179*80ee5cbfSDavid du Colombier 	cs.chains[1].leaf = 2;
1180*80ee5cbfSDavid du Colombier 	cs.chains[1].count = cs.leafcount[1];
1181*80ee5cbfSDavid du Colombier 	for(i = 0; i < maxbits-1; i++){
1182*80ee5cbfSDavid du Colombier 		cs.lists[i * 2] = &cs.chains[0];
1183*80ee5cbfSDavid du Colombier 		cs.lists[i * 2 + 1] = &cs.chains[1];
1184*80ee5cbfSDavid du Colombier 	}
1185*80ee5cbfSDavid du Colombier 
1186*80ee5cbfSDavid du Colombier 	cs.nlists = 2 * (maxbits - 1);
1187*80ee5cbfSDavid du Colombier 	m = 2 * m - 2;
1188*80ee5cbfSDavid du Colombier 	for(i = 2; i < m; i++)
1189*80ee5cbfSDavid du Colombier 		nextchain(&cs, cs.nlists - 2);
1190*80ee5cbfSDavid du Colombier 
1191*80ee5cbfSDavid du Colombier 	bits = 0;
1192*80ee5cbfSDavid du Colombier 	bitcount[0] = cs.nleaf;
1193*80ee5cbfSDavid du Colombier 	for(c = cs.lists[cs.nlists - 1]; c != nil; c = c->up){
1194*80ee5cbfSDavid du Colombier 		m = c->leaf;
1195*80ee5cbfSDavid du Colombier 		bitcount[bits++] -= m;
1196*80ee5cbfSDavid du Colombier 		bitcount[bits] = m;
1197*80ee5cbfSDavid du Colombier 	}
1198*80ee5cbfSDavid du Colombier 	m = 0;
1199*80ee5cbfSDavid du Colombier 	for(i = bits; i >= 0; i--)
1200*80ee5cbfSDavid du Colombier 		for(em = m + bitcount[i]; m < em; m++)
1201*80ee5cbfSDavid du Colombier 			tab[cs.leafmap[m]].bits = i;
1202*80ee5cbfSDavid du Colombier 
1203*80ee5cbfSDavid du Colombier 	return bits;
1204*80ee5cbfSDavid du Colombier }
1205*80ee5cbfSDavid du Colombier 
1206*80ee5cbfSDavid du Colombier /*
1207*80ee5cbfSDavid du Colombier  * calculate the next chain on the list
1208*80ee5cbfSDavid du Colombier  * we can always toss out the old chain
1209*80ee5cbfSDavid du Colombier  */
1210*80ee5cbfSDavid du Colombier static void
nextchain(Chains * cs,int list)1211*80ee5cbfSDavid du Colombier nextchain(Chains *cs, int list)
1212*80ee5cbfSDavid du Colombier {
1213*80ee5cbfSDavid du Colombier 	Chain *c, *oc;
1214*80ee5cbfSDavid du Colombier 	int i, nleaf, sumc;
1215*80ee5cbfSDavid du Colombier 
1216*80ee5cbfSDavid du Colombier 	oc = cs->lists[list + 1];
1217*80ee5cbfSDavid du Colombier 	cs->lists[list] = oc;
1218*80ee5cbfSDavid du Colombier 	if(oc == nil)
1219*80ee5cbfSDavid du Colombier 		return;
1220*80ee5cbfSDavid du Colombier 
1221*80ee5cbfSDavid du Colombier 	/*
1222*80ee5cbfSDavid du Colombier 	 * make sure we have all chains needed to make sumc
1223*80ee5cbfSDavid du Colombier 	 * note it is possible to generate only one of these,
1224*80ee5cbfSDavid du Colombier 	 * use twice that value for sumc, and then generate
1225*80ee5cbfSDavid du Colombier 	 * the second if that preliminary sumc would be chosen.
1226*80ee5cbfSDavid du Colombier 	 * however, this appears to be slower on current tests
1227*80ee5cbfSDavid du Colombier 	 */
1228*80ee5cbfSDavid du Colombier 	if(oc->gen){
1229*80ee5cbfSDavid du Colombier 		nextchain(cs, list - 2);
1230*80ee5cbfSDavid du Colombier 		nextchain(cs, list - 2);
1231*80ee5cbfSDavid du Colombier 		oc->gen = 0;
1232*80ee5cbfSDavid du Colombier 	}
1233*80ee5cbfSDavid du Colombier 
1234*80ee5cbfSDavid du Colombier 	/*
1235*80ee5cbfSDavid du Colombier 	 * pick up the chain we're going to add;
1236*80ee5cbfSDavid du Colombier 	 * collect unused chains no free ones are left
1237*80ee5cbfSDavid du Colombier 	 */
1238*80ee5cbfSDavid du Colombier 	for(c = cs->free; ; c++){
1239*80ee5cbfSDavid du Colombier 		if(c >= cs->echains){
1240*80ee5cbfSDavid du Colombier 			cs->col++;
1241*80ee5cbfSDavid du Colombier 			for(i = 0; i < cs->nlists; i++)
1242*80ee5cbfSDavid du Colombier 				for(c = cs->lists[i]; c != nil; c = c->up)
1243*80ee5cbfSDavid du Colombier 					c->col = cs->col;
1244*80ee5cbfSDavid du Colombier 			c = cs->chains;
1245*80ee5cbfSDavid du Colombier 		}
1246*80ee5cbfSDavid du Colombier 		if(c->col != cs->col)
1247*80ee5cbfSDavid du Colombier 			break;
1248*80ee5cbfSDavid du Colombier 	}
1249*80ee5cbfSDavid du Colombier 
1250*80ee5cbfSDavid du Colombier 	/*
1251*80ee5cbfSDavid du Colombier 	 * pick the cheapest of
1252*80ee5cbfSDavid du Colombier 	 * 1) the next package from the previous list
1253*80ee5cbfSDavid du Colombier 	 * 2) the next leaf
1254*80ee5cbfSDavid du Colombier 	 */
1255*80ee5cbfSDavid du Colombier 	nleaf = oc->leaf;
1256*80ee5cbfSDavid du Colombier 	sumc = 0;
1257*80ee5cbfSDavid du Colombier 	if(list > 0 && cs->lists[list-1] != nil)
1258*80ee5cbfSDavid du Colombier 		sumc = cs->lists[list-2]->count + cs->lists[list-1]->count;
1259*80ee5cbfSDavid du Colombier 	if(sumc != 0 && (nleaf >= cs->nleaf || cs->leafcount[nleaf] > sumc)){
1260*80ee5cbfSDavid du Colombier 		c->count = sumc;
1261*80ee5cbfSDavid du Colombier 		c->leaf = oc->leaf;
1262*80ee5cbfSDavid du Colombier 		c->up = cs->lists[list-1];
1263*80ee5cbfSDavid du Colombier 		c->gen = 1;
1264*80ee5cbfSDavid du Colombier 	}else if(nleaf >= cs->nleaf){
1265*80ee5cbfSDavid du Colombier 		cs->lists[list + 1] = nil;
1266*80ee5cbfSDavid du Colombier 		return;
1267*80ee5cbfSDavid du Colombier 	}else{
1268*80ee5cbfSDavid du Colombier 		c->leaf = nleaf + 1;
1269*80ee5cbfSDavid du Colombier 		c->count = cs->leafcount[nleaf];
1270*80ee5cbfSDavid du Colombier 		c->up = oc->up;
1271*80ee5cbfSDavid du Colombier 		c->gen = 0;
1272*80ee5cbfSDavid du Colombier 	}
1273*80ee5cbfSDavid du Colombier 	cs->free = c + 1;
1274*80ee5cbfSDavid du Colombier 
1275*80ee5cbfSDavid du Colombier 	cs->lists[list + 1] = c;
1276*80ee5cbfSDavid du Colombier 	c->col = cs->col;
1277*80ee5cbfSDavid du Colombier }
1278*80ee5cbfSDavid du Colombier 
1279*80ee5cbfSDavid du Colombier static int
pivot(ulong * c,int a,int n)1280*80ee5cbfSDavid du Colombier pivot(ulong *c, int a, int n)
1281*80ee5cbfSDavid du Colombier {
1282*80ee5cbfSDavid du Colombier 	int j, pi, pj, pk;
1283*80ee5cbfSDavid du Colombier 
1284*80ee5cbfSDavid du Colombier 	j = n/6;
1285*80ee5cbfSDavid du Colombier 	pi = a + j;	/* 1/6 */
1286*80ee5cbfSDavid du Colombier 	j += j;
1287*80ee5cbfSDavid du Colombier 	pj = pi + j;	/* 1/2 */
1288*80ee5cbfSDavid du Colombier 	pk = pj + j;	/* 5/6 */
1289*80ee5cbfSDavid du Colombier 	if(c[pi] < c[pj]){
1290*80ee5cbfSDavid du Colombier 		if(c[pi] < c[pk]){
1291*80ee5cbfSDavid du Colombier 			if(c[pj] < c[pk])
1292*80ee5cbfSDavid du Colombier 				return pj;
1293*80ee5cbfSDavid du Colombier 			return pk;
1294*80ee5cbfSDavid du Colombier 		}
1295*80ee5cbfSDavid du Colombier 		return pi;
1296*80ee5cbfSDavid du Colombier 	}
1297*80ee5cbfSDavid du Colombier 	if(c[pj] < c[pk]){
1298*80ee5cbfSDavid du Colombier 		if(c[pi] < c[pk])
1299*80ee5cbfSDavid du Colombier 			return pi;
1300*80ee5cbfSDavid du Colombier 		return pk;
1301*80ee5cbfSDavid du Colombier 	}
1302*80ee5cbfSDavid du Colombier 	return pj;
1303*80ee5cbfSDavid du Colombier }
1304*80ee5cbfSDavid du Colombier 
1305*80ee5cbfSDavid du Colombier static	void
leafsort(ulong * leafcount,ushort * leafmap,int a,int n)1306*80ee5cbfSDavid du Colombier leafsort(ulong *leafcount, ushort *leafmap, int a, int n)
1307*80ee5cbfSDavid du Colombier {
1308*80ee5cbfSDavid du Colombier 	ulong t;
1309*80ee5cbfSDavid du Colombier 	int j, pi, pj, pn;
1310*80ee5cbfSDavid du Colombier 
1311*80ee5cbfSDavid du Colombier 	while(n > 1){
1312*80ee5cbfSDavid du Colombier 		if(n > 10){
1313*80ee5cbfSDavid du Colombier 			pi = pivot(leafcount, a, n);
1314*80ee5cbfSDavid du Colombier 		}else
1315*80ee5cbfSDavid du Colombier 			pi = a + (n>>1);
1316*80ee5cbfSDavid du Colombier 
1317*80ee5cbfSDavid du Colombier 		t = leafcount[pi];
1318*80ee5cbfSDavid du Colombier 		leafcount[pi] = leafcount[a];
1319*80ee5cbfSDavid du Colombier 		leafcount[a] = t;
1320*80ee5cbfSDavid du Colombier 		t = leafmap[pi];
1321*80ee5cbfSDavid du Colombier 		leafmap[pi] = leafmap[a];
1322*80ee5cbfSDavid du Colombier 		leafmap[a] = t;
1323*80ee5cbfSDavid du Colombier 		pi = a;
1324*80ee5cbfSDavid du Colombier 		pn = a + n;
1325*80ee5cbfSDavid du Colombier 		pj = pn;
1326*80ee5cbfSDavid du Colombier 		for(;;){
1327*80ee5cbfSDavid du Colombier 			do
1328*80ee5cbfSDavid du Colombier 				pi++;
1329*80ee5cbfSDavid du Colombier 			while(pi < pn && (leafcount[pi] < leafcount[a] || leafcount[pi] == leafcount[a] && leafmap[pi] > leafmap[a]));
1330*80ee5cbfSDavid du Colombier 			do
1331*80ee5cbfSDavid du Colombier 				pj--;
1332*80ee5cbfSDavid du Colombier 			while(pj > a && (leafcount[pj] > leafcount[a] || leafcount[pj] == leafcount[a] && leafmap[pj] < leafmap[a]));
1333*80ee5cbfSDavid du Colombier 			if(pj < pi)
1334*80ee5cbfSDavid du Colombier 				break;
1335*80ee5cbfSDavid du Colombier 			t = leafcount[pi];
1336*80ee5cbfSDavid du Colombier 			leafcount[pi] = leafcount[pj];
1337*80ee5cbfSDavid du Colombier 			leafcount[pj] = t;
1338*80ee5cbfSDavid du Colombier 			t = leafmap[pi];
1339*80ee5cbfSDavid du Colombier 			leafmap[pi] = leafmap[pj];
1340*80ee5cbfSDavid du Colombier 			leafmap[pj] = t;
1341*80ee5cbfSDavid du Colombier 		}
1342*80ee5cbfSDavid du Colombier 		t = leafcount[a];
1343*80ee5cbfSDavid du Colombier 		leafcount[a] = leafcount[pj];
1344*80ee5cbfSDavid du Colombier 		leafcount[pj] = t;
1345*80ee5cbfSDavid du Colombier 		t = leafmap[a];
1346*80ee5cbfSDavid du Colombier 		leafmap[a] = leafmap[pj];
1347*80ee5cbfSDavid du Colombier 		leafmap[pj] = t;
1348*80ee5cbfSDavid du Colombier 		j = pj - a;
1349*80ee5cbfSDavid du Colombier 
1350*80ee5cbfSDavid du Colombier 		n = n-j-1;
1351*80ee5cbfSDavid du Colombier 		if(j >= n){
1352*80ee5cbfSDavid du Colombier 			leafsort(leafcount, leafmap, a, j);
1353*80ee5cbfSDavid du Colombier 			a += j+1;
1354*80ee5cbfSDavid du Colombier 		}else{
1355*80ee5cbfSDavid du Colombier 			leafsort(leafcount, leafmap, a + (j+1), n);
1356*80ee5cbfSDavid du Colombier 			n = j;
1357*80ee5cbfSDavid du Colombier 		}
1358*80ee5cbfSDavid du Colombier 	}
1359*80ee5cbfSDavid du Colombier }
1360