| [1049] | 1 | /* gun.c -- simple gunzip to give an example of the use of inflateBack()
 | 
|---|
 | 2 |  * Copyright (C) 2003, 2005, 2008, 2010, 2012 Mark Adler
 | 
|---|
 | 3 |  * For conditions of distribution and use, see copyright notice in zlib.h
 | 
|---|
 | 4 |    Version 1.7  12 August 2012  Mark Adler */
 | 
|---|
 | 5 | 
 | 
|---|
 | 6 | /* Version history:
 | 
|---|
 | 7 |    1.0  16 Feb 2003  First version for testing of inflateBack()
 | 
|---|
 | 8 |    1.1  21 Feb 2005  Decompress concatenated gzip streams
 | 
|---|
 | 9 |                      Remove use of "this" variable (C++ keyword)
 | 
|---|
 | 10 |                      Fix return value for in()
 | 
|---|
 | 11 |                      Improve allocation failure checking
 | 
|---|
 | 12 |                      Add typecasting for void * structures
 | 
|---|
 | 13 |                      Add -h option for command version and usage
 | 
|---|
 | 14 |                      Add a bunch of comments
 | 
|---|
 | 15 |    1.2  20 Mar 2005  Add Unix compress (LZW) decompression
 | 
|---|
 | 16 |                      Copy file attributes from input file to output file
 | 
|---|
 | 17 |    1.3  12 Jun 2005  Add casts for error messages [Oberhumer]
 | 
|---|
 | 18 |    1.4   8 Dec 2006  LZW decompression speed improvements
 | 
|---|
 | 19 |    1.5   9 Feb 2008  Avoid warning in latest version of gcc
 | 
|---|
 | 20 |    1.6  17 Jan 2010  Avoid signed/unsigned comparison warnings
 | 
|---|
 | 21 |    1.7  12 Aug 2012  Update for z_const usage in zlib 1.2.8
 | 
|---|
 | 22 |  */
 | 
|---|
 | 23 | 
 | 
|---|
 | 24 | /*
 | 
|---|
 | 25 |    gun [ -t ] [ name ... ]
 | 
|---|
 | 26 | 
 | 
|---|
 | 27 |    decompresses the data in the named gzip files.  If no arguments are given,
 | 
|---|
 | 28 |    gun will decompress from stdin to stdout.  The names must end in .gz, -gz,
 | 
|---|
 | 29 |    .z, -z, _z, or .Z.  The uncompressed data will be written to a file name
 | 
|---|
 | 30 |    with the suffix stripped.  On success, the original file is deleted.  On
 | 
|---|
 | 31 |    failure, the output file is deleted.  For most failures, the command will
 | 
|---|
 | 32 |    continue to process the remaining names on the command line.  A memory
 | 
|---|
 | 33 |    allocation failure will abort the command.  If -t is specified, then the
 | 
|---|
 | 34 |    listed files or stdin will be tested as gzip files for integrity (without
 | 
|---|
 | 35 |    checking for a proper suffix), no output will be written, and no files
 | 
|---|
 | 36 |    will be deleted.
 | 
|---|
 | 37 | 
 | 
|---|
 | 38 |    Like gzip, gun allows concatenated gzip streams and will decompress them,
 | 
|---|
 | 39 |    writing all of the uncompressed data to the output.  Unlike gzip, gun allows
 | 
|---|
 | 40 |    an empty file on input, and will produce no error writing an empty output
 | 
|---|
 | 41 |    file.
 | 
|---|
 | 42 | 
 | 
|---|
 | 43 |    gun will also decompress files made by Unix compress, which uses LZW
 | 
|---|
 | 44 |    compression.  These files are automatically detected by virtue of their
 | 
|---|
 | 45 |    magic header bytes.  Since the end of Unix compress stream is marked by the
 | 
|---|
 | 46 |    end-of-file, they cannot be concantenated.  If a Unix compress stream is
 | 
|---|
 | 47 |    encountered in an input file, it is the last stream in that file.
 | 
|---|
 | 48 | 
 | 
|---|
 | 49 |    Like gunzip and uncompress, the file attributes of the orignal compressed
 | 
|---|
 | 50 |    file are maintained in the final uncompressed file, to the extent that the
 | 
|---|
 | 51 |    user permissions allow it.
 | 
|---|
 | 52 | 
 | 
|---|
 | 53 |    On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
 | 
|---|
 | 54 |    1.2.4) is on the same file, when gun is linked with zlib 1.2.2.  Also the
 | 
|---|
 | 55 |    LZW decompression provided by gun is about twice as fast as the standard
 | 
|---|
 | 56 |    Unix uncompress command.
 | 
|---|
 | 57 |  */
 | 
|---|
 | 58 | 
 | 
|---|
 | 59 | /* external functions and related types and constants */
 | 
|---|
 | 60 | #include <stdio.h>          /* fprintf() */
 | 
|---|
 | 61 | #include <stdlib.h>         /* malloc(), free() */
 | 
|---|
 | 62 | #include <string.h>         /* strerror(), strcmp(), strlen(), memcpy() */
 | 
|---|
 | 63 | #include <errno.h>          /* errno */
 | 
|---|
 | 64 | #include <fcntl.h>          /* open() */
 | 
|---|
 | 65 | #include <unistd.h>         /* read(), write(), close(), chown(), unlink() */
 | 
|---|
 | 66 | #include <sys/types.h>
 | 
|---|
 | 67 | #include <sys/stat.h>       /* stat(), chmod() */
 | 
|---|
 | 68 | #include <utime.h>          /* utime() */
 | 
|---|
 | 69 | #include "zlib.h"           /* inflateBackInit(), inflateBack(), */
 | 
|---|
 | 70 |                             /* inflateBackEnd(), crc32() */
 | 
|---|
 | 71 | 
 | 
|---|
 | 72 | /* function declaration */
 | 
|---|
 | 73 | #define local static
 | 
|---|
 | 74 | 
 | 
|---|
 | 75 | /* buffer constants */
 | 
