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