xref: /netbsd-src/external/gpl3/binutils.old/dist/zlib/examples/gun.c (revision ede781334f5dc56e6b74c3945d364b5b98850996)
116dce513Schristos /* gun.c -- simple gunzip to give an example of the use of inflateBack()
216dce513Schristos  * Copyright (C) 2003, 2005, 2008, 2010, 2012 Mark Adler
316dce513Schristos  * For conditions of distribution and use, see copyright notice in zlib.h
416dce513Schristos    Version 1.7  12 August 2012  Mark Adler */
516dce513Schristos 
616dce513Schristos /* Version history:
716dce513Schristos    1.0  16 Feb 2003  First version for testing of inflateBack()
816dce513Schristos    1.1  21 Feb 2005  Decompress concatenated gzip streams
916dce513Schristos                      Remove use of "this" variable (C++ keyword)
1016dce513Schristos                      Fix return value for in()
1116dce513Schristos                      Improve allocation failure checking
1216dce513Schristos                      Add typecasting for void * structures
1316dce513Schristos                      Add -h option for command version and usage
1416dce513Schristos                      Add a bunch of comments
1516dce513Schristos    1.2  20 Mar 2005  Add Unix compress (LZW) decompression
1616dce513Schristos                      Copy file attributes from input file to output file
1716dce513Schristos    1.3  12 Jun 2005  Add casts for error messages [Oberhumer]
1816dce513Schristos    1.4   8 Dec 2006  LZW decompression speed improvements
1916dce513Schristos    1.5   9 Feb 2008  Avoid warning in latest version of gcc
2016dce513Schristos    1.6  17 Jan 2010  Avoid signed/unsigned comparison warnings
2116dce513Schristos    1.7  12 Aug 2012  Update for z_const usage in zlib 1.2.8
2216dce513Schristos  */
2316dce513Schristos 
2416dce513Schristos /*
2516dce513Schristos    gun [ -t ] [ name ... ]
2616dce513Schristos 
2716dce513Schristos    decompresses the data in the named gzip files.  If no arguments are given,
2816dce513Schristos    gun will decompress from stdin to stdout.  The names must end in .gz, -gz,
2916dce513Schristos    .z, -z, _z, or .Z.  The uncompressed data will be written to a file name
3016dce513Schristos    with the suffix stripped.  On success, the original file is deleted.  On
3116dce513Schristos    failure, the output file is deleted.  For most failures, the command will
3216dce513Schristos    continue to process the remaining names on the command line.  A memory
3316dce513Schristos    allocation failure will abort the command.  If -t is specified, then the
3416dce513Schristos    listed files or stdin will be tested as gzip files for integrity (without
3516dce513Schristos    checking for a proper suffix), no output will be written, and no files
3616dce513Schristos    will be deleted.
3716dce513Schristos 
3816dce513Schristos    Like gzip, gun allows concatenated gzip streams and will decompress them,
3916dce513Schristos    writing all of the uncompressed data to the output.  Unlike gzip, gun allows
4016dce513Schristos    an empty file on input, and will produce no error writing an empty output
4116dce513Schristos    file.
4216dce513Schristos 
4316dce513Schristos    gun will also decompress files made by Unix compress, which uses LZW
4416dce513Schristos    compression.  These files are automatically detected by virtue of their
4516dce513Schristos    magic header bytes.  Since the end of Unix compress stream is marked by the
4616dce513Schristos    end-of-file, they cannot be concantenated.  If a Unix compress stream is
4716dce513Schristos    encountered in an input file, it is the last stream in that file.
4816dce513Schristos 
49*ede78133Schristos    Like gunzip and uncompress, the file attributes of the original compressed
5016dce513Schristos    file are maintained in the final uncompressed file, to the extent that the
5116dce513Schristos    user permissions allow it.
5216dce513Schristos 
5316dce513Schristos    On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
5416dce513Schristos    1.2.4) is on the same file, when gun is linked with zlib 1.2.2.  Also the
5516dce513Schristos    LZW decompression provided by gun is about twice as fast as the standard
5616dce513Schristos    Unix uncompress command.
5716dce513Schristos  */
5816dce513Schristos 
5916dce513Schristos /* external functions and related types and constants */
6016dce513Schristos #include <stdio.h>          /* fprintf() */
6116dce513Schristos #include <stdlib.h>         /* malloc(), free() */
6216dce513Schristos #include <string.h>         /* strerror(), strcmp(), strlen(), memcpy() */
6316dce513Schristos #include <errno.h>          /* errno */
6416dce513Schristos #include <fcntl.h>          /* open() */
6516dce513Schristos #include <unistd.h>         /* read(), write(), close(), chown(), unlink() */
6616dce513Schristos #include <sys/types.h>
6716dce513Schristos #include <sys/stat.h>       /* stat(), chmod() */
6816dce513Schristos #include <utime.h>          /* utime() */
6916dce513Schristos #include "zlib.h"           /* inflateBackInit(), inflateBack(), */
7016dce513Schristos                             /* inflateBackEnd(), crc32() */
7116dce513Schristos 
7216dce513Schristos /* function declaration */
7316dce513Schristos #define local static
7416dce513Schristos 
7516dce513Schristos /* buffer constants */
7616dce513Schristos #define SIZE 32768U         /* input and output buffer sizes */
7716dce513Schristos #define PIECE 16384         /* limits i/o chunks for 16-bit int case */
7816dce513Schristos 
7916dce513Schristos /* structure for infback() to pass to input function in() -- it maintains the
8016dce513Schristos    input file and a buffer of size SIZE */
8116dce513Schristos struct ind {
8216dce513Schristos     int infile;
8316dce513Schristos     unsigned char *inbuf;
8416dce513Schristos };
8516dce513Schristos 
8616dce513Schristos /* Load input buffer, assumed to be empty, and return bytes loaded and a
8716dce513Schristos    pointer to them.  read() is called until the buffer is full, or until it
8816dce513Schristos    returns end-of-file or error.  Return 0 on error. */
in(void * in_desc,z_const unsigned char ** buf)8916dce513Schristos local unsigned in(void *in_desc, z_const unsigned char **buf)
9016dce513Schristos {
9116dce513Schristos     int ret;
9216dce513Schristos     unsigned len;
9316dce513Schristos     unsigned char *next;
9416dce513Schristos     struct ind *me = (struct ind *)in_desc;
9516dce513Schristos 
9616dce513Schristos     next = me->inbuf;
9716dce513Schristos     *buf = next;
9816dce513Schristos     len = 0;
9916dce513Schristos     do {
10016dce513Schristos         ret = PIECE;
10116dce513Schristos         if ((unsigned)ret > SIZE - len)
10216dce513Schristos             ret = (int)(SIZE - len);
10316dce513Schristos         ret = (int)read(me->infile, next, ret);
10416dce513Schristos         if (ret == -1) {
10516dce513Schristos             len = 0;
10616dce513Schristos             break;
10716dce513Schristos         }
10816dce513Schristos         next += ret;
10916dce513Schristos         len += ret;
11016dce513Schristos     } while (ret != 0 && len < SIZE);
11116dce513Schristos     return len;
11216dce513Schristos }
11316dce513Schristos 
11416dce513Schristos /* structure for infback() to pass to output function out() -- it maintains the
11516dce513Schristos    output file, a running CRC-32 check on the output and the total number of
11616dce513Schristos    bytes output, both for checking against the gzip trailer.  (The length in
11716dce513Schristos    the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
11816dce513Schristos    the output is greater than 4 GB.) */
11916dce513Schristos struct outd {
12016dce513Schristos     int outfile;
12116dce513Schristos     int check;                  /* true if checking crc and total */
12216dce513Schristos     unsigned long crc;
12316dce513Schristos     unsigned long total;
12416dce513Schristos };
12516dce513Schristos 
12616dce513Schristos /* Write output buffer and update the CRC-32 and total bytes written.  write()
12716dce513Schristos    is called until all of the output is written or an error is encountered.
12816dce513Schristos    On success out() returns 0.  For a write failure, out() returns 1.  If the
12916dce513Schristos    output file descriptor is -1, then nothing is written.
13016dce513Schristos  */
out(void * out_desc,unsigned char * buf,unsigned len)13116dce513Schristos local int out(void *out_desc, unsigned char *buf, unsigned len)
13216dce513Schristos {
13316dce513Schristos     int ret;
13416dce513Schristos     struct outd *me = (struct outd *)out_desc;
13516dce513Schristos 
13616dce513Schristos     if (me->check) {
13716dce513Schristos         me->crc = crc32(me->crc, buf, len);
13816dce513Schristos         me->total += len;
13916dce513Schristos     }
14016dce513Schristos     if (me->outfile != -1)
14116dce513Schristos         do {
14216dce513Schristos             ret = PIECE;
14316dce513Schristos             if ((unsigned)ret > len)
14416dce513Schristos                 ret = (int)len;
14516dce513Schristos             ret = (int)write(me->outfile, buf, ret);
14616dce513Schristos             if (ret == -1)
14716dce513Schristos                 return 1;
14816dce513Schristos             buf += ret;
14916dce513Schristos             len -= ret;
15016dce513Schristos         } while (len != 0);
15116dce513Schristos     return 0;
15216dce513Schristos }
15316dce513Schristos 
15416dce513Schristos /* next input byte macro for use inside lunpipe() and gunpipe() */
15516dce513Schristos #define NEXT() (have ? 0 : (have = in(indp, &next)), \
15616dce513Schristos                 last = have ? (have--, (int)(*next++)) : -1)
15716dce513Schristos 
15816dce513Schristos /* memory for gunpipe() and lunpipe() --
15916dce513Schristos    the first 256 entries of prefix[] and suffix[] are never used, could
16016dce513Schristos    have offset the index, but it's faster to waste the memory */
16116dce513Schristos unsigned char inbuf[SIZE];              /* input buffer */
16216dce513Schristos unsigned char outbuf[SIZE];             /* output buffer */
16316dce513Schristos unsigned short prefix[65536];           /* index to LZW prefix string */
16416dce513Schristos unsigned char suffix[65536];            /* one-character LZW suffix */
16516dce513Schristos unsigned char match[65280 + 2];         /* buffer for reversed match or gzip
16616dce513Schristos                                            32K sliding window */
16716dce513Schristos 
16816dce513Schristos /* throw out what's left in the current bits byte buffer (this is a vestigial
16916dce513Schristos    aspect of the compressed data format derived from an implementation that
17016dce513Schristos    made use of a special VAX machine instruction!) */
17116dce513Schristos #define FLUSHCODE() \
17216dce513Schristos     do { \
17316dce513Schristos         left = 0; \
17416dce513Schristos         rem = 0; \
17516dce513Schristos         if (chunk > have) { \
17616dce513Schristos             chunk -= have; \
17716dce513Schristos             have = 0; \
17816dce513Schristos             if (NEXT() == -1) \
17916dce513Schristos                 break; \
18016dce513Schristos             chunk--; \
18116dce513Schristos             if (chunk > have) { \
18216dce513Schristos                 chunk = have = 0; \
18316dce513Schristos                 break; \
18416dce513Schristos             } \
18516dce513Schristos         } \
18616dce513Schristos         have -= chunk; \
18716dce513Schristos         next += chunk; \
18816dce513Schristos         chunk = 0; \
18916dce513Schristos     } while (0)
19016dce513Schristos 
19116dce513Schristos /* Decompress a compress (LZW) file from indp to outfile.  The compress magic
19216dce513Schristos    header (two bytes) has already been read and verified.  There are have bytes
19316dce513Schristos    of buffered input at next.  strm is used for passing error information back
19416dce513Schristos    to gunpipe().
19516dce513Schristos 
19616dce513Schristos    lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
19716dce513Schristos    file, read error, or write error (a write error indicated by strm->next_in
19816dce513Schristos    not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
19916dce513Schristos  */
lunpipe(unsigned have,z_const unsigned char * next,struct ind * indp,int outfile,z_stream * strm)20016dce513Schristos local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp,
20116dce513Schristos                   int outfile, z_stream *strm)
20216dce513Schristos {
20316dce513Schristos     int last;                   /* last byte read by NEXT(), or -1 if EOF */
20416dce513Schristos     unsigned chunk;             /* bytes left in current chunk */
20516dce513Schristos     int left;                   /* bits left in rem */
20616dce513Schristos     unsigned rem;               /* unused bits from input */
20716dce513Schristos     int bits;                   /* current bits per code */
20816dce513Schristos     unsigned code;              /* code, table traversal index */
20916dce513Schristos     unsigned mask;              /* mask for current bits codes */
21016dce513Schristos     int max;                    /* maximum bits per code for this stream */
21116dce513Schristos     unsigned flags;             /* compress flags, then block compress flag */
21216dce513Schristos     unsigned end;               /* last valid entry in prefix/suffix tables */
21316dce513Schristos     unsigned temp;              /* current code */
21416dce513Schristos     unsigned prev;              /* previous code */
21516dce513Schristos     unsigned final;             /* last character written for previous code */
21616dce513Schristos     unsigned stack;             /* next position for reversed string */
21716dce513Schristos     unsigned outcnt;            /* bytes in output buffer */
21816dce513Schristos     struct outd outd;           /* output structure */
21916dce513Schristos     unsigned char *p;
22016dce513Schristos 
22116dce513Schristos     /* set up output */
22216dce513Schristos     outd.outfile = outfile;
22316dce513Schristos     outd.check = 0;
22416dce513Schristos 
22516dce513Schristos     /* process remainder of compress header -- a flags byte */
22616dce513Schristos     flags = NEXT();
22716dce513Schristos     if (last == -1)
22816dce513Schristos         return Z_BUF_ERROR;
22916dce513Schristos     if (flags & 0x60) {
23016dce513Schristos         strm->msg = (char *)"unknown lzw flags set";
23116dce513Schristos         return Z_DATA_ERROR;
23216dce513Schristos     }
23316dce513Schristos     max = flags & 0x1f;
23416dce513Schristos     if (max < 9 || max > 16) {
23516dce513Schristos         strm->msg = (char *)"lzw bits out of range";
23616dce513Schristos         return Z_DATA_ERROR;
23716dce513Schristos     }
23816dce513Schristos     if (max == 9)                           /* 9 doesn't really mean 9 */
23916dce513Schristos         max = 10;
24016dce513Schristos     flags &= 0x80;                          /* true if block compress */
24116dce513Schristos 
24216dce513Schristos     /* clear table */
24316dce513Schristos     bits = 9;
24416dce513Schristos     mask = 0x1ff;
24516dce513Schristos     end = flags ? 256 : 255;
24616dce513Schristos 
24716dce513Schristos     /* set up: get first 9-bit code, which is the first decompressed byte, but
24816dce513Schristos        don't create a table entry until the next code */
24916dce513Schristos     if (NEXT() == -1)                       /* no compressed data is ok */
25016dce513Schristos         return Z_OK;
25116dce513Schristos     final = prev = (unsigned)last;          /* low 8 bits of code */
25216dce513Schristos     if (NEXT() == -1)                       /* missing a bit */
25316dce513Schristos         return Z_BUF_ERROR;
25416dce513Schristos     if (last & 1) {                         /* code must be < 256 */
25516dce513Schristos         strm->msg = (char *)"invalid lzw code";
25616dce513Schristos         return Z_DATA_ERROR;
25716dce513Schristos     }
25816dce513Schristos     rem = (unsigned)last >> 1;              /* remaining 7 bits */
25916dce513Schristos     left = 7;
26016dce513Schristos     chunk = bits - 2;                       /* 7 bytes left in this chunk */
26116dce513Schristos     outbuf[0] = (unsigned char)final;       /* write first decompressed byte */
26216dce513Schristos     outcnt = 1;
26316dce513Schristos 
26416dce513Schristos     /* decode codes */
26516dce513Schristos     stack = 0;
26616dce513Schristos     for (;;) {
26716dce513Schristos         /* if the table will be full after this, increment the code size */
26816dce513Schristos         if (end >= mask && bits < max) {
26916dce513Schristos             FLUSHCODE();
27016dce513Schristos             bits++;
27116dce513Schristos             mask <<= 1;
27216dce513Schristos             mask++;
27316dce513Schristos         }
27416dce513Schristos 
27516dce513Schristos         /* get a code of length bits */
27616dce513Schristos         if (chunk == 0)                     /* decrement chunk modulo bits */
27716dce513Schristos             chunk = bits;
27816dce513Schristos         code = rem;                         /* low bits of code */
27916dce513Schristos         if (NEXT() == -1) {                 /* EOF is end of compressed data */
28016dce513Schristos             /* write remaining buffered output */
28116dce513Schristos             if (outcnt && out(&outd, outbuf, outcnt)) {
28216dce513Schristos                 strm->next_in = outbuf;     /* signal write error */
28316dce513Schristos                 return Z_BUF_ERROR;
28416dce513Schristos             }
28516dce513Schristos             return Z_OK;
28616dce513Schristos         }
28716dce513Schristos         code += (unsigned)last << left;     /* middle (or high) bits of code */
28816dce513Schristos         left += 8;
28916dce513Schristos         chunk--;
29016dce513Schristos         if (bits > left) {                  /* need more bits */
29116dce513Schristos             if (NEXT() == -1)               /* can't end in middle of code */
29216dce513Schristos                 return Z_BUF_ERROR;
29316dce513Schristos             code += (unsigned)last << left; /* high bits of code */
29416dce513Schristos             left += 8;
29516dce513Schristos             chunk--;
29616dce513Schristos         }
29716dce513Schristos         code &= mask;                       /* mask to current code length */
29816dce513Schristos         left -= bits;                       /* number of unused bits */
29916dce513Schristos         rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
30016dce513Schristos 
30116dce513Schristos         /* process clear code (256) */
30216dce513Schristos         if (code == 256 && flags) {
30316dce513Schristos             FLUSHCODE();
30416dce513Schristos             bits = 9;                       /* initialize bits and mask */
30516dce513Schristos             mask = 0x1ff;
30616dce513Schristos             end = 255;                      /* empty table */
30716dce513Schristos             continue;                       /* get next code */
30816dce513Schristos         }
30916dce513Schristos 
31016dce513Schristos         /* special code to reuse last match */
31116dce513Schristos         temp = code;                        /* save the current code */
31216dce513Schristos         if (code > end) {
31316dce513Schristos             /* Be picky on the allowed code here, and make sure that the code
31416dce513Schristos                we drop through (prev) will be a valid index so that random
31516dce513Schristos                input does not cause an exception.  The code != end + 1 check is
31616dce513Schristos                empirically derived, and not checked in the original uncompress
31716dce513Schristos                code.  If this ever causes a problem, that check could be safely
31816dce513Schristos                removed.  Leaving this check in greatly improves gun's ability
31916dce513Schristos                to detect random or corrupted input after a compress header.
32016dce513Schristos                In any case, the prev > end check must be retained. */
32116dce513Schristos             if (code != end + 1 || prev > end) {
32216dce513Schristos                 strm->msg = (char *)"invalid lzw code";
32316dce513Schristos                 return Z_DATA_ERROR;
32416dce513Schristos             }
32516dce513Schristos             match[stack++] = (unsigned char)final;
32616dce513Schristos             code = prev;
32716dce513Schristos         }
32816dce513Schristos 
32916dce513Schristos         /* walk through linked list to generate output in reverse order */
33016dce513Schristos         p = match + stack;
33116dce513Schristos         while (code >= 256) {
33216dce513Schristos             *p++ = suffix[code];
33316dce513Schristos             code = prefix[code];
33416dce513Schristos         }
33516dce513Schristos         stack = p - match;
33616dce513Schristos         match[stack++] = (unsigned char)code;
33716dce513Schristos         final = code;
33816dce513Schristos 
33916dce513Schristos         /* link new table entry */
34016dce513Schristos         if (end < mask) {
34116dce513Schristos             end++;
34216dce513Schristos             prefix[end] = (unsigned short)prev;
34316dce513Schristos             suffix[end] = (unsigned char)final;
34416dce513Schristos         }
34516dce513Schristos 
34616dce513Schristos         /* set previous code for next iteration */
34716dce513Schristos         prev = temp;
34816dce513Schristos 
34916dce513Schristos         /* write output in forward order */
35016dce513Schristos         while (stack > SIZE - outcnt) {
35116dce513Schristos             while (outcnt < SIZE)
35216dce513Schristos                 outbuf[outcnt++] = match[--stack];
35316dce513Schristos             if (out(&outd, outbuf, outcnt)) {
35416dce513Schristos                 strm->next_in = outbuf; /* signal write error */
35516dce513Schristos                 return Z_BUF_ERROR;
35616dce513Schristos             }
35716dce513Schristos             outcnt = 0;
35816dce513Schristos         }
35916dce513Schristos         p = match + stack;
36016dce513Schristos         do {
36116dce513Schristos             outbuf[outcnt++] = *--p;
36216dce513Schristos         } while (p > match);
36316dce513Schristos         stack = 0;
36416dce513Schristos 
36516dce513Schristos         /* loop for next code with final and prev as the last match, rem and
36616dce513Schristos            left provide the first 0..7 bits of the next code, end is the last
36716dce513Schristos            valid table entry */
36816dce513Schristos     }
36916dce513Schristos }
37016dce513Schristos 
37116dce513Schristos /* Decompress a gzip file from infile to outfile.  strm is assumed to have been
37216dce513Schristos    successfully initialized with inflateBackInit().  The input file may consist
37316dce513Schristos    of a series of gzip streams, in which case all of them will be decompressed
37416dce513Schristos    to the output file.  If outfile is -1, then the gzip stream(s) integrity is
37516dce513Schristos    checked and nothing is written.
37616dce513Schristos 
37716dce513Schristos    The return value is a zlib error code: Z_MEM_ERROR if out of memory,
37816dce513Schristos    Z_DATA_ERROR if the header or the compressed data is invalid, or if the
37916dce513Schristos    trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
38016dce513Schristos    prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
38116dce513Schristos    stream) follows a valid gzip stream.
38216dce513Schristos  */
gunpipe(z_stream * strm,int infile,int outfile)38316dce513Schristos local int gunpipe(z_stream *strm, int infile, int outfile)
38416dce513Schristos {
38516dce513Schristos     int ret, first, last;
38616dce513Schristos     unsigned have, flags, len;
38716dce513Schristos     z_const unsigned char *next = NULL;
38816dce513Schristos     struct ind ind, *indp;
38916dce513Schristos     struct outd outd;
39016dce513Schristos 
39116dce513Schristos     /* setup input buffer */
39216dce513Schristos     ind.infile = infile;
39316dce513Schristos     ind.inbuf = inbuf;
39416dce513Schristos     indp = &ind;
39516dce513Schristos 
39616dce513Schristos     /* decompress concatenated gzip streams */
39716dce513Schristos     have = 0;                               /* no input data read in yet */
39816dce513Schristos     first = 1;                              /* looking for first gzip header */
39916dce513Schristos     strm->next_in = Z_NULL;                 /* so Z_BUF_ERROR means EOF */
40016dce513Schristos     for (;;) {
40116dce513Schristos         /* look for the two magic header bytes for a gzip stream */
40216dce513Schristos         if (NEXT() == -1) {
40316dce513Schristos             ret = Z_OK;
40416dce513Schristos             break;                          /* empty gzip stream is ok */
40516dce513Schristos         }
40616dce513Schristos         if (last != 31 || (NEXT() != 139 && last != 157)) {
40716dce513Schristos             strm->msg = (char *)"incorrect header check";
40816dce513Schristos             ret = first ? Z_DATA_ERROR : Z_ERRNO;
40916dce513Schristos             break;                          /* not a gzip or compress header */
41016dce513Schristos         }
41116dce513Schristos         first = 0;                          /* next non-header is junk */
41216dce513Schristos 
41316dce513Schristos         /* process a compress (LZW) file -- can't be concatenated after this */
41416dce513Schristos         if (last == 157) {
41516dce513Schristos             ret = lunpipe(have, next, indp, outfile, strm);
41616dce513Schristos             break;
41716dce513Schristos         }
41816dce513Schristos 
41916dce513Schristos         /* process remainder of gzip header */
42016dce513Schristos         ret = Z_BUF_ERROR;
42116dce513Schristos         if (NEXT() != 8) {                  /* only deflate method allowed */
42216dce513Schristos             if (last == -1) break;
42316dce513Schristos             strm->msg = (char *)"unknown compression method";
42416dce513Schristos             ret = Z_DATA_ERROR;
42516dce513Schristos             break;
42616dce513Schristos         }
42716dce513Schristos         flags = NEXT();                     /* header flags */
42816dce513Schristos         NEXT();                             /* discard mod time, xflgs, os */
42916dce513Schristos         NEXT();
43016dce513Schristos         NEXT();
43116dce513Schristos         NEXT();
43216dce513Schristos         NEXT();
43316dce513Schristos         NEXT();
43416dce513Schristos         if (last == -1) break;
43516dce513Schristos         if (flags & 0xe0) {
43616dce513Schristos             strm->msg = (char *)"unknown header flags set";
43716dce513Schristos             ret = Z_DATA_ERROR;
43816dce513Schristos             break;
43916dce513Schristos         }
44016dce513Schristos         if (flags & 4) {                    /* extra field */
44116dce513Schristos             len = NEXT();
44216dce513Schristos             len += (unsigned)(NEXT()) << 8;
44316dce513Schristos             if (last == -1) break;
44416dce513Schristos             while (len > have) {
44516dce513Schristos                 len -= have;
44616dce513Schristos                 have = 0;
44716dce513Schristos                 if (NEXT() == -1) break;
44816dce513Schristos                 len--;
44916dce513Schristos             }
45016dce513Schristos             if (last == -1) break;
45116dce513Schristos             have -= len;
45216dce513Schristos             next += len;
45316dce513Schristos         }
45416dce513Schristos         if (flags & 8)                      /* file name */
45516dce513Schristos             while (NEXT() != 0 && last != -1)
45616dce513Schristos                 ;
45716dce513Schristos         if (flags & 16)                     /* comment */
45816dce513Schristos             while (NEXT() != 0 && last != -1)
45916dce513Schristos                 ;
46016dce513Schristos         if (flags & 2) {                    /* header crc */
46116dce513Schristos             NEXT();
46216dce513Schristos             NEXT();
46316dce513Schristos         }
46416dce513Schristos         if (last == -1) break;
46516dce513Schristos 
46616dce513Schristos         /* set up output */
46716dce513Schristos         outd.outfile = outfile;
46816dce513Schristos         outd.check = 1;
46916dce513Schristos         outd.crc = crc32(0L, Z_NULL, 0);
47016dce513Schristos         outd.total = 0;
47116dce513Schristos 
47216dce513Schristos         /* decompress data to output */
47316dce513Schristos         strm->next_in = next;
47416dce513Schristos         strm->avail_in = have;
47516dce513Schristos         ret = inflateBack(strm, in, indp, out, &outd);
47616dce513Schristos         if (ret != Z_STREAM_END) break;
47716dce513Schristos         next = strm->next_in;
47816dce513Schristos         have = strm->avail_in;
47916dce513Schristos         strm->next_in = Z_NULL;             /* so Z_BUF_ERROR means EOF */
48016dce513Schristos 
48116dce513Schristos         /* check trailer */
48216dce513Schristos         ret = Z_BUF_ERROR;
48316dce513Schristos         if (NEXT() != (int)(outd.crc & 0xff) ||
48416dce513Schristos             NEXT() != (int)((outd.crc >> 8) & 0xff) ||
48516dce513Schristos             NEXT() != (int)((outd.crc >> 16) & 0xff) ||
48616dce513Schristos             NEXT() != (int)((outd.crc >> 24) & 0xff)) {
48716dce513Schristos             /* crc error */
48816dce513Schristos             if (last != -1) {
48916dce513Schristos                 strm->msg = (char *)"incorrect data check";
49016dce513Schristos                 ret = Z_DATA_ERROR;
49116dce513Schristos             }
49216dce513Schristos             break;
49316dce513Schristos         }
49416dce513Schristos         if (NEXT() != (int)(outd.total & 0xff) ||
49516dce513Schristos             NEXT() != (int)((outd.total >> 8) & 0xff) ||
49616dce513Schristos             NEXT() != (int)((outd.total >> 16) & 0xff) ||
49716dce513Schristos             NEXT() != (int)((outd.total >> 24) & 0xff)) {
49816dce513Schristos             /* length error */
49916dce513Schristos             if (last != -1) {
50016dce513Schristos                 strm->msg = (char *)"incorrect length check";
50116dce513Schristos                 ret = Z_DATA_ERROR;
50216dce513Schristos             }
50316dce513Schristos             break;
50416dce513Schristos         }
50516dce513Schristos 
50616dce513Schristos         /* go back and look for another gzip stream */
50716dce513Schristos     }
50816dce513Schristos 
50916dce513Schristos     /* clean up and return */
51016dce513Schristos     return ret;
51116dce513Schristos }
51216dce513Schristos 
51316dce513Schristos /* Copy file attributes, from -> to, as best we can.  This is best effort, so
51416dce513Schristos    no errors are reported.  The mode bits, including suid, sgid, and the sticky
51516dce513Schristos    bit are copied (if allowed), the owner's user id and group id are copied
51616dce513Schristos    (again if allowed), and the access and modify times are copied. */
copymeta(char * from,char * to)51716dce513Schristos local void copymeta(char *from, char *to)
51816dce513Schristos {
51916dce513Schristos     struct stat was;
52016dce513Schristos     struct utimbuf when;
52116dce513Schristos 
52216dce513Schristos     /* get all of from's Unix meta data, return if not a regular file */
52316dce513Schristos     if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
52416dce513Schristos         return;
52516dce513Schristos 
52616dce513Schristos     /* set to's mode bits, ignore errors */
52716dce513Schristos     (void)chmod(to, was.st_mode & 07777);
52816dce513Schristos 
52916dce513Schristos     /* copy owner's user and group, ignore errors */
53016dce513Schristos     (void)chown(to, was.st_uid, was.st_gid);
53116dce513Schristos 
53216dce513Schristos     /* copy access and modify times, ignore errors */
53316dce513Schristos     when.actime = was.st_atime;
53416dce513Schristos     when.modtime = was.st_mtime;
53516dce513Schristos     (void)utime(to, &when);
53616dce513Schristos }
53716dce513Schristos 
53816dce513Schristos /* Decompress the file inname to the file outnname, of if test is true, just
53916dce513Schristos    decompress without writing and check the gzip trailer for integrity.  If
54016dce513Schristos    inname is NULL or an empty string, read from stdin.  If outname is NULL or
54116dce513Schristos    an empty string, write to stdout.  strm is a pre-initialized inflateBack
54216dce513Schristos    structure.  When appropriate, copy the file attributes from inname to
54316dce513Schristos    outname.
54416dce513Schristos 
54516dce513Schristos    gunzip() returns 1 if there is an out-of-memory error or an unexpected
54616dce513Schristos    return code from gunpipe().  Otherwise it returns 0.
54716dce513Schristos  */
gunzip(z_stream * strm,char * inname,char * outname,int test)54816dce513Schristos local int gunzip(z_stream *strm, char *inname, char *outname, int test)
54916dce513Schristos {
55016dce513Schristos     int ret;
55116dce513Schristos     int infile, outfile;
55216dce513Schristos 
55316dce513Schristos     /* open files */
55416dce513Schristos     if (inname == NULL || *inname == 0) {
55516dce513Schristos         inname = "-";
55616dce513Schristos         infile = 0;     /* stdin */
55716dce513Schristos     }
55816dce513Schristos     else {
55916dce513Schristos         infile = open(inname, O_RDONLY, 0);
56016dce513Schristos         if (infile == -1) {
56116dce513Schristos             fprintf(stderr, "gun cannot open %s\n", inname);
56216dce513Schristos             return 0;
56316dce513Schristos         }
56416dce513Schristos     }
56516dce513Schristos     if (test)
56616dce513Schristos         outfile = -1;
56716dce513Schristos     else if (outname == NULL || *outname == 0) {
56816dce513Schristos         outname = "-";
56916dce513Schristos         outfile = 1;    /* stdout */
57016dce513Schristos     }
57116dce513Schristos     else {
57216dce513Schristos         outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
57316dce513Schristos         if (outfile == -1) {
57416dce513Schristos             close(infile);
57516dce513Schristos             fprintf(stderr, "gun cannot create %s\n", outname);
57616dce513Schristos             return 0;
57716dce513Schristos         }
57816dce513Schristos     }
57916dce513Schristos     errno = 0;
58016dce513Schristos 
58116dce513Schristos     /* decompress */
58216dce513Schristos     ret = gunpipe(strm, infile, outfile);
58316dce513Schristos     if (outfile > 2) close(outfile);
58416dce513Schristos     if (infile > 2) close(infile);
58516dce513Schristos 
58616dce513Schristos     /* interpret result */
58716dce513Schristos     switch (ret) {
58816dce513Schristos     case Z_OK:
58916dce513Schristos     case Z_ERRNO:
59016dce513Schristos         if (infile > 2 && outfile > 2) {
59116dce513Schristos             copymeta(inname, outname);          /* copy attributes */
59216dce513Schristos             unlink(inname);
59316dce513Schristos         }
59416dce513Schristos         if (ret == Z_ERRNO)
59516dce513Schristos             fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
59616dce513Schristos                     inname);
59716dce513Schristos         break;
59816dce513Schristos     case Z_DATA_ERROR:
59916dce513Schristos         if (outfile > 2) unlink(outname);
60016dce513Schristos         fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
60116dce513Schristos         break;
60216dce513Schristos     case Z_MEM_ERROR:
60316dce513Schristos         if (outfile > 2) unlink(outname);
60416dce513Schristos         fprintf(stderr, "gun out of memory error--aborting\n");
60516dce513Schristos         return 1;
60616dce513Schristos     case Z_BUF_ERROR:
60716dce513Schristos         if (outfile > 2) unlink(outname);
60816dce513Schristos         if (strm->next_in != Z_NULL) {
60916dce513Schristos             fprintf(stderr, "gun write error on %s: %s\n",
61016dce513Schristos                     outname, strerror(errno));
61116dce513Schristos         }
61216dce513Schristos         else if (errno) {
61316dce513Schristos             fprintf(stderr, "gun read error on %s: %s\n",
61416dce513Schristos                     inname, strerror(errno));
61516dce513Schristos         }
61616dce513Schristos         else {
61716dce513Schristos             fprintf(stderr, "gun unexpected end of file on %s\n",
61816dce513Schristos                     inname);
61916dce513Schristos         }
62016dce513Schristos         break;
62116dce513Schristos     default:
62216dce513Schristos         if (outfile > 2) unlink(outname);
62316dce513Schristos         fprintf(stderr, "gun internal error--aborting\n");
62416dce513Schristos         return 1;
62516dce513Schristos     }
62616dce513Schristos     return 0;
62716dce513Schristos }
62816dce513Schristos 
62916dce513Schristos /* Process the gun command line arguments.  See the command syntax near the
63016dce513Schristos    beginning of this source file. */
main(int argc,char ** argv)63116dce513Schristos int main(int argc, char **argv)
63216dce513Schristos {
63316dce513Schristos     int ret, len, test;
63416dce513Schristos     char *outname;
63516dce513Schristos     unsigned char *window;
63616dce513Schristos     z_stream strm;
63716dce513Schristos 
63816dce513Schristos     /* initialize inflateBack state for repeated use */
63916dce513Schristos     window = match;                         /* reuse LZW match buffer */
64016dce513Schristos     strm.zalloc = Z_NULL;
64116dce513Schristos     strm.zfree = Z_NULL;
64216dce513Schristos     strm.opaque = Z_NULL;
64316dce513Schristos     ret = inflateBackInit(&strm, 15, window);
64416dce513Schristos     if (ret != Z_OK) {
64516dce513Schristos         fprintf(stderr, "gun out of memory error--aborting\n");
64616dce513Schristos         return 1;
64716dce513Schristos     }
64816dce513Schristos 
64916dce513Schristos     /* decompress each file to the same name with the suffix removed */
65016dce513Schristos     argc--;
65116dce513Schristos     argv++;
65216dce513Schristos     test = 0;
65316dce513Schristos     if (argc && strcmp(*argv, "-h") == 0) {
65416dce513Schristos         fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
65516dce513Schristos         fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
65616dce513Schristos         fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
65716dce513Schristos         return 0;
65816dce513Schristos     }
65916dce513Schristos     if (argc && strcmp(*argv, "-t") == 0) {
66016dce513Schristos         test = 1;
66116dce513Schristos         argc--;
66216dce513Schristos         argv++;
66316dce513Schristos     }
66416dce513Schristos     if (argc)
66516dce513Schristos         do {
66616dce513Schristos             if (test)
66716dce513Schristos                 outname = NULL;
66816dce513Schristos             else {
66916dce513Schristos                 len = (int)strlen(*argv);
67016dce513Schristos                 if (strcmp(*argv + len - 3, ".gz") == 0 ||
67116dce513Schristos                     strcmp(*argv + len - 3, "-gz") == 0)
67216dce513Schristos                     len -= 3;
67316dce513Schristos                 else if (strcmp(*argv + len - 2, ".z") == 0 ||
67416dce513Schristos                     strcmp(*argv + len - 2, "-z") == 0 ||
67516dce513Schristos                     strcmp(*argv + len - 2, "_z") == 0 ||
67616dce513Schristos                     strcmp(*argv + len - 2, ".Z") == 0)
67716dce513Schristos                     len -= 2;
67816dce513Schristos                 else {
67916dce513Schristos                     fprintf(stderr, "gun error: no gz type on %s--skipping\n",
68016dce513Schristos                             *argv);
68116dce513Schristos                     continue;
68216dce513Schristos                 }
68316dce513Schristos                 outname = malloc(len + 1);
68416dce513Schristos                 if (outname == NULL) {
68516dce513Schristos                     fprintf(stderr, "gun out of memory error--aborting\n");
68616dce513Schristos                     ret = 1;
68716dce513Schristos                     break;
68816dce513Schristos                 }
68916dce513Schristos                 memcpy(outname, *argv, len);
69016dce513Schristos                 outname[len] = 0;
69116dce513Schristos             }
69216dce513Schristos             ret = gunzip(&strm, *argv, outname, test);
69316dce513Schristos             if (outname != NULL) free(outname);
69416dce513Schristos             if (ret) break;
69516dce513Schristos         } while (argv++, --argc);
69616dce513Schristos     else
69716dce513Schristos         ret = gunzip(&strm, NULL, NULL, test);
69816dce513Schristos 
69916dce513Schristos     /* clean up */
70016dce513Schristos     inflateBackEnd(&strm);
70116dce513Schristos     return ret;
70216dce513Schristos }
703