|---|
 | 76 | #define SIZE 32768U         /* input and output buffer sizes */
 | 
|---|
 | 77 | #define PIECE 16384         /* limits i/o chunks for 16-bit int case */
 | 
|---|
 | 78 | 
 | 
|---|
 | 79 | /* structure for infback() to pass to input function in() -- it maintains the
 | 
|---|
 | 80 |    input file and a buffer of size SIZE */
 | 
|---|
 | 81 | struct ind {
 | 
|---|
 | 82 |     int infile;
 | 
|---|
 | 83 |     unsigned char *inbuf;
 | 
|---|
 | 84 | };
 | 
|---|
 | 85 | 
 | 
|---|
 | 86 | /* Load input buffer, assumed to be empty, and return bytes loaded and a
 | 
|---|
 | 87 |    pointer to them.  read() is called until the buffer is full, or until it
 | 
|---|
 | 88 |    returns end-of-file or error.  Return 0 on error. */
 | 
|---|
 | 89 | local unsigned in(void *in_desc, z_const unsigned char **buf)
 | 
|---|
 | 90 | {
 | 
|---|
 | 91 |     int ret;
 | 
|---|
 | 92 |     unsigned len;
 | 
|---|
 | 93 |     unsigned char *next;
 | 
|---|
 | 94 |     struct ind *me = (struct ind *)in_desc;
 | 
|---|
 | 95 | 
 | 
|---|
 | 96 |     next = me->inbuf;
 | 
|---|
 | 97 |     *buf = next;
 | 
|---|
 | 98 |     len = 0;
 | 
|---|
 | 99 |     do {
 | 
|---|
 | 100 |         ret = PIECE;
 | 
|---|
 | 101 |         if ((unsigned)ret > SIZE - len)
 | 
|---|
 | 102 |             ret = (int)(SIZE - len);
 | 
|---|
 | 103 |         ret = (int)read(me->infile, next, ret);
 | 
|---|
 | 104 |         if (ret == -1) {
 | 
|---|
 | 105 |             len = 0;
 | 
|---|
 | 106 |             break;
 | 
|---|
 | 107 |         }
 | 
|---|
 | 108 |         next += ret;
 | 
|---|
 | 109 |         len += ret;
 | 
|---|
 | 110 |     } while (ret != 0 && len < SIZE);
 | 
|---|
 | 111 |     return len;
 | 
|---|
 | 112 | }
 | 
|---|
 | 113 | 
 | 
|---|
 | 114 | /* structure for infback() to pass to output function out() -- it maintains the
 | 
|---|
 | 115 |    output file, a running CRC-32 check on the output and the total number of
 | 
|---|
 | 116 |    bytes output, both for checking against the gzip trailer.  (The length in
 | 
|---|
 | 117 |    the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
 | 
|---|
 | 118 |    the output is greater than 4 GB.) */
 | 
|---|
 | 119 | struct outd {
 | 
|---|
 | 120 |     int outfile;
 | 
|---|
 | 121 |     int check;                  /* true if checking crc and total */
 | 
|---|
 | 122 |     unsigned long crc;
 | 
|---|
 | 123 |     unsigned long total;
 | 
|---|
 | 124 | };
 | 
|---|
 | 125 | 
 | 
|---|
 | 126 | /* Write output buffer and update the CRC-32 and total bytes written.  write()
 | 
|---|
 | 127 |    is called until all of the output is written or an error is encountered.
 | 
|---|
 | 128 |    On success out() returns 0.  For a write failure, out() returns 1.  If the
 | 
|---|
 | 129 |    output file descriptor is -1, then nothing is written.
 | 
|---|
 | 130 |  */
 | 
|---|
 | 131 | local int out(void *out_desc, unsigned char *buf, unsigned len)
 | 
|---|
 | 132 | {
 | 
|---|
 | 133 |     int ret;
 | 
|---|
 | 134 |     struct outd *me = (struct outd *)out_desc;
 | 
|---|
 | 135 | 
 | 
|---|
 | 136 |     if (me->check) {
 | 
|---|
 | 137 |         me->crc = crc32(me->crc, buf, len);
 | 
|---|
 | 138 |         me->total += len;
 | 
|---|
 | 139 |     }
 | 
|---|
 | 140 |     if (me->outfile != -1)
 | 
|---|
 | 141 |         do {
 | 
|---|
 | 142 |             ret = PIECE;
 | 
|---|
 | 143 |             if ((unsigned)ret > len)
 | 
|---|
 | 144 |                 ret = (int)len;
 | 
|---|
 | 145 |             ret = (int)write(me->outfile, buf, ret);
 | 
|---|
 | 146 |             if (ret == -1)
 | 
|---|
 | 147 |                 return 1;
 | 
|---|
 | 148 |             buf += ret;
 | 
|---|
 | 149 |             len -= ret;
 | 
|---|
 | 150 |         } while (len != 0);
 | 
|---|
 | 151 |     return 0;
 | 
|---|
 | 152 | }
 | 
|---|
 | 153 | 
 | 
|---|
 | 154 | /* next input byte macro for use inside lunpipe() and gunpipe() */
 | 
|---|
 | 155 | #define NEXT() (have ? 0 : (have = in(indp, &next)), \
 | 
|---|
 | 156 |                 last = have ? (have--, (int)(*next++)) : -1)
 | 
|---|
 | 157 | 
 | 
|---|
 | 158 | /* memory for gunpipe() and lunpipe() --
 | 
|---|
 | 159 |    the first 256 entries of prefix[] and suffix[] are never used, could
 | 
|---|
 | 160 |    have offset the index, but it's faster to waste the memory */
 | 
|---|
 | 161 | unsigned char inbuf[SIZE];              /* input buffer */
 | 
|---|
 | 162 | unsigned char outbuf[SIZE];             /* output buffer */
 | 
|---|
 | 163 | unsigned short prefix[65536];           /* index to LZW prefix string */
 | 
|---|
 | 164 | unsigned char suffix[65536];            /* one-character LZW suffix */
 | 
