#include #include #include #include #include #include #include <9p.h> #include "gzfs.h" enum { HistorySize= 32*1024, MaxBits= 16, /* 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<0; i--) Bgetc(bin); } /* name */ if(flag&Fname) { while((c = Bgetc(bin)) != 0) { if(c < 0) fatal("unexpected eof"); } } /* comment */ if(flag&Fcomment) { while((c = Bgetc(bin)) != 0) if(c < 0) fatal("unexpected eof"); } /* crc16 */ if(flag&Fhcrc) { Bgetc(bin); Bgetc(bin); } return 1; } static void trailer(Biobuf *bout, Biobuf *bin, int ooffset) { int c; int i; long len; /* crc32 */ for(i=0; i<4; i++) if(Bgetc(bin)<0) fatal("unexpected eof"); /* length */ len = 0; for(i=0; i<4; i++) { c = Bgetc(bin); if(c < 0) fatal("unexpected eof - len", i); len |= c<<(i*8); } } void inflateinit(void) { int litlen[Nlitlen]; int off[Noff]; int i, j, base; /* byte reverse table */ for(i=0; i<256; i++) for(j=0; j<8; j++) if(i & (1<> j; for(i=257,base=3; i>1) & 0x3; in.sreg >>= 3; in.nbits -= 3; //print("type = %d\n", type); //print("."); switch(type) { default: werrstr("illegal block type %d", type); return 0; case 0: /* uncompressed */ if(!uncblock(bout, &in, &his)) return 0; break; case 1: /* fixed huffman */ if(!fixedblock(bout, &in, &his)) return 0; break; case 2: /* dynamic huffman */ if(!dynamicblock(bout, &in, &his)) return 0; break; } } while(!final); hiswrite(bout, &his, his.cp); sregunget(&in); return 1; } int gzexpand(int in) { int rv, out; int p[2]; if(pipe(p) < 0) sysfatal("pipe: %r"); rv = p[0]; out = p[1]; switch(rfork(RFPROC|RFFDG|RFNOTEG)){ case -1: sysfatal("fork: %r"); case 0: close(rv); gunzip(in, out); _exits(0); break; default: close(in); close(out); return rv; } return -1; } static int uncblock(Biobuf *bout, Input *in, History *his) { Biobuf *bin; int len, nlen, n; uchar *hs, *hp, *he; sregunget(in); bin = in->bin; len = Bgetc(bin); len |= Bgetc(bin)<<8; nlen = Bgetc(bin); nlen |= Bgetc(bin)<<8; if(debug) print("uncompressed block: len = %d\n", len); if(len != (~nlen&0xffff)) { werrstr("uncompressed block: bad len=%ux nlen=%ux", len, ~nlen&0xffff); return 0; } hp = his->cp; hs = his->his; he = hs + HistorySize; while(len > 0) { n = he - his->cp; if(n > len) n = len; if(Bread(bin, hp, n) != n) return 0; hp += n; if(hp == he) { his->full = 1; hiswrite(bout, his, hp); hp = hs; } len -= n; } his->cp = hp; return 1; } static int fixedblock(Biobuf *bout, Input *in, History *his) { return decode(bout, in, his, litlentab, offtab); } static int dynamicblock(Biobuf *bout, Input *in, History *his) { int i, j, n, c, code, nlit, ndist, nclen; int res; int nb; /* static to avoid overflowing the stack */ static int litlen[Nlitlen], off[Noff], clen[Nclen]; static Huff litlentab[MaxBits], offtab[MaxBits], clentab[MaxBits]; static int len[Nlitlen+Noff]; static short litspace[MaxSpace], offspace[MaxSpace], clenspace[MaxSpace]; /* huff table header */ memset(litlen, 0, sizeof(litlen)); memset(off, 0, sizeof(off)); memset(clen, 0, sizeof(clen)); 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) { werrstr("bad huffman table header"); return 0; } for(i=0; isreg & 0x7; in->sreg >>= 3; in->nbits -= 3; } hufftabinit(clentab, clen, Nclen, ClenBits, clenspace); n = nlit+ndist; for(i=0; inbitssreg&((1<>LenShift; in->sreg >>= nb; in->nbits -= nb; if(code < 16) { j = 1; c = code; } else if(code == 16) { if(in->nbits<2 && !sregfill(in, 2)) return 0; j = (in->sreg&0x3)+3; in->sreg >>= 2; in->nbits -= 2; if(i == 0) { werrstr("bad code len code 16"); return 0; } c = len[i-1]; } else if(code == 17) { if(in->nbits<3 && !sregfill(in, 3)) return 0; j = (in->sreg&0x7)+3; in->sreg >>= 3; in->nbits -= 3; c = 0; } else if(code == 18) { if(in->nbits<7 && !sregfill(in, 7)) return 0; j = (in->sreg&0x7f)+11; in->sreg >>= 7; in->nbits -= 7; c = 0; } else { werrstr("bad code len code"); return 0; } if(i+j > n) { werrstr("bad code len code"); return 0; } while(j) { len[i] = c; i++; j--; } } for(i=0; i LitlenBits) nb = LitlenBits; hufftabinit(litlentab, litlen, nlit, nb, litspace); hufftabinit(offtab, off, ndist, OffBits, offspace); res = decode(bout, in, his, litlentab, offtab); hufftabfree(litlentab); hufftabfree(offtab); hufftabfree(clentab); return res; } static int decode(Biobuf *bout, Input *in, History *his, Huff *litlentab, Huff *offtab) { int len, off; uchar *hs, *hp, *hq, *he; int c, code; int nb; hs = his->his; he = hs + HistorySize; hp = his->cp; for(;;) { nb = litlentab[0].bits; if(in->nbitssreg&((1<>LenShift; in->sreg >>= nb; in->nbits -= nb; if(code < 256) { if(debug)print("\tlit %.2ux %c\n", code, code); /* literal */ *hp++ = code; if(hp == he) { his->full = 1; hiswrite(bout, his, hp); hp = hs; } continue; } if(code == 256) break; if(code > 285) { werrstr("illegal lit/len code"); return 0; } code -= 257; nb = litlenextra[code]; if(in->nbits < nb && !sregfill(in, nb)) return 0; len = litlenbase[code] + (in->sreg & ((1<sreg >>= nb; in->nbits -= nb; /* get offset */ nb = offtab[0].bits; if(in->nbitssreg&((1<>LenShift; in->sreg >>= nb; in->nbits -= nb; if(code > 29) { werrstr("illegal lit/len code"); return 0; } nb = offextra[code]; if(in->nbits < nb && !sregfill(in, nb)) return 0; off = offbase[code] + (in->sreg & ((1<sreg >>= nb; in->nbits -= nb; hq = hp - off; if(hq < hs) { if(!his->full) { werrstr("access before begining of history"); return 0; } hq += HistorySize; } if(debug)print("\t<%d, %d>\n", off, len); /* slow but correct */ while(len) { *hp = *hq; hq++; hp++; if(hq >= he) hq = hs; if(hp >= he) { his->full = 1; hiswrite(bout, his, hp); hp = hs; } len--; } } his->cp = hp; return 1; /* avoid compiler warning */ } static void hufftabinit(Huff *tab, int *bitlen, int n, int bits, short *space) { int i, j, k, nc, bl, v, ec; int count[MaxBits]; ulong encode[MaxBits]; short *code[MaxBits], *ospace; ospace = space; nc = 1< ospace+MaxSpace) fatal("not enough space"); memset(count, 0, sizeof(count)); for(i=0; i>8] | (revtab[ec&0xff]<<8); k = 1<bits; h++) { nb = h->bits; if(in->nbitssreg&0xff]<<8; ec |= revtab[(in->sreg>>8)&0xff]; ec >>= (16-nb); if(ec < h->last) return h->code[ec-h->first]; } werrstr("unkown huff code %x", ec); return 0; } static void hufftabfree(Huff tab[MaxBits]) { USED(tab); } static void hiswrite(Biobuf *bout, History *his, uchar *hp) { if(Bwrite(bout, his->his, hp-his->his) != hp-his->his) ; // fatal("Bwrite failed"); } static int sregfill(Input *in, int n) { int c; while(n > in->nbits) { c = Bgetc(in->bin); if(c < 0) { werrstr("out of input"); return 0; } in->sreg |= c<nbits; in->nbits += 8; } return 1; } static int sregunget(Input *in) { if(in->nbits >= 8) fatal("bad unget"); /* throw other bits on the floor */ in->nbits = 0; in->sreg = 0; return 1; } static void fatal(char *fmt, ...) { print("%s\n", fmt); exits(0); } static void mismatch(void) { fatal("missmatch: out = %d\n", Boffset(bcmp)); }