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