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