diff options
author | Glenn L McGrath <bug1@ihug.co.nz> | 2001-03-28 05:38:24 +0000 |
---|---|---|
committer | Glenn L McGrath <bug1@ihug.co.nz> | 2001-03-28 05:38:24 +0000 |
commit | 58e42d5356bfbb8ed817a782901bf52d9b8f54bf (patch) | |
tree | a7293aaecbaf442947c1a5fbd089b45c6099ec4e /gunzip.c | |
parent | f58efb57d1c7134cfeaf73e84f210c2458826b80 (diff) |
Major cleanup to better adhere to style guide and use standard busybox functions
Diffstat (limited to 'gunzip.c')
-rw-r--r-- | gunzip.c | 1622 |
1 files changed, 724 insertions, 898 deletions
@@ -11,6 +11,9 @@ * to support files as well as stdin/stdout, and to generally behave itself wrt * command line handling. * + * General cleanup to better adhere to the style guide and make use of standard + * busybox functions by Glenn McGrath <bug1@optushome.com.au> + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -60,8 +63,9 @@ static char *license_msg[] = { #include <getopt.h> #include <ctype.h> #include <sys/types.h> +#include <sys/wait.h> #include <signal.h> -#include <errno.h> +//#include <errno.h> #include <stdio.h> #include <string.h> #include <memory.h> @@ -76,363 +80,85 @@ static char *license_msg[] = { #define bb_need_name_too_long #include "messages.c" -static const int RECORD_IO = 0; +FILE *in_file, *out_file; + +static unsigned long *crc_table; +static unsigned long crc = 0xffffffffL; /* shift register contents */ /* Return codes from gzip */ -static const int OK = 0; static const int ERROR = 1; -static const int WARNING = 2; - -static const int DEFLATED = 8; -static const int INBUFSIZ = 0x2000; /* input buffer size */ -static const int INBUF_EXTRA = 64; /* required by unlzw() */ -static const int OUTBUFSIZ = 8192; /* output buffer size */ -static const int OUTBUF_EXTRA = 2048; /* required by unlzw() */ -static const int DIST_BUFSIZE = 0x2000; /* buffer for distances, see trees.c */ - -#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */ -/* gzip flag byte */ -static const int EXTRA_FIELD = 0x04; /* bit 2 set: extra field present */ -static const int ORIG_NAME = 0x08; /* bit 3 set: original file name present */ -static const int COMMENT = 0x10; /* bit 4 set: file comment present */ -static const int WSIZE = 0x8000; /* window size--must be a power of two, and */ - /* at least 32K for zip's deflate method */ +/* + * window size--must be a power of two, and + * at least 32K for zip's deflate method + */ +static const int WSIZE = 0x8000; /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ static const int BMAX = 16; /* maximum bit length of any code (16 for explode) */ static const int N_MAX = 288; /* maximum number of codes in any set */ -/* PKZIP header definitions */ -static const int LOCSIG = 0x04034b50L; /* four-byte lead-in (lsb first) */ -static const int LOCCRC = 14; /* offset of crc */ -static const int LOCLEN = 22; /* offset of uncompressed length */ -static const int EXTHDR = 16; /* size of extended local header, inc sig */ - -static const int BITS = 16; - -/* Diagnostic functions */ -#ifdef DEBUG -# define Assert(cond,msg) {if(!(cond)) error_msg(msg);} -# define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif +static unsigned char *window; -#ifndef MAX_PATH_LEN /* max pathname length */ -# ifdef BUFSIZ -# define MAX_PATH_LEN BUFSIZ -# else -static const int MAX_PATH_LEN = 1024; -# endif -#endif - -#define NEXTBYTE() (uch)get_byte() -#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}} -#define DUMPBITS(n) {b>>=(n);k-=(n);} - -#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(0)) - -/* Macros for getting two-byte and four-byte header values */ -#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)) -#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)) - - /* in gzip.c */ -void abort_gzip (void); -typedef void (*sig_type) (int); - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; -typedef int file_t; /* Do not use stdio */ - -static uch *inbuf; -static uch *outbuf; -static ush *d_buf; -static uch *window; -static ush *tab_prefix0; -static ush *tab_prefix1; - -/* local variables */ -static int test_mode = 0; /* check file integrity option */ -static int foreground; /* set if program run in foreground */ -static int method; /* compression method */ -static int exit_code; /* program exit code */ -static int last_member; /* set for .zip and .Z files */ -static int part_nb; /* number of parts in .gz file */ -static long ifile_size; /* input file size, -1 for devices (debug only) */ -static long bytes_in; /* number of input bytes */ static long bytes_out; /* number of output bytes */ -static int ifd; /* input file descriptor */ -static int ofd; /* output file descriptor */ -static unsigned insize; /* valid bytes in inbuf */ -static unsigned inptr; /* index of next byte to be processed in inbuf */ -static unsigned outcnt; /* bytes in output buffer */ +static unsigned long outcnt; /* bytes in output buffer */ unsigned hufts; /* track memory usage */ -ulg bb; /* bit buffer */ +unsigned long bb; /* bit buffer */ unsigned bk; /* bits in bit buffer */ -int crc_table_empty = 1; -struct huft { - uch e; /* number of extra bits or operation */ - uch b; /* number of bits in this code or subcode */ +typedef struct huft_s { + unsigned char e; /* number of extra bits or operation */ + unsigned char b; /* number of bits in this code or subcode */ union { - ush n; /* literal, length base, or distance base */ - struct huft *t; /* pointer to next level of table */ + unsigned short n; /* literal, length base, or distance base */ + struct huft_s *t; /* pointer to next level of table */ } v; -}; +} huft_t; -/* Tables for deflate from PKZIP's appnote.txt. */ -static unsigned border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 -}; -static ush cplens[] = { /* Copy lengths for literal codes 257..285 */ - 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, 0, 0 -}; - -/* note: see note #13 above about the 258 in this list. */ -static ush cplext[] = { /* Extra bits for literal codes 257..285 */ - 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, 99, 99 -}; /* 99==invalid */ - -static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ - 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 -}; - -static ush cpdext[] = { /* Extra bits for distance codes */ - 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 -}; - -ush mask_bits[] = { +unsigned short mask_bits[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff }; -/* ======================================================================== - * Error handlers. - */ -void read_error_msg() -{ - fprintf(stderr, "\n"); - if (errno != 0) { - perror(""); - } else { - fprintf(stderr, "unexpected end of file\n"); - } - abort_gzip(); -} - -/* =========================================================================== - * Fill the input buffer. This is called only when the buffer is empty. - */ -int fill_inbuf(eof_ok) -int eof_ok; /* set if EOF acceptable as a result */ -{ - int len; - - /* Read as much as possible */ - insize = 0; - errno = 0; - do { - len = read(ifd, (char *) inbuf + insize, INBUFSIZ - insize); - if (len == 0 || len == EOF) - break; - insize += len; - } while (insize < INBUFSIZ); - - if (insize == 0) { - if (eof_ok) - return EOF; - read_error_msg(); - } - bytes_in += (ulg) insize; - inptr = 1; - return inbuf[0]; -} - - -/* ======================================================================== - * Check the magic number of the input file and update ofname if an - * original name was given and tostdout is not set. - * Return the compression method, -1 for error, -2 for warning. - * Set inptr to the offset of the next byte to be processed. - * Updates time_stamp if there is one and --no-time is not used. - * This function may be called repeatedly for an input file consisting - * of several contiguous gzip'ed members. - * IN assertions: there is at least one remaining compressed member. - * If the member is a zip file, it must be the only one. - */ -static int get_method(in) -int in; /* input file descriptor */ -{ - uch flags; /* compression flags */ - char magic[2]; /* magic header */ - long header_bytes = 0; /* number of bytes in gzip header */ - - magic[0] = (char) get_byte(); - magic[1] = (char) get_byte(); - method = -1; /* unknown yet */ - part_nb++; /* number of parts in gzip file */ - last_member = RECORD_IO; - /* assume multiple members in gzip file except for record oriented I/O */ - - if (memcmp(magic, GZIP_MAGIC, 2) == 0) { - - method = (int) get_byte(); - if (method != DEFLATED) { - error_msg("unknown method %d -- get newer version of gzip", method); - exit_code = ERROR; - return -1; - } - flags = (uch) get_byte(); - - (ulg) get_byte(); /* Ignore time stamp */ - (ulg) get_byte(); - (ulg) get_byte(); - (ulg) get_byte(); - - (void) get_byte(); /* Ignore extra flags for the moment */ - (void) get_byte(); /* Ignore OS type for the moment */ - - if ((flags & EXTRA_FIELD) != 0) { - unsigned len = (unsigned) get_byte(); - len |= ((unsigned) get_byte()) << 8; - while (len--) - (void) get_byte(); - } - - /* Discard original name if any */ - if ((flags & ORIG_NAME) != 0) { - while (get_byte() != 0); /* null */ - } - - /* Discard file comment if any */ - if ((flags & COMMENT) != 0) { - while (get_byte() != 0) /* null */ - ; - } - if (part_nb == 1) { - header_bytes = inptr + 2 * sizeof(long); /* include crc and size */ - } - - } - - if (method >= 0) - return method; - - if (part_nb == 1) { - fprintf(stderr, "\nnot in gzip format\n"); - exit_code = ERROR; - return -1; - } else { - fprintf(stderr, "\ndecompression OK, trailing garbage ignored\n"); - if (exit_code == OK) - exit_code = WARNING; - return -2; - } -} - +//static int error_number = 0; /* ======================================================================== * Signal and error handler. */ -void abort_gzip() +static void abort_gzip() { - exit(ERROR); + error_msg("gzip aborted\n"); +// exit(ERROR); + return; } -/* =========================================================================== - * Run a set of bytes through the crc shift register. If s is a NULL - * pointer, then initialize the crc shift register contents instead. - * Return the current crc in either case. - */ -ulg updcrc(s, n) -uch *s; /* pointer to bytes to pump through */ -unsigned n; /* number of bytes in s[] */ +static void make_crc_table() { - static ulg crc = (ulg) 0xffffffffL; /* shift register contents */ - register ulg c; /* temporary variable */ - static unsigned long crc_32_tab[256]; - if (crc_table_empty) { - unsigned long csr; /* crc shift register */ - unsigned long e; /* polynomial exclusive-or pattern */ - int i; /* counter for all possible eight bit values */ - int k; /* byte being shifted into crc apparatus */ - - /* terms of polynomial defining this crc (except x^32): */ - static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* Make exclusive-or pattern from polynomial (0xedb88320) */ - e = 0; - for (i = 0; i < sizeof(p)/sizeof(int); i++) - e |= 1L << (31 - p[i]); - - /* Compute and print table of CRC's, five per line */ - crc_32_tab[0] = 0x00000000L; - for (i = 1; i < 256; i++) { - csr = i; - /* The idea to initialize the register with the byte instead of - * zero was stolen from Haruhiko Okumura's ar002 - */ - for (k = 8; k; k--) - csr = csr & 1 ? (csr >> 1) ^ e : csr >> 1; - crc_32_tab[i]=csr; + unsigned long table_entry; /* crc shift register */ + unsigned long poly = 0; /* polynomial exclusive-or pattern */ + int i; /* counter for all possible eight bit values */ + int k; /* byte being shifted into crc apparatus */ + + /* terms of polynomial defining this crc (except x^32): */ + static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long)); + + /* Make exclusive-or pattern from polynomial (0xedb88320) */ + for (i = 0; i < sizeof(p)/sizeof(int); i++) + poly |= 1L << (31 - p[i]); + + /* Compute and print table of CRC's, five per line */ + for (i = 0; i < 256; i++) { + table_entry = i; + /* The idea to initialize the register with the byte instead of + * zero was stolen from Haruhiko Okumura's ar002 + */ + for (k = 8; k; k--) { + table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1; } - } - - if (s == NULL) { - c = 0xffffffffL; - } else { - c = crc; - if (n) - do { - c = crc_32_tab[((int) c ^ (*s++)) & 0xff] ^ (c >> 8); - } while (--n); - } - crc = c; - return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ -} - -void write_error_msg() -{ - fprintf(stderr, "\n"); - perror(""); - abort_gzip(); -} - -/* =========================================================================== - * Does the same as write(), but also handles partial pipe writes and checks - * for error return. - */ -void write_buf(fd, buf, cnt) -int fd; -void * buf; -unsigned cnt; -{ - unsigned n; - - while ((n = write(fd, buf, cnt)) != cnt) { - if (n == (unsigned) (-1)) { - write_error_msg(); - } - cnt -= n; - buf = (void *) ((char *) buf + n); + crc_table[i]=table_entry; } } @@ -442,74 +168,35 @@ unsigned cnt; */ void flush_window() { + int n; + if (outcnt == 0) return; - updcrc(window, outcnt); - - if (!test_mode) - write_buf(ofd, (char *) window, outcnt); - bytes_out += (ulg) outcnt; - outcnt = 0; -} - -int inflate_stored() -/* "decompress" an inflated type 0 (stored) block. */ -{ - unsigned n; /* number of bytes in block */ - unsigned w; /* current window position */ - register ulg b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - /* make local copies of globals */ - b = bb; /* initialize bit buffer */ - k = bk; - w = outcnt; /* initialize window position */ - - /* go to byte boundary */ - n = k & 7; - DUMPBITS(n); - - /* get the length and its complement */ - NEEDBITS(16) - n = ((unsigned) b & 0xffff); - DUMPBITS(16) - NEEDBITS(16) - if (n != (unsigned) ((~b) & 0xffff)) - return 1; /* error in compressed data */ - DUMPBITS(16) - - /* read and output the compressed data */ - while (n--) { - NEEDBITS(8) - window[w++] = (uch) b; - if (w == WSIZE) { -// flush_output(w); - outcnt=(w), - flush_window(); - w = 0; - } - DUMPBITS(8) + for (n = 0; n < outcnt; n++) { + crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); } - /* restore the globals from the locals */ - outcnt = w; /* restore global window pointer */ - bb = b; /* restore global bit buffer */ - bk = k; - return 0; + if (fwrite(window, 1, outcnt, out_file) != outcnt) { + error_msg_and_die("Couldnt write"); + } + bytes_out += (unsigned long) outcnt; + outcnt = 0; } -int huft_free(t) -struct huft *t; /* table to free */ - -/* Free the malloc'ed tables built by huft_build(), which makes a linked - list of the tables it made, with the links in a dummy first entry of - each table. */ +/* + * Free the malloc'ed tables built by huft_build(), which makes a linked + * list of the tables it made, with the links in a dummy first entry of + * each table. + * t: table to free + */ +static int huft_free(huft_t *t) { - register struct huft *p, *q; + huft_t *p, *q; /* Go through linked list, freeing from the malloced (t[-1]) address. */ p = t; - while (p != (struct huft *) NULL) { + while (p != (huft_t *) NULL) { q = (--p)->v.t; free((char *) p); p = q; @@ -517,21 +204,22 @@ struct huft *t; /* table to free */ return 0; } - -int huft_build(b, n, s, d, e, t, m) -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 */ - /* 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. */ + * 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. + * + * b: code lengths in bits (all assumed <= BMAX) + * n: number of codes (assumed <= N_MAX) + * s: number of simple-valued codes (0..s-1) + * d: list of base values for non-simple codes + * e: list of extra bits for non-simple codes + * t: result: starting table + * m: maximum lookup bits, returns actual + */ +static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, + const unsigned short *d, const unsigned short *e, huft_t **t, int *m) { unsigned a; /* counter for codes of length k */ unsigned c[BMAX + 1]; /* bit length count table */ @@ -543,9 +231,9 @@ int *m; /* maximum lookup bits, returns actual */ 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 */ + register huft_t *q; /* points to current table */ + huft_t r; /* table entry for structure assignment */ + huft_t *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 */ @@ -558,12 +246,11 @@ int *m; /* maximum lookup bits, returns actual */ p = b; i = n; do { - Tracecv(*p,(stderr, (n - i >= ' ' && n - i <= '~' ? "%c %d\n" : "0x%x %d\n"), n - i, *p)); 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; + *t = (huft_t *) NULL; *m = 0; return 0; } @@ -613,8 +300,8 @@ int *m; /* maximum lookup bits, returns actual */ 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 */ + u[0] = (huft_t *) NULL; /* just to keep compilers happy */ + q = (huft_t *) NULL; /* ditto */ z = 0; /* ditto */ /* go through the bit lengths (k already is bits in shortest code) */ @@ -641,25 +328,22 @@ int *m; /* maximum lookup bits, returns actual */ z = 1 << j; /* table entries for j-bit table */ /* allocate and link in new table */ - if ( - (q = - (struct huft *) malloc((z + 1) * - sizeof(struct huft))) == - (struct huft *) NULL) { - if (h) + if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) { + if (h) { huft_free(u[0]); + } return 3; /* not enough memory */ } hufts += z + 1; /* track memory usage */ *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->v.t)) = (struct huft *) NULL; + *(t = &(q->v.t)) = 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.b = (unsigned char) l; /* bits to dump before this table */ + r.e = (unsigned char) (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 */ @@ -667,15 +351,15 @@ int *m; /* maximum lookup bits, returns actual */ } /* set up table entry in r */ - r.b = (uch) (k - w); + r.b = (unsigned char) (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 */ + r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (unsigned short) (*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.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ r.v.n = d[*p++ - s]; } @@ -700,20 +384,21 @@ int *m; /* maximum lookup bits, returns actual */ return y != 0 && g != 1; } - -int inflate_codes(tl, td, bl, bd) -struct huft *tl, *td; /* literal/length and distance decoder tables */ -int bl, bd; /* number of bits decoded by tl[] and td[] */ - -/* inflate (decompress) the codes in a deflated (compressed) block. - Return an error code or zero if it all goes ok. */ +/* + * inflate (decompress) the codes in a deflated (compressed) block. + * Return an error code or zero if it all goes ok. + * + * tl, td: literal/length and distance decoder tables + * bl, bd: number of bits decoded by tl[] and td[] + */ +static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) { - 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 */ + register unsigned long e; /* table entry flag/number of extra bits */ + unsigned long n, d; /* length and index for copy */ + unsigned long w; /* current window position */ + huft_t *t; /* pointer to table entry */ unsigned ml, md; /* masks for bl and bd bits */ - register ulg b; /* bit buffer */ + register unsigned long b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ /* make local copies of globals */ @@ -725,20 +410,27 @@ int bl, bd; /* number of bits decoded by tl[] and td[] */ ml = mask_bits[bl]; /* precompute masks for speed */ md = mask_bits[bd]; for (;;) { /* do until end of block */ - NEEDBITS((unsigned) bl) - if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) - do { - if (e == 99) - return 1; - 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 */ - window[w++] = (uch) t->v.n; - Tracevv((stderr, "%c", window[w - 1])); + while (k < (unsigned) bl) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) + do { + if (e == 99) { + return 1; + } + b >>= t->b; + k -= t->b; + e -= 16; + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + b >>= t->b; + k -= t->b; + if (e == 16) { /* then it's a literal */ + window[w++] = (unsigned char) t->v.n; if (w == WSIZE) { // flush_output(w); outcnt=(w), @@ -748,41 +440,50 @@ int bl, bd; /* number of bits decoded by tl[] and td[] */ } else { /* it's an EOB or a length */ /* exit if end of block */ - if (e == 15) + if (e == 15) { break; + } /* get length of block to copy */ - NEEDBITS(e) - n = t->v.n + ((unsigned) b & mask_bits[e]); - DUMPBITS(e); + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + n = t->v.n + ((unsigned) b & mask_bits[e]); + b >>= e; + k -= e; /* decode distance of block to copy */ - NEEDBITS((unsigned) bd) - if ((e = (t = td + ((unsigned) b & md))->e) > 16) + while (k < (unsigned) bd) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + + if ((e = (t = td + ((unsigned) b & md))->e) > 16) do { if (e == 99) return 1; - 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) - Tracevv((stderr, "\\[%d,%d]", w - d, n)); + b >>= t->b; + k -= t->b; + e -= 16; + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + b >>= t->b; + k -= t->b; + while (k < e) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; + } + d = w - t->v.n - ((unsigned) b & mask_bits[e]); + b >>= e; + k -= e; /* do the copy */ do { - n -= (e = - (e = - WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > - n ? n : e); + n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); #if !defined(NOMEMCPY) && !defined(DEBUG) if (w - d >= e) { /* (this test assumes unsigned comparison) */ memcpy(window + w, window + d, e); @@ -792,12 +493,10 @@ int bl, bd; /* number of bits decoded by tl[] and td[] */ #endif /* !NOMEMCPY */ do { window[w++] = window[d++]; - Tracevv((stderr, "%c", window[w - 1])); } while (--e); if (w == WSIZE) { -// flush_output(w); - outcnt=(w), - flush_window(); + outcnt=(w), + flush_window(); w = 0; } } while (n); @@ -813,236 +512,365 @@ int bl, bd; /* number of bits decoded by tl[] and td[] */ return 0; } -int inflate_fixed() -/* decompress an inflated type 1 (fixed Huffman codes) block. We should - either replace this with a custom decoder, or at least precompute the - Huffman tables. */ -{ - int i; /* temporary variable */ - struct huft *tl; /* literal/length code table */ - struct huft *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - 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) - return i; - - /* 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) { - huft_free(tl); - return i; - } - - /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) - return 1; - - /* free the decoding tables, return */ - huft_free(tl); - huft_free(td); - return 0; -} - -int inflate_dynamic() -/* decompress an inflated type 2 (dynamic Huffman codes) block. */ +/* + * decompress an inflated block + * e: last block flag + * + * GLOBAL VARIABLES: bb, kk, + */ +static int inflate_block(int *e) { - int dbits = 6; /* bits in base distance lookup table */ - int lbits = 9; /* bits in base literal/length lookup table */ - - int i; /* temporary variables */ - unsigned j; - unsigned l; /* last length */ - unsigned m; /* mask for bit lengths table */ - unsigned n; /* number of lengths to get */ - struct huft *tl; /* literal/length code table */ - struct huft *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - unsigned nb; /* number of bit length codes */ - unsigned nl; /* number of literal/length codes */ - unsigned nd; /* number of distance codes */ - -#ifdef PKZIP_BUG_WORKAROUND - unsigned ll[288 + 32]; /* literal/length and distance code lengths */ -#else - unsigned ll[286 + 30]; /* literal/length and distance code lengths */ -#endif - register ulg b; /* bit buffer */ + unsigned t; /* block type */ + register unsigned long b; /* bit buffer */ register unsigned k; /* number of bits in bit buffer */ + static unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ + 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, 0, 0 + }; + /* note: see note #13 above about the 258 in this list. */ + static unsigned short cplext[] = { /* Extra bits for literal codes 257..285 */ + 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, 99, 99 + }; /* 99==invalid */ + static unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 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 + }; + static unsigned short cpdext[] = { /* Extra bits for distance codes */ + 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 + }; /* 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) -#ifdef PKZIP_BUG_WORKAROUND - if (nl > 288 || nd > 32) -#else - if (nl > 286 || nd > 30) -#endif - return 1; /* bad lengths */ - - /* read in bit-length-code lengths */ - for (j = 0; j < nb; j++) { - NEEDBITS(3) - ll[border[j]] = (unsigned) b & 7; - DUMPBITS(3) + /* read in last block bit */ + while (k < 1) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; } - 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) { - if (i == 1) - huft_free(tl); - return i; /* incomplete code set */ + *e = (int) b & 1; + b >>= 1; + k -= 1; + + /* read in block type */ + while (k < 2) { + b |= ((unsigned long)fgetc(in_file)) << k; + k += 8; } - - /* 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) - return 1; - 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) - return 1; - 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) - return 1; - while (j--) - ll[i++] = 0; - l = 0; - } - } - - /* free decoding table for trees */ - huft_free(tl); + t = (unsigned) b & 3; + b >>= 2; + k -= 2; /* 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 (i == 1) { - fprintf(stderr, " incomplete literal tree\n"); - huft_free(tl); + /* inflate that block type */ + switch (t) { + case 0: /* Inflate stored */ + { + unsigned long n; /* number of bytes in block */ + unsigned long w; /* current window position */ + register unsigned long b_stored; /* bit buffer */ + register unsigned long k_stored; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b_stored = bb; /* initialize bit buffer */ + k_stored = bk; + w = outcnt; /* initialize window position */ + + /* go to byte boundary */ + n = k_stored & 7; + b_stored >>= n; + k_stored -= n; + + /* get the length and its complement */ + while (k_stored < 16) { + b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + k_stored += 8; + } + n = ((unsigned) b_stored & 0xffff); + b_stored >>= 16; + k_stored -= 16; + while (k_stored < 16) { + b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + k_stored += 8; + } + if (n != (unsigned) ((~b_stored) & 0xffff)) { + return 1; /* error in compressed data */ + } + b_stored >>= 16; + k_stored -= 16; + + /* read and output the compressed data */ + while (n--) { + while (k_stored < 8) { + b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; + k_stored += 8; + } + window[w++] = (unsigned char) b_stored; + if (w == (unsigned long)WSIZE) { + outcnt=(w), + flush_window(); + w = 0; + } + b_stored >>= 8; + k_stored -= 8; + } + + /* restore the globals from the locals */ + outcnt = w; /* restore global window pointer */ + bb = b_stored; /* restore global bit buffer */ + bk = k_stored; + return 0; } - return i; /* incomplete code set */ - } - bd = dbits; - if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { - if (i == 1) { - fprintf(stderr, " incomplete distance tree\n"); + case 1: /* Inflate fixed + * decompress an inflated type 1 (fixed Huffman codes) block. We should + * either replace this with a custom decoder, or at least precompute the + * Huffman tables. + */ + { + int i; /* temporary variable */ + huft_t *tl; /* literal/length code table */ + huft_t *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned int 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) { + return i; + } + + /* 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) { + huft_free(tl); + return i; + } + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + + /* free the decoding tables, return */ + huft_free(tl); huft_free(td); + return 0; } - huft_free(tl); - return i; /* incomplete code set */ - } + case 2: /* Inflate dynamic */ + { + /* Tables for deflate from PKZIP's appnote.txt. */ + static unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; + int dbits = 6; /* bits in base distance lookup table */ + int lbits = 9; /* bits in base literal/length lookup table */ + + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + huft_t *tl; /* literal/length code table */ + huft_t *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + 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 unsigned long b_dynamic; /* bit buffer */ + register unsigned k_dynamic; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b_dynamic = bb; + k_dynamic = bk; + + /* read in table lengths */ + while (k_dynamic < 5) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ + b_dynamic >>= 5; + k_dynamic -= 5; + while (k_dynamic < 5) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ + b_dynamic >>= 5; + k_dynamic -= 5; + while (k_dynamic < 4) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ + b_dynamic >>= 4; + k_dynamic -= 4; + if (nl > 286 || nd > 30) { + return 1; /* bad lengths */ + } - /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) - return 1; + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) { + while (k_dynamic < 3) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + ll[border[j]] = (unsigned) b_dynamic & 7; + b_dynamic >>= 3; + k_dynamic -= 3; + } + for (; j < 19; j++) { + ll[border[j]] = 0; + } - /* free the decoding tables, return */ - huft_free(tl); - huft_free(td); - return 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) { + if (i == 1) { + huft_free(tl); + } + return i; /* incomplete code set */ + } -/* decompress an inflated block */ -int inflate_block(e) -int *e; /* last block flag */ -{ - unsigned t; /* block type */ - register ulg b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned) i < n) { + while (k_dynamic < (unsigned) bl) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = (td = tl + ((unsigned) b_dynamic & m))->b; + b_dynamic >>= j; + k_dynamic -= 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 */ + while (k_dynamic < 2) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = 3 + ((unsigned) b_dynamic & 3); + b_dynamic >>= 2; + k_dynamic -= 2; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = l; + } + } else if (j == 17) { /* 3 to 10 zero length codes */ + while (k_dynamic < 3) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = 3 + ((unsigned) b_dynamic & 7); + b_dynamic >>= 3; + k_dynamic -= 3; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } else { /* j == 18: 11 to 138 zero length codes */ + while (k_dynamic < 7) { + b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; + k_dynamic += 8; + } + j = 11 + ((unsigned) b_dynamic & 0x7f); + b_dynamic >>= 7; + k_dynamic -= 7; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } + } - /* make local bit buffer */ - b = bb; - k = bk; + /* free decoding table for trees */ + huft_free(tl); - /* read in last block bit */ - NEEDBITS(1) - * e = (int) b & 1; - DUMPBITS(1) + /* restore the global bit buffer */ + bb = b_dynamic; + bk = k_dynamic; - /* read in block type */ - NEEDBITS(2) - t = (unsigned) b & 3; - DUMPBITS(2) + /* 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 (i == 1) { + error_msg("Incomplete literal tree"); + huft_free(tl); + } + return i; /* incomplete code set */ + } + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { + if (i == 1) { + error_msg("incomplete distance tree"); + huft_free(td); + } + huft_free(tl); + return i; /* incomplete code set */ + } - /* restore the global bit buffer */ - bb = b; - bk = k; + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; - /* inflate that block type */ - if (t == 2) - return inflate_dynamic(); - if (t == 0) - return inflate_stored(); - if (t == 1) - return inflate_fixed(); - - /* bad block type */ - return 2; + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; + } + default: + /* bad block type */ + return 2; + } } -int inflate() -/* decompress an inflated entry */ +/* + * decompress an inflated entry + * + * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr + */ +static int inflate() { int e; /* last block flag */ int r; /* result code */ - unsigned h; /* maximum struct huft's malloc'ed */ + unsigned h = 0; /* maximum struct huft's malloc'ed */ /* initialize window, bit buffer */ outcnt = 0; @@ -1050,30 +878,20 @@ int inflate() bb = 0; /* decompress until the last block */ - h = 0; do { hufts = 0; - if ((r = inflate_block(&e)) != 0) + if ((r = inflate_block(&e)) != 0) { return r; - if (hufts > h) + } + if (hufts > h) { h = hufts; + } } while (!e); - /* Undo too much lookahead. The next read will be byte aligned so we - * can discard unused bits in the last meaningful byte. - */ - while (bk >= 8) { - bk -= 8; - inptr--; - } - /* flush out window */ - outcnt=(outcnt), flush_window(); + /* return success */ -#ifdef DEBUG - fprintf(stderr, "<%u> ", h); -#endif /* DEBUG */ return 0; } @@ -1083,33 +901,89 @@ int inflate() * IN assertions: the buffer inbuf contains already the beginning of * the compressed data, from offsets inptr to insize-1 included. * The magic header has already been checked. The output buffer is cleared. + * in, out: input and output file descriptors */ -extern int unzip(in, out) -int in, out; /* input and output file descriptors */ +extern int unzip(FILE *l_in_file, FILE *l_out_file) { - int ext_header = 0; /* set if extended local header */ - int pkzip = 0; /* set for a pkzip file */ - ulg orig_crc = 0; /* original crc */ - ulg orig_len = 0; /* original uncompressed length */ - int n; - uch buf[EXTHDR]; /* extended local header */ + const int extra_field = 0x04; /* bit 2 set: extra field present */ + const int orig_name = 0x08; /* bit 3 set: original file name present */ + const int comment = 0x10; /* bit 4 set: file comment present */ + unsigned char buf[8]; /* extended local header */ + unsigned char flags; /* compression flags */ + char magic[2]; /* magic header */ + int method; + typedef void (*sig_type) (int); + int exit_code=0; /* program exit code */ - ifd = in; - ofd = out; - method = get_method(ifd); - if (method < 0) { - exit(exit_code); /* error message already emitted */ + in_file = l_in_file; + out_file = l_out_file; + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) { + (void) signal(SIGINT, (sig_type) abort_gzip); + } +#ifdef SIGTERM + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTERM, (sig_type) abort_gzip); + } +#endif +#ifdef SIGHUP + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { + (void) signal(SIGHUP, (sig_type) abort_gzip); } +#endif + + /* Allocate all global buffers (for DYN_ALLOC option) */ + window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char))); + outcnt = 0; + bytes_out = 0L; + + /* set the buffer size */ + setvbuf(in_file, NULL, _IOFBF, 0x8000); - updcrc(NULL, 0); /* initialize crc */ + magic[0] = fgetc(in_file); + magic[1] = fgetc(in_file); - if (pkzip && !ext_header) { /* crc and length at the end otherwise */ - orig_crc = LG(inbuf + LOCCRC); - orig_len = LG(inbuf + LOCLEN); + /* Magic header for gzip files, 1F 8B = \037\213 */ + if (memcmp(magic, "\037\213", 2) != 0) { + error_msg("Invalid gzip magic"); + return EXIT_FAILURE; } + method = (int) fgetc(in_file); + if (method != 8) { + error_msg("unknown method %d -- get newer version of gzip", method); + exit_code = 1; + return -1; + } + + flags = (unsigned char) fgetc(in_file); + + /* Ignore time stamp(4), extra flags(1), OS type(1) */ + fseek(in_file, 6, SEEK_CUR); + + if ((flags & extra_field) != 0) { + fseek(in_file, (size_t) fgetc(in_file) + ((size_t)fgetc(in_file) << 8), SEEK_CUR); + } + + /* Discard original name if any */ + if ((flags & orig_name) != 0) { + while (fgetc(in_file) != 0); /* null */ + } + + /* Discard file comment if any */ + if ((flags & comment) != 0) { + while (fgetc(in_file) != 0); /* null */ + } + + if (method < 0) { + printf("it failed\n"); + return(exit_code); /* error message already emitted */ + } + + make_crc_table(); + /* Decompress */ - if (method == DEFLATED) { + if (method == 8) { int res = inflate(); @@ -1123,241 +997,193 @@ int in, out; /* input and output file descriptors */ error_msg("internal error, invalid method"); } - /* Get the crc and original length */ - if (!pkzip) { - /* crc32 (see algorithm.doc) - * uncompressed input size modulo 2^32 - */ - for (n = 0; n < 8; n++) { - buf[n] = (uch) get_byte(); /* may cause an error if EOF */ - } - orig_crc = LG(buf); - orig_len = LG(buf + 4); - - } else if (ext_header) { /* If extended header, check it */ - /* signature - 4bytes: 0x50 0x4b 0x07 0x08 - * CRC-32 value - * compressed size 4-bytes - * uncompressed size 4-bytes - */ - for (n = 0; n < EXTHDR; n++) { - buf[n] = (uch) get_byte(); /* may cause an error if EOF */ - } - orig_crc = LG(buf + 4); - orig_len = LG(buf + 12); - } + /* Get the crc and original length + * crc32 (see algorithm.doc) + * uncompressed input size modulo 2^32 + */ + fread(buf, 1, 8, in_file); - /* Validate decompression */ - if (orig_crc != updcrc(outbuf, 0)) { + /* Validate decompression - crc */ + if (((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) { error_msg("invalid compressed data--crc error"); } - if (orig_len != (ulg) bytes_out) { + /* Validate decompression - size */ + if (((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) { error_msg("invalid compressed data--length error"); } - /* Check if there are more entries in a pkzip file */ - if (pkzip && inptr + 4 < insize && LG(inbuf + inptr) == LOCSIG) { - error_msg("has more than one entry--rest ignored"); - if (exit_code == OK) - exit_code = WARNING; - } - ext_header = pkzip = 0; /* for next file */ - return OK; -} + free(window); + free(crc_table); - -/* =========================================================================== - * Clear input and output buffers - */ -void clear_bufs(void) -{ - outcnt = 0; - insize = inptr = 0; - bytes_in = bytes_out = 0L; + return 0; } -/* =========================================================================== - * Initialize gunzip buffers and signals - */ -extern int gunzip_init() +extern FILE *gz_open(FILE *compressed_file, int *pid) { - foreground = signal(SIGINT, SIG_IGN) != SIG_IGN; - if (foreground) { - (void) signal(SIGINT, (sig_type) abort_gzip); + int unzip_pipe[2]; + + signal(SIGCHLD, abort_gzip); + if (pipe(unzip_pipe)!=0) { + error_msg("pipe error"); + return NULL; } -#ifdef SIGTERM - if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { - (void) signal(SIGTERM, (sig_type) abort_gzip); + if ((*pid = fork()) == -1) { + error_msg("fork failured"); + return NULL; } -#endif -#ifdef SIGHUP - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - (void) signal(SIGHUP, (sig_type) abort_gzip); + if (*pid==0) { + /* child process */ + close(unzip_pipe[0]); + unzip(compressed_file, fdopen(unzip_pipe[1], "w")); +// printf("finished unzipping\n"); + fflush(NULL); +// printf("fluched\n"); + fclose(compressed_file); + close(unzip_pipe[1]); + exit(EXIT_SUCCESS); } -#endif - - /* Allocate all global buffers (for DYN_ALLOC option) */ - inbuf = xmalloc((size_t)((INBUFSIZ+INBUF_EXTRA+1L)*sizeof(uch))); - outbuf = xmalloc((size_t)((OUTBUFSIZ+OUTBUF_EXTRA+1L)*sizeof(uch))); - d_buf = xmalloc((size_t)((DIST_BUFSIZE+1L)*sizeof(ush))); - window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(uch))); - tab_prefix0 = xmalloc((size_t)(((1L<<(BITS-1))+1L)*sizeof(ush))); - tab_prefix1 = xmalloc((size_t)(((1L<<(BITS-1))+1L)*sizeof(ush))); - clear_bufs(); /* clear input and output buffers */ - part_nb = 0; - return(EXIT_SUCCESS); + close(unzip_pipe[1]); + return (fdopen(unzip_pipe[0], "r")); } - -/* ======================================================================== */ -int gunzip_main(int argc, char **argv) +extern void gz_close(int gunzip_pid) { - int tostdout = 0; - int fromstdin = 0; - int result; - int inFileNum; - int outFileNum; - int delInputFile = 0; - int force = 0; - struct stat statBuf; - char *delFileName; - RESERVE_BB_BUFFER(ifname, MAX_PATH_LEN+1); /* input file name */ - RESERVE_BB_BUFFER(ofname, MAX_PATH_LEN+1); /* output file name */ - - method = DEFLATED; /* default compression method */ - exit_code = OK; /* let's go out on a limb and assume everything will run fine (wink wink) */ + if (kill(gunzip_pid, SIGTERM) == -1) { + error_msg_and_die("*** Couldnt kill old gunzip process *** aborting"); + } - if (strcmp(applet_name, "zcat") == 0) { - force = 1; - tostdout = 1; + if (waitpid(gunzip_pid, NULL, 0) == -1) { + printf("Couldnt wait ?"); } + free(window); + free(crc_table); +} + +extern int gunzip_main(int argc, char **argv) +{ + struct stat stat_buf; + + char *if_name = NULL; + char *of_name = NULL; + char *delete_file_name = NULL; + + const int gunzip_to_stdout = 1; + const int gunzip_from_stdin = 2; + const int gunzip_force = 4; + const int gunzip_test = 8; - /* Parse any options */ - while (--argc > 0 && **(++argv) == '-') { - if (*((*argv) + 1) == '\0') { - tostdout = 1; + int flags = 0; + int opt = 0; + int delete_old_file = FALSE; + +#ifdef BB_ZCAT + /* if called as zcat */ + if (strcmp(applet_name, "zcat") == 0) { + if (argc != 2) { + show_usage(); + } + flags |= gunzip_force; + flags |= gunzip_to_stdout; + } else +#endif + { + /* workout flags as regular gunzip */ + /* set default flags */ + if (argc == 1) { + flags |= (gunzip_from_stdin | gunzip_to_stdout); } - while (*(++(*argv))) { - switch (**argv) { + + /* Parse any options */ + while ((opt = getopt(argc, argv, "ctfh")) != -1) { + switch (opt) { case 'c': - tostdout = 1; - break; - case 't': - test_mode = 1; + flags |= gunzip_to_stdout; break; case 'f': - force = 1; + flags |= gunzip_force; + break; + case 't': + flags |= gunzip_test; break; + case 'h': default: - show_usage(); + show_usage(); /* exit's inside usage */ } } } - if (argc <= 0) { - tostdout = 1; - fromstdin = 1; - } - - if (isatty(fileno(stdin)) && fromstdin==1 && force==0) - error_msg_and_die( "data not read from terminal. Use -f to force it."); - if (isatty(fileno(stdout)) && tostdout==1 && force==0) - error_msg_and_die( "data not written to terminal. Use -f to force it."); - - gunzip_init(); - - if (fromstdin == 1) { - strcpy(ofname, "stdin"); - - inFileNum = fileno(stdin); - ifile_size = -1L; /* convention for unknown size */ - } else { - /* Open up the input file */ - if (argc <= 0) - show_usage(); - if (strlen(*argv) > MAX_PATH_LEN) { - error_msg(name_too_long); - exit(WARNING); + /* Set input filename and number */ + if (flags & gunzip_from_stdin) { + in_file = stdin; + if ((flags & gunzip_force) == 0) { + error_msg_and_die("data not written to terminal. Use -f to force it."); } - strcpy(ifname, *argv); + strcpy(if_name, "stdin"); + } else { + if_name = strdup(argv[optind]); + /* Open input file */ + in_file = xfopen(if_name, "r"); - /* Open input fille */ - inFileNum = open(ifname, O_RDONLY); - if (inFileNum < 0) { - perror(ifname); - exit(WARNING); - } /* Get the time stamp on the input file. */ - result = stat(ifname, &statBuf); - if (result < 0) { - perror(ifname); - exit(WARNING); + if (stat(if_name, &stat_buf) < 0) { + error_msg_and_die("Couldnt stat file %s",if_name); } - ifile_size = statBuf.st_size; } - if (tostdout == 1) { - /* And get to work */ - strcpy(ofname, "stdout"); - outFileNum = fileno(stdout); - - /* Actually do the compression/decompression. */ - unzip(inFileNum, outFileNum); + /* Set output filename and number */ + if (flags & gunzip_to_stdout) { + out_file = stdout; + /* whats the best way to do this with streams ? */ + if (isatty(fileno(out_file)) && ((flags & gunzip_force) == 0)) { + error_msg_and_die("data not written to terminal. Use -f to force it."); + } - } else if (test_mode) { - /* Actually do the compression/decompression. */ - unzip(inFileNum, 2); + strcpy(of_name, "stdout"); + } else if (flags & gunzip_test) { + out_file = xfopen("/dev/null", "w"); /* why does test use filenum 2 ? */ } else { - char *pos; - - /* And get to work */ - if (strlen(ifname) > MAX_PATH_LEN - 4) { - error_msg(name_too_long); - exit(WARNING); - } - strcpy(ofname, ifname); - pos = strstr(ofname, ".gz"); - if (pos != NULL) { - *pos = '\0'; - delInputFile = 1; + char *extension; + int length = strlen(if_name); + + delete_old_file = TRUE; + extension = strrchr(if_name, '.'); + if (strcmp(extension, ".gz") == 0) { + length -= 3; + } else if (strcmp(extension, ".tgz") == 0) { + length -= 4; } else { - pos = strstr(ofname, ".tgz"); - if (pos != NULL) { - *pos = '\0'; - strcat(pos, ".tar"); - delInputFile = 1; - } + error_msg_and_die("Invalid extension"); } + of_name = (char *) xcalloc(sizeof(char), length + 1); + strncpy(of_name, if_name, length); + + /* Open output file */ + out_file = xfopen(of_name, "w"); - /* Open output fille */ -#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) - outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW); -#else - outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL); -#endif - if (outFileNum < 0) { - perror(ofname); - exit(WARNING); - } /* Set permissions on the file */ - fchmod(outFileNum, statBuf.st_mode); - - /* Actually do the compression/decompression. */ - result = unzip(inFileNum, outFileNum); - - close(outFileNum); - close(inFileNum); - /* Delete the original file */ - if (result == OK) - delFileName = ifname; - else - delFileName = ofname; - - if (delInputFile == 1 && unlink(delFileName) < 0) { - perror(delFileName); - return EXIT_FAILURE; + chmod(of_name, stat_buf.st_mode); + } + + /* do the decompression, and cleanup */ + if (unzip(in_file, out_file) == 0) { + /* Success, remove .gz file */ + delete_file_name = if_name; + } else { + /* remove failed attempt */ + delete_file_name = of_name; + } + + fclose(out_file); + fclose(in_file); + + if (delete_old_file == TRUE) { + if (unlink(delete_file_name) < 0) { + error_msg_and_die("Couldnt remove %s", delete_file_name); } } - return(exit_code); + + free(of_name); + + return(EXIT_SUCCESS); } |