gun.c revision 1b33c96954667ba382fa595baf7b31290bfdd517
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* gun.c -- simple gunzip to give an example of the use of inflateBack()
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * Copyright (C) 2003, 2005, 2008, 2010 Mark Adler
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync * For conditions of distribution and use, see copyright notice in zlib.h
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Version 1.6 17 January 2010 Mark Adler */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* Version history:
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync 1.0 16 Feb 2003 First version for testing of inflateBack()
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync 1.1 21 Feb 2005 Decompress concatenated gzip streams
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Remove use of "this" variable (C++ keyword)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Fix return value for in()
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Improve allocation failure checking
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Add typecasting for void * structures
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Add -h option for command version and usage
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Add a bunch of comments
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync 1.2 20 Mar 2005 Add Unix compress (LZW) decompression
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Copy file attributes from input file to output file
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync 1.3 12 Jun 2005 Add casts for error messages [Oberhumer]
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync 1.4 8 Dec 2006 LZW decompression speed improvements
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync 1.5 9 Feb 2008 Avoid warning in latest version of gcc
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync 1.6 17 Jan 2010 Avoid signed/unsigned comparison warnings
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/*
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync gun [ -t ] [ name ... ]
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync decompresses the data in the named gzip files. If no arguments are given,
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync gun will decompress from stdin to stdout. The names must end in .gz, -gz,
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync .z, -z, _z, or .Z. The uncompressed data will be written to a file name
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync with the suffix stripped. On success, the original file is deleted. On
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync failure, the output file is deleted. For most failures, the command will
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync continue to process the remaining names on the command line. A memory
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync allocation failure will abort the command. If -t is specified, then the
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync listed files or stdin will be tested as gzip files for integrity (without
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync checking for a proper suffix), no output will be written, and no files
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync will be deleted.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Like gzip, gun allows concatenated gzip streams and will decompress them,
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync writing all of the uncompressed data to the output. Unlike gzip, gun allows
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync an empty file on input, and will produce no error writing an empty output
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync file.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync gun will also decompress files made by Unix compress, which uses LZW
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync compression. These files are automatically detected by virtue of their
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync magic header bytes. Since the end of Unix compress stream is marked by the
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync end-of-file, they cannot be concantenated. If a Unix compress stream is
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync encountered in an input file, it is the last stream in that file.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Like gunzip and uncompress, the file attributes of the orignal compressed
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync file are maintained in the final uncompressed file, to the extent that the
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync user permissions allow it.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync 1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync LZW decompression provided by gun is about twice as fast as the standard
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Unix uncompress command.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* external functions and related types and constants */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <stdio.h> /* fprintf() */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <stdlib.h> /* malloc(), free() */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <string.h> /* strerror(), strcmp(), strlen(), memcpy() */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <errno.h> /* errno */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <fcntl.h> /* open() */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <unistd.h> /* read(), write(), close(), chown(), unlink() */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <sys/types.h>
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <sys/stat.h> /* stat(), chmod() */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include <utime.h> /* utime() */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#include "zlib.h" /* inflateBackInit(), inflateBack(), */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* inflateBackEnd(), crc32() */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* function declaration */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#define local static
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* buffer constants */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#define SIZE 32768U /* input and output buffer sizes */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#define PIECE 16384 /* limits i/o chunks for 16-bit int case */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* structure for infback() to pass to input function in() -- it maintains the
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync input file and a buffer of size SIZE */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsyncstruct ind {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int infile;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned char *inbuf;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync};
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* Load input buffer, assumed to be empty, and return bytes loaded and a
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync pointer to them. read() is called until the buffer is full, or until it
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync returns end-of-file or error. Return 0 on error. */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsynclocal unsigned in(void *in_desc, unsigned char **buf)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync{
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int ret;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned len;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned char *next;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync struct ind *me = (struct ind *)in_desc;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync next = me->inbuf;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync *buf = next;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync len = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync do {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = PIECE;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if ((unsigned)ret > SIZE - len)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = (int)(SIZE - len);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = (int)read(me->infile, next, ret);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (ret == -1) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync len = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync next += ret;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync len += ret;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync } while (ret != 0 && len < SIZE);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return len;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync}
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* structure for infback() to pass to output function out() -- it maintains the
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync output file, a running CRC-32 check on the output and the total number of
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync bytes output, both for checking against the gzip trailer. (The length in
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync the output is greater than 4 GB.) */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsyncstruct outd {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int outfile;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int check; /* true if checking crc and total */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned long crc;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned long total;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync};
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* Write output buffer and update the CRC-32 and total bytes written. write()
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync is called until all of the output is written or an error is encountered.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync On success out() returns 0. For a write failure, out() returns 1. If the
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync output file descriptor is -1, then nothing is written.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsynclocal int out(void *out_desc, unsigned char *buf, unsigned len)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync{
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int ret;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync struct outd *me = (struct outd *)out_desc;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (me->check) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync me->crc = crc32(me->crc, buf, len);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync me->total += len;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (me->outfile != -1)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync do {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = PIECE;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if ((unsigned)ret > len)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = (int)len;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = (int)write(me->outfile, buf, ret);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (ret == -1)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync buf += ret;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync len -= ret;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync } while (len != 0);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync}
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* next input byte macro for use inside lunpipe() and gunpipe() */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#define NEXT() (have ? 0 : (have = in(indp, &next)), \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync last = have ? (have--, (int)(*next++)) : -1)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* memory for gunpipe() and lunpipe() --
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync the first 256 entries of prefix[] and suffix[] are never used, could
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync have offset the index, but it's faster to waste the memory */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsyncunsigned char inbuf[SIZE]; /* input buffer */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsyncunsigned char outbuf[SIZE]; /* output buffer */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsyncunsigned short prefix[65536]; /* index to LZW prefix string */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsyncunsigned char suffix[65536]; /* one-character LZW suffix */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsyncunsigned char match[65280 + 2]; /* buffer for reversed match or gzip
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync 32K sliding window */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* throw out what's left in the current bits byte buffer (this is a vestigial
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync aspect of the compressed data format derived from an implementation that
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync made use of a special VAX machine instruction!) */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync#define FLUSHCODE() \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync do { \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync left = 0; \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync rem = 0; \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (chunk > have) { \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync chunk -= have; \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync have = 0; \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (NEXT() == -1) \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break; \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync chunk--; \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (chunk > have) { \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync chunk = have = 0; \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break; \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync } \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync } \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync have -= chunk; \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync next += chunk; \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync chunk = 0; \
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync } while (0)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* Decompress a compress (LZW) file from indp to outfile. The compress magic
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync header (two bytes) has already been read and verified. There are have bytes
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync of buffered input at next. strm is used for passing error information back
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync to gunpipe().
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync file, read error, or write error (a write error indicated by strm->next_in
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsynclocal int lunpipe(unsigned have, unsigned char *next, struct ind *indp,
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int outfile, z_stream *strm)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync{
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int last; /* last byte read by NEXT(), or -1 if EOF */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned chunk; /* bytes left in current chunk */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int left; /* bits left in rem */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned rem; /* unused bits from input */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int bits; /* current bits per code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned code; /* code, table traversal index */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned mask; /* mask for current bits codes */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int max; /* maximum bits per code for this stream */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned flags; /* compress flags, then block compress flag */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned end; /* last valid entry in prefix/suffix tables */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned temp; /* current code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned prev; /* previous code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned final; /* last character written for previous code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned stack; /* next position for reversed string */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned outcnt; /* bytes in output buffer */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync struct outd outd; /* output structure */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned char *p;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* set up output */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outd.outfile = outfile;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outd.check = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* process remainder of compress header -- a flags byte */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync flags = NEXT();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (last == -1)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return Z_BUF_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (flags & 0x60) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->msg = (char *)"unknown lzw flags set";
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return Z_DATA_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync max = flags & 0x1f;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (max < 9 || max > 16) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->msg = (char *)"lzw bits out of range";
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return Z_DATA_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (max == 9) /* 9 doesn't really mean 9 */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync max = 10;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync flags &= 0x80; /* true if block compress */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* clear table */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync bits = 9;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync mask = 0x1ff;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync end = flags ? 256 : 255;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* set up: get first 9-bit code, which is the first decompressed byte, but
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync don't create a table entry until the next code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (NEXT() == -1) /* no compressed data is ok */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return Z_OK;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync final = prev = (unsigned)last; /* low 8 bits of code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (NEXT() == -1) /* missing a bit */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return Z_BUF_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (last & 1) { /* code must be < 256 */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->msg = (char *)"invalid lzw code";
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return Z_DATA_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync rem = (unsigned)last >> 1; /* remaining 7 bits */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync left = 7;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync chunk = bits - 2; /* 7 bytes left in this chunk */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outbuf[0] = (unsigned char)final; /* write first decompressed byte */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outcnt = 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* decode codes */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync stack = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync for (;;) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* if the table will be full after this, increment the code size */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (end >= mask && bits < max) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync FLUSHCODE();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync bits++;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync mask <<= 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync mask++;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* get a code of length bits */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (chunk == 0) /* decrement chunk modulo bits */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync chunk = bits;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync code = rem; /* low bits of code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (NEXT() == -1) { /* EOF is end of compressed data */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* write remaining buffered output */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (outcnt && out(&outd, outbuf, outcnt)) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->next_in = outbuf; /* signal write error */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return Z_BUF_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return Z_OK;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync code += (unsigned)last << left; /* middle (or high) bits of code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync left += 8;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync chunk--;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (bits > left) { /* need more bits */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (NEXT() == -1) /* can't end in middle of code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return Z_BUF_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync code += (unsigned)last << left; /* high bits of code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync left += 8;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync chunk--;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync code &= mask; /* mask to current code length */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync left -= bits; /* number of unused bits */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* process clear code (256) */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (code == 256 && flags) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync FLUSHCODE();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync bits = 9; /* initialize bits and mask */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync mask = 0x1ff;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync end = 255; /* empty table */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync continue; /* get next code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* special code to reuse last match */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync temp = code; /* save the current code */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (code > end) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* Be picky on the allowed code here, and make sure that the code
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync we drop through (prev) will be a valid index so that random
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync input does not cause an exception. The code != end + 1 check is
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync empirically derived, and not checked in the original uncompress
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync code. If this ever causes a problem, that check could be safely
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync removed. Leaving this check in greatly improves gun's ability
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync to detect random or corrupted input after a compress header.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync In any case, the prev > end check must be retained. */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (code != end + 1 || prev > end) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->msg = (char *)"invalid lzw code";
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return Z_DATA_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync match[stack++] = (unsigned char)final;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync code = prev;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* walk through linked list to generate output in reverse order */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync p = match + stack;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync while (code >= 256) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync *p++ = suffix[code];
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync code = prefix[code];
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync stack = p - match;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync match[stack++] = (unsigned char)code;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync final = code;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* link new table entry */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (end < mask) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync end++;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync prefix[end] = (unsigned short)prev;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync suffix[end] = (unsigned char)final;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* set previous code for next iteration */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync prev = temp;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* write output in forward order */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync while (stack > SIZE - outcnt) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync while (outcnt < SIZE)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outbuf[outcnt++] = match[--stack];
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (out(&outd, outbuf, outcnt)) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->next_in = outbuf; /* signal write error */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return Z_BUF_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outcnt = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync p = match + stack;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync do {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outbuf[outcnt++] = *--p;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync } while (p > match);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync stack = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* loop for next code with final and prev as the last match, rem and
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync left provide the first 0..7 bits of the next code, end is the last
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync valid table entry */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync}
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* Decompress a gzip file from infile to outfile. strm is assumed to have been
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync successfully initialized with inflateBackInit(). The input file may consist
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync of a series of gzip streams, in which case all of them will be decompressed
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync to the output file. If outfile is -1, then the gzip stream(s) integrity is
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync checked and nothing is written.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync The return value is a zlib error code: Z_MEM_ERROR if out of memory,
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync Z_DATA_ERROR if the header or the compressed data is invalid, or if the
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync stream) follows a valid gzip stream.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsynclocal int gunpipe(z_stream *strm, int infile, int outfile)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync{
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int ret, first, last;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned have, flags, len;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned char *next = NULL;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync struct ind ind, *indp;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync struct outd outd;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* setup input buffer */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ind.infile = infile;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ind.inbuf = inbuf;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync indp = &ind;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* decompress concatenated gzip streams */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync have = 0; /* no input data read in yet */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync first = 1; /* looking for first gzip header */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync for (;;) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* look for the two magic header bytes for a gzip stream */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (NEXT() == -1) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = Z_OK;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break; /* empty gzip stream is ok */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (last != 31 || (NEXT() != 139 && last != 157)) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->msg = (char *)"incorrect header check";
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = first ? Z_DATA_ERROR : Z_ERRNO;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break; /* not a gzip or compress header */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync first = 0; /* next non-header is junk */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* process a compress (LZW) file -- can't be concatenated after this */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (last == 157) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = lunpipe(have, next, indp, outfile, strm);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* process remainder of gzip header */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = Z_BUF_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (NEXT() != 8) { /* only deflate method allowed */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (last == -1) break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->msg = (char *)"unknown compression method";
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = Z_DATA_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync flags = NEXT(); /* header flags */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT(); /* discard mod time, xflgs, os */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (last == -1) break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (flags & 0xe0) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->msg = (char *)"unknown header flags set";
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = Z_DATA_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (flags & 4) { /* extra field */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync len = NEXT();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync len += (unsigned)(NEXT()) << 8;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (last == -1) break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync while (len > have) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync len -= have;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync have = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (NEXT() == -1) break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync len--;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (last == -1) break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync have -= len;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync next += len;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (flags & 8) /* file name */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync while (NEXT() != 0 && last != -1)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (flags & 16) /* comment */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync while (NEXT() != 0 && last != -1)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (flags & 2) { /* header crc */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT();
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (last == -1) break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* set up output */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outd.outfile = outfile;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outd.check = 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outd.crc = crc32(0L, Z_NULL, 0);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outd.total = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* decompress data to output */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->next_in = next;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->avail_in = have;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = inflateBack(strm, in, indp, out, &outd);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (ret != Z_STREAM_END) break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync next = strm->next_in;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync have = strm->avail_in;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* check trailer */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = Z_BUF_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (NEXT() != (int)(outd.crc & 0xff) ||
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT() != (int)((outd.crc >> 8) & 0xff) ||
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT() != (int)((outd.crc >> 16) & 0xff) ||
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT() != (int)((outd.crc >> 24) & 0xff)) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* crc error */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (last != -1) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->msg = (char *)"incorrect data check";
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = Z_DATA_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (NEXT() != (int)(outd.total & 0xff) ||
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT() != (int)((outd.total >> 8) & 0xff) ||
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT() != (int)((outd.total >> 16) & 0xff) ||
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync NEXT() != (int)((outd.total >> 24) & 0xff)) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* length error */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (last != -1) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm->msg = (char *)"incorrect length check";
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = Z_DATA_ERROR;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* go back and look for another gzip stream */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* clean up and return */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return ret;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync}
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* Copy file attributes, from -> to, as best we can. This is best effort, so
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync no errors are reported. The mode bits, including suid, sgid, and the sticky
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync bit are copied (if allowed), the owner's user id and group id are copied
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync (again if allowed), and the access and modify times are copied. */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsynclocal void copymeta(char *from, char *to)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync{
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync struct stat was;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync struct utimbuf when;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* get all of from's Unix meta data, return if not a regular file */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* set to's mode bits, ignore errors */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync (void)chmod(to, was.st_mode & 07777);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* copy owner's user and group, ignore errors */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync (void)chown(to, was.st_uid, was.st_gid);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* copy access and modify times, ignore errors */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync when.actime = was.st_atime;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync when.modtime = was.st_mtime;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync (void)utime(to, &when);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync}
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* Decompress the file inname to the file outnname, of if test is true, just
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync decompress without writing and check the gzip trailer for integrity. If
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync inname is NULL or an empty string, read from stdin. If outname is NULL or
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync an empty string, write to stdout. strm is a pre-initialized inflateBack
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync structure. When appropriate, copy the file attributes from inname to
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outname.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync gunzip() returns 1 if there is an out-of-memory error or an unexpected
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return code from gunpipe(). Otherwise it returns 0.
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsynclocal int gunzip(z_stream *strm, char *inname, char *outname, int test)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync{
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int ret;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int infile, outfile;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* open files */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (inname == NULL || *inname == 0) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync inname = "-";
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync infile = 0; /* stdin */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync infile = open(inname, O_RDONLY, 0);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (infile == -1) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun cannot open %s\n", inname);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (test)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outfile = -1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else if (outname == NULL || *outname == 0) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outname = "-";
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outfile = 1; /* stdout */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (outfile == -1) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync close(infile);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun cannot create %s\n", outname);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync errno = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* decompress */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = gunpipe(strm, infile, outfile);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (outfile > 2) close(outfile);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (infile > 2) close(infile);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* interpret result */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync switch (ret) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync case Z_OK:
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync case Z_ERRNO:
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (infile > 2 && outfile > 2) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync copymeta(inname, outname); /* copy attributes */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unlink(inname);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (ret == Z_ERRNO)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync inname);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync case Z_DATA_ERROR:
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (outfile > 2) unlink(outname);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync case Z_MEM_ERROR:
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (outfile > 2) unlink(outname);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun out of memory error--aborting\n");
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync case Z_BUF_ERROR:
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (outfile > 2) unlink(outname);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (strm->next_in != Z_NULL) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun write error on %s: %s\n",
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outname, strerror(errno));
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else if (errno) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun read error on %s: %s\n",
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync inname, strerror(errno));
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun unexpected end of file on %s\n",
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync inname);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync default:
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (outfile > 2) unlink(outname);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun internal error--aborting\n");
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync}
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync/* Process the gun command line arguments. See the command syntax near the
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync beginning of this source file. */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsyncint main(int argc, char **argv)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync{
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync int ret, len, test;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync char *outname;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync unsigned char *window;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync z_stream strm;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* initialize inflateBack state for repeated use */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync window = match; /* reuse LZW match buffer */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm.zalloc = Z_NULL;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm.zfree = Z_NULL;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strm.opaque = Z_NULL;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = inflateBackInit(&strm, 15, window);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (ret != Z_OK) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun out of memory error--aborting\n");
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* decompress each file to the same name with the suffix removed */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync argc--;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync argv++;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync test = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (argc && strcmp(*argv, "-h") == 0) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (argc && strcmp(*argv, "-t") == 0) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync test = 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync argc--;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync argv++;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (argc)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync do {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (test)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outname = NULL;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync len = (int)strlen(*argv);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (strcmp(*argv + len - 3, ".gz") == 0 ||
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strcmp(*argv + len - 3, "-gz") == 0)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync len -= 3;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else if (strcmp(*argv + len - 2, ".z") == 0 ||
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strcmp(*argv + len - 2, "-z") == 0 ||
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strcmp(*argv + len - 2, "_z") == 0 ||
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync strcmp(*argv + len - 2, ".Z") == 0)
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync len -= 2;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun error: no gz type on %s--skipping\n",
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync *argv);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync continue;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outname = malloc(len + 1);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (outname == NULL) {
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync fprintf(stderr, "gun out of memory error--aborting\n");
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = 1;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync memcpy(outname, *argv, len);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync outname[len] = 0;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync }
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = gunzip(&strm, *argv, outname, test);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (outname != NULL) free(outname);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync if (ret) break;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync } while (argv++, --argc);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync else
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync ret = gunzip(&strm, NULL, NULL, test);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync /* clean up */
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync inflateBackEnd(&strm);
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync return ret;
1b33c96954667ba382fa595baf7b31290bfdd517vboxsync}