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