~ubuntu-branches/debian/jessie/smplayer/jessie

« back to all changes in this revision

Viewing changes to zlib-1.2.6/examples/gun.c

  • Committer: Package Import Robot
  • Author(s): Alessio Treglia
  • Date: 2013-10-08 12:51:23 UTC
  • mfrom: (1.3.1) (21.1.2 experimental)
  • Revision ID: package-import@ubuntu.com-20131008125123-b3n39yi2i7dxvq5p
Tags: 0.8.6-1
* Team upload.
* Upload to unstable.
* New upstream release.
* Refresh patches.
* Fix VCS urls to meet the canonical form.

Show diffs side-by-side

added added

removed removed

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