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