Fossil SCM

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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button