1 /* zpipe.c: example of proper use of zlib's inflate() and deflate()
   2    Not copyrighted -- provided to the public domain
   3    Version 1.4  11 December 2005  Mark Adler */
   4 
   5 /* Version history:
   6    1.0  30 Oct 2004  First version
   7    1.1   8 Nov 2004  Add void casting for unused return values
   8                      Use switch statement for inflate() return values
   9    1.2   9 Nov 2004  Add assertions to document zlib guarantees
  10    1.3   6 Apr 2005  Remove incorrect assertion in inf()
  11    1.4  11 Dec 2005  Add hack to avoid MSDOS end-of-line conversions
  12                      Avoid some compiler warnings for input and output buffers
  13  */
  14 
  15 #include <stdio.h>
  16 #include <string.h>
  17 #include <assert.h>
  18 #include "zlib.h"
  19 
  20 #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
  21 #  include <fcntl.h>
  22 #  include <io.h>
  23 #  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
  24 #else
  25 #  define SET_BINARY_MODE(file)
  26 #endif
  27 
  28 #define CHUNK 16384
  29 
  30 /* Compress from file source to file dest until EOF on source.
  31    def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
  32    allocated for processing, Z_STREAM_ERROR if an invalid compression
  33    level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
  34    version of the library linked do not match, or Z_ERRNO if there is
  35    an error reading or writing the files. */
  36 int def(FILE *source, FILE *dest, int level)
  37 {
  38     int ret, flush;
  39     unsigned have;
  40     z_stream strm;
  41     unsigned char in[CHUNK];
  42     unsigned char out[CHUNK];
  43 
  44     /* allocate deflate state */
  45     strm.zalloc = Z_NULL;
  46     strm.zfree = Z_NULL;
  47     strm.opaque = Z_NULL;
  48     ret = deflateInit(&strm, level);
  49     if (ret != Z_OK)
  50         return ret;
  51 
  52     /* compress until end of file */
  53     do {
  54         strm.avail_in = fread(in, 1, CHUNK, source);
  55         if (ferror(source)) {
  56             (void)deflateEnd(&strm);
  57             return Z_ERRNO;
  58         }
  59         flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
  60         strm.next_in = in;
  61 
  62         /* run deflate() on input until output buffer not full, finish
  63            compression if all of source has been read in */
  64         do {
  65             strm.avail_out = CHUNK;
  66             strm.next_out = out;
  67             ret = deflate(&strm, flush);    /* no bad return value */
  68             assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
  69             have = CHUNK - strm.avail_out;
  70             if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
  71                 (void)deflateEnd(&strm);
  72                 return Z_ERRNO;
  73             }
  74         } while (strm.avail_out == 0);
  75         assert(strm.avail_in == 0);     /* all input will be used */
  76 
  77         /* done when last data in file processed */
  78     } while (flush != Z_FINISH);
  79     assert(ret == Z_STREAM_END);        /* stream will be complete */
  80 
  81     /* clean up and return */
  82     (void)deflateEnd(&strm);
  83     return Z_OK;
  84 }
  85 
  86 /* Decompress from file source to file dest until stream ends or EOF.
  87    inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
  88    allocated for processing, Z_DATA_ERROR if the deflate data is
  89    invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
  90    the version of the library linked do not match, or Z_ERRNO if there
  91    is an error reading or writing the files. */
  92 int inf(FILE *source, FILE *dest)
  93 {
  94     int ret;
  95     unsigned have;
  96     z_stream strm;
  97     unsigned char in[CHUNK];
  98     unsigned char out[CHUNK];
  99 
 100     /* allocate inflate state */
 101     strm.zalloc = Z_NULL;
 102     strm.zfree = Z_NULL;
 103     strm.opaque = Z_NULL;
 104     strm.avail_in = 0;
 105     strm.next_in = Z_NULL;
 106     ret = inflateInit(&strm);
 107     if (ret != Z_OK)
 108         return ret;
 109 
 110     /* decompress until deflate stream ends or end of file */
 111     do {
 112         strm.avail_in = fread(in, 1, CHUNK, source);
 113         if (ferror(source)) {
 114             (void)inflateEnd(&strm);
 115             return Z_ERRNO;
 116         }
 117         if (strm.avail_in == 0)
 118             break;
 119         strm.next_in = in;
 120 
 121         /* run inflate() on input until output buffer not full */
 122         do {
 123             strm.avail_out = CHUNK;
 124             strm.next_out = out;
 125             ret = inflate(&strm, Z_NO_FLUSH);
 126             assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
 127             switch (ret) {
 128             case Z_NEED_DICT:
 129                 ret = Z_DATA_ERROR;     /* and fall through */
 130             case Z_DATA_ERROR:
 131             case Z_MEM_ERROR:
 132                 (void)inflateEnd(&strm);
 133                 return ret;
 134             }
 135             have = CHUNK - strm.avail_out;
 136             if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
 137                 (void)inflateEnd(&strm);
 138                 return Z_ERRNO;
 139             }
 140         } while (strm.avail_out == 0);
 141 
 142         /* done when inflate() says it's done */
 143     } while (ret != Z_STREAM_END);
 144 
 145     /* clean up and return */
 146     (void)inflateEnd(&strm);
 147     return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
 148 }
 149 
 150 /* report a zlib or i/o error */
 151 void zerr(int ret)
 152 {
 153     fputs("zpipe: ", stderr);
 154     switch (ret) {
 155     case Z_ERRNO:
 156         if (ferror(stdin))
 157             fputs("error reading stdin\n", stderr);
 158         if (ferror(stdout))
 159             fputs("error writing stdout\n", stderr);
 160         break;
 161     case Z_STREAM_ERROR:
 162         fputs("invalid compression level\n", stderr);
 163         break;
 164     case Z_DATA_ERROR:
 165         fputs("invalid or incomplete deflate data\n", stderr);
 166         break;
 167     case Z_MEM_ERROR:
 168         fputs("out of memory\n", stderr);
 169         break;
 170     case Z_VERSION_ERROR:
 171         fputs("zlib version mismatch!\n", stderr);
 172     }
 173 }
 174 
 175 /* compress or decompress from stdin to stdout */
 176 int main(int argc, char **argv)
 177 {
 178     int ret;
 179 
 180     /* avoid end-of-line conversions */
 181     SET_BINARY_MODE(stdin);
 182     SET_BINARY_MODE(stdout);
 183 
 184     /* do compression if no arguments */
 185     if (argc == 1) {
 186         ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
 187         if (ret != Z_OK)
 188             zerr(ret);
 189         return ret;
 190     }
 191 
 192     /* do decompression if -d specified */
 193     else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
 194         ret = inf(stdin, stdout);
 195         if (ret != Z_OK)
 196             zerr(ret);
 197         return ret;
 198     }
 199 
 200     /* otherwise, report usage */
 201     else {
 202         fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
 203         return 1;
 204     }
 205 }