diff --git a/shared_src/gunzip.c b/shared_src/gunzip.c index ddae1ffe1..8b7206b42 100644 --- a/shared_src/gunzip.c +++ b/shared_src/gunzip.c @@ -146,14 +146,31 @@ static unsigned long gzip_crc; /* internal extra variables for use of inflate code */ static int block_type; static int block_len; +static int last_block; +static int code_state; /* Function prototypes */ static void initialize_tables(void); -static int huft_build(unsigned *, unsigned, unsigned, ush *, ush *, - struct huft **, int *); -static int huft_free(struct huft *); -static int inflate_codes(struct huft *, struct huft *, int, int); + +/* + * Linear allocator. + */ + +static unsigned long linalloc_topaddr; + +static void * +linalloc(int size) +{ + linalloc_topaddr = (linalloc_topaddr - size) & ~3; + return (void *)linalloc_topaddr; +} + +static void +reset_linalloc(void) +{ + linalloc_topaddr = (mbi.mem_upper << 10) + 0x100000; +} /* internal variable swap function */ @@ -303,9 +320,6 @@ gunzip_test_header(void) } -uch slide[WSIZE]; - - /* Huffman code lookup table entry--this entry is four bytes for machines that have 16-bit pointers (e.g. PC's in the small or medium model). Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 @@ -332,9 +346,12 @@ struct huft { "uch *slide;" and then malloc'ed in the latter case. The definition must be in unzip.h, included above. */ + +/* sliding window in uncompressed data */ +static uch slide[WSIZE]; + /* current position in slide */ -unsigned wp; -#define flush_output(w) (wp=(w),flush_window()) +static unsigned wp; /* Tables for deflate from PKZIP's appnote.txt. */ @@ -390,8 +407,8 @@ static ush cpdext[] = { /* Extra bits for distance codes */ */ -int lbits = 9; /* bits in base literal/length lookup table */ -int dbits = 6; /* bits in base distance lookup table */ +static int lbits = 9; /* bits in base literal/length lookup table */ +static int dbits = 6; /* bits in base distance lookup table */ /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ @@ -399,12 +416,9 @@ int dbits = 6; /* bits in base distance lookup table */ #define N_MAX 288 /* maximum number of codes in any set */ -unsigned hufts; /* track memory usage */ +static unsigned hufts; /* track memory usage */ - -/* XXXXXX */ - /* Macros for inflate() bit peeking and grabbing. The usage is: @@ -435,35 +449,361 @@ unsigned hufts; /* track memory usage */ the stream. */ -ulg bb; /* bit buffer */ -unsigned bk; /* bits in bit buffer */ +static ulg bb; /* bit buffer */ +static unsigned bk; /* bits in bit buffer */ -ush mask_bits[] = { +static ush mask_bits[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; -#define NEEDBITS(n) {while(k<(n)){b|=((ulg)get_byte())<>=(n);k-=(n);} +#define NEEDBITS(n) do {while(k<(n)){b|=((ulg)get_byte())<>=(n);k-=(n);} while (0) -static void -needbits(int n) +#define INBUFSIZ 0x2000 + +static uch inbuf[INBUFSIZ]; +static int bufloc; + +static int +get_byte(void) { - register k = bk; - - while (k < n) + if (filepos == gzip_data_offset || bufloc == INBUFSIZ) { - bb |= ((ulg) get_byte()) << k; - k += 8; + bufloc = 0; + read((int)inbuf, INBUFSIZ); } - bk = k; + return inbuf[bufloc++]; } -#define dumpbits(n) {bb>>=(n);bk-=(n);} +/* decompression global pointers */ +static struct huft *tl; /* literal/length code table */ +static struct huft *td; /* distance code table */ +static int bl; /* lookup bits for tl */ +static int bd; /* lookup bits for td */ +/* more function prototypes */ +static int huft_build(unsigned *, unsigned, unsigned, ush *, ush *, + struct huft **, int *); +static int inflate_codes_in_window(void); + + +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. */ + +static int +huft_build(unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ + unsigned n, /* number of codes (assumed <= N_MAX) */ + unsigned s, /* number of simple-valued codes (0..s-1) */ + ush *d, /* list of base values for non-simple codes */ + ush *e, /* list of extra bits for non-simple codes */ + struct huft **t, /* result: starting table */ + int *m) /* maximum lookup bits, returns actual */ +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX+1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX+1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + /* Generate counts for each bit length */ + bzero((char *)c, sizeof(c)); + p = b; i = n; + do { + c[*p]++; /* assume all entries <= BMAX */ + p++; /* Can't combine with above line (Solaris bug) */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (struct huft *)NULL; + *m = 0; + return 0; + } + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned)l > i) + l = i; + *m = l; + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (struct huft *)NULL; /* just to keep compilers happy */ + q = (struct huft *)NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + q = (struct huft *)linalloc((z + 1)*sizeof(struct huft)); + + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = (struct huft *)NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch)l; /* bits to dump before this table */ + r.e = (uch)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (uch)(k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (ush)(*p); /* simple code is just the value */ + p++; /* one compiler does not like *p++ */ + } + else + { + r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } + } + } + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + + +/* + * inflate (decompress) the codes in a deflated (compressed) block. + * Return an error code or zero if it all goes ok. + */ + +static unsigned inflate_n, inflate_d; + +static int +inflate_codes_in_window(void) +{ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + d = inflate_d; + n = inflate_n; + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + for (;;) /* do until end of block */ + { + if (!code_state) + { + NEEDBITS((unsigned)bl); + if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) + do { + if (e == 99) + { + errnum = ERR_BAD_GZIP_DATA; + return 0; + } + DUMPBITS(t->b); + e -= 16; + NEEDBITS(e); + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b); + + if (e == 16) /* then it's a literal */ + { + slide[w++] = (uch)t->v.n; + if (w == WSIZE) + break; + } + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if (e == 15) + { + block_len = 0; + break; + } + + /* get length of block to copy */ + NEEDBITS(e); + n = t->v.n + ((unsigned)b & mask_bits[e]); + DUMPBITS(e); + + /* decode distance of block to copy */ + NEEDBITS((unsigned)bd); + if ((e = (t = td + ((unsigned)b & md))->e) > 16) + do { + if (e == 99) + { + errnum = ERR_BAD_GZIP_DATA; + return 0; + } + DUMPBITS(t->b); + e -= 16; + NEEDBITS(e); + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b); + NEEDBITS(e); + d = w - t->v.n - ((unsigned)b & mask_bits[e]); + DUMPBITS(e); + code_state++; + } + } + + if (code_state) + { + /* do the copy */ + do { + n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); + if (w - d >= e) + { + bcopy(slide + d, slide + w, e); + w += e; + d += e; + } + else /* purposefully use the overlap for extra copies here!! */ + { + while (e--) + slide[w++] = slide[d++]; + } + if (w == WSIZE) + break; + } while (n); + + if (!n) + code_state--; + + /* did we break from the loop too soon? */ + if (w == WSIZE) + break; + } + } + + /* restore the globals from the locals */ + inflate_d = d; + inflate_n = n; + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + return !block_len; +} + + +/* get header for an inflated type 0 (stored) block. */ + static void init_stored_block(void) { @@ -474,8 +814,6 @@ init_stored_block(void) b = bb; /* initialize bit buffer */ k = bk; - new_block = 0; - /* go to byte boundary */ DUMPBITS(k & 7); @@ -494,6 +832,195 @@ init_stored_block(void) } +/* get header for an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ + +static void +init_fixed_block() +{ + int i; /* temporary variable */ + unsigned l[288]; /* length list for huft_build */ + + /* set up literal table */ + for (i = 0; i < 144; i++) + l[i] = 8; + for (; i < 256; i++) + l[i] = 9; + for (; i < 280; i++) + l[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + bl = 7; + if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + + /* set up distance table */ + for (i = 0; i < 30; i++) /* make an incomplete code set */ + l[i] = 5; + bd = 5; + if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + + /* indicate we're now working on a block */ + code_state = 0; + block_len++; +} + + +/* get header for an inflated type 2 (dynamic Huffman codes) block. */ + +static void +init_dynamic_block(void) +{ + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ + unsigned ll[286+30]; /* literal/length and distance code lengths */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b = bb; + k = bk; + + /* read in table lengths */ + NEEDBITS(5); + nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */ + DUMPBITS(5); + NEEDBITS(5); + nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */ + DUMPBITS(5); + NEEDBITS(4); + nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */ + DUMPBITS(4); + if (nl > 286 || nd > 30) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS(3); + ll[border[j]] = (unsigned)b & 7; + DUMPBITS(3); + } + for (; j < 19; j++) + ll[border[j]] = 0; + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned)i < n) + { + NEEDBITS((unsigned)bl); + j = (td = tl + ((unsigned)b & m))->b; + DUMPBITS(j); + j = td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS(2); + j = 3 + ((unsigned)b & 3); + DUMPBITS(2); + if ((unsigned)i + j > n) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS(3); + j = 3 + ((unsigned)b & 7); + DUMPBITS(3); + if ((unsigned)i + j > n) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS(7); + j = 11 + ((unsigned)b & 0x7f); + DUMPBITS(7); + if ((unsigned)i + j > n) + { + errnum = ERR_BAD_GZIP_DATA; + return; + } + while (j--) + ll[i++] = 0; + l = 0; + } + } + + /* free decoding table for trees */ + reset_linalloc(); + + /* restore the global bit buffer */ + bb = b; + bk = k; + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) + { +#if 0 + if (i == 1) + printf("gunzip: incomplete literal tree\n"); +#endif + + errnum = ERR_BAD_GZIP_DATA; + return; + } + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) + { +#if 0 + if (i == 1) + printf("gunzip: incomplete distance tree\n"); +#endif + + errnum = ERR_BAD_GZIP_DATA; + return; + } + + /* indicate we're now working on a block */ + code_state = 0; + block_len++; +} + + static void get_new_block(void) { @@ -519,6 +1046,13 @@ get_new_block(void) /* restore the global bit buffer */ bb = b; bk = k; + + if (block_type == INFLATE_STORED) + init_stored_block(); + if (block_type == INFLATE_FIXED) + init_fixed_block(); + if (block_type == INFLATE_DYNAMIC) + init_dynamic_block(); } @@ -535,57 +1069,52 @@ inflate_window(void) while (wp < WSIZE && !errnum) { if (!block_len) - get_new_block(); - - if (block_type > INFLATE_DYNAMIC) { - errnum = ERR_BAD_GZIP_DATA; - continue; + if (last_block) + break; + + get_new_block(); } + if (block_type > INFLATE_DYNAMIC) + errnum = ERR_BAD_GZIP_DATA; + + if (errnum) + return; + + /* + * Expand stored block here. + */ if (block_type == INFLATE_STORED) { + int w = wp; + /* * This is basically a glorified pass-through */ - if (!block_len) - init_stored_block(); - - while (block_len && wp < WSIZE && !errnum) + while (block_len && w < WSIZE && !errnum) { - slide[wp++] = get_byte(); + slide[w++] = get_byte(); block_len--; } + wp = w; + continue; } - /* - * Init other kind of block. - */ - - if (!block_len) - { - if (block_type == INFLATE_FIXED) - init_fixed_block(); - if (block_type == INFLATE_DYNAMIC) - init_dynamic_block(); - } - /* * Expand other kind of block. */ - if (inflate_codes() && !block_len) - { - /* we're done with the block, so free data structures */ - huft_free(tl); - huft_free(td); - } + if (inflate_codes_in_window()) + reset_linalloc(); } saved_filepos += WSIZE; + + /* XXX do CRC calculation here! */ } @@ -601,13 +1130,17 @@ initialize_tables(void) /* reset partial decompression code */ last_block = 0; + block_len = 0; + + /* reset memory allocation stuff */ + reset_linalloc(); } int gunzip_read(int addr, int len) { - int last_block, size; /* last block flag */ + int size; /* last block flag */ int ret = 0; compressed_file = 0; @@ -629,15 +1162,17 @@ gunzip_read(int addr, int len) while (len > 0 && !errnum) { register int size; + register char *srcaddr; while (gzip_filepos >= saved_filepos) inflate_window(); + srcaddr = (char *)((gzip_filepos & (WSIZE - 1)) + slide); size = saved_filepos - gzip_filepos; if (size > len) size = len; - bcopy((char *)slide, (char *)addr, size); + bcopy(srcaddr, (char *)addr, size); addr += size; len -= size;