|---|
 | 165 | unsigned char match[65280 + 2];         /* buffer for reversed match or gzip
 | 
|---|
 | 166 |                                            32K sliding window */
 | 
|---|
 | 167 | 
 | 
|---|
 | 168 | /* throw out what's left in the current bits byte buffer (this is a vestigial
 | 
|---|
 | 169 |    aspect of the compressed data format derived from an implementation that
 | 
|---|
 | 170 |    made use of a special VAX machine instruction!) */
 | 
|---|
 | 171 | #define FLUSHCODE() \
 | 
|---|
 | 172 |     do { \
 | 
|---|
 | 173 |         left = 0; \
 | 
|---|
 | 174 |         rem = 0; \
 | 
|---|
 | 175 |         if (chunk > have) { \
 | 
|---|
 | 176 |             chunk -= have; \
 | 
|---|
 | 177 |             have = 0; \
 | 
|---|
 | 178 |             if (NEXT() == -1) \
 | 
|---|
 | 179 |                 break; \
 | 
|---|
 | 180 |             chunk--; \
 | 
|---|
 | 181 |             if (chunk > have) { \
 | 
|---|
 | 182 |                 chunk = have = 0; \
 | 
|---|
 | 183 |                 break; \
 | 
|---|
 | 184 |             } \
 | 
|---|
 | 185 |         } \
 | 
|---|
 | 186 |         have -= chunk; \
 | 
|---|
 | 187 |         next += chunk; \
 | 
|---|
 | 188 |         chunk = 0; \
 | 
|---|
 | 189 |     } while (0)
 | 
|---|
 | 190 | 
 | 
|---|
 | 191 | /* Decompress a compress (LZW) file from indp to outfile.  The compress magic
 | 
|---|
 | 192 |    header (two bytes) has already been read and verified.  There are have bytes
 | 
|---|
 | 193 |    of buffered input at next.  strm is used for passing error information back
 | 
|---|
 | 194 |    to gunpipe().
 | 
|---|
 | 195 | 
 | 
|---|
 | 196 |    lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
 | 
|---|
 | 197 |    file, read error, or write error (a write error indicated by strm->next_in
 | 
|---|
 | 198 |    not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
 | 
|---|
 | 199 |  */
 | 
|---|
 | 200 | local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp,
 | 
|---|
 | 201 |                   int outfile, z_stream *strm)
 | 
