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