flate

deflate implementation
git clone git://git.suckless.org/flate
Log | Files | Refs | README

commit 125cf4e3c02d9e3e8258f164e73dbcc316d18310
parent 6f4def03127440b59a3f06f4e7ef119fdd1fcf8d
Author: nsz <nszabolcs@gmail.com>
Date:   Wed, 17 Jun 2009 09:28:04 +0200

halibut deflate mod (wip)
Diffstat:
deflate_simple.c | 850+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
inflate.c | 3++-
2 files changed, 852 insertions(+), 1 deletion(-)

diff --git a/deflate_simple.c b/deflate_simple.c @@ -0,0 +1,850 @@ +#include <stdlib.h> +#include <string.h> + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned int uint; + +enum { + Nmatch = 32, + HashSize = 2039, + HashChars = 3, + WinSize = 1 << 15, + WinMask = WinSize - 1, + SymSize = 1 << 16, +}; + +enum { + CodeBits = 16, /* max number of bits in a code + 1 */ + Nlit = 256, /* number of lit codes */ + Nlen = 29, /* number of len codes */ + Nlitlen = Nlit + Nlen + 3, /* litlen codes + block end + 2 unused */ + Ndist = 30, /* number of distance codes */ + Nclen = 19 /* number of code length codes */ +}; + +typedef struct { + ushort dist; + ushort len; +} Match; + +typedef struct { + short next; + short prev; /* index within s->win */ + short hash; +} Entry; + +typedef struct { + uchar *len; /* bit length of the code */ + ushort *code; +} Huff; + +typedef struct { + short tab[HashSize]; /* position of hash chain heads */ + int pos; /* position in win and data */ + Entry win[WinSize]; /* hash chains */ + uchar data[WinSize]; /* uncompressed character data */ + uchar pending[HashChars]; /* characters from previous compress */ + int npending; + + ushort *symbuf; /* lz77 literal and (len,dist) sequence */ + int symstart; + int symlen; + + uchar *outbuf; /* encoded output */ + int outpos; + int outlen; + uint bits; + int nbits; + + int type; + int firstblock; + int lastblock; + int finished; + + Huff fixed_litlen; + Huff fixed_dist; + Huff litlen; + Huff dist; + Huff clen; +} State; + +/* TODO: globals.. */ +static Huff lhuff; /* fixed lit/len huffman code tree */ +static Huff dhuff; /* fixed distance huffman code tree */ + +/* base offset and extra bits tables */ +static uchar lenbits[Nlen] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 +}; +static ushort lenbase[Nlen] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 +}; +static uchar distbits[Ndist] = { + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 +}; +static ushort distbase[Ndist] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 +}; + +/* ordering of code lengths */ +static uchar clenorder[Nclen] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; + +static short hash_chars(uchar *p) { + return (257 * p[0] + 263 * p[1] + 269 * p[2]) % HashSize; +} + +static int lz_init(State *s) { + int i; + + for (i = 0; i < WinSize; i++) + s->win[i].next = s->win[i].prev = s->win[i].hash = -1; + for (i = 0; i < HashSize; i++) + s->tab[i] = -1; + s->pos = 0; + s->npending = 0; + return 1; +} + +static void lz_advance(State *s, uchar c, int hash) { + int pos = s->pos; + int next; + + /* remove the hash entry at pos from its chain */ + if (s->win[pos].prev != -1) + s->win[s->win[pos].prev].next = -1; + else if (s->win[pos].hash != -1) + s->tab[s->win[pos].hash] = -1; + + /* create a new entry at pos */ + s->win[pos].hash = hash; + s->win[pos].prev = -1; + s->win[pos].next = next = s->tab[hash]; + s->tab[hash] = pos; + if (next != -1) + s->win[next].prev = pos; + s->data[pos] = c; + s->pos = (pos + 1) & WinMask; +} + +/* s->data[]: past, s->data[s->pos]: present, data[]: future */ +static uchar getbyte(State *s, uchar *data, int n) { + return n < 0 ? s->data[(s->pos + n) & WinMask] : data[n]; +} + +static void literal(State *s, ushort lit); +static void match(State *s, ushort dist, ushort len); + +static void lz_compress(State *s, uchar *data, int len) { + int i, hash, dist, off, nmatch, matchlen, nadvance; + Match defermatch, matches[Nmatch]; + int deferchr; + int pos; + + /* add pending characters from previous compress */ + for (i = 0; i < s->npending; i++) { + uchar a[HashChars]; + int j; + + if (len + s->npending - i < HashChars) { + for (j = i; j < s->npending; j++) + s->pending[j - i] = s->pending[j]; + break; + } + for (j = 0; j < HashChars; j++) + a[j] = i + j < s->npending ? s->pending[i + j] : data[i + j - s->npending]; + lz_advance(s, a[0], hash_chars(a)); + } + s->npending -= i; + + defermatch.len = 0; + deferchr = '\0'; + while (len > 0) { + if (len >= HashChars) { + /* find matches at least HashChars long */ + hash = hash_chars(data); + nmatch = 0; + for (pos = s->tab[hash]; pos != -1; pos = s->win[pos].next) { + /* dist = 1 if pos == s->pos - 1 */ + /* dist = WinSize if pos == s->pos */ + dist = WinSize - (pos + WinSize - s->pos) & WinMask; + for (i = 0; i < HashChars; i++) + if (data[i] != getbyte(s, data, i - dist)) + break; + if (i == HashChars) { + matches[nmatch].dist = dist; + matches[nmatch].len = HashChars; + if (++nmatch >= Nmatch) + break; + } + } + } else { + nmatch = 0; + hash = -1; + } + if (nmatch > 0) { + /* nmatch potential matches, we assume longer match is better */ + matchlen = HashChars; + while (matchlen < len) { + int j; + + for (i = j = 0; i < nmatch; i++) + if (getbyte(s, data, matchlen) == getbyte(s, data, matchlen - matches[i].dist)) + matches[j++] = matches[i]; + if (j == 0) + break; + matchlen++; + nmatch = j; + } + /* among the longest matches favour the shorter distance (matches[0]) */ + matches[0].len = matchlen; + if (defermatch.len > 0) { + if (matches[0].len > defermatch.len + 1) { + /* We have a better match. Emit the deferred char, + * and defer this match. */ + literal(s, deferchr); + defermatch = matches[0]; + deferchr = data[0]; + nadvance = 1; + } else { + /* We don't have a better match. Do the deferred one. */ + match(s, defermatch.dist, defermatch.len); + nadvance = defermatch.len - 1; + defermatch.len = 0; + } + } else { + /* There was no deferred match. Defer this one. */ + defermatch = matches[0]; + deferchr = data[0]; + nadvance = 1; + } + } else { + /* no matches, emit the deferred match or a literal. */ + if (defermatch.len > 0) { + match(s, defermatch.dist, defermatch.len); + nadvance = defermatch.len - 1; + defermatch.len = 0; + } else { + literal(s, data[0]); + nadvance = 1; + } + } + /* advance winpos and keep the window and hash chains consistent. */ + while (nadvance > 0) { + if (len >= HashChars) + lz_advance(s, *data, hash_chars(data)); + else + s->pending[s->npending++] = *data; + data++; + len--; + nadvance--; + } + } +} + +static uint revcode(uint c, int n) { + int i; + uint r = 0; + + for (i = 0; i < n; i++) { + r = (r << 1) | (c & 1); + c >>= 1; + } + return r; +} + +/* huffman codes from code lengths, return max code length */ +static int huffcodes(ushort *codes, const uchar *lens, int n) { + int c[CodeBits]; + int i, left, max; + + /* count code lengths */ + for (i = 0; i < CodeBits; i++) + c[i] = 0; + for (i = 0; i < n; i++) + c[lens[i]]++; + + /* calc max code lengths */ + for (i = CodeBits - 1; i > 0; i--) + if (c[i]) + break; + max = i; + + /* check if length is over-subscribed or incomplete */ + for (left = 2, i = 1; i <= max; i++) { + left -= c[i]; + if (left < 0) + /* over-subscribed */ + return -1; + left <<= 1; + } + if (left > 0) + /* incomlpete */; + + /* calc first code for each length */ + for (i = 2; i <= max; i++) + c[i] += c[i-1]; + + for (i = 0; i < n; i++) + if (lens[i]) + codes[i] = revcode(c[lens[i]]++, lens[i]); + else + codes[i] = 0; + return max; +} + +/* min-heap for buildhuf() */ + +typedef struct { + int key; + int value; +} Item; + +static int heapparent(int n) {return (n - 1)/2;} +static int heapleft(int n) {return 2 * n + 1;} +static int heapright(int n) {return 2 * n + 2;} + +static void heappush(Item *heap, int len, int key, int value) { + int n, dad; + Item tmp; + + heap[len].key = key; + heap[len].value = value; + n = len; + while (n > 0) { + dad = heapparent(n); + if (heap[n].key < heap[dad].key) { + tmp = heap[n]; + heap[n] = heap[dad]; + heap[dad] = tmp; + n = dad; + } else + break; + } +} + +static void heappop(Item *heap, int len, int *key, int *value) { + int n, lc, rc, child; + Item tmp; + + *key = heap[0].key; + *value = heap[0].value; + heap[0] = heap[--len]; + n = 0; + for (;;) { + lc = heapleft(n); + rc = heapright(n); + if (lc >= len) + break; + else if (rc >= len || heap[lc].key < heap[rc].key) + child = lc; + else + child = rc; + if (heap[n].key > heap[child].key) { + tmp = heap[n]; + heap[n] = heap[child]; + heap[child] = tmp; + } else + break; + n = child; + } +} + +/* symbol frequencies -> code lengths (limited to 255) */ +static void hufflens(const int *freqs, uchar *lens, int nsym) { + int parent[2*Nlitlen-1]; + int clen[2*Nlitlen-1]; + Item heap[Nlitlen]; + int n, len; + int i, j; + int wi, wj; + + if (nsym > Nlitlen) + /* TODO: error */; + + for (n = 0; n < nsym; n++) + if (freqs[n] > 0) + heappush(heap, n, freqs[n], n); + + /* build code tree */ + for (len = n; len > 1; n++) { + heappop(heap, len--, &wi, &i); + heappop(heap, len--, &wj, &j); + parent[i] = n; + parent[j] = n; + heappush(heap, len++, wi + wj, n); + } + + /* calc code length */ + clen[--n] = 0; + while (n--) + clen[n] = 1 + clen[parent[n]]; + + /* limit code length to 255 */ + for (n = 0; n < nsym; n++) + lens[n] = clen[n] > 255 ? 255 : clen[n]; +} + +/* F_n if n > 0 */ +static int fib(int n) { + int a, b, tmp; + + for (a = 0, b = 1; n > 1; n--) { + tmp = a; + a = b; + b += tmp; + } + return b; +} + +/* might modify freqs, limit code length */ +static void hufflenslimit(int *freqs, uchar *lens, int nsym, int limit) { + uint minfreq, sumfreq, nrealsym; + int num, den, adjust; + int i, maxprob, count; + + /* TODO: fewer than two symbols: add new */ + if (nsym < 2) + /* error */ abort(); + count = 0; + for (i = 0; i < nsym; i++) + if (freqs[i] > 0) + count++; + if (count < 2) + for (i = 0; count > 0 && i < nsym; i++) + if (freqs[i] == 0) { + freqs[i] = 1; + count--; /* what? */ + } + + /* try building the codes without limit */ + hufflens(freqs, lens, nsym); + + for (i = 0; i < nsym; i++) + if (lens[i] > limit) + break; + if (i == nsym) + return; + + /* + * The Huffman algorithm can only ever generate a code length + * of N bits or more if there is a symbol whose probability is + * less than the reciprocal of the (N+2)th Fibonacci number. + * + * If hufflens() has returned a long code, we add a constant to + * all the (non-zero) symbol frequencies, causing them to become + * more balanced and call hufflens() again. + */ + maxprob = fib(limit + 3); + sumfreq = nrealsym = 0; + minfreq = (uint)-1; + for (i = 0; i < nsym; i++) { + if (freqs[i] == 0) + continue; + if (minfreq > freqs[i]) + minfreq = freqs[i]; + sumfreq += freqs[i]; + nrealsym++; + } + if (minfreq > sumfreq / maxprob) + /* error */ abort(); + + /* + * increase freqs with adjust, the smallest integer such that + * (sumfreq + nrealsym * adjust)/(minfreq + adjust) < maxprob + */ + num = sumfreq - minfreq * maxprob; + den = maxprob - nrealsym; + adjust = (num + den - 1) / den; + for (i = 0; i < nsym; i++) + if (freqs[i] != 0) + freqs[i] += adjust; + + /* rebuild the hufftree */ + hufflens(freqs, lens, nsym); + for (i = 0; i < nsym; i++) + if (lens[i] > limit) + /* error */ abort(); +} + +/* adding < 16 bits to outbuf */ +static int outbits(State *s, uint bits, int nbits) { + s->bits |= bits << s->nbits; + s->nbits += nbits; + while (s->nbits >= 8) { + if (s->outpos == s->outlen) + return -1; + s->outbuf[s->outpos++] = s->bits & 0xff; + s->bits >>= 8; + s->nbits -= 8; + } + return 0; +} + +static void putsym(State *s, ushort sym) { + s->symbuf[(s->symstart + s->symlen++) % SymSize] = sym; +} + +static ushort getsym(State *s, int i) { + return s->symbuf[(s->symstart + i) % SymSize]; +} + +/* build dynamic block or a fixed block of given length */ +static void block(State *s, int dynlen, int fixlen) { + int lfreq[Nlitlen], dfreq[Ndist], cfreq[Nclen]; + uchar llen[Nlitlen], dlen[Ndist], clen[Nclen]; + ushort lcode[Nlitlen], dcode[Ndist], ccode[Nclen]; + int nlit, ndist, nclen, bfinal, btype; + int tree[Nlitlen + Ndist]; + int treesym[Nlitlen + Ndist]; + int codelen[Nclen]; + int i, ntree, ntreesym; + int dynamic, blocklen; + + memset(lfreq, 0, sizeof(lfreq)); + memset(dfreq, 0, sizeof(dfreq)); + lfreq[256] = 1; /* EOB */ + for (i = 0; i < s->symlen; i++) { + ushort sym = getsym(s, i); + + lfreq[sym]++; + if (sym > Nlit) { + i++; /* extra nbits */ + i++; /* extra bits */ + i++; /* dist sym */ + dfreq[getsym(s, i)]++; + i++; /* extra nbits */ + i++; /* extra bits */ + } + } + hufflenslimit(lfreq, llen, Nlitlen, CodeBits-1); + hufflenslimit(dfreq, dlen, Ndist, CodeBits-1); + huffcodes(lcode, llen, Nlitlen); + huffcodes(dcode, dlen, Ndist); + + for (nlit = Nlitlen; nlit > Nlit && llen[nlit-1] == 0; nlit--); + for (ndist = Ndist; ndist > 1 && dlen[ndist-1] == 0; ndist--); + + ntree = 0; + for (i = 0; i < nlit; i++) + tree[ntree++] = llen[i]; + for (i = 0; i < ndist; i++) + tree[ntree++] = dlen[i]; + ntreesym = 0; + for (i = 0; i < ntree;) { + int j = 1; + int k; + + /* get run length of the same item */ + while (i+j < ntree && tree[i+j] == tree[i]) + j++; + + /* encode economically */ + k = j; + if (tree[i] == 0) { + if (k < 3) + while (k--) + treesym[ntreesym++] = 0; + else + while (k > 0) { + int r = k < 138 ? k : 138; + + if (r > k - 3 && r < k) + r = k - 3; + if (r < 11) { + treesym[ntreesym++] = 17; + treesym[ntreesym++] = 3; + treesym[ntreesym++] = r - 3; + } else { + treesym[ntreesym++] = 18; + treesym[ntreesym++] = 7; + treesym[ntreesym++] = r - 11; + } + k -= r; + } + } else { + treesym[ntreesym++] = tree[i]; + k--; + if (k < 3) + while (k--) + treesym[ntreesym++] = tree[i]; + else + while (k > 0) { + int r = k < 6 ? k : 6; + + if (r > k - 3 && r < k) + r = k - 3; + treesym[ntreesym++] = 16; + treesym[ntreesym++] = 2; + treesym[ntreesym++] = r - 3; + k -= r; + } + } + i += j; + } + + memset(cfreq, 0, sizeof(cfreq)); + for (i = 0; i < ntreesym; i++) { + uint sym = treesym[i]; + + cfreq[sym]++; + if (sym >= 16) + i += 2; + } + hufflenslimit(cfreq, clen, Nclen, 7); + huffcodes(ccode, clen, Nclen); + + /* reorder */ + for (i = 0; i < Nclen; i++) + codelen[i] = clen[clenorder[i]]; + for (nclen = Nclen; nclen > 4 && codelen[nclen-1] == 0; nclen--); + + /* exact size of dynamic and fixed block */ + { + int fsize, dsize; + + /* dynamic block */ + dsize = 3 + 5 + 5 + 4; /* 3-bit header, nlit, ndist, nclen */ + dsize += 3 * nclen; /* code-length-alphabet code lengths */ + /* code lengths */ + for (i = 0; i < ntreesym; i++) { + uint sym = treesym[i]; + + dsize += clen[sym]; + if (sym >= 16) { + i++; + dsize += treesym[i]; + i++; + } + } + /* block data */ + for (i = 0; i < dynlen; i++) { + ushort sym = getsym(s, i); + + dsize += llen[sym]; + if (sym > Nlit) { + i++; /* extra nbits */ + dsize += getsym(s, i); + i++; /* extra bits */ + i++; /* dist sym */ + dsize += dlen[getsym(s, i)]; + i++; /* extra nbits */ + dsize += getsym(s, i); + i++; /* extra bits */ + } + } + /* EOB */ + dsize += llen[256]; + + /* fixed block.. TODO */ + fsize = 3; + /* The actual block data */ + for (i = 0; i < fixlen; i++) { + uint sym = getsym(s, i); + + fsize += fixedllen[sym]; + if (sym > Nlit) { + i++; /* extra nbits */ + fsize += getsym(s, i); + i++; /* extra bits */ + i++; /* dist sym */ + fsize += fixeddlen[getsym(s, i)]; + i++; /* extra nbits */ + fsize += getsym(s, i); + i++; /* extra bits */ + } + } + /* EOB */ + fsize += fixedllen[256]; + + dynamic = (long long)fsize * dynlen > (long long)dsize * fixlen; + blocklen = dynamic ? dlen : fixlen; + } + + /* transmit the block */ + + /* 3-bit block header */ + bfinal = s->lastblock ? 1 : 0; + btype = dynamic ? 2 : 1; + outbits(s, bfinal, 1); + outbits(s, btype, 2); + + if (dynamic) { + outbits(s, nlit - 257, 5); + outbits(s, ndist - 1, 5); + outbits(s, nclen - 4, 4); + + /* Code lengths for the auxiliary tree */ + for (i = 0; i < nclen; i++) + outbits(s, codelen[i], 3); + + /* Code lengths for the literal/length and distance trees */ + for (i = 0; i < ntreesym; i++) + writesym(s, treesym[i], ht); + } + + /* Output the actual symbols from the buffer */ + for (i = 0; i < blocklen; i++) + writesym(s, getsym(s, i), ht); + + /* Output the end-of-data symbol */ + writesym(s, 256, ht); + + s->symstart = (s->symstart + blocklen) % SymSize; + s->symlen -= blocklen; +} + +/* rounded 8 * log2(n) */ +static int log2_8(uint n) { + int r = 31*8; + + /* 8 * int log2() */ + if (n < 1U<<16) n <<= 16, r -= 16*8; + if (n < 1U<<24) n <<= 8, r -= 8*8; + if (n < 1U<<28) n <<= 4, r -= 4*8; + if (n < 1U<<30) n <<= 2, r -= 2*8; + if (n < 1U<<31) n <<= 1, r -= 1*8; + + /* + * result is in [r,r+8), to determine the bottom 3 digits: + * thresholds are 1<<31 times an odd power of 2^(1/16) + */ + if (n <= 0xAD583EEAU) { + if (n <= 0x91C3D373U) + r += (n <= 0x85AAC367U ? 0 : 1); + else + r += (n <= 0x9EF53260U ? 2 : 3); + } else { + if (n <= 0xCE248C15U) + r += (n <= 0xBD08A39FU ? 4 : 5); + else + r += (n <= 0xE0CCDEECU ? 6 : n <= 0xF5257D15L ? 7 : 8); + } + return r; +} + +static void chooseblock(State *s) { + int lfreq[Nlitlen], dfreq[Ndist]; + int i, len, bestlen, longestlen = 0; + int ltotal, dtotal; + int bestvfm; + + memset(lfreq, 0, sizeof(lfreq)); + memset(dfreq, 0, sizeof(dfreq)); + lfreq[256] = 1; /* we're bound to need one EOB */ + ltotal = 1; + dtotal = 0; + + /* + * Iterate over all possible block lengths, computing the + * entropic coding approximation to the final length at every + * stage. We divide the result by the number of symbols + * encoded, to determine the `value for money' (overall + * bits-per-symbol count) of a block of that length. + */ + bestlen = -1; + bestvfm = 0; + + len = 300 * 8; /* very approximate size of the Huffman trees */ + + for (i = 0; i < s->symlen; i++) { + ushort sym = getsym(s, i); + + if (i > 0 && sym < Nlit) { + /* + * This is a viable point at which to end the block. + * Compute the value for money. + */ + int vfm = i * 32768 / len; /* symbols encoded per bit */ + + if (bestlen < 0 || vfm > bestvfm) { + bestlen = i; + bestvfm = vfm; + } + + longestlen = i; + } + + /* + * Increment the occurrence counter for this symbol, if + * it's in one of the Huffman alphabets and isn't extra + * bits. + */ + len += lfreq[sym] * approxlog2(lfreq[sym]); + len -= ltotal * approxlog2(ltotal); + lfreq[sym]++; + ltotal++; + len -= lfreq[sym] * approxlog2(lfreq[sym]); + len += ltotal * approxlog2(ltotal); + if (sym > Nlit) { + i++; + sym = getsym(s, i); + len += 8 * sym; + i++; + i++; + sym = getsym(s, i); + len += dfreq[sym] * approxlog2(dfreq[sym]); + len -= dtotal * approxlog2(dtotal); + dfreq[sym]++; + dtotal++; + len -= dfreq[sym] * approxlog2(dfreq[sym]); + len += dtotal * approxlog2(dtotal); + i++; + sym = getsym(s, i); + len += 8 * sym; + i++; + } + } + block(s, bestlen, longestlen); +} + +static int bisect(ushort *base, int len, int n) { + int lo = 0; + int hi = len; + int k; + + while (lo < hi) { + k = (lo + hi) / 2; + if (n < base[k]) + hi = k; + else + lo = k + 1; + } + return lo - 1; +} + +/* place a symbol into the symbuf */ +static void literal(State *s, ushort lit) { + if (s->symlen == SymSize) + chooseblock(s); + putsym(s, lit); +} + +static void match(State *s, ushort dist, ushort len) { + if (s->symlen + 5 >= SymSize) + chooseblock(s); + while (len > 0) { + int n; + int i; + + /* match length can be 3..258 */ + n = len > 260 ? 258 : len <= 258 ? len : len - 3; + len -= n; + + i = bisect(lenbase, Nlen, n); + /* len symbol */ + putsym(s, Nlit + i + 1); + /* len extra */ + putsym(s, lenbits[i]); + putsym(s, n - lenbase[i]); + + i = bisect(distbase, Ndist, dist); + /* dist symbol */ + putsym(s, i); + /* dist extra */ + putsym(s, distbits[i]); + putsym(s, dist - distbase[i]); + } +} diff --git a/inflate.c b/inflate.c @@ -84,7 +84,7 @@ typedef struct { Huff dhuff; /* dynamic distance huffman code tree */ } State; -/* TODO: these globals are initialized in a lazy way (not thread safe) */ +/* TODO: globals.. initialization is not thread safe */ static Huff lhuff; /* fixed lit/len huffman code tree */ static Huff dhuff; /* fixed distance huffman code tree */ @@ -329,6 +329,7 @@ static uint decode_symbol(State *s, Huff *huff) { nbits += 8; } while (nbits < huffbits); } + /* decode bits */ entry = huff->table[bits & mask]; if (entry.len > 0) { s->bits = bits >> entry.len;