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