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