1275793eaSopenharmony_ci/* zpipe.c: example of proper use of zlib's inflate() and deflate() 2275793eaSopenharmony_ci Not copyrighted -- provided to the public domain 3275793eaSopenharmony_ci Version 1.4 11 December 2005 Mark Adler */ 4275793eaSopenharmony_ci 5275793eaSopenharmony_ci/* Version history: 6275793eaSopenharmony_ci 1.0 30 Oct 2004 First version 7275793eaSopenharmony_ci 1.1 8 Nov 2004 Add void casting for unused return values 8275793eaSopenharmony_ci Use switch statement for inflate() return values 9275793eaSopenharmony_ci 1.2 9 Nov 2004 Add assertions to document zlib guarantees 10275793eaSopenharmony_ci 1.3 6 Apr 2005 Remove incorrect assertion in inf() 11275793eaSopenharmony_ci 1.4 11 Dec 2005 Add hack to avoid MSDOS end-of-line conversions 12275793eaSopenharmony_ci Avoid some compiler warnings for input and output buffers 13275793eaSopenharmony_ci */ 14275793eaSopenharmony_ci 15275793eaSopenharmony_ci#include <stdio.h> 16275793eaSopenharmony_ci#include <string.h> 17275793eaSopenharmony_ci#include <assert.h> 18275793eaSopenharmony_ci#include "zlib.h" 19275793eaSopenharmony_ci 20275793eaSopenharmony_ci#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) 21275793eaSopenharmony_ci# include <fcntl.h> 22275793eaSopenharmony_ci# include <io.h> 23275793eaSopenharmony_ci# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) 24275793eaSopenharmony_ci#else 25275793eaSopenharmony_ci# define SET_BINARY_MODE(file) 26275793eaSopenharmony_ci#endif 27275793eaSopenharmony_ci 28275793eaSopenharmony_ci#define CHUNK 16384 29275793eaSopenharmony_ci 30275793eaSopenharmony_ci/* Compress from file source to file dest until EOF on source. 31275793eaSopenharmony_ci def() returns Z_OK on success, Z_MEM_ERROR if memory could not be 32275793eaSopenharmony_ci allocated for processing, Z_STREAM_ERROR if an invalid compression 33275793eaSopenharmony_ci level is supplied, Z_VERSION_ERROR if the version of zlib.h and the 34275793eaSopenharmony_ci version of the library linked do not match, or Z_ERRNO if there is 35275793eaSopenharmony_ci an error reading or writing the files. */ 36275793eaSopenharmony_ciint def(FILE *source, FILE *dest, int level) 37275793eaSopenharmony_ci{ 38275793eaSopenharmony_ci int ret, flush; 39275793eaSopenharmony_ci unsigned have; 40275793eaSopenharmony_ci z_stream strm; 41275793eaSopenharmony_ci unsigned char in[CHUNK]; 42275793eaSopenharmony_ci unsigned char out[CHUNK]; 43275793eaSopenharmony_ci 44275793eaSopenharmony_ci /* allocate deflate state */ 45275793eaSopenharmony_ci strm.zalloc = Z_NULL; 46275793eaSopenharmony_ci strm.zfree = Z_NULL; 47275793eaSopenharmony_ci strm.opaque = Z_NULL; 48275793eaSopenharmony_ci ret = deflateInit(&strm, level); 49275793eaSopenharmony_ci if (ret != Z_OK) 50275793eaSopenharmony_ci return ret; 51275793eaSopenharmony_ci 52275793eaSopenharmony_ci /* compress until end of file */ 53275793eaSopenharmony_ci do { 54275793eaSopenharmony_ci strm.avail_in = fread(in, 1, CHUNK, source); 55275793eaSopenharmony_ci if (ferror(source)) { 56275793eaSopenharmony_ci (void)deflateEnd(&strm); 57275793eaSopenharmony_ci return Z_ERRNO; 58275793eaSopenharmony_ci } 59275793eaSopenharmony_ci flush = feof(source) ? Z_FINISH : Z_NO_FLUSH; 60275793eaSopenharmony_ci strm.next_in = in; 61275793eaSopenharmony_ci 62275793eaSopenharmony_ci /* run deflate() on input until output buffer not full, finish 63275793eaSopenharmony_ci compression if all of source has been read in */ 64275793eaSopenharmony_ci do { 65275793eaSopenharmony_ci strm.avail_out = CHUNK; 66275793eaSopenharmony_ci strm.next_out = out; 67275793eaSopenharmony_ci ret = deflate(&strm, flush); /* no bad return value */ 68275793eaSopenharmony_ci assert(ret != Z_STREAM_ERROR); /* state not clobbered */ 69275793eaSopenharmony_ci have = CHUNK - strm.avail_out; 70275793eaSopenharmony_ci if (fwrite(out, 1, have, dest) != have || ferror(dest)) { 71275793eaSopenharmony_ci (void)deflateEnd(&strm); 72275793eaSopenharmony_ci return Z_ERRNO; 73275793eaSopenharmony_ci } 74275793eaSopenharmony_ci } while (strm.avail_out == 0); 75275793eaSopenharmony_ci assert(strm.avail_in == 0); /* all input will be used */ 76275793eaSopenharmony_ci 77275793eaSopenharmony_ci /* done when last data in file processed */ 78275793eaSopenharmony_ci } while (flush != Z_FINISH); 79275793eaSopenharmony_ci assert(ret == Z_STREAM_END); /* stream will be complete */ 80275793eaSopenharmony_ci 81275793eaSopenharmony_ci /* clean up and return */ 82275793eaSopenharmony_ci (void)deflateEnd(&strm); 83275793eaSopenharmony_ci return Z_OK; 84275793eaSopenharmony_ci} 85275793eaSopenharmony_ci 86275793eaSopenharmony_ci/* Decompress from file source to file dest until stream ends or EOF. 87275793eaSopenharmony_ci inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be 88275793eaSopenharmony_ci allocated for processing, Z_DATA_ERROR if the deflate data is 89275793eaSopenharmony_ci invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and 90275793eaSopenharmony_ci the version of the library linked do not match, or Z_ERRNO if there 91275793eaSopenharmony_ci is an error reading or writing the files. */ 92275793eaSopenharmony_ciint inf(FILE *source, FILE *dest) 93275793eaSopenharmony_ci{ 94275793eaSopenharmony_ci int ret; 95275793eaSopenharmony_ci unsigned have; 96275793eaSopenharmony_ci z_stream strm; 97275793eaSopenharmony_ci unsigned char in[CHUNK]; 98275793eaSopenharmony_ci unsigned char out[CHUNK]; 99275793eaSopenharmony_ci 100275793eaSopenharmony_ci /* allocate inflate state */ 101275793eaSopenharmony_ci strm.zalloc = Z_NULL; 102275793eaSopenharmony_ci strm.zfree = Z_NULL; 103275793eaSopenharmony_ci strm.opaque = Z_NULL; 104275793eaSopenharmony_ci strm.avail_in = 0; 105275793eaSopenharmony_ci strm.next_in = Z_NULL; 106275793eaSopenharmony_ci ret = inflateInit(&strm); 107275793eaSopenharmony_ci if (ret != Z_OK) 108275793eaSopenharmony_ci return ret; 109275793eaSopenharmony_ci 110275793eaSopenharmony_ci /* decompress until deflate stream ends or end of file */ 111275793eaSopenharmony_ci do { 112275793eaSopenharmony_ci strm.avail_in = fread(in, 1, CHUNK, source); 113275793eaSopenharmony_ci if (ferror(source)) { 114275793eaSopenharmony_ci (void)inflateEnd(&strm); 115275793eaSopenharmony_ci return Z_ERRNO; 116275793eaSopenharmony_ci } 117275793eaSopenharmony_ci if (strm.avail_in == 0) 118275793eaSopenharmony_ci break; 119275793eaSopenharmony_ci strm.next_in = in; 120275793eaSopenharmony_ci 121275793eaSopenharmony_ci /* run inflate() on input until output buffer not full */ 122275793eaSopenharmony_ci do { 123275793eaSopenharmony_ci strm.avail_out = CHUNK; 124275793eaSopenharmony_ci strm.next_out = out; 125275793eaSopenharmony_ci ret = inflate(&strm, Z_NO_FLUSH); 126275793eaSopenharmony_ci assert(ret != Z_STREAM_ERROR); /* state not clobbered */ 127275793eaSopenharmony_ci switch (ret) { 128275793eaSopenharmony_ci case Z_NEED_DICT: 129275793eaSopenharmony_ci ret = Z_DATA_ERROR; /* and fall through */ 130275793eaSopenharmony_ci case Z_DATA_ERROR: 131275793eaSopenharmony_ci case Z_MEM_ERROR: 132275793eaSopenharmony_ci (void)inflateEnd(&strm); 133275793eaSopenharmony_ci return ret; 134275793eaSopenharmony_ci } 135275793eaSopenharmony_ci have = CHUNK - strm.avail_out; 136275793eaSopenharmony_ci if (fwrite(out, 1, have, dest) != have || ferror(dest)) { 137275793eaSopenharmony_ci (void)inflateEnd(&strm); 138275793eaSopenharmony_ci return Z_ERRNO; 139275793eaSopenharmony_ci } 140275793eaSopenharmony_ci } while (strm.avail_out == 0); 141275793eaSopenharmony_ci 142275793eaSopenharmony_ci /* done when inflate() says it's done */ 143275793eaSopenharmony_ci } while (ret != Z_STREAM_END); 144275793eaSopenharmony_ci 145275793eaSopenharmony_ci /* clean up and return */ 146275793eaSopenharmony_ci (void)inflateEnd(&strm); 147275793eaSopenharmony_ci return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; 148275793eaSopenharmony_ci} 149275793eaSopenharmony_ci 150275793eaSopenharmony_ci/* report a zlib or i/o error */ 151275793eaSopenharmony_civoid zerr(int ret) 152275793eaSopenharmony_ci{ 153275793eaSopenharmony_ci fputs("zpipe: ", stderr); 154275793eaSopenharmony_ci switch (ret) { 155275793eaSopenharmony_ci case Z_ERRNO: 156275793eaSopenharmony_ci if (ferror(stdin)) 157275793eaSopenharmony_ci fputs("error reading stdin\n", stderr); 158275793eaSopenharmony_ci if (ferror(stdout)) 159275793eaSopenharmony_ci fputs("error writing stdout\n", stderr); 160275793eaSopenharmony_ci break; 161275793eaSopenharmony_ci case Z_STREAM_ERROR: 162275793eaSopenharmony_ci fputs("invalid compression level\n", stderr); 163275793eaSopenharmony_ci break; 164275793eaSopenharmony_ci case Z_DATA_ERROR: 165275793eaSopenharmony_ci fputs("invalid or incomplete deflate data\n", stderr); 166275793eaSopenharmony_ci break; 167275793eaSopenharmony_ci case Z_MEM_ERROR: 168275793eaSopenharmony_ci fputs("out of memory\n", stderr); 169275793eaSopenharmony_ci break; 170275793eaSopenharmony_ci case Z_VERSION_ERROR: 171275793eaSopenharmony_ci fputs("zlib version mismatch!\n", stderr); 172275793eaSopenharmony_ci } 173275793eaSopenharmony_ci} 174275793eaSopenharmony_ci 175275793eaSopenharmony_ci/* compress or decompress from stdin to stdout */ 176275793eaSopenharmony_ciint main(int argc, char **argv) 177275793eaSopenharmony_ci{ 178275793eaSopenharmony_ci int ret; 179275793eaSopenharmony_ci 180275793eaSopenharmony_ci /* avoid end-of-line conversions */ 181275793eaSopenharmony_ci SET_BINARY_MODE(stdin); 182275793eaSopenharmony_ci SET_BINARY_MODE(stdout); 183275793eaSopenharmony_ci 184275793eaSopenharmony_ci /* do compression if no arguments */ 185275793eaSopenharmony_ci if (argc == 1) { 186275793eaSopenharmony_ci ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION); 187275793eaSopenharmony_ci if (ret != Z_OK) 188275793eaSopenharmony_ci zerr(ret); 189275793eaSopenharmony_ci return ret; 190275793eaSopenharmony_ci } 191275793eaSopenharmony_ci 192275793eaSopenharmony_ci /* do decompression if -d specified */ 193275793eaSopenharmony_ci else if (argc == 2 && strcmp(argv[1], "-d") == 0) { 194275793eaSopenharmony_ci ret = inf(stdin, stdout); 195275793eaSopenharmony_ci if (ret != Z_OK) 196275793eaSopenharmony_ci zerr(ret); 197275793eaSopenharmony_ci return ret; 198275793eaSopenharmony_ci } 199275793eaSopenharmony_ci 200275793eaSopenharmony_ci /* otherwise, report usage */ 201275793eaSopenharmony_ci else { 202275793eaSopenharmony_ci fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr); 203275793eaSopenharmony_ci return 1; 204275793eaSopenharmony_ci } 205275793eaSopenharmony_ci} 206