|---|
 | 202 | {
 | 
|---|
 | 203 |     int last;                   /* last byte read by NEXT(), or -1 if EOF */
 | 
|---|
 | 204 |     unsigned chunk;             /* bytes left in current chunk */
 | 
|---|
 | 205 |     int left;                   /* bits left in rem */
 | 
|---|
 | 206 |     unsigned rem;               /* unused bits from input */
 | 
|---|
 | 207 |     int bits;                   /* current bits per code */
 | 
|---|
 | 208 |     unsigned code;              /* code, table traversal index */
 | 
|---|
 | 209 |     unsigned mask;              /* mask for current bits codes */
 | 
|---|
 | 210 |     int max;                    /* maximum bits per code for this stream */
 | 
|---|
 | 211 |     unsigned flags;             /* compress flags, then block compress flag */
 | 
|---|
 | 212 |     unsigned end;               /* last valid entry in prefix/suffix tables */
 | 
|---|
 | 213 |     unsigned temp;              /* current code */
 | 
|---|
 | 214 |     unsigned prev;              /* previous code */
 | 
|---|
 | 215 |     unsigned final;             /* last character written for previous code */
 | 
|---|
 | 216 |     unsigned stack;             /* next position for reversed string */
 | 
|---|
 | 217 |     unsigned outcnt;            /* bytes in output buffer */
 | 
|---|
 | 218 |     struct outd outd;           /* output structure */
 | 
|---|
 | 219 |     unsigned char *p;
 | 
|---|
 | 220 | 
 | 
|---|
 | 221 |     /* set up output */
 | 
|---|
 | 222 |     outd.outfile = outfile;
 | 
|---|
 | 223 |     outd.check = 0;
 | 
|---|
 | 224 | 
 | 
|---|
 | 225 |     /* process remainder of compress header -- a flags byte */
 | 
|---|
 | 226 |     flags = NEXT();
 | 
|---|
 | 227 |     if (last == -1)
 | 
|---|
 | 228 |         return Z_BUF_ERROR;
 | 
|---|
 | 229 |     if (flags & 0x60) {
 | 
|---|
 | 230 |         strm->msg = (char *)"unknown lzw flags set";
 | 
|---|
 | 231 |         return Z_DATA_ERROR;
 | 
|---|
 | 232 |     }
 | 
|---|
 | 233 |     max = flags & 0x1f;
 | 
|---|
 | 234 |     if (max < 9 || max > 16) {
 | 
|---|
 | 235 |         strm->msg = (char *)"lzw bits out of range";
 | 
|---|
 | 236 |         return Z_DATA_ERROR;
 | 
|---|
 | 237 |     }
 | 
|---|
 | 238 |     if (max == 9)                           /* 9 doesn't really mean 9 */
 | 
|---|
 | 239 |         max = 10;
 | 
|---|
 | 240 |     flags &= 0x80;                          /* true if block compress */
 | 
|---|
 | 241 | 
 | 
|---|
 | 242 |     /* clear table */
 | 
|---|
 | 243 |     bits = 9;
 | 
|---|
 | 244 |     mask = 0x1ff;
 | 
|---|
 | 245 |     end = flags ? 256 : 255;
 | 
|---|
 | 246 | 
 | 
|---|
 | 247 |     /* set up: get first 9-bit code, which is the first decompressed byte, but
 | 
|---|
 | 248 |        don't create a table entry until the next code */
 | 
|---|
 | 249 |     if (NEXT() == -1)                       /* no compressed data is ok */
 | 
|---|
 | 250 |         return Z_OK;
 | 
|---|
 | 251 |     final = prev = (unsigned)last;          /* low 8 bits of code */
 | 
|---|
 | 252 |     if (NEXT() == -1)                       /* missing a bit */
 | 
|---|
 | 253 |         return Z_BUF_ERROR;
 | 
|---|
 | 254 |     if (last & 1) {                         /* code must be < 256 */
 | 
|---|
 | 255 |         strm->msg = (char *)"invalid lzw code";
 | 
|---|
 | 256 |         return Z_DATA_ERROR;
 | 
|---|
 | 257 |     }
 | 
|---|
 | 258 |     rem = (unsigned)last >> 1;              /* remaining 7 bits */
 | 
|---|
 | 259 |     left = 7;
 | 
|---|
 | 260 |     chunk = bits - 2;                       /* 7 bytes left in this chunk */
 | 
|---|
 | 261 |     outbuf[0] = (unsigned char)final;       /* write first decompressed byte */
 | 
|---|
 | 262 |     outcnt = 1;
 | 
|---|
 | 263 | 
 | 
|---|
 | 264 |     /* decode codes */
 | 
|---|
 | 265 |     stack = 0;
 | 
|---|
 | 266 |     for (;;) {
 | 
|---|
 | 267 |         /* if the table will be full after this, increment the code size */
 | 
|---|
 | 268 |         if (end >= mask && bits < max) {
 | 
|---|
 | 269 |             FLUSHCODE();
 | 
|---|
 | 270 |             bits++;
 | 
|---|
 | 271 |             mask <<= 1;
 | 
|---|
 | 272 |             mask++;
 | 
|---|
 | 273 |         }
 | 
|---|
 | 274 | 
 | 
|---|
 | 275 |         /* get a code of length bits */
 | 
|---|
 | 276 |         if (chunk == 0)                     /* decrement chunk modulo bits */
 | 
|---|
 | 277 |             chunk = bits;
 | 
|---|
 | 278 |         code = rem;                         /* low bits of code */
 | 
|---|
 | 279 |         if (NEXT() == -1) {                 /* EOF is end of compressed data */
 | 
|---|
 | 280 |             /* write remaining buffered output */
 | 
|---|
 | 281 |             if (outcnt && out(&outd, outbuf, outcnt)) {
 | 
|---|
 | 282 |                 strm->next_in = outbuf;     /* signal write error */
 | 
|---|
 | 283 |                 return Z_BUF_ERROR;
 | 
|---|
 | 284 |             }
 | 
|---|
 | 285 |             return Z_OK;
 | 
|---|
 | 286 |         }
 | 
|---|
 | 287 |         code += (unsigned)last << left;     /* middle (or high) bits of code */
 | 
|---|
 | 288 |         left += 8;
 | 
|---|
 | 289 |         chunk--;
 | 
|---|
 | 290 |         if (bits > left) {                  /* need more bits */
 | 
|---|
 | 291 |             if (NEXT() == -1)               /* can't end in middle of code */
 | 
|---|
 | 292 |                 return Z_BUF_ERROR;
 | 
|---|
 | 293 |             code += (unsigned)last << left; /* high bits of code */
 | 
|---|
 | 294 |             left += 8;
 | 
|---|
 | 295 |             chunk--;
 | 
|---|
 | 296 |         }
 | 
|---|
 | 297 |         code &= mask;                       /* mask to current code length */
 | 
|---|
 | 298 |         left -= bits;                       /* number of unused bits */
 | 
|---|
 | 299 |         rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
 | 
|---|
 | 300 | 
 | 
|---|
 | 301 |         /* process clear code (256) */
 | 
|---|
 | 302 |         if (code == 256 && flags) {
 | 
|---|
 | 303 |             FLUSHCODE();
 | 
|---|
 | 304 |             bits = 9;                       /* initialize bits and mask */
 | 
|---|
 | 305 |             mask = 0x1ff;
 | 
|---|
 | 306 |             end = 255;                      /* empty table */
 | 
|---|
 | 307 |             continue;                       /* get next code */
 | 
|---|
 | 308 |         }
 | 
|---|
 | 309 | 
 | 
|---|
 | 310 |         /* special code to reuse last match */
 | 
|---|
 | 311 |         temp = code;                        /* save the current code */
 | 
|---|
 | 312 |         if (code > end) {
 | 
|---|
 | 313 |             /* Be picky on the allowed code here, and make sure that the code
 | 
|---|
 | 314 |                we drop through (prev) will be a valid index so that random
 | 
|---|
 | 315 |                input does not cause an exception.  The code != end + 1 check is
 | 
|---|
 | 316 |                empirically derived, and not checked in the original uncompress
 | 
|---|
 | 317 |                code.  If this ever causes a problem, that check could be safely
 | 
|---|
 | 318 |                removed.  Leaving this check in greatly improves gun's ability
 | 
|---|
 | 319 |                to detect random or corrupted input after a compress header.
 | 
|---|
 | 320 |                In any case, the prev > end check must be retained. */
 | 
|---|
 | 321 |             if (code != end + 1 || prev > end) {
 | 
|---|
 | 322 |                 strm->msg = (char *)"invalid lzw code";
 | 
|---|
 | 323 |                 return Z_DATA_ERROR;
 | 
|---|
 | 324 |             }
 | 
|---|
 | 325 |             match[stack++] = (unsigned char)final;
 | 
|---|
 | 326 |             code = prev;
 | 
|---|
 | 327 |         }
 | 
|---|
 | 328 | 
 | 
|---|
 | 329 |         /* walk through linked list to generate output in reverse order */
 | 
|---|
 | 330 |         p = match + stack;
 | 
|---|
 | 331 |         while (code >= 256) {
 | 
|---|
 | 332 |             *p++ = suffix[code];
 | 
|---|
 | 333 |             code = prefix[code];
 | 
|---|
 | 334 |         }
 | 
|---|
 | 335 |         stack = p - match;
 | 
|---|
 | 336 |         match[stack++] = (unsigned char)code;
 | 
|---|
 | 337 |         final = code;
 | 
|---|
 | 338 | 
 | 
|---|
 | 339 |         /* link new table entry */
 | 
|---|
 | 340 |         if (end < mask) {
 | 
|---|
 | 341 |             end++;
 | 
|---|
 | 342 |             prefix[end] = (unsigned short)prev;
 | 
|---|
 | 343 |             suffix[end] = (unsigned char)final;
 | 
|---|
 | 344 |         }
 | 
|---|
 | 345 | 
 | 
|---|
 | 346 |         /* set previous code for next iteration */
 | 
|---|
 | 347 |         prev = temp;
 | 
|---|
 | 348 | 
 | 
|---|
 | 349 |         /* write output in forward order */
 | 
|---|
 | 350 |         while (stack > SIZE - outcnt) {
 | 
|---|
 | 351 |             while (outcnt < SIZE)
 | 
|---|
 | 352 |                 outbuf[outcnt++] = match[--stack];
 | 
|---|
 | 353 |             if (out(&outd, outbuf, outcnt)) {
 | 
|---|
 | 354 |                 strm->next_in = outbuf; /* signal write error */
 | 
|---|
 | 355 |                 return Z_BUF_ERROR;
 | 
|---|
 | 356 |             }
 | 
|---|
 | 357 |             outcnt = 0;
 | 
|---|
 | 358 |         }
 | 
|---|
 | 359 |         p = match + stack;
 | 
|---|
 | 360 |         do {
 | 
|---|
 | 361 |             outbuf[outcnt++] = *--p;
 | 
|---|
 | 362 |         } while (p > match);
 | 
|---|
 | 363 |         stack = 0;
 | 
|---|
 | 364 | 
 | 
|---|
 | 365 |         /* loop for next code with final and prev as the last match, rem and
 | 
|---|
 | 366 |            left provide the first 0..7 bits of the next code, end is the last
 | 
|---|
 | 367 |            valid table entry */
 | 
|---|
 | 368 |     }
 | 
|---|
 | 369 | }
 | 
