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