| #include <u.h> |
| #include <libc.h> |
| #include <flate.h> |
| |
| enum { |
| HistorySize= 32*1024, |
| BufSize= 4*1024, |
| MaxHuffBits= 17, /* maximum bits in a encoded code */ |
| Nlitlen= 288, /* number of litlen codes */ |
| Noff= 32, /* number of offset codes */ |
| Nclen= 19, /* number of codelen codes */ |
| LenShift= 10, /* code = len<<LenShift|code */ |
| LitlenBits= 7, /* number of bits in litlen decode table */ |
| OffBits= 6, /* number of bits in offset decode table */ |
| ClenBits= 6, /* number of bits in code len decode table */ |
| MaxFlatBits= LitlenBits, |
| MaxLeaf= Nlitlen |
| }; |
| |
| typedef struct Input Input; |
| typedef struct History History; |
| typedef struct Huff Huff; |
| |
| struct Input |
| { |
| int error; /* first error encountered, or FlateOk */ |
| void *wr; |
| int (*w)(void*, void*, int); |
| void *getr; |
| int (*get)(void*); |
| ulong sreg; |
| int nbits; |
| }; |
| |
| struct History |
| { |
| uchar his[HistorySize]; |
| uchar *cp; /* current pointer in history */ |
| int full; /* his has been filled up at least once */ |
| }; |
| |
| struct Huff |
| { |
| int maxbits; /* max bits for any code */ |
| int minbits; /* min bits to get before looking in flat */ |
| int flatmask; /* bits used in "flat" fast decoding table */ |
| ulong flat[1<<MaxFlatBits]; |
| ulong maxcode[MaxHuffBits]; |
| ulong last[MaxHuffBits]; |
| ulong decode[MaxLeaf]; |
| }; |
| |
| /* litlen code words 257-285 extra bits */ |
| static int litlenextra[Nlitlen-257] = |
| { |
| /* 257 */ 0, 0, 0, |
| /* 260 */ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, |
| /* 270 */ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, |
| /* 280 */ 4, 5, 5, 5, 5, 0, 0, 0 |
| }; |
| |
| static int litlenbase[Nlitlen-257]; |
| |
| /* offset code word extra bits */ |
| static int offextra[Noff] = |
| { |
| 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, |
| 0, 0, |
| }; |
| static int offbase[Noff]; |
| |
| /* order code lengths */ |
| static int clenorder[Nclen] = |
| { |
| 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 |
| }; |
| |
| /* for static huffman tables */ |
| static Huff litlentab; |
| static Huff offtab; |
| static uchar revtab[256]; |
| |
| static int uncblock(Input *in, History*); |
| static int fixedblock(Input *in, History*); |
| static int dynamicblock(Input *in, History*); |
| static int sregfill(Input *in, int n); |
| static int sregunget(Input *in); |
| static int decode(Input*, History*, Huff*, Huff*); |
| static int hufftab(Huff*, char*, int, int); |
| static int hdecsym(Input *in, Huff *h, int b); |
| |
| int |
| inflateinit(void) |
| { |
| char *len; |
| int i, j, base; |
| |
| /* byte reverse table */ |
| for(i=0; i<256; i++) |
| for(j=0; j<8; j++) |
| if(i & (1<<j)) |
| revtab[i] |= 0x80 >> j; |
| |
| for(i=257,base=3; i<Nlitlen; i++) { |
| litlenbase[i-257] = base; |
| base += 1<<litlenextra[i-257]; |
| } |
| /* strange table entry in spec... */ |
| litlenbase[285-257]--; |
| |
| for(i=0,base=1; i<Noff; i++) { |
| offbase[i] = base; |
| base += 1<<offextra[i]; |
| } |
| |
| len = malloc(MaxLeaf); |
| if(len == nil) |
| return FlateNoMem; |
| |
| /* static Litlen bit lengths */ |
| for(i=0; i<144; i++) |
| len[i] = 8; |
| for(i=144; i<256; i++) |
| len[i] = 9; |
| for(i=256; i<280; i++) |
| len[i] = 7; |
| for(i=280; i<Nlitlen; i++) |
| len[i] = 8; |
| |
| if(!hufftab(&litlentab, len, Nlitlen, MaxFlatBits)) |
| return FlateInternal; |
| |
| /* static Offset bit lengths */ |
| for(i=0; i<Noff; i++) |
| len[i] = 5; |
| |
| if(!hufftab(&offtab, len, Noff, MaxFlatBits)) |
| return FlateInternal; |
| free(len); |
| |
| return FlateOk; |
| } |
| |
| int |
| inflate(void *wr, int (*w)(void*, void*, int), void *getr, int (*get)(void*)) |
| { |
| History *his; |
| Input in; |
| int final, type; |
| |
| his = malloc(sizeof(History)); |
| if(his == nil) |
| return FlateNoMem; |
| his->cp = his->his; |
| his->full = 0; |
| in.getr = getr; |
| in.get = get; |
| in.wr = wr; |
| in.w = w; |
| in.nbits = 0; |
| in.sreg = 0; |
| in.error = FlateOk; |
| |
| do { |
| if(!sregfill(&in, 3)) |
| goto bad; |
| final = in.sreg & 0x1; |
| type = (in.sreg>>1) & 0x3; |
| in.sreg >>= 3; |
| in.nbits -= 3; |
| switch(type) { |
| default: |
| in.error = FlateCorrupted; |
| goto bad; |
| case 0: |
| /* uncompressed */ |
| if(!uncblock(&in, his)) |
| goto bad; |
| break; |
| case 1: |
| /* fixed huffman */ |
| if(!fixedblock(&in, his)) |
| goto bad; |
| break; |
| case 2: |
| /* dynamic huffman */ |
| if(!dynamicblock(&in, his)) |
| goto bad; |
| break; |
| } |
| } while(!final); |
| |
| if(his->cp != his->his && (*w)(wr, his->his, his->cp - his->his) != his->cp - his->his) { |
| in.error = FlateOutputFail; |
| goto bad; |
| } |
| |
| if(!sregunget(&in)) |
| goto bad; |
| |
| free(his); |
| if(in.error != FlateOk) |
| return FlateInternal; |
| return FlateOk; |
| |
| bad: |
| free(his); |
| if(in.error == FlateOk) |
| return FlateInternal; |
| return in.error; |
| } |
| |
| static int |
| uncblock(Input *in, History *his) |
| { |
| int len, nlen, c; |
| uchar *hs, *hp, *he; |
| |
| if(!sregunget(in)) |
| return 0; |
| len = (*in->get)(in->getr); |
| len |= (*in->get)(in->getr)<<8; |
| nlen = (*in->get)(in->getr); |
| nlen |= (*in->get)(in->getr)<<8; |
| if(len != (~nlen&0xffff)) { |
| in->error = FlateCorrupted; |
| return 0; |
| } |
| |
| hp = his->cp; |
| hs = his->his; |
| he = hs + HistorySize; |
| |
| while(len > 0) { |
| c = (*in->get)(in->getr); |
| if(c < 0) |
| return 0; |
| *hp++ = c; |
| if(hp == he) { |
| his->full = 1; |
| if((*in->w)(in->wr, hs, HistorySize) != HistorySize) { |
| in->error = FlateOutputFail; |
| return 0; |
| } |
| hp = hs; |
| } |
| len--; |
| } |
| |
| his->cp = hp; |
| |
| return 1; |
| } |
| |
| static int |
| fixedblock(Input *in, History *his) |
| { |
| return decode(in, his, &litlentab, &offtab); |
| } |
| |
| static int |
| dynamicblock(Input *in, History *his) |
| { |
| Huff *lentab, *offtab; |
| char *len; |
| int i, j, n, c, nlit, ndist, nclen, res, nb; |
| |
| if(!sregfill(in, 14)) |
| return 0; |
| nlit = (in->sreg&0x1f) + 257; |
| ndist = ((in->sreg>>5) & 0x1f) + 1; |
| nclen = ((in->sreg>>10) & 0xf) + 4; |
| in->sreg >>= 14; |
| in->nbits -= 14; |
| |
| if(nlit > Nlitlen || ndist > Noff || nlit < 257) { |
| in->error = FlateCorrupted; |
| return 0; |
| } |
| |
| /* huff table header */ |
| len = malloc(Nlitlen+Noff); |
| lentab = malloc(sizeof(Huff)); |
| offtab = malloc(sizeof(Huff)); |
| if(len == nil || lentab == nil || offtab == nil){ |
| in->error = FlateNoMem; |
| goto bad; |
| } |
| for(i=0; i < Nclen; i++) |
| len[i] = 0; |
| for(i=0; i<nclen; i++) { |
| if(!sregfill(in, 3)) |
| goto bad; |
| len[clenorder[i]] = in->sreg & 0x7; |
| in->sreg >>= 3; |
| in->nbits -= 3; |
| } |
| |
| if(!hufftab(lentab, len, Nclen, ClenBits)){ |
| in->error = FlateCorrupted; |
| goto bad; |
| } |
| |
| n = nlit+ndist; |
| for(i=0; i<n;) { |
| nb = lentab->minbits; |
| for(;;){ |
| if(in->nbits<nb && !sregfill(in, nb)) |
| goto bad; |
| c = lentab->flat[in->sreg & lentab->flatmask]; |
| nb = c & 0xff; |
| if(nb > in->nbits){ |
| if(nb != 0xff) |
| continue; |
| c = hdecsym(in, lentab, c); |
| if(c < 0) |
| goto bad; |
| }else{ |
| c >>= 8; |
| in->sreg >>= nb; |
| in->nbits -= nb; |
| } |
| break; |
| } |
| |
| if(c < 16) { |
| j = 1; |
| } else if(c == 16) { |
| if(in->nbits<2 && !sregfill(in, 2)) |
| goto bad; |
| j = (in->sreg&0x3)+3; |
| in->sreg >>= 2; |
| in->nbits -= 2; |
| if(i == 0) { |
| in->error = FlateCorrupted; |
| goto bad; |
| } |
| c = len[i-1]; |
| } else if(c == 17) { |
| if(in->nbits<3 && !sregfill(in, 3)) |
| goto bad; |
| j = (in->sreg&0x7)+3; |
| in->sreg >>= 3; |
| in->nbits -= 3; |
| c = 0; |
| } else if(c == 18) { |
| if(in->nbits<7 && !sregfill(in, 7)) |
| goto bad; |
| j = (in->sreg&0x7f)+11; |
| in->sreg >>= 7; |
| in->nbits -= 7; |
| c = 0; |
| } else { |
| in->error = FlateCorrupted; |
| goto bad; |
| } |
| |
| if(i+j > n) { |
| in->error = FlateCorrupted; |
| goto bad; |
| } |
| |
| while(j) { |
| len[i] = c; |
| i++; |
| j--; |
| } |
| } |
| |
| if(!hufftab(lentab, len, nlit, LitlenBits) |
| || !hufftab(offtab, &len[nlit], ndist, OffBits)){ |
| in->error = FlateCorrupted; |
| goto bad; |
| } |
| |
| res = decode(in, his, lentab, offtab); |
| |
| free(len); |
| free(lentab); |
| free(offtab); |
| |
| return res; |
| |
| bad: |
| free(len); |
| free(lentab); |
| free(offtab); |
| return 0; |
| } |
| |
| static int |
| decode(Input *in, History *his, Huff *litlentab, Huff *offtab) |
| { |
| int len, off; |
| uchar *hs, *hp, *hq, *he; |
| int c; |
| int nb; |
| |
| hs = his->his; |
| he = hs + HistorySize; |
| hp = his->cp; |
| |
| for(;;) { |
| nb = litlentab->minbits; |
| for(;;){ |
| if(in->nbits<nb && !sregfill(in, nb)) |
| return 0; |
| c = litlentab->flat[in->sreg & litlentab->flatmask]; |
| nb = c & 0xff; |
| if(nb > in->nbits){ |
| if(nb != 0xff) |
| continue; |
| c = hdecsym(in, litlentab, c); |
| if(c < 0) |
| return 0; |
| }else{ |
| c >>= 8; |
| in->sreg >>= nb; |
| in->nbits -= nb; |
| } |
| break; |
| } |
| |
| if(c < 256) { |
| /* literal */ |
| *hp++ = c; |
| if(hp == he) { |
| his->full = 1; |
| if((*in->w)(in->wr, hs, HistorySize) != HistorySize) { |
| in->error = FlateOutputFail; |
| return 0; |
| } |
| hp = hs; |
| } |
| continue; |
| } |
| |
| if(c == 256) |
| break; |
| |
| if(c > 285) { |
| in->error = FlateCorrupted; |
| return 0; |
| } |
| |
| c -= 257; |
| nb = litlenextra[c]; |
| if(in->nbits < nb && !sregfill(in, nb)) |
| return 0; |
| len = litlenbase[c] + (in->sreg & ((1<<nb)-1)); |
| in->sreg >>= nb; |
| in->nbits -= nb; |
| |
| /* get offset */ |
| nb = offtab->minbits; |
| for(;;){ |
| if(in->nbits<nb && !sregfill(in, nb)) |
| return 0; |
| c = offtab->flat[in->sreg & offtab->flatmask]; |
| nb = c & 0xff; |
| if(nb > in->nbits){ |
| if(nb != 0xff) |
| continue; |
| c = hdecsym(in, offtab, c); |
| if(c < 0) |
| return 0; |
| }else{ |
| c >>= 8; |
| in->sreg >>= nb; |
| in->nbits -= nb; |
| } |
| break; |
| } |
| |
| if(c > 29) { |
| in->error = FlateCorrupted; |
| return 0; |
| } |
| |
| nb = offextra[c]; |
| if(in->nbits < nb && !sregfill(in, nb)) |
| return 0; |
| |
| off = offbase[c] + (in->sreg & ((1<<nb)-1)); |
| in->sreg >>= nb; |
| in->nbits -= nb; |
| |
| hq = hp - off; |
| if(hq < hs) { |
| if(!his->full) { |
| in->error = FlateCorrupted; |
| return 0; |
| } |
| hq += HistorySize; |
| } |
| |
| /* slow but correct */ |
| while(len) { |
| *hp = *hq; |
| hq++; |
| hp++; |
| if(hq >= he) |
| hq = hs; |
| if(hp == he) { |
| his->full = 1; |
| if((*in->w)(in->wr, hs, HistorySize) != HistorySize) { |
| in->error = FlateOutputFail; |
| return 0; |
| } |
| hp = hs; |
| } |
| len--; |
| } |
| |
| } |
| |
| his->cp = hp; |
| |
| return 1; |
| } |
| |
| static int |
| revcode(int c, int b) |
| { |
| /* shift encode up so it starts on bit 15 then reverse */ |
| c <<= (16-b); |
| c = revtab[c>>8] | (revtab[c&0xff]<<8); |
| return c; |
| } |
| |
| /* |
| * construct the huffman decoding arrays and a fast lookup table. |
| * the fast lookup is a table indexed by the next flatbits bits, |
| * which returns the symbol matched and the number of bits consumed, |
| * or the minimum number of bits needed and 0xff if more than flatbits |
| * bits are needed. |
| * |
| * flatbits can be longer than the smallest huffman code, |
| * because shorter codes are assigned smaller lexical prefixes. |
| * this means assuming zeros for the next few bits will give a |
| * conservative answer, in the sense that it will either give the |
| * correct answer, or return the minimum number of bits which |
| * are needed for an answer. |
| */ |
| static int |
| hufftab(Huff *h, char *hb, int maxleaf, int flatbits) |
| { |
| ulong bitcount[MaxHuffBits]; |
| ulong c, fc, ec, mincode, code, nc[MaxHuffBits]; |
| int i, b, minbits, maxbits; |
| |
| for(i = 0; i < MaxHuffBits; i++) |
| bitcount[i] = 0; |
| maxbits = -1; |
| minbits = MaxHuffBits + 1; |
| for(i=0; i < maxleaf; i++){ |
| b = hb[i]; |
| if(b){ |
| bitcount[b]++; |
| if(b < minbits) |
| minbits = b; |
| if(b > maxbits) |
| maxbits = b; |
| } |
| } |
| |
| h->maxbits = maxbits; |
| if(maxbits <= 0){ |
| h->maxbits = 0; |
| h->minbits = 0; |
| h->flatmask = 0; |
| return 1; |
| } |
| code = 0; |
| c = 0; |
| for(b = 0; b <= maxbits; b++){ |
| h->last[b] = c; |
| c += bitcount[b]; |
| mincode = code << 1; |
| nc[b] = mincode; |
| code = mincode + bitcount[b]; |
| if(code > (1 << b)) |
| return 0; |
| h->maxcode[b] = code - 1; |
| h->last[b] += code - 1; |
| } |
| |
| if(flatbits > maxbits) |
| flatbits = maxbits; |
| h->flatmask = (1 << flatbits) - 1; |
| if(minbits > flatbits) |
| minbits = flatbits; |
| h->minbits = minbits; |
| |
| b = 1 << flatbits; |
| for(i = 0; i < b; i++) |
| h->flat[i] = ~0; |
| |
| /* |
| * initialize the flat table to include the minimum possible |
| * bit length for each code prefix |
| */ |
| for(b = maxbits; b > flatbits; b--){ |
| code = h->maxcode[b]; |
| if(code == -1) |
| break; |
| mincode = code + 1 - bitcount[b]; |
| mincode >>= b - flatbits; |
| code >>= b - flatbits; |
| for(; mincode <= code; mincode++) |
| h->flat[revcode(mincode, flatbits)] = (b << 8) | 0xff; |
| } |
| |
| for(i = 0; i < maxleaf; i++){ |
| b = hb[i]; |
| if(b <= 0) |
| continue; |
| c = nc[b]++; |
| if(b <= flatbits){ |
| code = (i << 8) | b; |
| ec = (c + 1) << (flatbits - b); |
| if(ec > (1<<flatbits)) |
| return 0; /* this is actually an internal error */ |
| for(fc = c << (flatbits - b); fc < ec; fc++) |
| h->flat[revcode(fc, flatbits)] = code; |
| } |
| if(b > minbits){ |
| c = h->last[b] - c; |
| if(c >= maxleaf) |
| return 0; |
| h->decode[c] = i; |
| } |
| } |
| return 1; |
| } |
| |
| static int |
| hdecsym(Input *in, Huff *h, int nb) |
| { |
| long c; |
| |
| if((nb & 0xff) == 0xff) |
| nb = nb >> 8; |
| else |
| nb = nb & 0xff; |
| for(; nb <= h->maxbits; nb++){ |
| if(in->nbits<nb && !sregfill(in, nb)) |
| return -1; |
| c = revtab[in->sreg&0xff]<<8; |
| c |= revtab[(in->sreg>>8)&0xff]; |
| c >>= (16-nb); |
| if(c <= h->maxcode[nb]){ |
| in->sreg >>= nb; |
| in->nbits -= nb; |
| return h->decode[h->last[nb] - c]; |
| } |
| } |
| in->error = FlateCorrupted; |
| return -1; |
| } |
| |
| static int |
| sregfill(Input *in, int n) |
| { |
| int c; |
| |
| while(n > in->nbits) { |
| c = (*in->get)(in->getr); |
| if(c < 0){ |
| in->error = FlateInputFail; |
| return 0; |
| } |
| in->sreg |= c<<in->nbits; |
| in->nbits += 8; |
| } |
| return 1; |
| } |
| |
| static int |
| sregunget(Input *in) |
| { |
| if(in->nbits >= 8) { |
| in->error = FlateInternal; |
| return 0; |
| } |
| |
| /* throw other bits on the floor */ |
| in->nbits = 0; |
| in->sreg = 0; |
| return 1; |
| } |