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