• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

contrib/zlib/examples/gun.c

00001 /* gun.c -- simple gunzip to give an example of the use of inflateBack()
00002  * Copyright (C) 2003, 2005, 2008, 2010 Mark Adler
00003  * For conditions of distribution and use, see copyright notice in zlib.h
00004    Version 1.6  17 January 2010  Mark Adler */
00005 
00006 /* Version history:
00007    1.0  16 Feb 2003  First version for testing of inflateBack()
00008    1.1  21 Feb 2005  Decompress concatenated gzip streams
00009                      Remove use of "this" variable (C++ keyword)
00010                      Fix return value for in()
00011                      Improve allocation failure checking
00012                      Add typecasting for void * structures
00013                      Add -h option for command version and usage
00014                      Add a bunch of comments
00015    1.2  20 Mar 2005  Add Unix compress (LZW) decompression
00016                      Copy file attributes from input file to output file
00017    1.3  12 Jun 2005  Add casts for error messages [Oberhumer]
00018    1.4   8 Dec 2006  LZW decompression speed improvements
00019    1.5   9 Feb 2008  Avoid warning in latest version of gcc
00020    1.6  17 Jan 2010  Avoid signed/unsigned comparison warnings
00021  */
00022 
00023 /*
00024    gun [ -t ] [ name ... ]
00025 
00026    decompresses the data in the named gzip files.  If no arguments are given,
00027    gun will decompress from stdin to stdout.  The names must end in .gz, -gz,
00028    .z, -z, _z, or .Z.  The uncompressed data will be written to a file name
00029    with the suffix stripped.  On success, the original file is deleted.  On
00030    failure, the output file is deleted.  For most failures, the command will
00031    continue to process the remaining names on the command line.  A memory
00032    allocation failure will abort the command.  If -t is specified, then the
00033    listed files or stdin will be tested as gzip files for integrity (without
00034    checking for a proper suffix), no output will be written, and no files
00035    will be deleted.
00036 
00037    Like gzip, gun allows concatenated gzip streams and will decompress them,
00038    writing all of the uncompressed data to the output.  Unlike gzip, gun allows
00039    an empty file on input, and will produce no error writing an empty output
00040    file.
00041 
00042    gun will also decompress files made by Unix compress, which uses LZW
00043    compression.  These files are automatically detected by virtue of their
00044    magic header bytes.  Since the end of Unix compress stream is marked by the
00045    end-of-file, they cannot be concantenated.  If a Unix compress stream is
00046    encountered in an input file, it is the last stream in that file.
00047 
00048    Like gunzip and uncompress, the file attributes of the orignal compressed
00049    file are maintained in the final uncompressed file, to the extent that the
00050    user permissions allow it.
00051 
00052    On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
00053    1.2.4) is on the same file, when gun is linked with zlib 1.2.2.  Also the
00054    LZW decompression provided by gun is about twice as fast as the standard
00055    Unix uncompress command.
00056  */
00057 
00058 /* external functions and related types and constants */
00059 #include <stdio.h>          /* fprintf() */
00060 #include <stdlib.h>         /* malloc(), free() */
00061 #include <string.h>         /* strerror(), strcmp(), strlen(), memcpy() */
00062 #include <errno.h>          /* errno */
00063 #include <fcntl.h>          /* open() */
00064 #include <unistd.h>         /* read(), write(), close(), chown(), unlink() */
00065 #include <sys/types.h>
00066 #include <sys/stat.h>       /* stat(), chmod() */
00067 #include <utime.h>          /* utime() */
00068 #include "zlib.h"           /* inflateBackInit(), inflateBack(), */
00069                             /* inflateBackEnd(), crc32() */
00070 
00071 /* function declaration */
00072 #define local static
00073 
00074 /* buffer constants */
00075 #define SIZE 32768U         /* input and output buffer sizes */
00076 #define PIECE 16384         /* limits i/o chunks for 16-bit int case */
00077 
00078 /* structure for infback() to pass to input function in() -- it maintains the
00079    input file and a buffer of size SIZE */
00080 struct ind {
00081     int infile;
00082     unsigned char *inbuf;
00083 };
00084 
00085 /* Load input buffer, assumed to be empty, and return bytes loaded and a
00086    pointer to them.  read() is called until the buffer is full, or until it
00087    returns end-of-file or error.  Return 0 on error. */
00088 local unsigned in(void *in_desc, unsigned char **buf)
00089 {
00090     int ret;
00091     unsigned len;
00092     unsigned char *next;
00093     struct ind *me = (struct ind *)in_desc;
00094 
00095     next = me->inbuf;
00096     *buf = next;
00097     len = 0;
00098     do {
00099         ret = PIECE;
00100         if ((unsigned)ret > SIZE - len)
00101             ret = (int)(SIZE - len);
00102         ret = (int)read(me->infile, next, ret);
00103         if (ret == -1) {
00104             len = 0;
00105             break;
00106         }
00107         next += ret;
00108         len += ret;
00109     } while (ret != 0 && len < SIZE);
00110     return len;
00111 }
00112 
00113 /* structure for infback() to pass to output function out() -- it maintains the
00114    output file, a running CRC-32 check on the output and the total number of
00115    bytes output, both for checking against the gzip trailer.  (The length in
00116    the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
00117    the output is greater than 4 GB.) */
00118 struct outd {
00119     int outfile;
00120     int check;                  /* true if checking crc and total */
00121     unsigned long crc;
00122     unsigned long total;
00123 };
00124 
00125 /* Write output buffer and update the CRC-32 and total bytes written.  write()
00126    is called until all of the output is written or an error is encountered.
00127    On success out() returns 0.  For a write failure, out() returns 1.  If the
00128    output file descriptor is -1, then nothing is written.
00129  */
00130 local int out(void *out_desc, unsigned char *buf, unsigned len)
00131 {
00132     int ret;
00133     struct outd *me = (struct outd *)out_desc;
00134 
00135     if (me->check) {
00136         me->crc = crc32(me->crc, buf, len);
00137         me->total += len;
00138     }
00139     if (me->outfile != -1)
00140         do {
00141             ret = PIECE;
00142             if ((unsigned)ret > len)
00143                 ret = (int)len;
00144             ret = (int)write(me->outfile, buf, ret);
00145             if (ret == -1)
00146                 return 1;
00147             buf += ret;
00148             len -= ret;
00149         } while (len != 0);
00150     return 0;
00151 }
00152 
00153 /* next input byte macro for use inside lunpipe() and gunpipe() */
00154 #define NEXT() (have ? 0 : (have = in(indp, &next)), \
00155                 last = have ? (have--, (int)(*next++)) : -1)
00156 
00157 /* memory for gunpipe() and lunpipe() --
00158    the first 256 entries of prefix[] and suffix[] are never used, could
00159    have offset the index, but it's faster to waste the memory */
00160 unsigned char inbuf[SIZE];              /* input buffer */
00161 unsigned char outbuf[SIZE];             /* output buffer */
00162 unsigned short prefix[65536];           /* index to LZW prefix string */
00163 unsigned char suffix[65536];            /* one-character LZW suffix */
00164 unsigned char match[65280 + 2];         /* buffer for reversed match or gzip
00165                                            32K sliding window */
00166 
00167 /* throw out what's left in the current bits byte buffer (this is a vestigial
00168    aspect of the compressed data format derived from an implementation that
00169    made use of a special VAX machine instruction!) */
00170 #define FLUSHCODE() \
00171     do { \
00172         left = 0; \
00173         rem = 0; \
00174         if (chunk > have) { \
00175             chunk -= have; \
00176             have = 0; \
00177             if (NEXT() == -1) \
00178                 break; \
00179             chunk--; \
00180             if (chunk > have) { \
00181                 chunk = have = 0; \
00182                 break; \
00183             } \
00184         } \
00185         have -= chunk; \
00186         next += chunk; \
00187         chunk = 0; \
00188     } while (0)
00189 
00190 /* Decompress a compress (LZW) file from indp to outfile.  The compress magic
00191    header (two bytes) has already been read and verified.  There are have bytes
00192    of buffered input at next.  strm is used for passing error information back
00193    to gunpipe().
00194 
00195    lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
00196    file, read error, or write error (a write error indicated by strm->next_in
00197    not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
00198  */
00199 local int lunpipe(unsigned have, unsigned char *next, struct ind *indp,
00200                   int outfile, z_stream *strm)
00201 {
00202     int last;                   /* last byte read by NEXT(), or -1 if EOF */
00203     unsigned chunk;             /* bytes left in current chunk */
00204     int left;                   /* bits left in rem */
00205     unsigned rem;               /* unused bits from input */
00206     int bits;                   /* current bits per code */
00207     unsigned code;              /* code, table traversal index */
00208     unsigned mask;              /* mask for current bits codes */
00209     int max;                    /* maximum bits per code for this stream */
00210     unsigned flags;             /* compress flags, then block compress flag */
00211     unsigned end;               /* last valid entry in prefix/suffix tables */
00212     unsigned temp;              /* current code */
00213     unsigned prev;              /* previous code */
00214     unsigned final;             /* last character written for previous code */
00215     unsigned stack;             /* next position for reversed string */
00216     unsigned outcnt;            /* bytes in output buffer */
00217     struct outd outd;           /* output structure */
00218     unsigned char *p;
00219 
00220     /* set up output */
00221     outd.outfile = outfile;
00222     outd.check = 0;
00223 
00224     /* process remainder of compress header -- a flags byte */
00225     flags = NEXT();
00226     if (last == -1)
00227         return Z_BUF_ERROR;
00228     if (flags & 0x60) {
00229         strm->msg = (char *)"unknown lzw flags set";
00230         return Z_DATA_ERROR;
00231     }
00232     max = flags & 0x1f;
00233     if (max < 9 || max > 16) {
00234         strm->msg = (char *)"lzw bits out of range";
00235         return Z_DATA_ERROR;
00236     }
00237     if (max == 9)                           /* 9 doesn't really mean 9 */
00238         max = 10;
00239     flags &= 0x80;                          /* true if block compress */
00240 
00241     /* clear table */
00242     bits = 9;
00243     mask = 0x1ff;
00244     end = flags ? 256 : 255;
00245 
00246     /* set up: get first 9-bit code, which is the first decompressed byte, but
00247        don't create a table entry until the next code */
00248     if (NEXT() == -1)                       /* no compressed data is ok */
00249         return Z_OK;
00250     final = prev = (unsigned)last;          /* low 8 bits of code */
00251     if (NEXT() == -1)                       /* missing a bit */
00252         return Z_BUF_ERROR;
00253     if (last & 1) {                         /* code must be < 256 */
00254         strm->msg = (char *)"invalid lzw code";
00255         return Z_DATA_ERROR;
00256     }
00257     rem = (unsigned)last >> 1;              /* remaining 7 bits */
00258     left = 7;
00259     chunk = bits - 2;                       /* 7 bytes left in this chunk */
00260     outbuf[0] = (unsigned char)final;       /* write first decompressed byte */
00261     outcnt = 1;
00262 
00263     /* decode codes */
00264     stack = 0;
00265     for (;;) {
00266         /* if the table will be full after this, increment the code size */
00267         if (end >= mask && bits < max) {
00268             FLUSHCODE();
00269             bits++;
00270             mask <<= 1;
00271             mask++;
00272         }
00273 
00274         /* get a code of length bits */
00275         if (chunk == 0)                     /* decrement chunk modulo bits */
00276             chunk = bits;
00277         code = rem;                         /* low bits of code */
00278         if (NEXT() == -1) {                 /* EOF is end of compressed data */
00279             /* write remaining buffered output */
00280             if (outcnt && out(&outd, outbuf, outcnt)) {
00281                 strm->next_in = outbuf;     /* signal write error */
00282                 return Z_BUF_ERROR;
00283             }
00284             return Z_OK;
00285         }
00286         code += (unsigned)last << left;     /* middle (or high) bits of code */
00287         left += 8;
00288         chunk--;
00289         if (bits > left) {                  /* need more bits */
00290             if (NEXT() == -1)               /* can't end in middle of code */
00291                 return Z_BUF_ERROR;
00292             code += (unsigned)last << left; /* high bits of code */
00293             left += 8;
00294             chunk--;
00295         }
00296         code &= mask;                       /* mask to current code length */
00297         left -= bits;                       /* number of unused bits */
00298         rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
00299 
00300         /* process clear code (256) */
00301         if (code == 256 && flags) {
00302             FLUSHCODE();
00303             bits = 9;                       /* initialize bits and mask */
00304             mask = 0x1ff;
00305             end = 255;                      /* empty table */
00306             continue;                       /* get next code */
00307         }
00308 
00309         /* special code to reuse last match */
00310         temp = code;                        /* save the current code */
00311         if (code > end) {
00312             /* Be picky on the allowed code here, and make sure that the code
00313                we drop through (prev) will be a valid index so that random
00314                input does not cause an exception.  The code != end + 1 check is
00315                empirically derived, and not checked in the original uncompress
00316                code.  If this ever causes a problem, that check could be safely
00317                removed.  Leaving this check in greatly improves gun's ability
00318                to detect random or corrupted input after a compress header.
00319                In any case, the prev > end check must be retained. */
00320             if (code != end + 1 || prev > end) {
00321                 strm->msg = (char *)"invalid lzw code";
00322                 return Z_DATA_ERROR;
00323             }
00324             match[stack++] = (unsigned char)final;
00325             code = prev;
00326         }
00327 
00328         /* walk through linked list to generate output in reverse order */
00329         p = match + stack;
00330         while (code >= 256) {
00331             *p++ = suffix[code];
00332             code = prefix[code];
00333         }
00334         stack = p - match;
00335         match[stack++] = (unsigned char)code;
00336         final = code;
00337 
00338         /* link new table entry */
00339         if (end < mask) {
00340             end++;
00341             prefix[end] = (unsigned short)prev;
00342             suffix[end] = (unsigned char)final;
00343         }
00344 
00345         /* set previous code for next iteration */
00346         prev = temp;
00347 
00348         /* write output in forward order */
00349         while (stack > SIZE - outcnt) {
00350             while (outcnt < SIZE)
00351                 outbuf[outcnt++] = match[--stack];
00352             if (out(&outd, outbuf, outcnt)) {
00353                 strm->next_in = outbuf; /* signal write error */
00354                 return Z_BUF_ERROR;
00355             }
00356             outcnt = 0;
00357         }
00358         p = match + stack;
00359         do {
00360             outbuf[outcnt++] = *--p;
00361         } while (p > match);
00362         stack = 0;
00363 
00364         /* loop for next code with final and prev as the last match, rem and
00365            left provide the first 0..7 bits of the next code, end is the last
00366            valid table entry */
00367     }
00368 }
00369 
00370 /* Decompress a gzip file from infile to outfile.  strm is assumed to have been
00371    successfully initialized with inflateBackInit().  The input file may consist
00372    of a series of gzip streams, in which case all of them will be decompressed
00373    to the output file.  If outfile is -1, then the gzip stream(s) integrity is
00374    checked and nothing is written.
00375 
00376    The return value is a zlib error code: Z_MEM_ERROR if out of memory,
00377    Z_DATA_ERROR if the header or the compressed data is invalid, or if the
00378    trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
00379    prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
00380    stream) follows a valid gzip stream.
00381  */
00382 local int gunpipe(z_stream *strm, int infile, int outfile)
00383 {
00384     int ret, first, last;
00385     unsigned have, flags, len;
00386     unsigned char *next = NULL;
00387     struct ind ind, *indp;
00388     struct outd outd;
00389 
00390     /* setup input buffer */
00391     ind.infile = infile;
00392     ind.inbuf = inbuf;
00393     indp = &ind;
00394 
00395     /* decompress concatenated gzip streams */
00396     have = 0;                               /* no input data read in yet */
00397     first = 1;                              /* looking for first gzip header */
00398     strm->next_in = Z_NULL;                 /* so Z_BUF_ERROR means EOF */
00399     for (;;) {
00400         /* look for the two magic header bytes for a gzip stream */
00401         if (NEXT() == -1) {
00402             ret = Z_OK;
00403             break;                          /* empty gzip stream is ok */
00404         }
00405         if (last != 31 || (NEXT() != 139 && last != 157)) {
00406             strm->msg = (char *)"incorrect header check";
00407             ret = first ? Z_DATA_ERROR : Z_ERRNO;
00408             break;                          /* not a gzip or compress header */
00409         }
00410         first = 0;                          /* next non-header is junk */
00411 
00412         /* process a compress (LZW) file -- can't be concatenated after this */
00413         if (last == 157) {
00414             ret = lunpipe(have, next, indp, outfile, strm);
00415             break;
00416         }
00417 
00418         /* process remainder of gzip header */
00419         ret = Z_BUF_ERROR;
00420         if (NEXT() != 8) {                  /* only deflate method allowed */
00421             if (last == -1) break;
00422             strm->msg = (char *)"unknown compression method";
00423             ret = Z_DATA_ERROR;
00424             break;
00425         }
00426         flags = NEXT();                     /* header flags */
00427         NEXT();                             /* discard mod time, xflgs, os */
00428         NEXT();
00429         NEXT();
00430         NEXT();
00431         NEXT();
00432         NEXT();
00433         if (last == -1) break;
00434         if (flags & 0xe0) {
00435             strm->msg = (char *)"unknown header flags set";
00436             ret = Z_DATA_ERROR;
00437             break;
00438         }
00439         if (flags & 4) {                    /* extra field */
00440             len = NEXT();
00441             len += (unsigned)(NEXT()) << 8;
00442             if (last == -1) break;
00443             while (len > have) {
00444                 len -= have;
00445                 have = 0;
00446                 if (NEXT() == -1) break;
00447                 len--;
00448             }
00449             if (last == -1) break;
00450             have -= len;
00451             next += len;
00452         }
00453         if (flags & 8)                      /* file name */
00454             while (NEXT() != 0 && last != -1)
00455                 ;
00456         if (flags & 16)                     /* comment */
00457             while (NEXT() != 0 && last != -1)
00458                 ;
00459         if (flags & 2) {                    /* header crc */
00460             NEXT();
00461             NEXT();
00462         }
00463         if (last == -1) break;
00464 
00465         /* set up output */
00466         outd.outfile = outfile;
00467         outd.check = 1;
00468         outd.crc = crc32(0L, Z_NULL, 0);
00469         outd.total = 0;
00470 
00471         /* decompress data to output */
00472         strm->next_in = next;
00473         strm->avail_in = have;
00474         ret = inflateBack(strm, in, indp, out, &outd);
00475         if (ret != Z_STREAM_END) break;
00476         next = strm->next_in;
00477         have = strm->avail_in;
00478         strm->next_in = Z_NULL;             /* so Z_BUF_ERROR means EOF */
00479 
00480         /* check trailer */
00481         ret = Z_BUF_ERROR;
00482         if (NEXT() != (int)(outd.crc & 0xff) ||
00483             NEXT() != (int)((outd.crc >> 8) & 0xff) ||
00484             NEXT() != (int)((outd.crc >> 16) & 0xff) ||
00485             NEXT() != (int)((outd.crc >> 24) & 0xff)) {
00486             /* crc error */
00487             if (last != -1) {
00488                 strm->msg = (char *)"incorrect data check";
00489                 ret = Z_DATA_ERROR;
00490             }
00491             break;
00492         }
00493         if (NEXT() != (int)(outd.total & 0xff) ||
00494             NEXT() != (int)((outd.total >> 8) & 0xff) ||
00495             NEXT() != (int)((outd.total >> 16) & 0xff) ||
00496             NEXT() != (int)((outd.total >> 24) & 0xff)) {
00497             /* length error */
00498             if (last != -1) {
00499                 strm->msg = (char *)"incorrect length check";
00500                 ret = Z_DATA_ERROR;
00501             }
00502             break;
00503         }
00504 
00505         /* go back and look for another gzip stream */
00506     }
00507 
00508     /* clean up and return */
00509     return ret;
00510 }
00511 
00512 /* Copy file attributes, from -> to, as best we can.  This is best effort, so
00513    no errors are reported.  The mode bits, including suid, sgid, and the sticky
00514    bit are copied (if allowed), the owner's user id and group id are copied
00515    (again if allowed), and the access and modify times are copied. */
00516 local void copymeta(char *from, char *to)
00517 {
00518     struct stat was;
00519     struct utimbuf when;
00520 
00521     /* get all of from's Unix meta data, return if not a regular file */
00522     if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
00523         return;
00524 
00525     /* set to's mode bits, ignore errors */
00526     (void)chmod(to, was.st_mode & 07777);
00527 
00528     /* copy owner's user and group, ignore errors */
00529     (void)chown(to, was.st_uid, was.st_gid);
00530 
00531     /* copy access and modify times, ignore errors */
00532     when.actime = was.st_atime;
00533     when.modtime = was.st_mtime;
00534     (void)utime(to, &when);
00535 }
00536 
00537 /* Decompress the file inname to the file outnname, of if test is true, just
00538    decompress without writing and check the gzip trailer for integrity.  If
00539    inname is NULL or an empty string, read from stdin.  If outname is NULL or
00540    an empty string, write to stdout.  strm is a pre-initialized inflateBack
00541    structure.  When appropriate, copy the file attributes from inname to
00542    outname.
00543 
00544    gunzip() returns 1 if there is an out-of-memory error or an unexpected
00545    return code from gunpipe().  Otherwise it returns 0.
00546  */
00547 local int gunzip(z_stream *strm, char *inname, char *outname, int test)
00548 {
00549     int ret;
00550     int infile, outfile;
00551 
00552     /* open files */
00553     if (inname == NULL || *inname == 0) {
00554         inname = "-";
00555         infile = 0;     /* stdin */
00556     }
00557     else {
00558         infile = open(inname, O_RDONLY, 0);
00559         if (infile == -1) {
00560             fprintf(stderr, "gun cannot open %s\n", inname);
00561             return 0;
00562         }
00563     }
00564     if (test)
00565         outfile = -1;
00566     else if (outname == NULL || *outname == 0) {
00567         outname = "-";
00568         outfile = 1;    /* stdout */
00569     }
00570     else {
00571         outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
00572         if (outfile == -1) {
00573             close(infile);
00574             fprintf(stderr, "gun cannot create %s\n", outname);
00575             return 0;
00576         }
00577     }
00578     errno = 0;
00579 
00580     /* decompress */
00581     ret = gunpipe(strm, infile, outfile);
00582     if (outfile > 2) close(outfile);
00583     if (infile > 2) close(infile);
00584 
00585     /* interpret result */
00586     switch (ret) {
00587     case Z_OK:
00588     case Z_ERRNO:
00589         if (infile > 2 && outfile > 2) {
00590             copymeta(inname, outname);          /* copy attributes */
00591             unlink(inname);
00592         }
00593         if (ret == Z_ERRNO)
00594             fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
00595                     inname);
00596         break;
00597     case Z_DATA_ERROR:
00598         if (outfile > 2) unlink(outname);
00599         fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
00600         break;
00601     case Z_MEM_ERROR:
00602         if (outfile > 2) unlink(outname);
00603         fprintf(stderr, "gun out of memory error--aborting\n");
00604         return 1;
00605     case Z_BUF_ERROR:
00606         if (outfile > 2) unlink(outname);
00607         if (strm->next_in != Z_NULL) {
00608             fprintf(stderr, "gun write error on %s: %s\n",
00609                     outname, strerror(errno));
00610         }
00611         else if (errno) {
00612             fprintf(stderr, "gun read error on %s: %s\n",
00613                     inname, strerror(errno));
00614         }
00615         else {
00616             fprintf(stderr, "gun unexpected end of file on %s\n",
00617                     inname);
00618         }
00619         break;
00620     default:
00621         if (outfile > 2) unlink(outname);
00622         fprintf(stderr, "gun internal error--aborting\n");
00623         return 1;
00624     }
00625     return 0;
00626 }
00627 
00628 /* Process the gun command line arguments.  See the command syntax near the
00629    beginning of this source file. */
00630 int main(int argc, char **argv)
00631 {
00632     int ret, len, test;
00633     char *outname;
00634     unsigned char *window;
00635     z_stream strm;
00636 
00637     /* initialize inflateBack state for repeated use */
00638     window = match;                         /* reuse LZW match buffer */
00639     strm.zalloc = Z_NULL;
00640     strm.zfree = Z_NULL;
00641     strm.opaque = Z_NULL;
00642     ret = inflateBackInit(&strm, 15, window);
00643     if (ret != Z_OK) {
00644         fprintf(stderr, "gun out of memory error--aborting\n");
00645         return 1;
00646     }
00647 
00648     /* decompress each file to the same name with the suffix removed */
00649     argc--;
00650     argv++;
00651     test = 0;
00652     if (argc && strcmp(*argv, "-h") == 0) {
00653         fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
00654         fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
00655         fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
00656         return 0;
00657     }
00658     if (argc && strcmp(*argv, "-t") == 0) {
00659         test = 1;
00660         argc--;
00661         argv++;
00662     }
00663     if (argc)
00664         do {
00665             if (test)
00666                 outname = NULL;
00667             else {
00668                 len = (int)strlen(*argv);
00669                 if (strcmp(*argv + len - 3, ".gz") == 0 ||
00670                     strcmp(*argv + len - 3, "-gz") == 0)
00671                     len -= 3;
00672                 else if (strcmp(*argv + len - 2, ".z") == 0 ||
00673                     strcmp(*argv + len - 2, "-z") == 0 ||
00674                     strcmp(*argv + len - 2, "_z") == 0 ||
00675                     strcmp(*argv + len - 2, ".Z") == 0)
00676                     len -= 2;
00677                 else {
00678                     fprintf(stderr, "gun error: no gz type on %s--skipping\n",
00679                             *argv);
00680                     continue;
00681                 }
00682                 outname = malloc(len + 1);
00683                 if (outname == NULL) {
00684                     fprintf(stderr, "gun out of memory error--aborting\n");
00685                     ret = 1;
00686                     break;
00687                 }
00688                 memcpy(outname, *argv, len);
00689                 outname[len] = 0;
00690             }
00691             ret = gunzip(&strm, *argv, outname, test);
00692             if (outname != NULL) free(outname);
00693             if (ret) break;
00694         } while (argv++, --argc);
00695     else
00696         ret = gunzip(&strm, NULL, NULL, test);
00697 
00698     /* clean up */
00699     inflateBackEnd(&strm);
00700     return ret;
00701 }

Generated on Wed Oct 20 2010 11:12:17 for APBS by  doxygen 1.7.2