|---|
 | 370 | 
 | 
|---|
 | 371 | /* Decompress a gzip file from infile to outfile.  strm is assumed to have been
 | 
|---|
 | 372 |    successfully initialized with inflateBackInit().  The input file may consist
 | 
|---|
 | 373 |    of a series of gzip streams, in which case all of them will be decompressed
 | 
|---|
 | 374 |    to the output file.  If outfile is -1, then the gzip stream(s) integrity is
 | 
|---|
 | 375 |    checked and nothing is written.
 | 
|---|
 | 376 | 
 | 
|---|
 | 377 |    The return value is a zlib error code: Z_MEM_ERROR if out of memory,
 | 
|---|
 | 378 |    Z_DATA_ERROR if the header or the compressed data is invalid, or if the
 | 
|---|
 | 379 |    trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
 | 
|---|
 | 380 |    prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
 | 
|---|
 | 381 |    stream) follows a valid gzip stream.
 | 
|---|
 | 382 |  */
 | 
|---|
 | 383 | local int gunpipe(z_stream *strm, int infile, int outfile)
 | 
|---|
 | 384 | {
 | 
|---|
 | 385 |     int ret, first, last;
 | 
|---|
 | 386 |     unsigned have, flags, len;
 | 
|---|
 | 387 |     z_const unsigned char *next = NULL;
 | 
|---|
 | 388 |     struct ind ind, *indp;
 | 
|---|
 | 389 |     struct outd outd;
 | 
|---|
 | 390 | 
 | 
|---|
 | 391 |     /* setup input buffer */
 | 
|---|
 | 392 |     ind.infile = infile;
 | 
|---|
 | 393 |     ind.inbuf = inbuf;
 | 
|---|
 | 394 |     indp = &ind;
 | 
|---|
 | 395 | 
 | 
|---|
 | 396 |     /* decompress concatenated gzip streams */
 | 
|---|
 | 397 |     have = 0;                               /* no input data read in yet */
 | 
|---|
 | 398 |     first = 1;                              /* looking for first gzip header */
 | 
|---|
 | 399 |     strm->next_in = Z_NULL;                 /* so Z_BUF_ERROR means EOF */
 | 
|---|
 | 400 |     for (;;) {
 | 
|---|
 | 401 |         /* look for the two magic header bytes for a gzip stream */
 | 
|---|
 | 402 |         if (NEXT() == -1) {
 | 
|---|
 | 403 |             ret = Z_OK;
 | 
|---|
 | 404 |             break;                          /* empty gzip stream is ok */
 | 
|---|
 | 405 |         }
 | 
|---|
 | 406 |         if (last != 31 || (NEXT() != 139 && last != 157)) {
 | 
|---|
 | 407 |             strm->msg = (char *)"incorrect header check";
 | 
|---|
 | 408 |             ret = first ? Z_DATA_ERROR : Z_ERRNO;
 | 
|---|
 | 409 |             break;                          /* not a gzip or compress header */
 | 
|---|
 | 410 |         }
 | 
|---|
 | 411 |         first = 0;                          /* next non-header is junk */
 | 
|---|
 | 412 | 
 | 
|---|
 | 413 |         /* process a compress (LZW) file -- can't be concatenated after this */
 | 
|---|
 | 414 |         if (last == 157) {
 | 
|---|
 | 415 |             ret = lunpipe(have, next, indp, outfile, strm);
 | 
|---|
 | 416 |             break;
 | 
|---|
 | 417 |         }
 | 
|---|
 | 418 | 
 | 
|---|
 | 419 |         /* process remainder of gzip header */
 | 
|---|
 | 420 |         ret = Z_BUF_ERROR;
 | 
|---|
 | 421 |         if (NEXT() != 8) {                  /* only deflate method allowed */
 | 
|---|
 | 422 |             if (last == -1) break;
 | 
|---|
 | 423 |             strm->msg = (char *)"unknown compression method";
 | 
|---|
 | 424 |             ret = Z_DATA_ERROR;
 | 
|---|
 | 425 |             break;
 | 
|---|
 | 426 |         }
 | 
|---|
 | 427 |         flags = NEXT();                     /* header flags */
 | 
|---|
 | 428 |         NEXT();                             /* discard mod time, xflgs, os */
 | 
|---|
 | 429 |         NEXT();
 | 
|---|
 | 430 |         NEXT();
 | 
|---|
 | 431 |         NEXT();
 | 
|---|
 | 432 |         NEXT();
 | 
|---|
 | 433 |         NEXT();
 | 
|---|
 | 434 |         if (last == -1) break;
 | 
|---|
 | 435 |         if (flags & 0xe0) {
 | 
|---|
 | 436 |             strm->msg = (char *)"unknown header flags set";
 | 
|---|
 | 437 |             ret = Z_DATA_ERROR;
 | 
|---|
 | 438 |             break;
 | 
|---|
 | 439 |         }
 | 
|---|
 | 440 |         if (flags & 4) {                    /* extra field */
 | 
|---|
 | 441 |             len = NEXT();
 | 
|---|
 | 442 |             len += (unsigned)(NEXT()) << 8;
 | 
|---|
 | 443 |             if (last == -1) break;
 | 
|---|
 | 444 |             while (len > have) {
 | 
|---|
 | 445 |                 len -= have;
 | 
|---|
 | 446 |                 have = 0;
 | 
|---|
 | 447 |                 if (NEXT() == -1) break;
 | 
|---|
 | 448 |                 len--;
 | 
|---|
 | 449 |             }
 | 
|---|
 | 450 |             if (last == -1) break;
 | 
|---|
 | 451 |             have -= len;
 | 
|---|
 | 452 |             next += len;
 | 
|---|
 | 453 |         }
 | 
|---|
 | 454 |         if (flags & 8)                      /* file name */
 | 
|---|
 | 455 |             while (NEXT() != 0 && last != -1)
 | 
|---|
 | 456 |                 ;
 | 
|---|
 | 457 |         if (flags & 16)                     /* comment */
 | 
|---|
 | 458 |             while (NEXT() != 0 && last != -1)
 | 
|---|
 | 459 |                 ;
 | 
|---|
 | 460 |         if (flags & 2) {                    /* header crc */
 | 
|---|
 | 461 |             NEXT();
 | 
|---|
 | 462 |             NEXT();
 | 
|---|
 | 463 |         }
 | 
|---|
 | 464 |         if (last == -1) break;
 | 
|---|
 | 465 | 
 | 
|---|
 | 466 |         /* set up output */
 | 
|---|
 | 467 |         outd.outfile = outfile;
 | 
|---|
 | 468 |         outd.check = 1;
 | 
|---|
 | 469 |         outd.crc = crc32(0L, Z_NULL, 0);
 | 
|---|
 | 470 |         outd.total = 0;
 | 
|---|
 | 471 | 
 | 
|---|
 | 472 |         /* decompress data to output */
 | 
|---|
 | 473 |         strm->next_in = next;
 | 
|---|
 | 474 |         strm->avail_in = have;
 | 
|---|
 | 475 |         ret = inflateBack(strm, in, indp, out, &outd);
 | 
|---|
 | 476 |         if (ret != Z_STREAM_END) break;
 | 
|---|
 | 477 |         next = strm->next_in;
 | 
|---|
 | 478 |         have = strm->avail_in;
 | 
|---|
 | 479 |         strm->next_in = Z_NULL;             /* so Z_BUF_ERROR means EOF */
 | 
|---|
 | 480 | 
 | 
|---|
 | 481 |         /* check trailer */
 | 
|---|
 | 482 |         ret = Z_BUF_ERROR;
 | 
|---|
 | 483 |         if (NEXT() != (int)(outd.crc & 0xff) ||
 | 
|---|
 | 484 |             NEXT() != (int)((outd.crc >> 8) & 0xff) ||
 | 
|---|
 | 485 |             NEXT() != (int)((outd.crc >> 16) & 0xff) ||
 | 
|---|
 | 486 |             NEXT() != (int)((outd.crc >> 24) & 0xff)) {
 | 
|---|
 | 487 |             /* crc error */
 | 
|---|
 | 488 |             if (last != -1) {
 | 
|---|
 | 489 |                 strm->msg = (char *)"incorrect data check";
 | 
|---|
 | 490 |                 ret = Z_DATA_ERROR;
 | 
|---|
 | 491 |             }
 | 
|---|
 | 492 |             break;
 | 
|---|
 | 493 |         }
 | 
|---|
 | 494 |         if (NEXT() != (int)(outd.total & 0xff) ||
 | 
|---|
 | 495 |             NEXT() != (int)((outd.total >> 8) & 0xff) ||
 | 
|---|
 | 496 |             NEXT() != (int)((outd.total >> 16) & 0xff) ||
 | 
|---|
 | 497 |             NEXT() != (int)((outd.total >> 24) & 0xff)) {
 | 
|---|
 | 498 |             /* length error */
 | 
|---|
 | 499 |             if (last != -1) {
 | 
|---|
 | 500 |                 strm->msg = (char *)"incorrect length check";
 | 
|---|
 | 501 |                 ret = Z_DATA_ERROR;
 | 
|---|
 | 502 |             }
 | 
|---|
 | 503 |             break;
 | 
|---|
 | 504 |         }
 | 
|---|
 | 505 | 
 | 
|---|
 | 506 |         /* go back and look for another gzip stream */
 | 
|---|
 | 507 |     }
 | 
|---|
 | 508 | 
 | 
|---|
 | 509 |     /* clean up and return */
 | 
|---|
 | 510 |     return ret;
 | 
|---|
 | 511 | }
 | 
