annotate src/zlib-1.2.8/examples/gun.c @ 56:af97cad61ff0

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