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