|---|
 | 512 | 
 | 
|---|
 | 513 | /* Copy file attributes, from -> to, as best we can.  This is best effort, so
 | 
|---|
 | 514 |    no errors are reported.  The mode bits, including suid, sgid, and the sticky
 | 
|---|
 | 515 |    bit are copied (if allowed), the owner's user id and group id are copied
 | 
|---|
 | 516 |    (again if allowed), and the access and modify times are copied. */
 | 
|---|
 | 517 | local void copymeta(char *from, char *to)
 | 
|---|
 | 518 | {
 | 
|---|
 | 519 |     struct stat was;
 | 
|---|
 | 520 |     struct utimbuf when;
 | 
|---|
 | 521 | 
 | 
|---|
 | 522 |     /* get all of from's Unix meta data, return if not a regular file */
 | 
|---|
 | 523 |     if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
 | 
|---|
 | 524 |         return;
 | 
|---|
 | 525 | 
 | 
|---|
 | 526 |     /* set to's mode bits, ignore errors */
 | 
|---|
 | 527 |     (void)chmod(to, was.st_mode & 07777);
 | 
|---|
 | 528 | 
 | 
|---|
 | 529 |     /* copy owner's user and group, ignore errors */
 | 
|---|
 | 530 |     (void)chown(to, was.st_uid, was.st_gid);
 | 
|---|
 | 531 | 
 | 
|---|
 | 532 |     /* copy access and modify times, ignore errors */
 | 
|---|
 | 533 |     when.actime = was.st_atime;
 | 
|---|
 | 534 |     when.modtime = was.st_mtime;
 | 
|---|
 | 535 |     (void)utime(to, &when);
 | 
|---|
 | 536 | }
 | 
