1 /* mz_strm_zlib.c -- Stream for zlib inflate/deflate
2 Version 2.8.1, December 1, 2018
3 part of the MiniZip project
4
5 Copyright (C) 2010-2018 Nathan Moinvaziri
6 https://github.com/nmoinvaz/minizip
7
8 This program is distributed under the terms of the same license as zlib.
9 See the accompanying LICENSE file for the full text of the license.
10 */
11
12
13 #include "mz.h"
14 #include "mz_strm.h"
15 #include "mz_strm_zlib.h"
16
17 #include "zlib.h"
18
19 /***************************************************************************/
20
21 #ifndef DEF_MEM_LEVEL
22 # if MAX_MEM_LEVEL >= 8
23 # define DEF_MEM_LEVEL 8
24 # else
25 # define DEF_MEM_LEVEL MAX_MEM_LEVEL
26 # endif
27 #endif
28
29 /***************************************************************************/
30
31 static mz_stream_vtbl mz_stream_zlib_vtbl = {
32 mz_stream_zlib_open,
33 mz_stream_zlib_is_open,
34 mz_stream_zlib_read,
35 mz_stream_zlib_write,
36 mz_stream_zlib_tell,
37 mz_stream_zlib_seek,
38 mz_stream_zlib_close,
39 mz_stream_zlib_error,
40 mz_stream_zlib_create,
41 mz_stream_zlib_delete,
42 mz_stream_zlib_get_prop_int64,
43 mz_stream_zlib_set_prop_int64
44 };
45
46 /***************************************************************************/
47
48 typedef struct mz_stream_zlib_s {
49 mz_stream stream;
50 z_stream zstream;
51 uint8_t buffer[INT16_MAX];
52 int32_t buffer_len;
53 int64_t total_in;
54 int64_t total_out;
55 int64_t max_total_in;
56 int8_t initialized;
57 int16_t level;
58 int32_t mode;
59 int32_t error;
60 } mz_stream_zlib;
61
62 /***************************************************************************/
63
mz_stream_zlib_open(void * stream,const char * path,int32_t mode)64 int32_t mz_stream_zlib_open(void *stream, const char *path, int32_t mode)
65 {
66 mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
67
68 MZ_UNUSED(path);
69
70 zlib->zstream.data_type = Z_BINARY;
71 zlib->zstream.zalloc = Z_NULL;
72 zlib->zstream.zfree = Z_NULL;
73 zlib->zstream.opaque = Z_NULL;
74 zlib->zstream.total_in = 0;
75 zlib->zstream.total_out = 0;
76
77 zlib->total_in = 0;
78 zlib->total_out = 0;
79
80 if (mode & MZ_OPEN_MODE_WRITE)
81 {
82 #ifdef MZ_ZIP_NO_COMPRESSION
83 return MZ_SUPPORT_ERROR;
84 #else
85 zlib->zstream.next_out = zlib->buffer;
86 zlib->zstream.avail_out = sizeof(zlib->buffer);
87
88 zlib->error = deflateInit2(&zlib->zstream, (int8_t)zlib->level, Z_DEFLATED,
89 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
90 #endif
91 }
92 else if (mode & MZ_OPEN_MODE_READ)
93 {
94 #ifdef MZ_ZIP_NO_DECOMPRESSION
95 return MZ_SUPPORT_ERROR;
96 #else
97 zlib->zstream.next_in = zlib->buffer;
98 zlib->zstream.avail_in = 0;
99
100 zlib->error = inflateInit2(&zlib->zstream, -MAX_WBITS);
101 #endif
102 }
103
104 if (zlib->error != Z_OK)
105 return MZ_OPEN_ERROR;
106
107 zlib->initialized = 1;
108 zlib->mode = mode;
109 return MZ_OK;
110 }
111
mz_stream_zlib_is_open(void * stream)112 int32_t mz_stream_zlib_is_open(void *stream)
113 {
114 mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
115 if (zlib->initialized != 1)
116 return MZ_OPEN_ERROR;
117 return MZ_OK;
118 }
119
mz_stream_zlib_read(void * stream,void * buf,int32_t size)120 int32_t mz_stream_zlib_read(void *stream, void *buf, int32_t size)
121 {
122 #ifdef MZ_ZIP_NO_DECOMPRESSION
123 MZ_UNUSED(stream);
124 MZ_UNUSED(buf);
125 MZ_UNUSED(size);
126 return MZ_SUPPORT_ERROR;
127 #else
128 mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
129 uint64_t total_in_before = 0;
130 uint64_t total_in_after = 0;
131 uint64_t total_out_before = 0;
132 uint64_t total_out_after = 0;
133 uint32_t total_in = 0;
134 uint32_t total_out = 0;
135 uint32_t in_bytes = 0;
136 uint32_t out_bytes = 0;
137 int32_t bytes_to_read = sizeof(zlib->buffer);
138 int32_t read = 0;
139 int32_t err = Z_OK;
140
141
142 zlib->zstream.next_out = (Bytef*)buf;
143 zlib->zstream.avail_out = (uInt)size;
144
145 do
146 {
147 if (zlib->zstream.avail_in == 0)
148 {
149 if (zlib->max_total_in > 0)
150 {
151 if ((int64_t)bytes_to_read > (zlib->max_total_in - zlib->total_in))
152 bytes_to_read = (int32_t)(zlib->max_total_in - zlib->total_in);
153 }
154
155 read = mz_stream_read(zlib->stream.base, zlib->buffer, bytes_to_read);
156
157 if (read < 0)
158 return read;
159 if (read == 0)
160 break;
161
162 zlib->zstream.next_in = zlib->buffer;
163 zlib->zstream.avail_in = read;
164 }
165
166 total_in_before = zlib->zstream.avail_in;
167 total_out_before = zlib->zstream.total_out;
168
169 err = inflate(&zlib->zstream, Z_SYNC_FLUSH);
170 if ((err >= Z_OK) && (zlib->zstream.msg != NULL))
171 {
172 zlib->error = Z_DATA_ERROR;
173 break;
174 }
175
176 total_in_after = zlib->zstream.avail_in;
177 total_out_after = zlib->zstream.total_out;
178
179 in_bytes = (uint32_t)(total_in_before - total_in_after);
180 out_bytes = (uint32_t)(total_out_after - total_out_before);
181
182 total_in += in_bytes;
183 total_out += out_bytes;
184
185 zlib->total_in += in_bytes;
186 zlib->total_out += out_bytes;
187
188 if (err == Z_STREAM_END)
189 break;
190 if (err != Z_OK)
191 {
192 zlib->error = err;
193 break;
194 }
195 }
196 while (zlib->zstream.avail_out > 0);
197
198 if (zlib->error != 0)
199 {
200 /* Zlib errors are compatible with MZ */
201 return zlib->error;
202 }
203
204 return total_out;
205 #endif
206 }
207
208 #ifndef MZ_ZIP_NO_COMPRESSION
mz_stream_zlib_flush(void * stream)209 static int32_t mz_stream_zlib_flush(void *stream)
210 {
211 mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
212 if (mz_stream_write(zlib->stream.base, zlib->buffer, zlib->buffer_len) != zlib->buffer_len)
213 return MZ_WRITE_ERROR;
214 return MZ_OK;
215 }
216
mz_stream_zlib_deflate(void * stream,int flush)217 static int32_t mz_stream_zlib_deflate(void *stream, int flush)
218 {
219 mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
220 uint64_t total_out_before = 0;
221 uint64_t total_out_after = 0;
222 int32_t out_bytes = 0;
223 int32_t err = Z_OK;
224
225
226 do
227 {
228 if (zlib->zstream.avail_out == 0)
229 {
230 err = mz_stream_zlib_flush(zlib);
231 if (err != MZ_OK)
232 return err;
233
234 zlib->zstream.avail_out = sizeof(zlib->buffer);
235 zlib->zstream.next_out = zlib->buffer;
236
237 zlib->buffer_len = 0;
238 }
239
240 total_out_before = zlib->zstream.total_out;
241 err = deflate(&zlib->zstream, flush);
242 total_out_after = zlib->zstream.total_out;
243
244 out_bytes = (uint32_t)(total_out_after - total_out_before);
245
246 zlib->buffer_len += out_bytes;
247 zlib->total_out += out_bytes;
248
249 if (err == Z_STREAM_END)
250 break;
251 if (err != Z_OK)
252 {
253 zlib->error = err;
254 return MZ_DATA_ERROR;
255 }
256 }
257 while ((zlib->zstream.avail_in > 0) || (flush == Z_FINISH && err == Z_OK));
258
259 return MZ_OK;
260 }
261 #endif
262
mz_stream_zlib_write(void * stream,const void * buf,int32_t size)263 int32_t mz_stream_zlib_write(void *stream, const void *buf, int32_t size)
264 {
265 mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
266 int32_t err = size;
267
268 #ifdef MZ_ZIP_NO_COMPRESSION
269 MZ_UNUSED(zlib);
270 MZ_UNUSED(buf);
271 err = MZ_SUPPORT_ERROR;
272 #else
273 zlib->zstream.next_in = (Bytef*)(intptr_t)buf;
274 zlib->zstream.avail_in = (uInt)size;
275
276 mz_stream_zlib_deflate(stream, Z_NO_FLUSH);
277
278 zlib->total_in += size;
279 #endif
280 return err;
281 }
282
mz_stream_zlib_tell(void * stream)283 int64_t mz_stream_zlib_tell(void *stream)
284 {
285 MZ_UNUSED(stream);
286
287 return MZ_TELL_ERROR;
288 }
289
mz_stream_zlib_seek(void * stream,int64_t offset,int32_t origin)290 int32_t mz_stream_zlib_seek(void *stream, int64_t offset, int32_t origin)
291 {
292 MZ_UNUSED(stream);
293 MZ_UNUSED(offset);
294 MZ_UNUSED(origin);
295
296 return MZ_SEEK_ERROR;
297 }
298
mz_stream_zlib_close(void * stream)299 int32_t mz_stream_zlib_close(void *stream)
300 {
301 mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
302
303
304 if (zlib->mode & MZ_OPEN_MODE_WRITE)
305 {
306 #ifdef MZ_ZIP_NO_COMPRESSION
307 return MZ_SUPPORT_ERROR;
308 #else
309 mz_stream_zlib_deflate(stream, Z_FINISH);
310 mz_stream_zlib_flush(stream);
311
312 deflateEnd(&zlib->zstream);
313 #endif
314 }
315 else if (zlib->mode & MZ_OPEN_MODE_READ)
316 {
317 #ifdef MZ_ZIP_NO_DECOMPRESSION
318 return MZ_SUPPORT_ERROR;
319 #else
320 inflateEnd(&zlib->zstream);
321 #endif
322 }
323
324 zlib->initialized = 0;
325
326 if (zlib->error != Z_OK)
327 return MZ_CLOSE_ERROR;
328 return MZ_OK;
329 }
330
mz_stream_zlib_error(void * stream)331 int32_t mz_stream_zlib_error(void *stream)
332 {
333 mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
334 return zlib->error;
335 }
336
mz_stream_zlib_get_prop_int64(void * stream,int32_t prop,int64_t * value)337 int32_t mz_stream_zlib_get_prop_int64(void *stream, int32_t prop, int64_t *value)
338 {
339 mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
340 switch (prop)
341 {
342 case MZ_STREAM_PROP_TOTAL_IN:
343 *value = zlib->total_in;
344 break;
345 case MZ_STREAM_PROP_TOTAL_IN_MAX:
346 *value = zlib->max_total_in;
347 break;
348 case MZ_STREAM_PROP_TOTAL_OUT:
349 *value = zlib->total_out;
350 break;
351 case MZ_STREAM_PROP_HEADER_SIZE:
352 *value = 0;
353 break;
354 default:
355 return MZ_EXIST_ERROR;
356 }
357 return MZ_OK;
358 }
359
mz_stream_zlib_set_prop_int64(void * stream,int32_t prop,int64_t value)360 int32_t mz_stream_zlib_set_prop_int64(void *stream, int32_t prop, int64_t value)
361 {
362 mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
363 switch (prop)
364 {
365 case MZ_STREAM_PROP_COMPRESS_LEVEL:
366 zlib->level = (int16_t)value;
367 break;
368 case MZ_STREAM_PROP_TOTAL_IN_MAX:
369 zlib->max_total_in = value;
370 break;
371 default:
372 return MZ_EXIST_ERROR;
373 }
374 return MZ_OK;
375 }
376
mz_stream_zlib_create(void ** stream)377 void *mz_stream_zlib_create(void **stream)
378 {
379 mz_stream_zlib *zlib = NULL;
380
381 zlib = (mz_stream_zlib *)MZ_ALLOC(sizeof(mz_stream_zlib));
382 if (zlib != NULL)
383 {
384 memset(zlib, 0, sizeof(mz_stream_zlib));
385 zlib->stream.vtbl = &mz_stream_zlib_vtbl;
386 zlib->level = Z_DEFAULT_COMPRESSION;
387 }
388 if (stream != NULL)
389 *stream = zlib;
390
391 return zlib;
392 }
393
mz_stream_zlib_delete(void ** stream)394 void mz_stream_zlib_delete(void **stream)
395 {
396 mz_stream_zlib *zlib = NULL;
397 if (stream == NULL)
398 return;
399 zlib = (mz_stream_zlib *)*stream;
400 if (zlib != NULL)
401 MZ_FREE(zlib);
402 *stream = NULL;
403 }
404
mz_stream_zlib_get_interface(void)405 void *mz_stream_zlib_get_interface(void)
406 {
407 return (void *)&mz_stream_zlib_vtbl;
408 }
409