xref: /netbsd-src/external/gpl3/gdb.old/dist/zlib/examples/gun.c (revision 699b0f9210494f137dd95d11c9bffdbb2f69ace2)
14e00368fSchristos /* gun.c -- simple gunzip to give an example of the use of inflateBack()
2ed8eb4c2Schristos  * Copyright (C) 2003, 2005, 2008, 2010, 2012 Mark Adler
34e00368fSchristos  * For conditions of distribution and use, see copyright notice in zlib.h
4ed8eb4c2Schristos    Version 1.7  12 August 2012  Mark Adler */
54e00368fSchristos 
64e00368fSchristos /* Version history:
74e00368fSchristos    1.0  16 Feb 2003  First version for testing of inflateBack()
84e00368fSchristos    1.1  21 Feb 2005  Decompress concatenated gzip streams
94e00368fSchristos                      Remove use of "this" variable (C++ keyword)
104e00368fSchristos                      Fix return value for in()
114e00368fSchristos                      Improve allocation failure checking
124e00368fSchristos                      Add typecasting for void * structures
134e00368fSchristos                      Add -h option for command version and usage
144e00368fSchristos                      Add a bunch of comments
154e00368fSchristos    1.2  20 Mar 2005  Add Unix compress (LZW) decompression
164e00368fSchristos                      Copy file attributes from input file to output file
174e00368fSchristos    1.3  12 Jun 2005  Add casts for error messages [Oberhumer]
184e00368fSchristos    1.4   8 Dec 2006  LZW decompression speed improvements
194e00368fSchristos    1.5   9 Feb 2008  Avoid warning in latest version of gcc
204e00368fSchristos    1.6  17 Jan 2010  Avoid signed/unsigned comparison warnings
21ed8eb4c2Schristos    1.7  12 Aug 2012  Update for z_const usage in zlib 1.2.8
224e00368fSchristos  */
234e00368fSchristos 
244e00368fSchristos /*
254e00368fSchristos    gun [ -t ] [ name ... ]
264e00368fSchristos 
274e00368fSchristos    decompresses the data in the named gzip files.  If no arguments are given,
284e00368fSchristos    gun will decompress from stdin to stdout.  The names must end in .gz, -gz,
294e00368fSchristos    .z, -z, _z, or .Z.  The uncompressed data will be written to a file name
304e00368fSchristos    with the suffix stripped.  On success, the original file is deleted.  On
314e00368fSchristos    failure, the output file is deleted.  For most failures, the command will
324e00368fSchristos    continue to process the remaining names on the command line.  A memory
334e00368fSchristos    allocation failure will abort the command.  If -t is specified, then the
344e00368fSchristos    listed files or stdin will be tested as gzip files for integrity (without
354e00368fSchristos    checking for a proper suffix), no output will be written, and no files
364e00368fSchristos    will be deleted.
374e00368fSchristos 
384e00368fSchristos    Like gzip, gun allows concatenated gzip streams and will decompress them,
394e00368fSchristos    writing all of the uncompressed data to the output.  Unlike gzip, gun allows
404e00368fSchristos    an empty file on input, and will produce no error writing an empty output
414e00368fSchristos    file.
424e00368fSchristos 
434e00368fSchristos    gun will also decompress files made by Unix compress, which uses LZW
444e00368fSchristos    compression.  These files are automatically detected by virtue of their
454e00368fSchristos    magic header bytes.  Since the end of Unix compress stream is marked by the
464e00368fSchristos    end-of-file, they cannot be concantenated.  If a Unix compress stream is
474e00368fSchristos    encountered in an input file, it is the last stream in that file.
484e00368fSchristos 
49*699b0f92Schristos    Like gunzip and uncompress, the file attributes of the original compressed
504e00368fSchristos    file are maintained in the final uncompressed file, to the extent that the
514e00368fSchristos    user permissions allow it.
524e00368fSchristos 
534e00368fSchristos    On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
544e00368fSchristos    1.2.4) is on the same file, when gun is linked with zlib 1.2.2.  Also the
554e00368fSchristos    LZW decompression provided by gun is about twice as fast as the standard
564e00368fSchristos    Unix uncompress command.
574e00368fSchristos  */
584e00368fSchristos 
594e00368fSchristos /* external functions and related types and constants */
604e00368fSchristos #include <stdio.h>          /* fprintf() */
614e00368fSchristos #include <stdlib.h>         /* malloc(), free() */
624e00368fSchristos #include <string.h>         /* strerror(), strcmp(), strlen(), memcpy() */
634e00368fSchristos #include <errno.h>          /* errno */
644e00368fSchristos #include <fcntl.h>          /* open() */
654e00368fSchristos #include <unistd.h>         /* read(), write(), close(), chown(), unlink() */
664e00368fSchristos #include <sys/types.h>
674e00368fSchristos #include <sys/stat.h>       /* stat(), chmod() */
684e00368fSchristos #include <utime.h>          /* utime() */
694e00368fSchristos #include "zlib.h"           /* inflateBackInit(), inflateBack(), */
704e00368fSchristos                             /* inflateBackEnd(), crc32() */
714e00368fSchristos 
724e00368fSchristos /* function declaration */
734e00368fSchristos #define local static
744e00368fSchristos 
754e00368fSchristos /* buffer constants */
764e00368fSchristos #define SIZE 32768U         /* input and output buffer sizes */
774e00368fSchristos #define PIECE 16384         /* limits i/o chunks for 16-bit int case */
784e00368fSchristos 
794e00368fSchristos /* structure for infback() to pass to input function in() -- it maintains the
804e00368fSchristos    input file and a buffer of size SIZE */
814e00368fSchristos struct ind {
824e00368fSchristos     int infile;
834e00368fSchristos     unsigned char *inbuf;
844e00368fSchristos };
854e00368fSchristos 
864e00368fSchristos /* Load input buffer, assumed to be empty, and return bytes loaded and a
874e00368fSchristos    pointer to them.  read() is called until the buffer is full, or until it
884e00368fSchristos    returns end-of-file or error.  Return 0 on error. */
in(void * in_desc,z_const unsigned char ** buf)89ed8eb4c2Schristos local unsigned in(void *in_desc, z_const unsigned char **buf)
904e00368fSchristos {
914e00368fSchristos     int ret;
924e00368fSchristos     unsigned len;
934e00368fSchristos     unsigned char *next;
944e00368fSchristos     struct ind *me = (struct ind *)in_desc;
954e00368fSchristos 
964e00368fSchristos     next = me->inbuf;
974e00368fSchristos     *buf = next;
984e00368fSchristos     len = 0;
994e00368fSchristos     do {
1004e00368fSchristos         ret = PIECE;
1014e00368fSchristos         if ((unsigned)ret > SIZE - len)
1024e00368fSchristos             ret = (int)(SIZE - len);
1034e00368fSchristos         ret = (int)read(me->infile, next, ret);
1044e00368fSchristos         if (ret == -1) {
1054e00368fSchristos             len = 0;
1064e00368fSchristos             break;
1074e00368fSchristos         }
1084e00368fSchristos         next += ret;
1094e00368fSchristos         len += ret;
1104e00368fSchristos     } while (ret != 0 && len < SIZE);
1114e00368fSchristos     return len;
1124e00368fSchristos }
1134e00368fSchristos 
1144e00368fSchristos /* structure for infback() to pass to output function out() -- it maintains the
1154e00368fSchristos    output file, a running CRC-32 check on the output and the total number of
1164e00368fSchristos    bytes output, both for checking against the gzip trailer.  (The length in
1174e00368fSchristos    the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
1184e00368fSchristos    the output is greater than 4 GB.) */
1194e00368fSchristos struct outd {
1204e00368fSchristos     int outfile;
1214e00368fSchristos     int check;                  /* true if checking crc and total */
1224e00368fSchristos     unsigned long crc;
1234e00368fSchristos     unsigned long total;
1244e00368fSchristos };
1254e00368fSchristos 
1264e00368fSchristos /* Write output buffer and update the CRC-32 and total bytes written.  write()
1274e00368fSchristos    is called until all of the output is written or an error is encountered.
1284e00368fSchristos    On success out() returns 0.  For a write failure, out() returns 1.  If the
1294e00368fSchristos    output file descriptor is -1, then nothing is written.
1304e00368fSchristos  */
out(void * out_desc,unsigned char * buf,unsigned len)1314e00368fSchristos local int out(void *out_desc, unsigned char *buf, unsigned len)
1324e00368fSchristos {
1334e00368fSchristos     int ret;
1344e00368fSchristos     struct outd *me = (struct outd *)out_desc;
1354e00368fSchristos 
1364e00368fSchristos     if (me->check) {
1374e00368fSchristos         me->crc = crc32(me->crc, buf, len);
1384e00368fSchristos         me->total += len;
1394e00368fSchristos     }
1404e00368fSchristos     if (me->outfile != -1)
1414e00368fSchristos         do {
1424e00368fSchristos             ret = PIECE;
1434e00368fSchristos             if ((unsigned)ret > len)
1444e00368fSchristos                 ret = (int)len;
1454e00368fSchristos             ret = (int)write(me->outfile, buf, ret);
1464e00368fSchristos             if (ret == -1)
1474e00368fSchristos                 return 1;
1484e00368fSchristos             buf += ret;
1494e00368fSchristos             len -= ret;
1504e00368fSchristos         } while (len != 0);
1514e00368fSchristos     return 0;
1524e00368fSchristos }
1534e00368fSchristos 
1544e00368fSchristos /* next input byte macro for use inside lunpipe() and gunpipe() */
1554e00368fSchristos #define NEXT() (have ? 0 : (have = in(indp, &next)), \
1564e00368fSchristos                 last = have ? (have--, (int)(*next++)) : -1)
1574e00368fSchristos 
1584e00368fSchristos /* memory for gunpipe() and lunpipe() --
1594e00368fSchristos    the first 256 entries of prefix[] and suffix[] are never used, could
1604e00368fSchristos    have offset the index, but it's faster to waste the memory */
1614e00368fSchristos unsigned char inbuf[SIZE];              /* input buffer */
1624e00368fSchristos unsigned char outbuf[SIZE];             /* output buffer */
1634e00368fSchristos unsigned short prefix[65536];           /* index to LZW prefix string */
1644e00368fSchristos unsigned char suffix[65536];            /* one-character LZW suffix */
1654e00368fSchristos unsigned char match[65280 + 2];         /* buffer for reversed match or gzip
1664e00368fSchristos                                            32K sliding window */
1674e00368fSchristos 
1684e00368fSchristos /* throw out what's left in the current bits byte buffer (this is a vestigial
1694e00368fSchristos    aspect of the compressed data format derived from an implementation that
1704e00368fSchristos    made use of a special VAX machine instruction!) */
1714e00368fSchristos #define FLUSHCODE() \
1724e00368fSchristos     do { \
1734e00368fSchristos         left = 0; \
1744e00368fSchristos         rem = 0; \
1754e00368fSchristos         if (chunk > have) { \
1764e00368fSchristos             chunk -= have; \
1774e00368fSchristos             have = 0; \
1784e00368fSchristos             if (NEXT() == -1) \
1794e00368fSchristos                 break; \
1804e00368fSchristos             chunk--; \
1814e00368fSchristos             if (chunk > have) { \
1824e00368fSchristos                 chunk = have = 0; \
1834e00368fSchristos                 break; \
1844e00368fSchristos             } \
1854e00368fSchristos         } \
1864e00368fSchristos         have -= chunk; \
1874e00368fSchristos         next += chunk; \
1884e00368fSchristos         chunk = 0; \
1894e00368fSchristos     } while (0)
1904e00368fSchristos 
1914e00368fSchristos /* Decompress a compress (LZW) file from indp to outfile.  The compress magic
1924e00368fSchristos    header (two bytes) has already been read and verified.  There are have bytes
1934e00368fSchristos    of buffered input at next.  strm is used for passing error information back
1944e00368fSchristos    to gunpipe().
1954e00368fSchristos 
1964e00368fSchristos    lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
1974e00368fSchristos    file, read error, or write error (a write error indicated by strm->next_in
1984e00368fSchristos    not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
1994e00368fSchristos  */
lunpipe(unsigned have,z_const unsigned char * next,struct ind * indp,int outfile,z_stream * strm)200ed8eb4c2Schristos local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp,
2014e00368fSchristos                   int outfile, z_stream *strm)
2024e00368fSchristos {
2034e00368fSchristos     int last;                   /* last byte read by NEXT(), or -1 if EOF */
2044e00368fSchristos     unsigned chunk;             /* bytes left in current chunk */
2054e00368fSchristos     int left;                   /* bits left in rem */
2064e00368fSchristos     unsigned rem;               /* unused bits from input */
2074e00368fSchristos     int bits;                   /* current bits per code */
2084e00368fSchristos     unsigned code;              /* code, table traversal index */
2094e00368fSchristos     unsigned mask;              /* mask for current bits codes */
2104e00368fSchristos     int max;                    /* maximum bits per code for this stream */
2114e00368fSchristos     unsigned flags;             /* compress flags, then block compress flag */
2124e00368fSchristos     unsigned end;               /* last valid entry in prefix/suffix tables */
2134e00368fSchristos     unsigned temp;              /* current code */
2144e00368fSchristos     unsigned prev;              /* previous code */
2154e00368fSchristos     unsigned final;             /* last character written for previous code */
2164e00368fSchristos     unsigned stack;             /* next position for reversed string */
2174e00368fSchristos     unsigned outcnt;            /* bytes in output buffer */
2184e00368fSchristos     struct outd outd;           /* output structure */
2194e00368fSchristos     unsigned char *p;
2204e00368fSchristos 
2214e00368fSchristos     /* set up output */
2224e00368fSchristos     outd.outfile = outfile;
2234e00368fSchristos     outd.check = 0;
2244e00368fSchristos 
2254e00368fSchristos     /* process remainder of compress header -- a flags byte */
2264e00368fSchristos     flags = NEXT();
2274e00368fSchristos     if (last == -1)
2284e00368fSchristos         return Z_BUF_ERROR;
2294e00368fSchristos     if (flags & 0x60) {
2304e00368fSchristos         strm->msg = (char *)"unknown lzw flags set";
2314e00368fSchristos         return Z_DATA_ERROR;
2324e00368fSchristos     }
2334e00368fSchristos     max = flags & 0x1f;
2344e00368fSchristos     if (max < 9 || max > 16) {
2354e00368fSchristos         strm->msg = (char *)"lzw bits out of range";
2364e00368fSchristos         return Z_DATA_ERROR;
2374e00368fSchristos     }
2384e00368fSchristos     if (max == 9)                           /* 9 doesn't really mean 9 */
2394e00368fSchristos         max = 10;
2404e00368fSchristos     flags &= 0x80;                          /* true if block compress */
2414e00368fSchristos 
2424e00368fSchristos     /* clear table */
2434e00368fSchristos     bits = 9;
2444e00368fSchristos     mask = 0x1ff;
2454e00368fSchristos     end = flags ? 256 : 255;
2464e00368fSchristos 
2474e00368fSchristos     /* set up: get first 9-bit code, which is the first decompressed byte, but
2484e00368fSchristos        don't create a table entry until the next code */
2494e00368fSchristos     if (NEXT() == -1)                       /* no compressed data is ok */
2504e00368fSchristos         return Z_OK;
2514e00368fSchristos     final = prev = (unsigned)last;          /* low 8 bits of code */
2524e00368fSchristos     if (NEXT() == -1)                       /* missing a bit */
2534e00368fSchristos         return Z_BUF_ERROR;
2544e00368fSchristos     if (last & 1) {                         /* code must be < 256 */
2554e00368fSchristos         strm->msg = (char *)"invalid lzw code";
2564e00368fSchristos         return Z_DATA_ERROR;
2574e00368fSchristos     }
2584e00368fSchristos     rem = (unsigned)last >> 1;              /* remaining 7 bits */
2594e00368fSchristos     left = 7;
2604e00368fSchristos     chunk = bits - 2;                       /* 7 bytes left in this chunk */
2614e00368fSchristos     outbuf[0] = (unsigned char)final;       /* write first decompressed byte */
2624e00368fSchristos     outcnt = 1;
2634e00368fSchristos 
2644e00368fSchristos     /* decode codes */
2654e00368fSchristos     stack = 0;
2664e00368fSchristos     for (;;) {
2674e00368fSchristos         /* if the table will be full after this, increment the code size */
2684e00368fSchristos         if (end >= mask && bits < max) {
2694e00368fSchristos             FLUSHCODE();
2704e00368fSchristos             bits++;
2714e00368fSchristos             mask <<= 1;
2724e00368fSchristos             mask++;
2734e00368fSchristos         }
2744e00368fSchristos 
2754e00368fSchristos         /* get a code of length bits */
2764e00368fSchristos         if (chunk == 0)                     /* decrement chunk modulo bits */
2774e00368fSchristos             chunk = bits;
2784e00368fSchristos         code = rem;                         /* low bits of code */
2794e00368fSchristos         if (NEXT() == -1) {                 /* EOF is end of compressed data */
2804e00368fSchristos             /* write remaining buffered output */
2814e00368fSchristos             if (outcnt && out(&outd, outbuf, outcnt)) {
2824e00368fSchristos                 strm->next_in = outbuf;     /* signal write error */
2834e00368fSchristos                 return Z_BUF_ERROR;
2844e00368fSchristos             }
2854e00368fSchristos             return Z_OK;
2864e00368fSchristos         }
2874e00368fSchristos         code += (unsigned)last << left;     /* middle (or high) bits of code */
2884e00368fSchristos         left += 8;
2894e00368fSchristos         chunk--;
2904e00368fSchristos         if (bits > left) {                  /* need more bits */
2914e00368fSchristos             if (NEXT() == -1)               /* can't end in middle of code */
2924e00368fSchristos                 return Z_BUF_ERROR;
2934e00368fSchristos             code += (unsigned)last << left; /* high bits of code */
2944e00368fSchristos             left += 8;
2954e00368fSchristos             chunk--;
2964e00368fSchristos         }
2974e00368fSchristos         code &= mask;                       /* mask to current code length */
2984e00368fSchristos         left -= bits;                       /* number of unused bits */
2994e00368fSchristos         rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
3004e00368fSchristos 
3014e00368fSchristos         /* process clear code (256) */
3024e00368fSchristos         if (code == 256 && flags) {
3034e00368fSchristos             FLUSHCODE();
3044e00368fSchristos             bits = 9;                       /* initialize bits and mask */
3054e00368fSchristos             mask = 0x1ff;
3064e00368fSchristos             end = 255;                      /* empty table */
3074e00368fSchristos             continue;                       /* get next code */
3084e00368fSchristos         }
3094e00368fSchristos 
3104e00368fSchristos         /* special code to reuse last match */
3114e00368fSchristos         temp = code;                        /* save the current code */
3124e00368fSchristos         if (code > end) {
3134e00368fSchristos             /* Be picky on the allowed code here, and make sure that the code
3144e00368fSchristos                we drop through (prev) will be a valid index so that random
3154e00368fSchristos                input does not cause an exception.  The code != end + 1 check is
3164e00368fSchristos                empirically derived, and not checked in the original uncompress
3174e00368fSchristos                code.  If this ever causes a problem, that check could be safely
3184e00368fSchristos                removed.  Leaving this check in greatly improves gun's ability
3194e00368fSchristos                to detect random or corrupted input after a compress header.
3204e00368fSchristos                In any case, the prev > end check must be retained. */
3214e00368fSchristos             if (code != end + 1 || prev > end) {
3224e00368fSchristos                 strm->msg = (char *)"invalid lzw code";
3234e00368fSchristos                 return Z_DATA_ERROR;
3244e00368fSchristos             }
3254e00368fSchristos             match[stack++] = (unsigned char)final;
3264e00368fSchristos             code = prev;
3274e00368fSchristos         }
3284e00368fSchristos 
3294e00368fSchristos         /* walk through linked list to generate output in reverse order */
3304e00368fSchristos         p = match + stack;
3314e00368fSchristos         while (code >= 256) {
3324e00368fSchristos             *p++ = suffix[code];
3334e00368fSchristos             code = prefix[code];
3344e00368fSchristos         }
3354e00368fSchristos         stack = p - match;
3364e00368fSchristos         match[stack++] = (unsigned char)code;
3374e00368fSchristos         final = code;
3384e00368fSchristos 
3394e00368fSchristos         /* link new table entry */
3404e00368fSchristos         if (end < mask) {
3414e00368fSchristos             end++;
3424e00368fSchristos             prefix[end] = (unsigned short)prev;
3434e00368fSchristos             suffix[end] = (unsigned char)final;
3444e00368fSchristos         }
3454e00368fSchristos 
3464e00368fSchristos         /* set previous code for next iteration */
3474e00368fSchristos         prev = temp;
3484e00368fSchristos 
3494e00368fSchristos         /* write output in forward order */
3504e00368fSchristos         while (stack > SIZE - outcnt) {
3514e00368fSchristos             while (outcnt < SIZE)
3524e00368fSchristos                 outbuf[outcnt++] = match[--stack];
3534e00368fSchristos             if (out(&outd, outbuf, outcnt)) {
3544e00368fSchristos                 strm->next_in = outbuf; /* signal write error */
3554e00368fSchristos                 return Z_BUF_ERROR;
3564e00368fSchristos             }
3574e00368fSchristos             outcnt = 0;
3584e00368fSchristos         }
3594e00368fSchristos         p = match + stack;
3604e00368fSchristos         do {
3614e00368fSchristos             outbuf[outcnt++] = *--p;
3624e00368fSchristos         } while (p > match);
3634e00368fSchristos         stack = 0;
3644e00368fSchristos 
3654e00368fSchristos         /* loop for next code with final and prev as the last match, rem and
3664e00368fSchristos            left provide the first 0..7 bits of the next code, end is the last
3674e00368fSchristos            valid table entry */
3684e00368fSchristos     }
3694e00368fSchristos }
3704e00368fSchristos 
3714e00368fSchristos /* Decompress a gzip file from infile to outfile.  strm is assumed to have been
3724e00368fSchristos    successfully initialized with inflateBackInit().  The input file may consist
3734e00368fSchristos    of a series of gzip streams, in which case all of them will be decompressed
3744e00368fSchristos    to the output file.  If outfile is -1, then the gzip stream(s) integrity is
3754e00368fSchristos    checked and nothing is written.
3764e00368fSchristos 
3774e00368fSchristos    The return value is a zlib error code: Z_MEM_ERROR if out of memory,
3784e00368fSchristos    Z_DATA_ERROR if the header or the compressed data is invalid, or if the
3794e00368fSchristos    trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
3804e00368fSchristos    prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
3814e00368fSchristos    stream) follows a valid gzip stream.
3824e00368fSchristos  */
gunpipe(z_stream * strm,int infile,int outfile)3834e00368fSchristos local int gunpipe(z_stream *strm, int infile, int outfile)
3844e00368fSchristos {
3854e00368fSchristos     int ret, first, last;
3864e00368fSchristos     unsigned have, flags, len;
387ed8eb4c2Schristos     z_const unsigned char *next = NULL;
3884e00368fSchristos     struct ind ind, *indp;
3894e00368fSchristos     struct outd outd;
3904e00368fSchristos 
3914e00368fSchristos     /* setup input buffer */
3924e00368fSchristos     ind.infile = infile;
3934e00368fSchristos     ind.inbuf = inbuf;
3944e00368fSchristos     indp = &ind;
3954e00368fSchristos 
3964e00368fSchristos     /* decompress concatenated gzip streams */
3974e00368fSchristos     have = 0;                               /* no input data read in yet */
3984e00368fSchristos     first = 1;                              /* looking for first gzip header */
3994e00368fSchristos     strm->next_in = Z_NULL;                 /* so Z_BUF_ERROR means EOF */
4004e00368fSchristos     for (;;) {
4014e00368fSchristos         /* look for the two magic header bytes for a gzip stream */
4024e00368fSchristos         if (NEXT() == -1) {
4034e00368fSchristos             ret = Z_OK;
4044e00368fSchristos             break;                          /* empty gzip stream is ok */
4054e00368fSchristos         }
4064e00368fSchristos         if (last != 31 || (NEXT() != 139 && last != 157)) {
4074e00368fSchristos             strm->msg = (char *)"incorrect header check";
4084e00368fSchristos             ret = first ? Z_DATA_ERROR : Z_ERRNO;
4094e00368fSchristos             break;                          /* not a gzip or compress header */
4104e00368fSchristos         }
4114e00368fSchristos         first = 0;                          /* next non-header is junk */
4124e00368fSchristos 
4134e00368fSchristos         /* process a compress (LZW) file -- can't be concatenated after this */
4144e00368fSchristos         if (last == 157) {
4154e00368fSchristos             ret = lunpipe(have, next, indp, outfile, strm);
4164e00368fSchristos             break;
4174e00368fSchristos         }
4184e00368fSchristos 
4194e00368fSchristos         /* process remainder of gzip header */
4204e00368fSchristos         ret = Z_BUF_ERROR;
4214e00368fSchristos         if (NEXT() != 8) {                  /* only deflate method allowed */
4224e00368fSchristos             if (last == -1) break;
4234e00368fSchristos             strm->msg = (char *)"unknown compression method";
4244e00368fSchristos             ret = Z_DATA_ERROR;
4254e00368fSchristos             break;
4264e00368fSchristos         }
4274e00368fSchristos         flags = NEXT();                     /* header flags */
4284e00368fSchristos         NEXT();                             /* discard mod time, xflgs, os */
4294e00368fSchristos         NEXT();
4304e00368fSchristos         NEXT();
4314e00368fSchristos         NEXT();
4324e00368fSchristos         NEXT();
4334e00368fSchristos         NEXT();
4344e00368fSchristos         if (last == -1) break;
4354e00368fSchristos         if (flags & 0xe0) {
4364e00368fSchristos             strm->msg = (char *)"unknown header flags set";
4374e00368fSchristos             ret = Z_DATA_ERROR;
4384e00368fSchristos             break;
4394e00368fSchristos         }
4404e00368fSchristos         if (flags & 4) {                    /* extra field */
4414e00368fSchristos             len = NEXT();
4424e00368fSchristos             len += (unsigned)(NEXT()) << 8;
4434e00368fSchristos             if (last == -1) break;
4444e00368fSchristos             while (len > have) {
4454e00368fSchristos                 len -= have;
4464e00368fSchristos                 have = 0;
4474e00368fSchristos                 if (NEXT() == -1) break;
4484e00368fSchristos                 len--;
4494e00368fSchristos             }
4504e00368fSchristos             if (last == -1) break;
4514e00368fSchristos             have -= len;
4524e00368fSchristos             next += len;
4534e00368fSchristos         }
4544e00368fSchristos         if (flags & 8)                      /* file name */
4554e00368fSchristos             while (NEXT() != 0 && last != -1)
4564e00368fSchristos                 ;
4574e00368fSchristos         if (flags & 16)                     /* comment */
4584e00368fSchristos             while (NEXT() != 0 && last != -1)
4594e00368fSchristos                 ;
4604e00368fSchristos         if (flags & 2) {                    /* header crc */
4614e00368fSchristos             NEXT();
4624e00368fSchristos             NEXT();
4634e00368fSchristos         }
4644e00368fSchristos         if (last == -1) break;
4654e00368fSchristos 
4664e00368fSchristos         /* set up output */
4674e00368fSchristos         outd.outfile = outfile;
4684e00368fSchristos         outd.check = 1;
4694e00368fSchristos         outd.crc = crc32(0L, Z_NULL, 0);
4704e00368fSchristos         outd.total = 0;
4714e00368fSchristos 
4724e00368fSchristos         /* decompress data to output */
4734e00368fSchristos         strm->next_in = next;
4744e00368fSchristos         strm->avail_in = have;
4754e00368fSchristos         ret = inflateBack(strm, in, indp, out, &outd);
4764e00368fSchristos         if (ret != Z_STREAM_END) break;
4774e00368fSchristos         next = strm->next_in;
4784e00368fSchristos         have = strm->avail_in;
4794e00368fSchristos         strm->next_in = Z_NULL;             /* so Z_BUF_ERROR means EOF */
4804e00368fSchristos 
4814e00368fSchristos         /* check trailer */
4824e00368fSchristos         ret = Z_BUF_ERROR;
4834e00368fSchristos         if (NEXT() != (int)(outd.crc & 0xff) ||
4844e00368fSchristos             NEXT() != (int)((outd.crc >> 8) & 0xff) ||
4854e00368fSchristos             NEXT() != (int)((outd.crc >> 16) & 0xff) ||
4864e00368fSchristos             NEXT() != (int)((outd.crc >> 24) & 0xff)) {
4874e00368fSchristos             /* crc error */
4884e00368fSchristos             if (last != -1) {
4894e00368fSchristos                 strm->msg = (char *)"incorrect data check";
4904e00368fSchristos                 ret = Z_DATA_ERROR;
4914e00368fSchristos             }
4924e00368fSchristos             break;
4934e00368fSchristos         }
4944e00368fSchristos         if (NEXT() != (int)(outd.total & 0xff) ||
4954e00368fSchristos             NEXT() != (int)((outd.total >> 8) & 0xff) ||
4964e00368fSchristos             NEXT() != (int)((outd.total >> 16) & 0xff) ||
4974e00368fSchristos             NEXT() != (int)((outd.total >> 24) & 0xff)) {
4984e00368fSchristos             /* length error */
4994e00368fSchristos             if (last != -1) {
5004e00368fSchristos                 strm->msg = (char *)"incorrect length check";
5014e00368fSchristos                 ret = Z_DATA_ERROR;
5024e00368fSchristos             }
5034e00368fSchristos             break;
5044e00368fSchristos         }
5054e00368fSchristos 
5064e00368fSchristos         /* go back and look for another gzip stream */
5074e00368fSchristos     }
5084e00368fSchristos 
5094e00368fSchristos     /* clean up and return */
5104e00368fSchristos     return ret;
5114e00368fSchristos }
5124e00368fSchristos 
5134e00368fSchristos /* Copy file attributes, from -> to, as best we can.  This is best effort, so
5144e00368fSchristos    no errors are reported.  The mode bits, including suid, sgid, and the sticky
5154e00368fSchristos    bit are copied (if allowed), the owner's user id and group id are copied
5164e00368fSchristos    (again if allowed), and the access and modify times are copied. */
copymeta(char * from,char * to)5174e00368fSchristos local void copymeta(char *from, char *to)
5184e00368fSchristos {
5194e00368fSchristos     struct stat was;
5204e00368fSchristos     struct utimbuf when;
5214e00368fSchristos 
5224e00368fSchristos     /* get all of from's Unix meta data, return if not a regular file */
5234e00368fSchristos     if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
5244e00368fSchristos         return;
5254e00368fSchristos 
5264e00368fSchristos     /* set to's mode bits, ignore errors */
5274e00368fSchristos     (void)chmod(to, was.st_mode & 07777);
5284e00368fSchristos 
5294e00368fSchristos     /* copy owner's user and group, ignore errors */
5304e00368fSchristos     (void)chown(to, was.st_uid, was.st_gid);
5314e00368fSchristos 
5324e00368fSchristos     /* copy access and modify times, ignore errors */
5334e00368fSchristos     when.actime = was.st_atime;
5344e00368fSchristos     when.modtime = was.st_mtime;
5354e00368fSchristos     (void)utime(to, &when);
5364e00368fSchristos }
5374e00368fSchristos 
5384e00368fSchristos /* Decompress the file inname to the file outnname, of if test is true, just
5394e00368fSchristos    decompress without writing and check the gzip trailer for integrity.  If
5404e00368fSchristos    inname is NULL or an empty string, read from stdin.  If outname is NULL or
5414e00368fSchristos    an empty string, write to stdout.  strm is a pre-initialized inflateBack
5424e00368fSchristos    structure.  When appropriate, copy the file attributes from inname to
5434e00368fSchristos    outname.
5444e00368fSchristos 
5454e00368fSchristos    gunzip() returns 1 if there is an out-of-memory error or an unexpected
5464e00368fSchristos    return code from gunpipe().  Otherwise it returns 0.
5474e00368fSchristos  */
gunzip(z_stream * strm,char * inname,char * outname,int test)5484e00368fSchristos local int gunzip(z_stream *strm, char *inname, char *outname, int test)
5494e00368fSchristos {
5504e00368fSchristos     int ret;
5514e00368fSchristos     int infile, outfile;
5524e00368fSchristos 
5534e00368fSchristos     /* open files */
5544e00368fSchristos     if (inname == NULL || *inname == 0) {
5554e00368fSchristos         inname = "-";
5564e00368fSchristos         infile = 0;     /* stdin */
5574e00368fSchristos     }
5584e00368fSchristos     else {
5594e00368fSchristos         infile = open(inname, O_RDONLY, 0);
5604e00368fSchristos         if (infile == -1) {
5614e00368fSchristos             fprintf(stderr, "gun cannot open %s\n", inname);
5624e00368fSchristos             return 0;
5634e00368fSchristos         }
5644e00368fSchristos     }
5654e00368fSchristos     if (test)
5664e00368fSchristos         outfile = -1;
5674e00368fSchristos     else if (outname == NULL || *outname == 0) {
5684e00368fSchristos         outname = "-";
5694e00368fSchristos         outfile = 1;    /* stdout */
5704e00368fSchristos     }
5714e00368fSchristos     else {
5724e00368fSchristos         outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
5734e00368fSchristos         if (outfile == -1) {
5744e00368fSchristos             close(infile);
5754e00368fSchristos             fprintf(stderr, "gun cannot create %s\n", outname);
5764e00368fSchristos             return 0;
5774e00368fSchristos         }
5784e00368fSchristos     }
5794e00368fSchristos     errno = 0;
5804e00368fSchristos 
5814e00368fSchristos     /* decompress */
5824e00368fSchristos     ret = gunpipe(strm, infile, outfile);
5834e00368fSchristos     if (outfile > 2) close(outfile);
5844e00368fSchristos     if (infile > 2) close(infile);
5854e00368fSchristos 
5864e00368fSchristos     /* interpret result */
5874e00368fSchristos     switch (ret) {
5884e00368fSchristos     case Z_OK:
5894e00368fSchristos     case Z_ERRNO:
5904e00368fSchristos         if (infile > 2 && outfile > 2) {
5914e00368fSchristos             copymeta(inname, outname);          /* copy attributes */
5924e00368fSchristos             unlink(inname);
5934e00368fSchristos         }
5944e00368fSchristos         if (ret == Z_ERRNO)
5954e00368fSchristos             fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
5964e00368fSchristos                     inname);
5974e00368fSchristos         break;
5984e00368fSchristos     case Z_DATA_ERROR:
5994e00368fSchristos         if (outfile > 2) unlink(outname);
6004e00368fSchristos         fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
6014e00368fSchristos         break;
6024e00368fSchristos     case Z_MEM_ERROR:
6034e00368fSchristos         if (outfile > 2) unlink(outname);
6044e00368fSchristos         fprintf(stderr, "gun out of memory error--aborting\n");
6054e00368fSchristos         return 1;
6064e00368fSchristos     case Z_BUF_ERROR:
6074e00368fSchristos         if (outfile > 2) unlink(outname);
6084e00368fSchristos         if (strm->next_in != Z_NULL) {
6094e00368fSchristos             fprintf(stderr, "gun write error on %s: %s\n",
6104e00368fSchristos                     outname, strerror(errno));
6114e00368fSchristos         }
6124e00368fSchristos         else if (errno) {
6134e00368fSchristos             fprintf(stderr, "gun read error on %s: %s\n",
6144e00368fSchristos                     inname, strerror(errno));
6154e00368fSchristos         }
6164e00368fSchristos         else {
6174e00368fSchristos             fprintf(stderr, "gun unexpected end of file on %s\n",
6184e00368fSchristos                     inname);
6194e00368fSchristos         }
6204e00368fSchristos         break;
6214e00368fSchristos     default:
6224e00368fSchristos         if (outfile > 2) unlink(outname);
6234e00368fSchristos         fprintf(stderr, "gun internal error--aborting\n");
6244e00368fSchristos         return 1;
6254e00368fSchristos     }
6264e00368fSchristos     return 0;
6274e00368fSchristos }
6284e00368fSchristos 
6294e00368fSchristos /* Process the gun command line arguments.  See the command syntax near the
6304e00368fSchristos    beginning of this source file. */
main(int argc,char ** argv)6314e00368fSchristos int main(int argc, char **argv)
6324e00368fSchristos {
6334e00368fSchristos     int ret, len, test;
6344e00368fSchristos     char *outname;
6354e00368fSchristos     unsigned char *window;
6364e00368fSchristos     z_stream strm;
6374e00368fSchristos 
6384e00368fSchristos     /* initialize inflateBack state for repeated use */
6394e00368fSchristos     window = match;                         /* reuse LZW match buffer */
6404e00368fSchristos     strm.zalloc = Z_NULL;
6414e00368fSchristos     strm.zfree = Z_NULL;
6424e00368fSchristos     strm.opaque = Z_NULL;
6434e00368fSchristos     ret = inflateBackInit(&strm, 15, window);
6444e00368fSchristos     if (ret != Z_OK) {
6454e00368fSchristos         fprintf(stderr, "gun out of memory error--aborting\n");
6464e00368fSchristos         return 1;
6474e00368fSchristos     }
6484e00368fSchristos 
6494e00368fSchristos     /* decompress each file to the same name with the suffix removed */
6504e00368fSchristos     argc--;
6514e00368fSchristos     argv++;
6524e00368fSchristos     test = 0;
6534e00368fSchristos     if (argc && strcmp(*argv, "-h") == 0) {
6544e00368fSchristos         fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
6554e00368fSchristos         fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
6564e00368fSchristos         fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
6574e00368fSchristos         return 0;
6584e00368fSchristos     }
6594e00368fSchristos     if (argc && strcmp(*argv, "-t") == 0) {
6604e00368fSchristos         test = 1;
6614e00368fSchristos         argc--;
6624e00368fSchristos         argv++;
6634e00368fSchristos     }
6644e00368fSchristos     if (argc)
6654e00368fSchristos         do {
6664e00368fSchristos             if (test)
6674e00368fSchristos                 outname = NULL;
6684e00368fSchristos             else {
6694e00368fSchristos                 len = (int)strlen(*argv);
6704e00368fSchristos                 if (strcmp(*argv + len - 3, ".gz") == 0 ||
6714e00368fSchristos                     strcmp(*argv + len - 3, "-gz") == 0)
6724e00368fSchristos                     len -= 3;
6734e00368fSchristos                 else if (strcmp(*argv + len - 2, ".z") == 0 ||
6744e00368fSchristos                     strcmp(*argv + len - 2, "-z") == 0 ||
6754e00368fSchristos                     strcmp(*argv + len - 2, "_z") == 0 ||
6764e00368fSchristos                     strcmp(*argv + len - 2, ".Z") == 0)
6774e00368fSchristos                     len -= 2;
6784e00368fSchristos                 else {
6794e00368fSchristos                     fprintf(stderr, "gun error: no gz type on %s--skipping\n",
6804e00368fSchristos                             *argv);
6814e00368fSchristos                     continue;
6824e00368fSchristos                 }
6834e00368fSchristos                 outname = malloc(len + 1);
6844e00368fSchristos                 if (outname == NULL) {
6854e00368fSchristos                     fprintf(stderr, "gun out of memory error--aborting\n");
6864e00368fSchristos                     ret = 1;
6874e00368fSchristos                     break;
6884e00368fSchristos                 }
6894e00368fSchristos                 memcpy(outname, *argv, len);
6904e00368fSchristos                 outname[len] = 0;
6914e00368fSchristos             }
6924e00368fSchristos             ret = gunzip(&strm, *argv, outname, test);
6934e00368fSchristos             if (outname != NULL) free(outname);
6944e00368fSchristos             if (ret) break;
6954e00368fSchristos         } while (argv++, --argc);
6964e00368fSchristos     else
6974e00368fSchristos         ret = gunzip(&strm, NULL, NULL, test);
6984e00368fSchristos 
6994e00368fSchristos     /* clean up */
7004e00368fSchristos     inflateBackEnd(&strm);
7014e00368fSchristos     return ret;
7024e00368fSchristos }
703