|---|
 | 537 | 
 | 
|---|
 | 538 | /* Decompress the file inname to the file outnname, of if test is true, just
 | 
|---|
 | 539 |    decompress without writing and check the gzip trailer for integrity.  If
 | 
|---|
 | 540 |    inname is NULL or an empty string, read from stdin.  If outname is NULL or
 | 
|---|
 | 541 |    an empty string, write to stdout.  strm is a pre-initialized inflateBack
 | 
|---|
 | 542 |    structure.  When appropriate, copy the file attributes from inname to
 | 
|---|
 | 543 |    outname.
 | 
|---|
 | 544 | 
 | 
|---|
 | 545 |    gunzip() returns 1 if there is an out-of-memory error or an unexpected
 | 
|---|
 | 546 |    return code from gunpipe().  Otherwise it returns 0.
 | 
|---|
 | 547 |  */
 | 
|---|
 | 548 | local int gunzip(z_stream *strm, char *inname, char *outname, int test)
 | 
|---|
 | 549 | {
 | 
|---|
 | 550 |     int ret;
 | 
|---|
 | 551 |     int infile, outfile;
 | 
|---|
 | 552 | 
 | 
|---|
 | 553 |     /* open files */
 | 
|---|
 | 554 |     if (inname == NULL || *inname == 0) {
 | 
|---|
 | 555 |         inname = "-";
 | 
|---|
 | 556 |         infile = 0;     /* stdin */
 | 
|---|
 | 557 |     }
 | 
|---|
 | 558 |     else {
 | 
|---|
 | 559 |         infile = open(inname, O_RDONLY, 0);
 | 
|---|
 | 560 |         if (infile == -1) {
 | 
|---|
 | 561 |             fprintf(stderr, "gun cannot open %s\n", inname);
 | 
|---|
 | 562 |             return 0;
 | 
|---|
 | 563 |         }
 | 
|---|
 | 564 |     }
 | 
|---|
 | 565 |     if (test)
 | 
|---|
 | 566 |         outfile = -1;
 | 
|---|
 | 567 |     else if (outname == NULL || *outname == 0) {
 | 
|---|
 | 568 |         outname = "-";
 | 
|---|
 | 569 |         outfile = 1;    /* stdout */
 | 
|---|
 | 570 |     }
 | 
|---|
 | 571 |     else {
 | 
|---|
 | 572 |         outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
 | 
|---|
 | 573 |         if (outfile == -1) {
 | 
|---|
 | 574 |             close(infile);
 | 
|---|
 | 575 |             fprintf(stderr, "gun cannot create %s\n", outname);
 | 
|---|
 | 576 |             return 0;
 | 
|---|
 | 577 |         }
 | 
|---|
 | 578 |     }
 | 
|---|
 | 579 |     errno = 0;
 | 
|---|
 | 580 | 
 | 
|---|
 | 581 |     /* decompress */
 | 
|---|
 | 582 |     ret = gunpipe(strm, infile, outfile);
 | 
|---|
 | 583 |     if (outfile > 2) close(outfile);
 | 
|---|
 | 584 |     if (infile > 2) close(infile);
 | 
|---|
 | 585 | 
 | 
|---|
 | 586 |     /* interpret result */
 | 
|---|
 | 587 |     switch (ret) {
 | 
|---|
 | 588 |     case Z_OK:
 | 
|---|
 | 589 |     case Z_ERRNO:
 | 
|---|
 | 590 |         if (infile > 2 && outfile > 2) {
 | 
|---|
 | 591 |             copymeta(inname, outname);          /* copy attributes */
 | 
|---|
 | 592 |             unlink(inname);
 | 
|---|
 | 593 |         }
 | 
|---|
 | 594 |         if (ret == Z_ERRNO)
 | 
|---|
 | 595 |             fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
 | 
|---|
 | 596 |                     inname);
 | 
|---|
 | 597 |         break;
 | 
|---|
 | 598 |     case Z_DATA_ERROR:
 | 
|---|
 | 599 |         if (outfile > 2) unlink(outname);
 | 
|---|
 | 600 |         fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
 | 
|---|
 | 601 |         break;
 | 
|---|
 | 602 |     case Z_MEM_ERROR:
 | 
|---|
 | 603 |         if (outfile > 2) unlink(outname);
 | 
|---|
 | 604 |         fprintf(stderr, "gun out of memory error--aborting\n");
 | 
|---|
 | 605 |         return 1;
 | 
|---|
 | 606 |     case Z_BUF_ERROR:
 | 
|---|
 | 607 |         if (outfile > 2) unlink(outname);
 | 
|---|
 | 608 |         if (strm->next_in != Z_NULL) {
 | 
|---|
 | 609 |             fprintf(stderr, "gun write error on %s: %s\n",
 | 
|---|
 | 610 |                     outname, strerror(errno));
 | 
|---|
 | 611 |         }
 | 
|---|
 | 612 |         else if (errno) {
 | 
|---|
 | 613 |             fprintf(stderr, "gun read error on %s: %s\n",
 | 
|---|
 | 614 |                     inname, strerror(errno));
 | 
|---|
 | 615 |         }
 | 
|---|
 | 616 |         else {
 | 
|---|
 | 617 |             fprintf(stderr, "gun unexpected end of file on %s\n",
 | 
|---|
 | 618 |                     inname);
 | 
|---|
 | 619 |         }
 | 
|---|
 | 620 |         break;
 | 
|---|
 | 621 |     default:
 | 
|---|
 | 622 |         if (outfile > 2) unlink(outname);
 | 
|---|
 | 623 |         fprintf(stderr, "gun internal error--aborting\n");
 | 
|---|
 | 624 |         return 1;
 | 
|---|
 | 625 |     }
 | 
|---|
 | 626 |     return 0;
 | 
|---|
 | 627 | }
 | 
|---|
 | 628 | 
 | 
|---|
 | 629 | /* Process the gun command line arguments.  See the command syntax near the
 | 
|---|
 | 630 |    beginning of this source file. */
 | 
|---|
 | 631 | int main(int argc, char **argv)
 | 
|---|
 | 632 | {
 | 
|---|
 | 633 |     int ret, len, test;
 | 
|---|
 | 634 |     char *outname;
 | 
|---|
 | 635 |     unsigned char *window;
 | 
|---|
 | 636 |     z_stream strm;
 | 
|---|
 | 637 | 
 | 
|---|
 | 638 |     /* initialize inflateBack state for repeated use */
 | 
|---|
 | 639 |     window = match;                         /* reuse LZW match buffer */
 | 
|---|
 | 640 |     strm.zalloc = Z_NULL;
 | 
|---|
 | 641 |     strm.zfree = Z_NULL;
 | 
|---|
 | 642 |     strm.opaque = Z_NULL;
 | 
|---|
 | 643 |     ret = inflateBackInit(&strm, 15, window);
 | 
|---|
 | 644 |     if (ret != Z_OK) {
 | 
|---|
 | 645 |         fprintf(stderr, "gun out of memory error--aborting\n");
 | 
|---|
 | 646 |         return 1;
 | 
|---|
 | 647 |     }
 | 
|---|
 | 648 | 
 | 
|---|
 | 649 |     /* decompress each file to the same name with the suffix removed */
 | 
|---|
 | 650 |     argc--;
 | 
|---|
 | 651 |     argv++;
 | 
|---|
 | 652 |     test = 0;
 | 
|---|
 | 653 |     if (argc && strcmp(*argv, "-h") == 0) {
 | 
|---|
 | 654 |         fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
 | 
|---|
 | 655 |         fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
 | 
|---|
 | 656 |         fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
 | 
|---|
 | 657 |         return 0;
 | 
|---|
 | 658 |     }
 | 
|---|
 | 659 |     if (argc && strcmp(*argv, "-t") == 0) {
 | 
|---|
 | 660 |         test = 1;
 | 
|---|
 | 661 |         argc--;
 | 
|---|
 | 662 |         argv++;
 | 
|---|
 | 663 |     }
 | 
|---|
 | 664 |     if (argc)
 | 
|---|
 | 665 |         do {
 | 
|---|
 | 666 |             if (test)
 | 
|---|
 | 667 |                 outname = NULL;
 | 
|---|
 | 668 |             else {
 | 
|---|
 | 669 |                 len = (int)strlen(*argv);
 | 
|---|
 | 670 |                 if (strcmp(*argv + len - 3, ".gz") == 0 ||
 | 
|---|
 | 671 |                     strcmp(*argv + len - 3, "-gz") == 0)
 | 
|---|
 | 672 |                     len -= 3;
 | 
|---|
 | 673 |                 else if (strcmp(*argv + len - 2, ".z") == 0 ||
 | 
|---|
 | 674 |                     strcmp(*argv + len - 2, "-z") == 0 ||
 | 
|---|
 | 675 |                     strcmp(*argv + len - 2, "_z") == 0 ||
 | 
|---|
 | 676 |                     strcmp(*argv + len - 2, ".Z") == 0)
 | 
|---|
 | 677 |                     len -= 2;
 | 
|---|
 | 678 |                 else {
 | 
|---|
 | 679 |                     fprintf(stderr, "gun error: no gz type on %s--skipping\n",
 | 
|---|
 | 680 |                             *argv);
 | 
|---|
 | 681 |                     continue;
 | 
|---|
 | 682 |                 }
 | 
|---|
 | 683 |                 outname = malloc(len + 1);
 | 
|---|
 | 684 |                 if (outname == NULL) {
 | 
|---|
 | 685 |                     fprintf(stderr, "gun out of memory error--aborting\n");
 | 
|---|
 | 686 |                     ret = 1;
 | 
|---|
 | 687 |                     break;
 | 
|---|
 | 688 |                 }
 | 
|---|
 | 689 |                 memcpy(outname, *argv, len);
 | 
|---|
 | 690 |                 outname[len] = 0;
 | 
|---|
 | 691 |             }
 | 
|---|
 | 692 |             ret = gunzip(&strm, *argv, outname, test);
 | 
|---|
 | 693 |             if (outname != NULL) free(outname);
 | 
|---|
 | 694 |             if (ret) break;
 | 
|---|
 | 695 |         } while (argv++, --argc);
 | 
|---|
 | 696 |     else
 | 
|---|
 | 697 |         ret = gunzip(&strm, NULL, NULL, test);
 | 
|---|
 | 698 | 
 | 
|---|
 | 699 |     /* clean up */
 | 
|---|
 | 700 |     inflateBackEnd(&strm);
 | 
|---|
 | 701 |     return ret;
 | 
|---|
 | 702 | }
 | 
|---|