1#include "miniz.h"
2/**************************************************************************
3 *
4 * Copyright 2013-2014 RAD Game Tools and Valve Software
5 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 *
26 **************************************************************************/
27
28typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];
29typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];
30typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
31
32#ifdef __cplusplus
33extern "C" {
34#endif
35
36/* ------------------- zlib-style API's */
37
38mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) {
39 mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16);
40 size_t block_len = buf_len % 5552;
41 if (!ptr)
42 return MZ_ADLER32_INIT;
43 while (buf_len) {
44 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
45 s1 += ptr[0], s2 += s1;
46 s1 += ptr[1], s2 += s1;
47 s1 += ptr[2], s2 += s1;
48 s1 += ptr[3], s2 += s1;
49 s1 += ptr[4], s2 += s1;
50 s1 += ptr[5], s2 += s1;
51 s1 += ptr[6], s2 += s1;
52 s1 += ptr[7], s2 += s1;
53 }
54 for (; i < block_len; ++i)
55 s1 += *ptr++, s2 += s1;
56 s1 %= 65521U, s2 %= 65521U;
57 buf_len -= block_len;
58 block_len = 5552;
59 }
60 return (s2 << 16) + s1;
61}
62
63/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C
64 * implementation that balances processor cache usage against speed":
65 * http://www.geocities.com/malbrain/ */
66#if 0
67 mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
68 {
69 static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
70 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
71 mz_uint32 crcu32 = (mz_uint32)crc;
72 if (!ptr)
73 return MZ_CRC32_INIT;
74 crcu32 = ~crcu32;
75 while (buf_len--)
76 {
77 mz_uint8 b = *ptr++;
78 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];
79 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];
80 }
81 return ~crcu32;
82 }
83#elif defined(USE_EXTERNAL_MZCRC)
84/* If USE_EXTERNAL_CRC is defined, an external module will export the
85 * mz_crc32() symbol for us to use, e.g. an SSE-accelerated version.
86 * Depending on the impl, it may be necessary to ~ the input/output crc values.
87 */
88mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len);
89#else
90/* Faster, but larger CPU cache footprint.
91 */
92mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) {
93 static const mz_uint32 s_crc_table[256] = {
94 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
95 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
96 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
97 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
98 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
99 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
100 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
101 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
102 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
103 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
104 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
105 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
106 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
107 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
108 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
109 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
110 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
111 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
112 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
113 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
114 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
115 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
116 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
117 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
118 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
119 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
120 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
121 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
122 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
123 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
124 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
125 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
126 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
127 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
128 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
129 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
130 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
131 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
132 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
133 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
134 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
135 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
136 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
137
138 mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF;
139 const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr;
140
141 while (buf_len >= 4) {
142 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];
143 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF];
144 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF];
145 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF];
146 pByte_buf += 4;
147 buf_len -= 4;
148 }
149
150 while (buf_len) {
151 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];
152 ++pByte_buf;
153 --buf_len;
154 }
155
156 return ~crc32;
157}
158#endif
159
160void mz_free(void *p) {
161 MZ_FREE(p);
162}
163
164MINIZ_EXPORT void *miniz_def_alloc_func(void *opaque,
165 size_t items,
166 size_t size) {
167 (void)opaque, (void)items, (void)size;
168 return MZ_MALLOC(items * size);
169}
170MINIZ_EXPORT void miniz_def_free_func(void *opaque, void *address) {
171 (void)opaque, (void)address;
172 MZ_FREE(address);
173}
174MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque,
175 void *address,
176 size_t items,
177 size_t size) {
178 (void)opaque, (void)address, (void)items, (void)size;
179 return MZ_REALLOC(address, items * size);
180}
181
182const char *mz_version(void) {
183 return MZ_VERSION;
184}
185
186#ifndef MINIZ_NO_ZLIB_APIS
187
188#ifndef MINIZ_NO_DEFLATE_APIS
189
190int mz_deflateInit(mz_streamp pStream, int level) {
191 return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9,
192 MZ_DEFAULT_STRATEGY);
193}
194
195int mz_deflateInit2(mz_streamp pStream,
196 int level,
197 int method,
198 int window_bits,
199 int mem_level,
200 int strategy) {
201 tdefl_compressor *pComp;
202 mz_uint comp_flags =
203 TDEFL_COMPUTE_ADLER32 |
204 tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
205
206 if (!pStream)
207 return MZ_STREAM_ERROR;
208 if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) ||
209 ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
210 (-window_bits != MZ_DEFAULT_WINDOW_BITS)))
211 return MZ_PARAM_ERROR;
212
213 pStream->data_type = 0;
214 pStream->adler = MZ_ADLER32_INIT;
215 pStream->msg = NULL;
216 pStream->reserved = 0;
217 pStream->total_in = 0;
218 pStream->total_out = 0;
219 if (!pStream->zalloc)
220 pStream->zalloc = miniz_def_alloc_func;
221 if (!pStream->zfree)
222 pStream->zfree = miniz_def_free_func;
223
224 pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1,
225 sizeof(tdefl_compressor));
226 if (!pComp)
227 return MZ_MEM_ERROR;
228
229 pStream->state = (struct mz_internal_state *)pComp;
230
231 if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) {
232 mz_deflateEnd(pStream);
233 return MZ_PARAM_ERROR;
234 }
235
236 return MZ_OK;
237}
238
239int mz_deflateReset(mz_streamp pStream) {
240 if ((!pStream) || (!pStream->state) || (!pStream->zalloc) ||
241 (!pStream->zfree))
242 return MZ_STREAM_ERROR;
243 pStream->total_in = pStream->total_out = 0;
244 tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL,
245 ((tdefl_compressor *)pStream->state)->m_flags);
246 return MZ_OK;
247}
248
249int mz_deflate(mz_streamp pStream, int flush) {
250 size_t in_bytes, out_bytes;
251 mz_ulong orig_total_in, orig_total_out;
252 int mz_status = MZ_OK;
253
254 if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) ||
255 (!pStream->next_out))
256 return MZ_STREAM_ERROR;
257 if (!pStream->avail_out)
258 return MZ_BUF_ERROR;
259
260 if (flush == MZ_PARTIAL_FLUSH)
261 flush = MZ_SYNC_FLUSH;
262
263 if (((tdefl_compressor *)pStream->state)->m_prev_return_status ==
264 TDEFL_STATUS_DONE)
265 return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
266
267 orig_total_in = pStream->total_in;
268 orig_total_out = pStream->total_out;
269 for (;;) {
270 tdefl_status defl_status;
271 in_bytes = pStream->avail_in;
272 out_bytes = pStream->avail_out;
273
274 defl_status = tdefl_compress((tdefl_compressor *)pStream->state,
275 pStream->next_in, &in_bytes, pStream->next_out,
276 &out_bytes, (tdefl_flush)flush);
277 pStream->next_in += (mz_uint)in_bytes;
278 pStream->avail_in -= (mz_uint)in_bytes;
279 pStream->total_in += (mz_uint)in_bytes;
280 pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state);
281
282 pStream->next_out += (mz_uint)out_bytes;
283 pStream->avail_out -= (mz_uint)out_bytes;
284 pStream->total_out += (mz_uint)out_bytes;
285
286 if (defl_status < 0) {
287 mz_status = MZ_STREAM_ERROR;
288 break;
289 } else if (defl_status == TDEFL_STATUS_DONE) {
290 mz_status = MZ_STREAM_END;
291 break;
292 } else if (!pStream->avail_out)
293 break;
294 else if ((!pStream->avail_in) && (flush != MZ_FINISH)) {
295 if ((flush) || (pStream->total_in != orig_total_in) ||
296 (pStream->total_out != orig_total_out))
297 break;
298 return MZ_BUF_ERROR; /* Can't make forward progress without some input.
299 */
300 }
301 }
302 return mz_status;
303}
304
305int mz_deflateEnd(mz_streamp pStream) {
306 if (!pStream)
307 return MZ_STREAM_ERROR;
308 if (pStream->state) {
309 pStream->zfree(pStream->opaque, pStream->state);
310 pStream->state = NULL;
311 }
312 return MZ_OK;
313}
314
315mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) {
316 (void)pStream;
317 /* This is really over conservative. (And lame, but it's actually pretty
318 * tricky to compute a true upper bound given the way tdefl's blocking works.)
319 */
320 return MZ_MAX(128 + (source_len * 110) / 100,
321 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
322}
323
324int mz_compress2(unsigned char *pDest,
325 mz_ulong *pDest_len,
326 const unsigned char *pSource,
327 mz_ulong source_len,
328 int level) {
329 int status;
330 mz_stream stream;
331 memset(&stream, 0, sizeof(stream));
332
333 /* In case mz_ulong is 64-bits (argh I hate longs). */
334 if ((mz_uint64)(source_len | *pDest_len) > 0xFFFFFFFFU)
335 return MZ_PARAM_ERROR;
336
337 stream.next_in = pSource;
338 stream.avail_in = (mz_uint32)source_len;
339 stream.next_out = pDest;
340 stream.avail_out = (mz_uint32)*pDest_len;
341
342 status = mz_deflateInit(&stream, level);
343 if (status != MZ_OK)
344 return status;
345
346 status = mz_deflate(&stream, MZ_FINISH);
347 if (status != MZ_STREAM_END) {
348 mz_deflateEnd(&stream);
349 return (status == MZ_OK) ? MZ_BUF_ERROR : status;
350 }
351
352 *pDest_len = stream.total_out;
353 return mz_deflateEnd(&stream);
354}
355
356int mz_compress(unsigned char *pDest,
357 mz_ulong *pDest_len,
358 const unsigned char *pSource,
359 mz_ulong source_len) {
360 return mz_compress2(pDest, pDest_len, pSource, source_len,
361 MZ_DEFAULT_COMPRESSION);
362}
363
364mz_ulong mz_compressBound(mz_ulong source_len) {
365 return mz_deflateBound(NULL, source_len);
366}
367
368#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/
369
370#ifndef MINIZ_NO_INFLATE_APIS
371
372typedef struct {
373 tinfl_decompressor m_decomp;
374 mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed;
375 int m_window_bits;
376 mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
377 tinfl_status m_last_status;
378} inflate_state;
379
380int mz_inflateInit2(mz_streamp pStream, int window_bits) {
381 inflate_state *pDecomp;
382 if (!pStream)
383 return MZ_STREAM_ERROR;
384 if ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
385 (-window_bits != MZ_DEFAULT_WINDOW_BITS))
386 return MZ_PARAM_ERROR;
387
388 pStream->data_type = 0;
389 pStream->adler = 0;
390 pStream->msg = NULL;
391 pStream->total_in = 0;
392 pStream->total_out = 0;
393 pStream->reserved = 0;
394 if (!pStream->zalloc)
395 pStream->zalloc = miniz_def_alloc_func;
396 if (!pStream->zfree)
397 pStream->zfree = miniz_def_free_func;
398
399 pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1,
400 sizeof(inflate_state));
401 if (!pDecomp)
402 return MZ_MEM_ERROR;
403
404 pStream->state = (struct mz_internal_state *)pDecomp;
405
406 tinfl_init(&pDecomp->m_decomp);
407 pDecomp->m_dict_ofs = 0;
408 pDecomp->m_dict_avail = 0;
409 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
410 pDecomp->m_first_call = 1;
411 pDecomp->m_has_flushed = 0;
412 pDecomp->m_window_bits = window_bits;
413
414 return MZ_OK;
415}
416
417int mz_inflateInit(mz_streamp pStream) {
418 return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
419}
420
421int mz_inflateReset(mz_streamp pStream) {
422 inflate_state *pDecomp;
423 if (!pStream)
424 return MZ_STREAM_ERROR;
425
426 pStream->data_type = 0;
427 pStream->adler = 0;
428 pStream->msg = NULL;
429 pStream->total_in = 0;
430 pStream->total_out = 0;
431 pStream->reserved = 0;
432
433 pDecomp = (inflate_state *)pStream->state;
434
435 tinfl_init(&pDecomp->m_decomp);
436 pDecomp->m_dict_ofs = 0;
437 pDecomp->m_dict_avail = 0;
438 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
439 pDecomp->m_first_call = 1;
440 pDecomp->m_has_flushed = 0;
441 /* pDecomp->m_window_bits = window_bits */;
442
443 return MZ_OK;
444}
445
446int mz_inflate(mz_streamp pStream, int flush) {
447 inflate_state *pState;
448 mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
449 size_t in_bytes, out_bytes, orig_avail_in;
450 tinfl_status status;
451
452 if ((!pStream) || (!pStream->state))
453 return MZ_STREAM_ERROR;
454 if (flush == MZ_PARTIAL_FLUSH)
455 flush = MZ_SYNC_FLUSH;
456 if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH))
457 return MZ_STREAM_ERROR;
458
459 pState = (inflate_state *)pStream->state;
460 if (pState->m_window_bits > 0)
461 decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
462 orig_avail_in = pStream->avail_in;
463
464 first_call = pState->m_first_call;
465 pState->m_first_call = 0;
466 if (pState->m_last_status < 0)
467 return MZ_DATA_ERROR;
468
469 if (pState->m_has_flushed && (flush != MZ_FINISH))
470 return MZ_STREAM_ERROR;
471 pState->m_has_flushed |= (flush == MZ_FINISH);
472
473 if ((flush == MZ_FINISH) && (first_call)) {
474 /* MZ_FINISH on the first call implies that the input and output buffers are
475 * large enough to hold the entire compressed/decompressed file. */
476 decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
477 in_bytes = pStream->avail_in;
478 out_bytes = pStream->avail_out;
479 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes,
480 pStream->next_out, pStream->next_out, &out_bytes,
481 decomp_flags);
482 pState->m_last_status = status;
483 pStream->next_in += (mz_uint)in_bytes;
484 pStream->avail_in -= (mz_uint)in_bytes;
485 pStream->total_in += (mz_uint)in_bytes;
486 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
487 pStream->next_out += (mz_uint)out_bytes;
488 pStream->avail_out -= (mz_uint)out_bytes;
489 pStream->total_out += (mz_uint)out_bytes;
490
491 if (status < 0)
492 return MZ_DATA_ERROR;
493 else if (status != TINFL_STATUS_DONE) {
494 pState->m_last_status = TINFL_STATUS_FAILED;
495 return MZ_BUF_ERROR;
496 }
497 return MZ_STREAM_END;
498 }
499 /* flush != MZ_FINISH then we must assume there's more input. */
500 if (flush != MZ_FINISH)
501 decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
502
503 if (pState->m_dict_avail) {
504 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
505 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
506 pStream->next_out += n;
507 pStream->avail_out -= n;
508 pStream->total_out += n;
509 pState->m_dict_avail -= n;
510 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
511 return ((pState->m_last_status == TINFL_STATUS_DONE) &&
512 (!pState->m_dict_avail))
513 ? MZ_STREAM_END
514 : MZ_OK;
515 }
516
517 for (;;) {
518 in_bytes = pStream->avail_in;
519 out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
520
521 status = tinfl_decompress(
522 &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict,
523 pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
524 pState->m_last_status = status;
525
526 pStream->next_in += (mz_uint)in_bytes;
527 pStream->avail_in -= (mz_uint)in_bytes;
528 pStream->total_in += (mz_uint)in_bytes;
529 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
530
531 pState->m_dict_avail = (mz_uint)out_bytes;
532
533 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
534 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
535 pStream->next_out += n;
536 pStream->avail_out -= n;
537 pStream->total_out += n;
538 pState->m_dict_avail -= n;
539 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
540
541 if (status < 0)
542 return MZ_DATA_ERROR; /* Stream is corrupted (there could be some
543 uncompressed data left in the output dictionary -
544 oh well). */
545 else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
546 return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress
547 without supplying more input or by setting flush
548 to MZ_FINISH. */
549 else if (flush == MZ_FINISH) {
550 /* The output buffer MUST be large to hold the remaining uncompressed data
551 * when flush==MZ_FINISH. */
552 if (status == TINFL_STATUS_DONE)
553 return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
554 /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's
555 * at least 1 more byte on the way. If there's no more room left in the
556 * output buffer then something is wrong. */
557 else if (!pStream->avail_out)
558 return MZ_BUF_ERROR;
559 } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) ||
560 (!pStream->avail_out) || (pState->m_dict_avail))
561 break;
562 }
563
564 return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail))
565 ? MZ_STREAM_END
566 : MZ_OK;
567}
568
569int mz_inflateEnd(mz_streamp pStream) {
570 if (!pStream)
571 return MZ_STREAM_ERROR;
572 if (pStream->state) {
573 pStream->zfree(pStream->opaque, pStream->state);
574 pStream->state = NULL;
575 }
576 return MZ_OK;
577}
578int mz_uncompress2(unsigned char *pDest,
579 mz_ulong *pDest_len,
580 const unsigned char *pSource,
581 mz_ulong *pSource_len) {
582 mz_stream stream;
583 int status;
584 memset(&stream, 0, sizeof(stream));
585
586 /* In case mz_ulong is 64-bits (argh I hate longs). */
587 if ((mz_uint64)(*pSource_len | *pDest_len) > 0xFFFFFFFFU)
588 return MZ_PARAM_ERROR;
589
590 stream.next_in = pSource;
591 stream.avail_in = (mz_uint32)*pSource_len;
592 stream.next_out = pDest;
593 stream.avail_out = (mz_uint32)*pDest_len;
594
595 status = mz_inflateInit(&stream);
596 if (status != MZ_OK)
597 return status;
598
599 status = mz_inflate(&stream, MZ_FINISH);
600 *pSource_len = *pSource_len - stream.avail_in;
601 if (status != MZ_STREAM_END) {
602 mz_inflateEnd(&stream);
603 return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR
604 : status;
605 }
606 *pDest_len = stream.total_out;
607
608 return mz_inflateEnd(&stream);
609}
610
611int mz_uncompress(unsigned char *pDest,
612 mz_ulong *pDest_len,
613 const unsigned char *pSource,
614 mz_ulong source_len) {
615 return mz_uncompress2(pDest, pDest_len, pSource, &source_len);
616}
617
618#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/
619
620const char *mz_error(int err) {
621 static struct {
622 int m_err;
623 const char *m_pDesc;
624 } s_error_descs[] = {{MZ_OK, ""},
625 {MZ_STREAM_END, "stream end"},
626 {MZ_NEED_DICT, "need dictionary"},
627 {MZ_ERRNO, "file error"},
628 {MZ_STREAM_ERROR, "stream error"},
629 {MZ_DATA_ERROR, "data error"},
630 {MZ_MEM_ERROR, "out of memory"},
631 {MZ_BUF_ERROR, "buf error"},
632 {MZ_VERSION_ERROR, "version error"},
633 {MZ_PARAM_ERROR, "parameter error"}};
634 mz_uint i;
635 for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i)
636 if (s_error_descs[i].m_err == err)
637 return s_error_descs[i].m_pDesc;
638 return NULL;
639}
640
641#endif /*MINIZ_NO_ZLIB_APIS */
642
643#ifdef __cplusplus
644}
645#endif
646
647/*
648 This is free and unencumbered software released into the public domain.
649
650 Anyone is free to copy, modify, publish, use, compile, sell, or
651 distribute this software, either in source code form or as a compiled
652 binary, for any purpose, commercial or non-commercial, and by any
653 means.
654
655 In jurisdictions that recognize copyright laws, the author or authors
656 of this software dedicate any and all copyright interest in the
657 software to the public domain. We make this dedication for the benefit
658 of the public at large and to the detriment of our heirs and
659 successors. We intend this dedication to be an overt act of
660 relinquishment in perpetuity of all present and future rights to this
661 software under copyright law.
662
663 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
664 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
665 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
666 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
667 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
668 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
669 OTHER DEALINGS IN THE SOFTWARE.
670
671 For more information, please refer to <http://unlicense.org/>
672*/
673/**************************************************************************
674 *
675 * Copyright 2013-2014 RAD Game Tools and Valve Software
676 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
677 * All Rights Reserved.
678 *
679 * Permission is hereby granted, free of charge, to any person obtaining a copy
680 * of this software and associated documentation files (the "Software"), to deal
681 * in the Software without restriction, including without limitation the rights
682 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
683 * copies of the Software, and to permit persons to whom the Software is
684 * furnished to do so, subject to the following conditions:
685 *
686 * The above copyright notice and this permission notice shall be included in
687 * all copies or substantial portions of the Software.
688 *
689 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
690 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
691 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
692 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
693 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
694 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
695 * THE SOFTWARE.
696 *
697 **************************************************************************/
698
699#ifndef MINIZ_NO_DEFLATE_APIS
700
701#ifdef __cplusplus
702extern "C" {
703#endif
704
705/* ------------------- Low-level Compression (independent from all decompression
706 * API's) */
707
708/* Purposely making these tables static for faster init and thread safety. */
709static const mz_uint16 s_tdefl_len_sym[256] = {
710 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268,
711 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272,
712 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274,
713 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276,
714 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
715 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
716 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279,
717 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280,
718 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281,
719 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
720 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282,
721 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
722 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283,
723 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
724 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284,
725 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
726 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
727 285};
728
729static const mz_uint8 s_tdefl_len_extra[256] = {
730 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
731 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
732 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
733 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
734 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
735 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
736 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
737 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
738 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
739 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
740 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0};
741
742static const mz_uint8 s_tdefl_small_dist_sym[512] = {
743 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
744 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
745 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
746 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
747 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
748 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
749 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14,
750 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
751 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
752 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
753 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
754 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
755 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
756 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
757 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
758 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
759 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
760 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
761 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
762 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
763 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
764 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
765 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
766 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
767 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
768 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
769 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17};
770
771static const mz_uint8 s_tdefl_small_dist_extra[512] = {
772 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
773 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
774 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
775 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
776 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
777 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
778 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
779 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
780 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
781 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
782 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
783 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
784 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
785 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
786 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
787 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
788 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
789 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
790 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
791 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
792 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
793
794static const mz_uint8 s_tdefl_large_dist_sym[128] = {
795 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24,
796 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26,
797 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27,
798 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
799 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
800 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
801 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29};
802
803static const mz_uint8 s_tdefl_large_dist_extra[128] = {
804 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11,
805 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12,
806 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
807 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
808 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
809 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
810 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
811
812/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted
813 * values. */
814typedef struct {
815 mz_uint16 m_key, m_sym_index;
816} tdefl_sym_freq;
817static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms,
818 tdefl_sym_freq *pSyms0,
819 tdefl_sym_freq *pSyms1) {
820 mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2];
821 tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1;
822 MZ_CLEAR_ARR(hist);
823 for (i = 0; i < num_syms; i++) {
824 mz_uint freq = pSyms0[i].m_key;
825 hist[freq & 0xFF]++;
826 hist[256 + ((freq >> 8) & 0xFF)]++;
827 }
828 while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256]))
829 total_passes--;
830 for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) {
831 const mz_uint32 *pHist = &hist[pass << 8];
832 mz_uint offsets[256], cur_ofs = 0;
833 for (i = 0; i < 256; i++) {
834 offsets[i] = cur_ofs;
835 cur_ofs += pHist[i];
836 }
837 for (i = 0; i < num_syms; i++)
838 pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] =
839 pCur_syms[i];
840 {
841 tdefl_sym_freq *t = pCur_syms;
842 pCur_syms = pNew_syms;
843 pNew_syms = t;
844 }
845 }
846 return pCur_syms;
847}
848
849/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat,
850 * [email protected], Jyrki Katajainen, [email protected], November 1996. */
851static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) {
852 int root, leaf, next, avbl, used, dpth;
853 if (n == 0)
854 return;
855 else if (n == 1) {
856 A[0].m_key = 1;
857 return;
858 }
859 A[0].m_key += A[1].m_key;
860 root = 0;
861 leaf = 2;
862 for (next = 1; next < n - 1; next++) {
863 if (leaf >= n || A[root].m_key < A[leaf].m_key) {
864 A[next].m_key = A[root].m_key;
865 A[root++].m_key = (mz_uint16)next;
866 } else
867 A[next].m_key = A[leaf++].m_key;
868 if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) {
869 A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key);
870 A[root++].m_key = (mz_uint16)next;
871 } else
872 A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
873 }
874 A[n - 2].m_key = 0;
875 for (next = n - 3; next >= 0; next--)
876 A[next].m_key = A[A[next].m_key].m_key + 1;
877 avbl = 1;
878 used = dpth = 0;
879 root = n - 2;
880 next = n - 1;
881 while (avbl > 0) {
882 while (root >= 0 && (int)A[root].m_key == dpth) {
883 used++;
884 root--;
885 }
886 while (avbl > used) {
887 A[next--].m_key = (mz_uint16)(dpth);
888 avbl--;
889 }
890 avbl = 2 * used;
891 dpth++;
892 used = 0;
893 }
894}
895
896/* Limits canonical Huffman code table's max code size. */
897enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
898static void tdefl_huffman_enforce_max_code_size(int *pNum_codes,
899 int code_list_len,
900 int max_code_size) {
901 int i;
902 mz_uint32 total = 0;
903 if (code_list_len <= 1)
904 return;
905 for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++)
906 pNum_codes[max_code_size] += pNum_codes[i];
907 for (i = max_code_size; i > 0; i--)
908 total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
909 while (total != (1UL << max_code_size)) {
910 pNum_codes[max_code_size]--;
911 for (i = max_code_size - 1; i > 0; i--)
912 if (pNum_codes[i]) {
913 pNum_codes[i]--;
914 pNum_codes[i + 1] += 2;
915 break;
916 }
917 total--;
918 }
919}
920
921static void tdefl_optimize_huffman_table(tdefl_compressor *d,
922 int table_num,
923 int table_len,
924 int code_size_limit,
925 int static_table) {
926 int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE];
927 mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1];
928 MZ_CLEAR_ARR(num_codes);
929 if (static_table) {
930 for (i = 0; i < table_len; i++)
931 num_codes[d->m_huff_code_sizes[table_num][i]]++;
932 } else {
933 tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS],
934 *pSyms;
935 int num_used_syms = 0;
936 const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
937 for (i = 0; i < table_len; i++)
938 if (pSym_count[i]) {
939 syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i];
940 syms0[num_used_syms++].m_sym_index = (mz_uint16)i;
941 }
942
943 pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1);
944 tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
945
946 for (i = 0; i < num_used_syms; i++)
947 num_codes[pSyms[i].m_key]++;
948
949 tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms,
950 code_size_limit);
951
952 MZ_CLEAR_ARR(d->m_huff_code_sizes[table_num]);
953 MZ_CLEAR_ARR(d->m_huff_codes[table_num]);
954 for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
955 for (l = num_codes[i]; l > 0; l--)
956 d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
957 }
958
959 next_code[1] = 0;
960 for (j = 0, i = 2; i <= code_size_limit; i++)
961 next_code[i] = j = ((j + num_codes[i - 1]) << 1);
962
963 for (i = 0; i < table_len; i++) {
964 mz_uint rev_code = 0, code, code_size;
965 if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0)
966 continue;
967 code = next_code[code_size]++;
968 for (l = code_size; l > 0; l--, code >>= 1)
969 rev_code = (rev_code << 1) | (code & 1);
970 d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
971 }
972}
973
974#define TDEFL_PUT_BITS(b, l) \
975 do { \
976 mz_uint bits = b; \
977 mz_uint len = l; \
978 MZ_ASSERT(bits <= ((1U << len) - 1U)); \
979 d->m_bit_buffer |= (bits << d->m_bits_in); \
980 d->m_bits_in += len; \
981 while (d->m_bits_in >= 8) { \
982 if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
983 *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
984 d->m_bit_buffer >>= 8; \
985 d->m_bits_in -= 8; \
986 } \
987 } \
988 MZ_MACRO_END
989
990#define TDEFL_RLE_PREV_CODE_SIZE() \
991 { \
992 if (rle_repeat_count) { \
993 if (rle_repeat_count < 3) { \
994 d->m_huff_count[2][prev_code_size] = \
995 (mz_uint16)(d->m_huff_count[2][prev_code_size] + \
996 rle_repeat_count); \
997 while (rle_repeat_count--) \
998 packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
999 } else { \
1000 d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \
1001 packed_code_sizes[num_packed_code_sizes++] = 16; \
1002 packed_code_sizes[num_packed_code_sizes++] = \
1003 (mz_uint8)(rle_repeat_count - 3); \
1004 } \
1005 rle_repeat_count = 0; \
1006 } \
1007 }
1008
1009#define TDEFL_RLE_ZERO_CODE_SIZE() \
1010 { \
1011 if (rle_z_count) { \
1012 if (rle_z_count < 3) { \
1013 d->m_huff_count[2][0] = \
1014 (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \
1015 while (rle_z_count--) \
1016 packed_code_sizes[num_packed_code_sizes++] = 0; \
1017 } else if (rle_z_count <= 10) { \
1018 d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \
1019 packed_code_sizes[num_packed_code_sizes++] = 17; \
1020 packed_code_sizes[num_packed_code_sizes++] = \
1021 (mz_uint8)(rle_z_count - 3); \
1022 } else { \
1023 d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \
1024 packed_code_sizes[num_packed_code_sizes++] = 18; \
1025 packed_code_sizes[num_packed_code_sizes++] = \
1026 (mz_uint8)(rle_z_count - 11); \
1027 } \
1028 rle_z_count = 0; \
1029 } \
1030 }
1031
1032static const mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = {
1033 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
1034
1035static void tdefl_start_dynamic_block(tdefl_compressor *d) {
1036 int num_lit_codes, num_dist_codes, num_bit_lengths;
1037 mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count,
1038 rle_repeat_count, packed_code_sizes_index;
1039 mz_uint8
1040 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
1041 packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
1042 prev_code_size = 0xFF;
1043
1044 d->m_huff_count[0][256] = 1;
1045
1046 tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
1047 tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
1048
1049 for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--)
1050 if (d->m_huff_code_sizes[0][num_lit_codes - 1])
1051 break;
1052 for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--)
1053 if (d->m_huff_code_sizes[1][num_dist_codes - 1])
1054 break;
1055
1056 memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
1057 memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0],
1058 num_dist_codes);
1059 total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
1060 num_packed_code_sizes = 0;
1061 rle_z_count = 0;
1062 rle_repeat_count = 0;
1063
1064 memset(&d->m_huff_count[2][0], 0,
1065 sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
1066 for (i = 0; i < total_code_sizes_to_pack; i++) {
1067 mz_uint8 code_size = code_sizes_to_pack[i];
1068 if (!code_size) {
1069 TDEFL_RLE_PREV_CODE_SIZE();
1070 if (++rle_z_count == 138) {
1071 TDEFL_RLE_ZERO_CODE_SIZE();
1072 }
1073 } else {
1074 TDEFL_RLE_ZERO_CODE_SIZE();
1075 if (code_size != prev_code_size) {
1076 TDEFL_RLE_PREV_CODE_SIZE();
1077 d->m_huff_count[2][code_size] =
1078 (mz_uint16)(d->m_huff_count[2][code_size] + 1);
1079 packed_code_sizes[num_packed_code_sizes++] = code_size;
1080 } else if (++rle_repeat_count == 6) {
1081 TDEFL_RLE_PREV_CODE_SIZE();
1082 }
1083 }
1084 prev_code_size = code_size;
1085 }
1086 if (rle_repeat_count) {
1087 TDEFL_RLE_PREV_CODE_SIZE();
1088 } else {
1089 TDEFL_RLE_ZERO_CODE_SIZE();
1090 }
1091
1092 tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
1093
1094 TDEFL_PUT_BITS(2, 2);
1095
1096 TDEFL_PUT_BITS(num_lit_codes - 257, 5);
1097 TDEFL_PUT_BITS(num_dist_codes - 1, 5);
1098
1099 for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--)
1100 if (d->m_huff_code_sizes
1101 [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]])
1102 break;
1103 num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1));
1104 TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
1105 for (i = 0; (int)i < num_bit_lengths; i++)
1106 TDEFL_PUT_BITS(
1107 d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
1108
1109 for (packed_code_sizes_index = 0;
1110 packed_code_sizes_index < num_packed_code_sizes;) {
1111 mz_uint code = packed_code_sizes[packed_code_sizes_index++];
1112 MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
1113 TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
1114 if (code >= 16)
1115 TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++],
1116 "\02\03\07"[code - 16]);
1117 }
1118}
1119
1120static void tdefl_start_static_block(tdefl_compressor *d) {
1121 mz_uint i;
1122 mz_uint8 *p = &d->m_huff_code_sizes[0][0];
1123
1124 for (i = 0; i <= 143; ++i)
1125 *p++ = 8;
1126 for (; i <= 255; ++i)
1127 *p++ = 9;
1128 for (; i <= 279; ++i)
1129 *p++ = 7;
1130 for (; i <= 287; ++i)
1131 *p++ = 8;
1132
1133 memset(d->m_huff_code_sizes[1], 5, 32);
1134
1135 tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
1136 tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
1137
1138 TDEFL_PUT_BITS(1, 2);
1139}
1140
1141static const mz_uint mz_bitmasks[17] = {
1142 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
1143 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF};
1144
1145#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \
1146 MINIZ_HAS_64BIT_REGISTERS
1147static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
1148 mz_uint flags;
1149 mz_uint8 *pLZ_codes;
1150 mz_uint8 *pOutput_buf = d->m_pOutput_buf;
1151 mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
1152 mz_uint64 bit_buffer = d->m_bit_buffer;
1153 mz_uint bits_in = d->m_bits_in;
1154
1155#define TDEFL_PUT_BITS_FAST(b, l) \
1156 { \
1157 bit_buffer |= (((mz_uint64)(b)) << bits_in); \
1158 bits_in += (l); \
1159 }
1160
1161 flags = 1;
1162 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end;
1163 flags >>= 1) {
1164 if (flags == 1)
1165 flags = *pLZ_codes++ | 0x100;
1166
1167 if (flags & 1) {
1168 mz_uint s0, s1, n0, n1, sym, num_extra_bits;
1169 mz_uint match_len = pLZ_codes[0];
1170 mz_uint match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));
1171 pLZ_codes += 3;
1172
1173 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
1174 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
1175 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
1176 TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
1177 s_tdefl_len_extra[match_len]);
1178
1179 /* This sequence coaxes MSVC into using cmov's vs. jmp's. */
1180 s0 = s_tdefl_small_dist_sym[match_dist & 511];
1181 n0 = s_tdefl_small_dist_extra[match_dist & 511];
1182 s1 = s_tdefl_large_dist_sym[match_dist >> 8];
1183 n1 = s_tdefl_large_dist_extra[match_dist >> 8];
1184 sym = (match_dist < 512) ? s0 : s1;
1185 num_extra_bits = (match_dist < 512) ? n0 : n1;
1186
1187 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
1188 TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym],
1189 d->m_huff_code_sizes[1][sym]);
1190 TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits],
1191 num_extra_bits);
1192 } else {
1193 mz_uint lit = *pLZ_codes++;
1194 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1195 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
1196 d->m_huff_code_sizes[0][lit]);
1197
1198 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
1199 flags >>= 1;
1200 lit = *pLZ_codes++;
1201 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1202 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
1203 d->m_huff_code_sizes[0][lit]);
1204
1205 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
1206 flags >>= 1;
1207 lit = *pLZ_codes++;
1208 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1209 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
1210 d->m_huff_code_sizes[0][lit]);
1211 }
1212 }
1213 }
1214
1215 if (pOutput_buf >= d->m_pOutput_buf_end)
1216 return MZ_FALSE;
1217
1218 memcpy(pOutput_buf, &bit_buffer, sizeof(mz_uint64));
1219 pOutput_buf += (bits_in >> 3);
1220 bit_buffer >>= (bits_in & ~7);
1221 bits_in &= 7;
1222 }
1223
1224#undef TDEFL_PUT_BITS_FAST
1225
1226 d->m_pOutput_buf = pOutput_buf;
1227 d->m_bits_in = 0;
1228 d->m_bit_buffer = 0;
1229
1230 while (bits_in) {
1231 mz_uint32 n = MZ_MIN(bits_in, 16);
1232 TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
1233 bit_buffer >>= n;
1234 bits_in -= n;
1235 }
1236
1237 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
1238
1239 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
1240}
1241#else
1242static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
1243 mz_uint flags;
1244 mz_uint8 *pLZ_codes;
1245
1246 flags = 1;
1247 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf;
1248 flags >>= 1) {
1249 if (flags == 1)
1250 flags = *pLZ_codes++ | 0x100;
1251 if (flags & 1) {
1252 mz_uint sym, num_extra_bits;
1253 mz_uint match_len = pLZ_codes[0],
1254 match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));
1255 pLZ_codes += 3;
1256
1257 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
1258 TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
1259 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
1260 TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
1261 s_tdefl_len_extra[match_len]);
1262
1263 if (match_dist < 512) {
1264 sym = s_tdefl_small_dist_sym[match_dist];
1265 num_extra_bits = s_tdefl_small_dist_extra[match_dist];
1266 } else {
1267 sym = s_tdefl_large_dist_sym[match_dist >> 8];
1268 num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
1269 }
1270 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
1271 TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
1272 TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
1273 } else {
1274 mz_uint lit = *pLZ_codes++;
1275 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1276 TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
1277 }
1278 }
1279
1280 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
1281
1282 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
1283}
1284#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \
1285 MINIZ_HAS_64BIT_REGISTERS */
1286
1287static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) {
1288 if (static_block)
1289 tdefl_start_static_block(d);
1290 else
1291 tdefl_start_dynamic_block(d);
1292 return tdefl_compress_lz_codes(d);
1293}
1294
1295static const mz_uint s_tdefl_num_probes[11];
1296
1297static int tdefl_flush_block(tdefl_compressor *d, int flush) {
1298 mz_uint saved_bit_buf, saved_bits_in;
1299 mz_uint8 *pSaved_output_buf;
1300 mz_bool comp_block_succeeded = MZ_FALSE;
1301 int n, use_raw_block =
1302 ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
1303 (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
1304 mz_uint8 *pOutput_buf_start =
1305 ((d->m_pPut_buf_func == NULL) &&
1306 ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE))
1307 ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs)
1308 : d->m_output_buf;
1309
1310 d->m_pOutput_buf = pOutput_buf_start;
1311 d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
1312
1313 MZ_ASSERT(!d->m_output_flush_remaining);
1314 d->m_output_flush_ofs = 0;
1315 d->m_output_flush_remaining = 0;
1316
1317 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
1318 d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
1319
1320 if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) {
1321 const mz_uint8 cmf = 0x78;
1322 mz_uint8 flg, flevel = 3;
1323 mz_uint header, i, mz_un = sizeof(s_tdefl_num_probes) / sizeof(mz_uint);
1324
1325 /* Determine compression level by reversing the process in
1326 * tdefl_create_comp_flags_from_zip_params() */
1327 for (i = 0; i < mz_un; i++)
1328 if (s_tdefl_num_probes[i] == (d->m_flags & 0xFFF))
1329 break;
1330
1331 if (i < 2)
1332 flevel = 0;
1333 else if (i < 6)
1334 flevel = 1;
1335 else if (i == 6)
1336 flevel = 2;
1337
1338 header = cmf << 8 | (flevel << 6);
1339 header += 31 - (header % 31);
1340 flg = header & 0xFF;
1341
1342 TDEFL_PUT_BITS(cmf, 8);
1343 TDEFL_PUT_BITS(flg, 8);
1344 }
1345
1346 TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
1347
1348 pSaved_output_buf = d->m_pOutput_buf;
1349 saved_bit_buf = d->m_bit_buffer;
1350 saved_bits_in = d->m_bits_in;
1351
1352 if (!use_raw_block)
1353 comp_block_succeeded =
1354 tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
1355 (d->m_total_lz_bytes < 48));
1356
1357 /* If the block gets expanded, forget the current contents of the output
1358 * buffer and send a raw block instead. */
1359 if (((use_raw_block) ||
1360 ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >=
1361 d->m_total_lz_bytes))) &&
1362 ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) {
1363 mz_uint i;
1364 d->m_pOutput_buf = pSaved_output_buf;
1365 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
1366 TDEFL_PUT_BITS(0, 2);
1367 if (d->m_bits_in) {
1368 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
1369 }
1370 for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) {
1371 TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
1372 }
1373 for (i = 0; i < d->m_total_lz_bytes; ++i) {
1374 TDEFL_PUT_BITS(
1375 d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK],
1376 8);
1377 }
1378 }
1379 /* Check for the extremely unlikely (if not impossible) case of the compressed
1380 block not fitting into the output buffer when using dynamic codes. */
1381 else if (!comp_block_succeeded) {
1382 d->m_pOutput_buf = pSaved_output_buf;
1383 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
1384 tdefl_compress_block(d, MZ_TRUE);
1385 }
1386
1387 if (flush) {
1388 if (flush == TDEFL_FINISH) {
1389 if (d->m_bits_in) {
1390 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
1391 }
1392 if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) {
1393 mz_uint i, a = d->m_adler32;
1394 for (i = 0; i < 4; i++) {
1395 TDEFL_PUT_BITS((a >> 24) & 0xFF, 8);
1396 a <<= 8;
1397 }
1398 }
1399 } else {
1400 mz_uint i, z = 0;
1401 TDEFL_PUT_BITS(0, 3);
1402 if (d->m_bits_in) {
1403 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
1404 }
1405 for (i = 2; i; --i, z ^= 0xFFFF) {
1406 TDEFL_PUT_BITS(z & 0xFFFF, 16);
1407 }
1408 }
1409 }
1410
1411 MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
1412
1413 memset(&d->m_huff_count[0][0], 0,
1414 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
1415 memset(&d->m_huff_count[1][0], 0,
1416 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
1417
1418 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
1419 d->m_pLZ_flags = d->m_lz_code_buf;
1420 d->m_num_flags_left = 8;
1421 d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes;
1422 d->m_total_lz_bytes = 0;
1423 d->m_block_index++;
1424
1425 if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) {
1426 if (d->m_pPut_buf_func) {
1427 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
1428 if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
1429 return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
1430 } else if (pOutput_buf_start == d->m_output_buf) {
1431 int bytes_to_copy = (int)MZ_MIN(
1432 (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
1433 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf,
1434 bytes_to_copy);
1435 d->m_out_buf_ofs += bytes_to_copy;
1436 if ((n -= bytes_to_copy) != 0) {
1437 d->m_output_flush_ofs = bytes_to_copy;
1438 d->m_output_flush_remaining = n;
1439 }
1440 } else {
1441 d->m_out_buf_ofs += n;
1442 }
1443 }
1444
1445 return d->m_output_flush_remaining;
1446}
1447
1448#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
1449#ifdef MINIZ_UNALIGNED_USE_MEMCPY
1450static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8 *p) {
1451 mz_uint16 ret;
1452 memcpy(&ret, p, sizeof(mz_uint16));
1453 return ret;
1454}
1455static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16 *p) {
1456 mz_uint16 ret;
1457 memcpy(&ret, p, sizeof(mz_uint16));
1458 return ret;
1459}
1460#else
1461#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p)
1462#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p)
1463#endif
1464static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d,
1465 mz_uint lookahead_pos,
1466 mz_uint max_dist,
1467 mz_uint max_match_len,
1468 mz_uint *pMatch_dist,
1469 mz_uint *pMatch_len) {
1470 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
1471 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
1472 probe_len;
1473 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
1474 const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q;
1475 mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]),
1476 s01 = TDEFL_READ_UNALIGNED_WORD2(s);
1477 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
1478 if (max_match_len <= match_len)
1479 return;
1480 for (;;) {
1481 for (;;) {
1482 if (--num_probes_left == 0)
1483 return;
1484#define TDEFL_PROBE \
1485 next_probe_pos = d->m_next[probe_pos]; \
1486 if ((!next_probe_pos) || \
1487 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
1488 return; \
1489 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
1490 if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \
1491 break;
1492 TDEFL_PROBE;
1493 TDEFL_PROBE;
1494 TDEFL_PROBE;
1495 }
1496 if (!dist)
1497 break;
1498 q = (const mz_uint16 *)(d->m_dict + probe_pos);
1499 if (TDEFL_READ_UNALIGNED_WORD2(q) != s01)
1500 continue;
1501 p = s;
1502 probe_len = 32;
1503 do {
1504 } while (
1505 (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&
1506 (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&
1507 (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&
1508 (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&
1509 (--probe_len > 0));
1510 if (!probe_len) {
1511 *pMatch_dist = dist;
1512 *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN);
1513 break;
1514 } else if ((probe_len = ((mz_uint)(p - s) * 2) +
1515 (mz_uint)(*(const mz_uint8 *)p ==
1516 *(const mz_uint8 *)q)) > match_len) {
1517 *pMatch_dist = dist;
1518 if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) ==
1519 max_match_len)
1520 break;
1521 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
1522 }
1523 }
1524}
1525#else
1526static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d,
1527 mz_uint lookahead_pos,
1528 mz_uint max_dist,
1529 mz_uint max_match_len,
1530 mz_uint *pMatch_dist,
1531 mz_uint *pMatch_len) {
1532 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
1533 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
1534 probe_len;
1535 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
1536 const mz_uint8 *s = d->m_dict + pos, *p, *q;
1537 mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
1538 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
1539 if (max_match_len <= match_len)
1540 return;
1541 for (;;) {
1542 for (;;) {
1543 if (--num_probes_left == 0)
1544 return;
1545#define TDEFL_PROBE \
1546 next_probe_pos = d->m_next[probe_pos]; \
1547 if ((!next_probe_pos) || \
1548 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
1549 return; \
1550 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
1551 if ((d->m_dict[probe_pos + match_len] == c0) && \
1552 (d->m_dict[probe_pos + match_len - 1] == c1)) \
1553 break;
1554 TDEFL_PROBE;
1555 TDEFL_PROBE;
1556 TDEFL_PROBE;
1557 }
1558 if (!dist)
1559 break;
1560 p = s;
1561 q = d->m_dict + probe_pos;
1562 for (probe_len = 0; probe_len < max_match_len; probe_len++)
1563 if (*p++ != *q++)
1564 break;
1565 if (probe_len > match_len) {
1566 *pMatch_dist = dist;
1567 if ((*pMatch_len = match_len = probe_len) == max_match_len)
1568 return;
1569 c0 = d->m_dict[pos + match_len];
1570 c1 = d->m_dict[pos + match_len - 1];
1571 }
1572 }
1573}
1574#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */
1575
1576#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1577#ifdef MINIZ_UNALIGNED_USE_MEMCPY
1578static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8 *p) {
1579 mz_uint32 ret;
1580 memcpy(&ret, p, sizeof(mz_uint32));
1581 return ret;
1582}
1583#else
1584#define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p)
1585#endif
1586static mz_bool tdefl_compress_fast(tdefl_compressor *d) {
1587 /* Faster, minimally featured LZRW1-style match+parse loop with better
1588 * register utilization. Intended for applications where raw throughput is
1589 * valued more highly than ratio. */
1590 mz_uint lookahead_pos = d->m_lookahead_pos,
1591 lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size,
1592 total_lz_bytes = d->m_total_lz_bytes,
1593 num_flags_left = d->m_num_flags_left;
1594 mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
1595 mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
1596
1597 while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) {
1598 const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
1599 mz_uint dst_pos =
1600 (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
1601 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
1602 d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
1603 d->m_src_buf_left -= num_bytes_to_process;
1604 lookahead_size += num_bytes_to_process;
1605
1606 while (num_bytes_to_process) {
1607 mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
1608 memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
1609 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
1610 memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc,
1611 MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
1612 d->m_pSrc += n;
1613 dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
1614 num_bytes_to_process -= n;
1615 }
1616
1617 dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
1618 if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE))
1619 break;
1620
1621 while (lookahead_size >= 4) {
1622 mz_uint cur_match_dist, cur_match_len = 1;
1623 mz_uint8 *pCur_dict = d->m_dict + cur_pos;
1624 mz_uint first_trigram = TDEFL_READ_UNALIGNED_WORD32(pCur_dict) & 0xFFFFFF;
1625 mz_uint hash =
1626 (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) &
1627 TDEFL_LEVEL1_HASH_SIZE_MASK;
1628 mz_uint probe_pos = d->m_hash[hash];
1629 d->m_hash[hash] = (mz_uint16)lookahead_pos;
1630
1631 if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <=
1632 dict_size) &&
1633 ((TDEFL_READ_UNALIGNED_WORD32(
1634 d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) &
1635 0xFFFFFF) == first_trigram)) {
1636 const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
1637 const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
1638 mz_uint32 probe_len = 32;
1639 do {
1640 } while ((TDEFL_READ_UNALIGNED_WORD2(++p) ==
1641 TDEFL_READ_UNALIGNED_WORD2(++q)) &&
1642 (TDEFL_READ_UNALIGNED_WORD2(++p) ==
1643 TDEFL_READ_UNALIGNED_WORD2(++q)) &&
1644 (TDEFL_READ_UNALIGNED_WORD2(++p) ==
1645 TDEFL_READ_UNALIGNED_WORD2(++q)) &&
1646 (TDEFL_READ_UNALIGNED_WORD2(++p) ==
1647 TDEFL_READ_UNALIGNED_WORD2(++q)) &&
1648 (--probe_len > 0));
1649 cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) +
1650 (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
1651 if (!probe_len)
1652 cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
1653
1654 if ((cur_match_len < TDEFL_MIN_MATCH_LEN) ||
1655 ((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
1656 (cur_match_dist >= 8U * 1024U))) {
1657 cur_match_len = 1;
1658 *pLZ_code_buf++ = (mz_uint8)first_trigram;
1659 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
1660 d->m_huff_count[0][(mz_uint8)first_trigram]++;
1661 } else {
1662 mz_uint32 s0, s1;
1663 cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
1664
1665 MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) &&
1666 (cur_match_dist >= 1) &&
1667 (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
1668
1669 cur_match_dist--;
1670
1671 pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
1672#ifdef MINIZ_UNALIGNED_USE_MEMCPY
1673 memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist));
1674#else
1675 *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
1676#endif
1677 pLZ_code_buf += 3;
1678 *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
1679
1680 s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
1681 s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
1682 d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
1683
1684 d->m_huff_count[0][s_tdefl_len_sym[cur_match_len -
1685 TDEFL_MIN_MATCH_LEN]]++;
1686 }
1687 } else {
1688 *pLZ_code_buf++ = (mz_uint8)first_trigram;
1689 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
1690 d->m_huff_count[0][(mz_uint8)first_trigram]++;
1691 }
1692
1693 if (--num_flags_left == 0) {
1694 num_flags_left = 8;
1695 pLZ_flags = pLZ_code_buf++;
1696 }
1697
1698 total_lz_bytes += cur_match_len;
1699 lookahead_pos += cur_match_len;
1700 dict_size =
1701 MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE);
1702 cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
1703 MZ_ASSERT(lookahead_size >= cur_match_len);
1704 lookahead_size -= cur_match_len;
1705
1706 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
1707 int n;
1708 d->m_lookahead_pos = lookahead_pos;
1709 d->m_lookahead_size = lookahead_size;
1710 d->m_dict_size = dict_size;
1711 d->m_total_lz_bytes = total_lz_bytes;
1712 d->m_pLZ_code_buf = pLZ_code_buf;
1713 d->m_pLZ_flags = pLZ_flags;
1714 d->m_num_flags_left = num_flags_left;
1715 if ((n = tdefl_flush_block(d, 0)) != 0)
1716 return (n < 0) ? MZ_FALSE : MZ_TRUE;
1717 total_lz_bytes = d->m_total_lz_bytes;
1718 pLZ_code_buf = d->m_pLZ_code_buf;
1719 pLZ_flags = d->m_pLZ_flags;
1720 num_flags_left = d->m_num_flags_left;
1721 }
1722 }
1723
1724 while (lookahead_size) {
1725 mz_uint8 lit = d->m_dict[cur_pos];
1726
1727 total_lz_bytes++;
1728 *pLZ_code_buf++ = lit;
1729 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
1730 if (--num_flags_left == 0) {
1731 num_flags_left = 8;
1732 pLZ_flags = pLZ_code_buf++;
1733 }
1734
1735 d->m_huff_count[0][lit]++;
1736
1737 lookahead_pos++;
1738 dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE);
1739 cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
1740 lookahead_size--;
1741
1742 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
1743 int n;
1744 d->m_lookahead_pos = lookahead_pos;
1745 d->m_lookahead_size = lookahead_size;
1746 d->m_dict_size = dict_size;
1747 d->m_total_lz_bytes = total_lz_bytes;
1748 d->m_pLZ_code_buf = pLZ_code_buf;
1749 d->m_pLZ_flags = pLZ_flags;
1750 d->m_num_flags_left = num_flags_left;
1751 if ((n = tdefl_flush_block(d, 0)) != 0)
1752 return (n < 0) ? MZ_FALSE : MZ_TRUE;
1753 total_lz_bytes = d->m_total_lz_bytes;
1754 pLZ_code_buf = d->m_pLZ_code_buf;
1755 pLZ_flags = d->m_pLZ_flags;
1756 num_flags_left = d->m_num_flags_left;
1757 }
1758 }
1759 }
1760
1761 d->m_lookahead_pos = lookahead_pos;
1762 d->m_lookahead_size = lookahead_size;
1763 d->m_dict_size = dict_size;
1764 d->m_total_lz_bytes = total_lz_bytes;
1765 d->m_pLZ_code_buf = pLZ_code_buf;
1766 d->m_pLZ_flags = pLZ_flags;
1767 d->m_num_flags_left = num_flags_left;
1768 return MZ_TRUE;
1769}
1770#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */
1771
1772static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d,
1773 mz_uint8 lit) {
1774 d->m_total_lz_bytes++;
1775 *d->m_pLZ_code_buf++ = lit;
1776 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1);
1777 if (--d->m_num_flags_left == 0) {
1778 d->m_num_flags_left = 8;
1779 d->m_pLZ_flags = d->m_pLZ_code_buf++;
1780 }
1781 d->m_huff_count[0][lit]++;
1782}
1783
1784static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d,
1785 mz_uint match_len,
1786 mz_uint match_dist) {
1787 mz_uint32 s0, s1;
1788
1789 MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) &&
1790 (match_dist <= TDEFL_LZ_DICT_SIZE));
1791
1792 d->m_total_lz_bytes += match_len;
1793
1794 d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
1795
1796 match_dist -= 1;
1797 d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
1798 d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8);
1799 d->m_pLZ_code_buf += 3;
1800
1801 *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80);
1802 if (--d->m_num_flags_left == 0) {
1803 d->m_num_flags_left = 8;
1804 d->m_pLZ_flags = d->m_pLZ_code_buf++;
1805 }
1806
1807 s0 = s_tdefl_small_dist_sym[match_dist & 511];
1808 s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
1809 d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
1810 d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
1811}
1812
1813static mz_bool tdefl_compress_normal(tdefl_compressor *d) {
1814 const mz_uint8 *pSrc = d->m_pSrc;
1815 size_t src_buf_left = d->m_src_buf_left;
1816 tdefl_flush flush = d->m_flush;
1817
1818 while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) {
1819 mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
1820 /* Update dictionary and hash chains. Keeps the lookahead size equal to
1821 * TDEFL_MAX_MATCH_LEN. */
1822 if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) {
1823 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
1824 TDEFL_LZ_DICT_SIZE_MASK,
1825 ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;
1826 mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
1827 << TDEFL_LZ_HASH_SHIFT) ^
1828 d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];
1829 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
1830 src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
1831 const mz_uint8 *pSrc_end = pSrc ? pSrc + num_bytes_to_process : NULL;
1832 src_buf_left -= num_bytes_to_process;
1833 d->m_lookahead_size += num_bytes_to_process;
1834 while (pSrc != pSrc_end) {
1835 mz_uint8 c = *pSrc++;
1836 d->m_dict[dst_pos] = c;
1837 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
1838 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
1839 hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
1840 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
1841 d->m_hash[hash] = (mz_uint16)(ins_pos);
1842 dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
1843 ins_pos++;
1844 }
1845 } else {
1846 while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) {
1847 mz_uint8 c = *pSrc++;
1848 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
1849 TDEFL_LZ_DICT_SIZE_MASK;
1850 src_buf_left--;
1851 d->m_dict[dst_pos] = c;
1852 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
1853 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
1854 if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) {
1855 mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
1856 mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
1857 << (TDEFL_LZ_HASH_SHIFT * 2)) ^
1858 (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]
1859 << TDEFL_LZ_HASH_SHIFT) ^
1860 c) &
1861 (TDEFL_LZ_HASH_SIZE - 1);
1862 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
1863 d->m_hash[hash] = (mz_uint16)(ins_pos);
1864 }
1865 }
1866 }
1867 d->m_dict_size =
1868 MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
1869 if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
1870 break;
1871
1872 /* Simple lazy/greedy parsing state machine. */
1873 len_to_move = 1;
1874 cur_match_dist = 0;
1875 cur_match_len =
1876 d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1);
1877 cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
1878 if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) {
1879 if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) {
1880 mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
1881 cur_match_len = 0;
1882 while (cur_match_len < d->m_lookahead_size) {
1883 if (d->m_dict[cur_pos + cur_match_len] != c)
1884 break;
1885 cur_match_len++;
1886 }
1887 if (cur_match_len < TDEFL_MIN_MATCH_LEN)
1888 cur_match_len = 0;
1889 else
1890 cur_match_dist = 1;
1891 }
1892 } else {
1893 tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size,
1894 d->m_lookahead_size, &cur_match_dist, &cur_match_len);
1895 }
1896 if (((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
1897 (cur_match_dist >= 8U * 1024U)) ||
1898 (cur_pos == cur_match_dist) ||
1899 ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) {
1900 cur_match_dist = cur_match_len = 0;
1901 }
1902 if (d->m_saved_match_len) {
1903 if (cur_match_len > d->m_saved_match_len) {
1904 tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
1905 if (cur_match_len >= 128) {
1906 tdefl_record_match(d, cur_match_len, cur_match_dist);
1907 d->m_saved_match_len = 0;
1908 len_to_move = cur_match_len;
1909 } else {
1910 d->m_saved_lit = d->m_dict[cur_pos];
1911 d->m_saved_match_dist = cur_match_dist;
1912 d->m_saved_match_len = cur_match_len;
1913 }
1914 } else {
1915 tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
1916 len_to_move = d->m_saved_match_len - 1;
1917 d->m_saved_match_len = 0;
1918 }
1919 } else if (!cur_match_dist)
1920 tdefl_record_literal(d,
1921 d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
1922 else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) ||
1923 (cur_match_len >= 128)) {
1924 tdefl_record_match(d, cur_match_len, cur_match_dist);
1925 len_to_move = cur_match_len;
1926 } else {
1927 d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)];
1928 d->m_saved_match_dist = cur_match_dist;
1929 d->m_saved_match_len = cur_match_len;
1930 }
1931 /* Move the lookahead forward by len_to_move bytes. */
1932 d->m_lookahead_pos += len_to_move;
1933 MZ_ASSERT(d->m_lookahead_size >= len_to_move);
1934 d->m_lookahead_size -= len_to_move;
1935 d->m_dict_size =
1936 MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE);
1937 /* Check if it's time to flush the current LZ codes to the internal output
1938 * buffer. */
1939 if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
1940 ((d->m_total_lz_bytes > 31 * 1024) &&
1941 (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >=
1942 d->m_total_lz_bytes) ||
1943 (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) {
1944 int n;
1945 d->m_pSrc = pSrc;
1946 d->m_src_buf_left = src_buf_left;
1947 if ((n = tdefl_flush_block(d, 0)) != 0)
1948 return (n < 0) ? MZ_FALSE : MZ_TRUE;
1949 }
1950 }
1951
1952 d->m_pSrc = pSrc;
1953 d->m_src_buf_left = src_buf_left;
1954 return MZ_TRUE;
1955}
1956
1957static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) {
1958 if (d->m_pIn_buf_size) {
1959 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
1960 }
1961
1962 if (d->m_pOut_buf_size) {
1963 size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs,
1964 d->m_output_flush_remaining);
1965 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs,
1966 d->m_output_buf + d->m_output_flush_ofs, n);
1967 d->m_output_flush_ofs += (mz_uint)n;
1968 d->m_output_flush_remaining -= (mz_uint)n;
1969 d->m_out_buf_ofs += n;
1970
1971 *d->m_pOut_buf_size = d->m_out_buf_ofs;
1972 }
1973
1974 return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE
1975 : TDEFL_STATUS_OKAY;
1976}
1977
1978tdefl_status tdefl_compress(tdefl_compressor *d,
1979 const void *pIn_buf,
1980 size_t *pIn_buf_size,
1981 void *pOut_buf,
1982 size_t *pOut_buf_size,
1983 tdefl_flush flush) {
1984 if (!d) {
1985 if (pIn_buf_size)
1986 *pIn_buf_size = 0;
1987 if (pOut_buf_size)
1988 *pOut_buf_size = 0;
1989 return TDEFL_STATUS_BAD_PARAM;
1990 }
1991
1992 d->m_pIn_buf = pIn_buf;
1993 d->m_pIn_buf_size = pIn_buf_size;
1994 d->m_pOut_buf = pOut_buf;
1995 d->m_pOut_buf_size = pOut_buf_size;
1996 d->m_pSrc = (const mz_uint8 *)(pIn_buf);
1997 d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
1998 d->m_out_buf_ofs = 0;
1999 d->m_flush = flush;
2000
2001 if (((d->m_pPut_buf_func != NULL) ==
2002 ((pOut_buf != NULL) || (pOut_buf_size != NULL))) ||
2003 (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
2004 (d->m_wants_to_finish && (flush != TDEFL_FINISH)) ||
2005 (pIn_buf_size && *pIn_buf_size && !pIn_buf) ||
2006 (pOut_buf_size && *pOut_buf_size && !pOut_buf)) {
2007 if (pIn_buf_size)
2008 *pIn_buf_size = 0;
2009 if (pOut_buf_size)
2010 *pOut_buf_size = 0;
2011 return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
2012 }
2013 d->m_wants_to_finish |= (flush == TDEFL_FINISH);
2014
2015 if ((d->m_output_flush_remaining) || (d->m_finished))
2016 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
2017
2018#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
2019 if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
2020 ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
2021 ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS |
2022 TDEFL_RLE_MATCHES)) == 0)) {
2023 if (!tdefl_compress_fast(d))
2024 return d->m_prev_return_status;
2025 } else
2026#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */
2027 {
2028 if (!tdefl_compress_normal(d))
2029 return d->m_prev_return_status;
2030 }
2031
2032 if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) &&
2033 (pIn_buf))
2034 d->m_adler32 =
2035 (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf,
2036 d->m_pSrc - (const mz_uint8 *)pIn_buf);
2037
2038 if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) &&
2039 (!d->m_output_flush_remaining)) {
2040 if (tdefl_flush_block(d, flush) < 0)
2041 return d->m_prev_return_status;
2042 d->m_finished = (flush == TDEFL_FINISH);
2043 if (flush == TDEFL_FULL_FLUSH) {
2044 MZ_CLEAR_ARR(d->m_hash);
2045 MZ_CLEAR_ARR(d->m_next);
2046 d->m_dict_size = 0;
2047 }
2048 }
2049
2050 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
2051}
2052
2053tdefl_status tdefl_compress_buffer(tdefl_compressor *d,
2054 const void *pIn_buf,
2055 size_t in_buf_size,
2056 tdefl_flush flush) {
2057 MZ_ASSERT(d->m_pPut_buf_func);
2058 return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
2059}
2060
2061tdefl_status tdefl_init(tdefl_compressor *d,
2062 tdefl_put_buf_func_ptr pPut_buf_func,
2063 void *pPut_buf_user,
2064 int flags) {
2065 d->m_pPut_buf_func = pPut_buf_func;
2066 d->m_pPut_buf_user = pPut_buf_user;
2067 d->m_flags = (mz_uint)(flags);
2068 d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3;
2069 d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
2070 d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
2071 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG))
2072 MZ_CLEAR_ARR(d->m_hash);
2073 d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size =
2074 d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;
2075 d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished =
2076 d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;
2077 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
2078 d->m_pLZ_flags = d->m_lz_code_buf;
2079 *d->m_pLZ_flags = 0;
2080 d->m_num_flags_left = 8;
2081 d->m_pOutput_buf = d->m_output_buf;
2082 d->m_pOutput_buf_end = d->m_output_buf;
2083 d->m_prev_return_status = TDEFL_STATUS_OKAY;
2084 d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0;
2085 d->m_adler32 = 1;
2086 d->m_pIn_buf = NULL;
2087 d->m_pOut_buf = NULL;
2088 d->m_pIn_buf_size = NULL;
2089 d->m_pOut_buf_size = NULL;
2090 d->m_flush = TDEFL_NO_FLUSH;
2091 d->m_pSrc = NULL;
2092 d->m_src_buf_left = 0;
2093 d->m_out_buf_ofs = 0;
2094 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG))
2095 MZ_CLEAR_ARR(d->m_dict);
2096 memset(&d->m_huff_count[0][0], 0,
2097 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
2098 memset(&d->m_huff_count[1][0], 0,
2099 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
2100 return TDEFL_STATUS_OKAY;
2101}
2102
2103tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) {
2104 return d->m_prev_return_status;
2105}
2106
2107mz_uint32 tdefl_get_adler32(tdefl_compressor *d) {
2108 return d->m_adler32;
2109}
2110
2111mz_bool tdefl_compress_mem_to_output(const void *pBuf,
2112 size_t buf_len,
2113 tdefl_put_buf_func_ptr pPut_buf_func,
2114 void *pPut_buf_user,
2115 int flags) {
2116 tdefl_compressor *pComp;
2117 mz_bool succeeded;
2118 if (((buf_len) && (!pBuf)) || (!pPut_buf_func))
2119 return MZ_FALSE;
2120 pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
2121 if (!pComp)
2122 return MZ_FALSE;
2123 succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) ==
2124 TDEFL_STATUS_OKAY);
2125 succeeded =
2126 succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) ==
2127 TDEFL_STATUS_DONE);
2128 MZ_FREE(pComp);
2129 return succeeded;
2130}
2131
2132typedef struct {
2133 size_t m_size, m_capacity;
2134 mz_uint8 *m_pBuf;
2135 mz_bool m_expandable;
2136} tdefl_output_buffer;
2137
2138static mz_bool tdefl_output_buffer_putter(const void *pBuf,
2139 int len,
2140 void *pUser) {
2141 tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
2142 size_t new_size = p->m_size + len;
2143 if (new_size > p->m_capacity) {
2144 size_t new_capacity = p->m_capacity;
2145 mz_uint8 *pNew_buf;
2146 if (!p->m_expandable)
2147 return MZ_FALSE;
2148 do {
2149 new_capacity = MZ_MAX(128U, new_capacity << 1U);
2150 } while (new_size > new_capacity);
2151 pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity);
2152 if (!pNew_buf)
2153 return MZ_FALSE;
2154 p->m_pBuf = pNew_buf;
2155 p->m_capacity = new_capacity;
2156 }
2157 memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len);
2158 p->m_size = new_size;
2159 return MZ_TRUE;
2160}
2161
2162void *tdefl_compress_mem_to_heap(const void *pSrc_buf,
2163 size_t src_buf_len,
2164 size_t *pOut_len,
2165 int flags) {
2166 tdefl_output_buffer out_buf;
2167 MZ_CLEAR_OBJ(out_buf);
2168 if (!pOut_len)
2169 return MZ_FALSE;
2170 else
2171 *pOut_len = 0;
2172 out_buf.m_expandable = MZ_TRUE;
2173 if (!tdefl_compress_mem_to_output(
2174 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
2175 return NULL;
2176 *pOut_len = out_buf.m_size;
2177 return out_buf.m_pBuf;
2178}
2179
2180size_t tdefl_compress_mem_to_mem(void *pOut_buf,
2181 size_t out_buf_len,
2182 const void *pSrc_buf,
2183 size_t src_buf_len,
2184 int flags) {
2185 tdefl_output_buffer out_buf;
2186 MZ_CLEAR_OBJ(out_buf);
2187 if (!pOut_buf)
2188 return 0;
2189 out_buf.m_pBuf = (mz_uint8 *)pOut_buf;
2190 out_buf.m_capacity = out_buf_len;
2191 if (!tdefl_compress_mem_to_output(
2192 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
2193 return 0;
2194 return out_buf.m_size;
2195}
2196
2197static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32,
2198 128, 256, 512, 768, 1500};
2199
2200/* level may actually range from [0,10] (10 is a "hidden" max level, where we
2201 * want a bit more compression and it's fine if throughput to fall off a cliff
2202 * on some files). */
2203mz_uint tdefl_create_comp_flags_from_zip_params(int level,
2204 int window_bits,
2205 int strategy) {
2206 mz_uint comp_flags =
2207 s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] |
2208 ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
2209 if (window_bits > 0)
2210 comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
2211
2212 if (!level)
2213 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
2214 else if (strategy == MZ_FILTERED)
2215 comp_flags |= TDEFL_FILTER_MATCHES;
2216 else if (strategy == MZ_HUFFMAN_ONLY)
2217 comp_flags &= ~TDEFL_MAX_PROBES_MASK;
2218 else if (strategy == MZ_FIXED)
2219 comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
2220 else if (strategy == MZ_RLE)
2221 comp_flags |= TDEFL_RLE_MATCHES;
2222
2223 return comp_flags;
2224}
2225
2226#ifdef _MSC_VER
2227#pragma warning(push)
2228#pragma warning(disable : 4204) /* nonstandard extension used : non-constant \
2229 aggregate initializer (also supported by \
2230 GNU C and C99, so no big deal) */
2231#endif
2232
2233/* Simple PNG writer function by Alex Evans, 2011. Released into the public
2234 domain: https://gist.github.com/908299, more context at
2235 http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
2236 This is actually a modification of Alex's original code so PNG files generated
2237 by this function pass pngcheck. */
2238void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage,
2239 int w,
2240 int h,
2241 int num_chans,
2242 size_t *pLen_out,
2243 mz_uint level,
2244 mz_bool flip) {
2245 /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was
2246 * defined. */
2247 static const mz_uint s_tdefl_png_num_probes[11] = {
2248 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500};
2249 tdefl_compressor *pComp =
2250 (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
2251 tdefl_output_buffer out_buf;
2252 int i, bpl = w * num_chans, y, z;
2253 mz_uint32 c;
2254 *pLen_out = 0;
2255 if (!pComp)
2256 return NULL;
2257 MZ_CLEAR_OBJ(out_buf);
2258 out_buf.m_expandable = MZ_TRUE;
2259 out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h);
2260 if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) {
2261 MZ_FREE(pComp);
2262 return NULL;
2263 }
2264 /* write dummy header */
2265 for (z = 41; z; --z)
2266 tdefl_output_buffer_putter(&z, 1, &out_buf);
2267 /* compress image data */
2268 tdefl_init(
2269 pComp, tdefl_output_buffer_putter, &out_buf,
2270 s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
2271 for (y = 0; y < h; ++y) {
2272 tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH);
2273 tdefl_compress_buffer(pComp,
2274 (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl,
2275 bpl, TDEFL_NO_FLUSH);
2276 }
2277 if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) !=
2278 TDEFL_STATUS_DONE) {
2279 MZ_FREE(pComp);
2280 MZ_FREE(out_buf.m_pBuf);
2281 return NULL;
2282 }
2283 /* write real header */
2284 *pLen_out = out_buf.m_size - 41;
2285 {
2286 static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06};
2287 mz_uint8 pnghdr[41] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
2288 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
2289 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
2290 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2291 0x00, 0x49, 0x44, 0x41, 0x54};
2292 pnghdr[18] = (mz_uint8)(w >> 8);
2293 pnghdr[19] = (mz_uint8)w;
2294 pnghdr[22] = (mz_uint8)(h >> 8);
2295 pnghdr[23] = (mz_uint8)h;
2296 pnghdr[25] = chans[num_chans];
2297 pnghdr[33] = (mz_uint8)(*pLen_out >> 24);
2298 pnghdr[34] = (mz_uint8)(*pLen_out >> 16);
2299 pnghdr[35] = (mz_uint8)(*pLen_out >> 8);
2300 pnghdr[36] = (mz_uint8)*pLen_out;
2301 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17);
2302 for (i = 0; i < 4; ++i, c <<= 8)
2303 ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24);
2304 memcpy(out_buf.m_pBuf, pnghdr, 41);
2305 }
2306 /* write footer (IDAT CRC-32, followed by IEND chunk) */
2307 if (!tdefl_output_buffer_putter(
2308 "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) {
2309 *pLen_out = 0;
2310 MZ_FREE(pComp);
2311 MZ_FREE(out_buf.m_pBuf);
2312 return NULL;
2313 }
2314 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4,
2315 *pLen_out + 4);
2316 for (i = 0; i < 4; ++i, c <<= 8)
2317 (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24);
2318 /* compute final size of file, grab compressed data buffer and return */
2319 *pLen_out += 57;
2320 MZ_FREE(pComp);
2321 return out_buf.m_pBuf;
2322}
2323void *tdefl_write_image_to_png_file_in_memory(const void *pImage,
2324 int w,
2325 int h,
2326 int num_chans,
2327 size_t *pLen_out) {
2328 /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we
2329 * can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's
2330 * where #defined out) */
2331 return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans,
2332 pLen_out, 6, MZ_FALSE);
2333}
2334
2335#ifndef MINIZ_NO_MALLOC
2336/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that
2337 */
2338/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */
2339/* structure size and allocation mechanism. */
2340tdefl_compressor *tdefl_compressor_alloc(void) {
2341 return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
2342}
2343
2344void tdefl_compressor_free(tdefl_compressor *pComp) {
2345 MZ_FREE(pComp);
2346}
2347#endif
2348
2349#ifdef _MSC_VER
2350#pragma warning(pop)
2351#endif
2352
2353#ifdef __cplusplus
2354}
2355#endif
2356
2357#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/
2358/**************************************************************************
2359 *
2360 * Copyright 2013-2014 RAD Game Tools and Valve Software
2361 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
2362 * All Rights Reserved.
2363 *
2364 * Permission is hereby granted, free of charge, to any person obtaining a copy
2365 * of this software and associated documentation files (the "Software"), to deal
2366 * in the Software without restriction, including without limitation the rights
2367 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2368 * copies of the Software, and to permit persons to whom the Software is
2369 * furnished to do so, subject to the following conditions:
2370 *
2371 * The above copyright notice and this permission notice shall be included in
2372 * all copies or substantial portions of the Software.
2373 *
2374 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2375 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2376 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2377 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2378 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2379 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2380 * THE SOFTWARE.
2381 *
2382 **************************************************************************/
2383
2384#ifndef MINIZ_NO_INFLATE_APIS
2385
2386#ifdef __cplusplus
2387extern "C" {
2388#endif
2389
2390/* ------------------- Low-level Decompression (completely independent from all
2391 * compression API's) */
2392
2393#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
2394#define TINFL_MEMSET(p, c, l) memset(p, c, l)
2395
2396#define TINFL_CR_BEGIN \
2397 switch (r->m_state) { \
2398 case 0:
2399#define TINFL_CR_RETURN(state_index, result) \
2400 do { \
2401 status = result; \
2402 r->m_state = state_index; \
2403 goto common_exit; \
2404 case state_index:; \
2405 } \
2406 MZ_MACRO_END
2407#define TINFL_CR_RETURN_FOREVER(state_index, result) \
2408 do { \
2409 for (;;) { \
2410 TINFL_CR_RETURN(state_index, result); \
2411 } \
2412 } \
2413 MZ_MACRO_END
2414#define TINFL_CR_FINISH }
2415
2416#define TINFL_GET_BYTE(state_index, c) \
2417 do { \
2418 while (pIn_buf_cur >= pIn_buf_end) { \
2419 TINFL_CR_RETURN(state_index, \
2420 (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) \
2421 ? TINFL_STATUS_NEEDS_MORE_INPUT \
2422 : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \
2423 } \
2424 c = *pIn_buf_cur++; \
2425 } \
2426 MZ_MACRO_END
2427
2428#define TINFL_NEED_BITS(state_index, n) \
2429 do { \
2430 mz_uint c; \
2431 TINFL_GET_BYTE(state_index, c); \
2432 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
2433 num_bits += 8; \
2434 } while (num_bits < (mz_uint)(n))
2435#define TINFL_SKIP_BITS(state_index, n) \
2436 do { \
2437 if (num_bits < (mz_uint)(n)) { \
2438 TINFL_NEED_BITS(state_index, n); \
2439 } \
2440 bit_buf >>= (n); \
2441 num_bits -= (n); \
2442 } \
2443 MZ_MACRO_END
2444#define TINFL_GET_BITS(state_index, b, n) \
2445 do { \
2446 if (num_bits < (mz_uint)(n)) { \
2447 TINFL_NEED_BITS(state_index, n); \
2448 } \
2449 b = bit_buf & ((1 << (n)) - 1); \
2450 bit_buf >>= (n); \
2451 num_bits -= (n); \
2452 } \
2453 MZ_MACRO_END
2454
2455/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes
2456 * remaining in the input buffer falls below 2. */
2457/* It reads just enough bytes from the input stream that are needed to decode
2458 * the next Huffman code (and absolutely no more). It works by trying to fully
2459 * decode a */
2460/* Huffman code by using whatever bits are currently present in the bit buffer.
2461 * If this fails, it reads another byte, and tries again until it succeeds or
2462 * until the */
2463/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */
2464#define TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree) \
2465 do { \
2466 temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
2467 if (temp >= 0) { \
2468 code_len = temp >> 9; \
2469 if ((code_len) && (num_bits >= code_len)) \
2470 break; \
2471 } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
2472 code_len = TINFL_FAST_LOOKUP_BITS; \
2473 do { \
2474 temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \
2475 } while ((temp < 0) && (num_bits >= (code_len + 1))); \
2476 if (temp >= 0) \
2477 break; \
2478 } \
2479 TINFL_GET_BYTE(state_index, c); \
2480 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
2481 num_bits += 8; \
2482 } while (num_bits < 15);
2483
2484/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex
2485 * than you would initially expect because the zlib API expects the decompressor
2486 * to never read */
2487/* beyond the final byte of the deflate stream. (In other words, when this macro
2488 * wants to read another byte from the input, it REALLY needs another byte in
2489 * order to fully */
2490/* decode the next Huffman code.) Handling this properly is particularly
2491 * important on raw deflate (non-zlib) streams, which aren't followed by a byte
2492 * aligned adler-32. */
2493/* The slow path is only executed at the very end of the input buffer. */
2494/* v1.16: The original macro handled the case at the very end of the passed-in
2495 * input buffer, but we also need to handle the case where the user passes in
2496 * 1+zillion bytes */
2497/* following the deflate data and our non-conservative read-ahead path won't
2498 * kick in here on this code. This is much trickier. */
2499#define TINFL_HUFF_DECODE(state_index, sym, pLookUp, pTree) \
2500 do { \
2501 int temp; \
2502 mz_uint code_len, c; \
2503 if (num_bits < 15) { \
2504 if ((pIn_buf_end - pIn_buf_cur) < 2) { \
2505 TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree); \
2506 } else { \
2507 bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \
2508 (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \
2509 pIn_buf_cur += 2; \
2510 num_bits += 16; \
2511 } \
2512 } \
2513 if ((temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
2514 code_len = temp >> 9, temp &= 511; \
2515 else { \
2516 code_len = TINFL_FAST_LOOKUP_BITS; \
2517 do { \
2518 temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \
2519 } while (temp < 0); \
2520 } \
2521 sym = temp; \
2522 bit_buf >>= code_len; \
2523 num_bits -= code_len; \
2524 } \
2525 MZ_MACRO_END
2526
2527static void tinfl_clear_tree(tinfl_decompressor *r) {
2528 if (r->m_type == 0)
2529 MZ_CLEAR_ARR(r->m_tree_0);
2530 else if (r->m_type == 1)
2531 MZ_CLEAR_ARR(r->m_tree_1);
2532 else
2533 MZ_CLEAR_ARR(r->m_tree_2);
2534}
2535
2536tinfl_status tinfl_decompress(tinfl_decompressor *r,
2537 const mz_uint8 *pIn_buf_next,
2538 size_t *pIn_buf_size,
2539 mz_uint8 *pOut_buf_start,
2540 mz_uint8 *pOut_buf_next,
2541 size_t *pOut_buf_size,
2542 const mz_uint32 decomp_flags) {
2543 static const mz_uint16 s_length_base[31] = {
2544 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
2545 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
2546 static const mz_uint8 s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
2547 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
2548 4, 4, 5, 5, 5, 5, 0, 0, 0};
2549 static const mz_uint16 s_dist_base[32] = {
2550 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33,
2551 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
2552 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0};
2553 static const mz_uint8 s_dist_extra[32] = {
2554 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6,
2555 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
2556 static const mz_uint8 s_length_dezigzag[19] = {
2557 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
2558 static const mz_uint16 s_min_table_sizes[3] = {257, 1, 4};
2559
2560 mz_int16 *pTrees[3];
2561 mz_uint8 *pCode_sizes[3];
2562
2563 tinfl_status status = TINFL_STATUS_FAILED;
2564 mz_uint32 num_bits, dist, counter, num_extra;
2565 tinfl_bit_buf_t bit_buf;
2566 const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end =
2567 pIn_buf_next + *pIn_buf_size;
2568 mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end =
2569 pOut_buf_next ? pOut_buf_next +
2570 *pOut_buf_size
2571 : NULL;
2572 size_t out_buf_size_mask =
2573 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)
2574 ? (size_t)-1
2575 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1,
2576 dist_from_out_buf_start;
2577
2578 /* Ensure the output buffer's size is a power of 2, unless the output buffer
2579 * is large enough to hold the entire output file (in which case it doesn't
2580 * matter). */
2581 if (((out_buf_size_mask + 1) & out_buf_size_mask) ||
2582 (pOut_buf_next < pOut_buf_start)) {
2583 *pIn_buf_size = *pOut_buf_size = 0;
2584 return TINFL_STATUS_BAD_PARAM;
2585 }
2586
2587 pTrees[0] = r->m_tree_0;
2588 pTrees[1] = r->m_tree_1;
2589 pTrees[2] = r->m_tree_2;
2590 pCode_sizes[0] = r->m_code_size_0;
2591 pCode_sizes[1] = r->m_code_size_1;
2592 pCode_sizes[2] = r->m_code_size_2;
2593
2594 num_bits = r->m_num_bits;
2595 bit_buf = r->m_bit_buf;
2596 dist = r->m_dist;
2597 counter = r->m_counter;
2598 num_extra = r->m_num_extra;
2599 dist_from_out_buf_start = r->m_dist_from_out_buf_start;
2600 TINFL_CR_BEGIN
2601
2602 bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0;
2603 r->m_z_adler32 = r->m_check_adler32 = 1;
2604 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
2605 TINFL_GET_BYTE(1, r->m_zhdr0);
2606 TINFL_GET_BYTE(2, r->m_zhdr1);
2607 counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) ||
2608 (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
2609 if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
2610 counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) ||
2611 ((out_buf_size_mask + 1) <
2612 (size_t)((size_t)1 << (8U + (r->m_zhdr0 >> 4)))));
2613 if (counter) {
2614 TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED);
2615 }
2616 }
2617
2618 do {
2619 TINFL_GET_BITS(3, r->m_final, 3);
2620 r->m_type = r->m_final >> 1;
2621 if (r->m_type == 0) {
2622 TINFL_SKIP_BITS(5, num_bits & 7);
2623 for (counter = 0; counter < 4; ++counter) {
2624 if (num_bits)
2625 TINFL_GET_BITS(6, r->m_raw_header[counter], 8);
2626 else
2627 TINFL_GET_BYTE(7, r->m_raw_header[counter]);
2628 }
2629 if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) !=
2630 (mz_uint)(0xFFFF ^
2631 (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) {
2632 TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED);
2633 }
2634 while ((counter) && (num_bits)) {
2635 TINFL_GET_BITS(51, dist, 8);
2636 while (pOut_buf_cur >= pOut_buf_end) {
2637 TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT);
2638 }
2639 *pOut_buf_cur++ = (mz_uint8)dist;
2640 counter--;
2641 }
2642 while (counter) {
2643 size_t n;
2644 while (pOut_buf_cur >= pOut_buf_end) {
2645 TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT);
2646 }
2647 while (pIn_buf_cur >= pIn_buf_end) {
2648 TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
2649 ? TINFL_STATUS_NEEDS_MORE_INPUT
2650 : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS);
2651 }
2652 n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur),
2653 (size_t)(pIn_buf_end - pIn_buf_cur)),
2654 counter);
2655 TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n);
2656 pIn_buf_cur += n;
2657 pOut_buf_cur += n;
2658 counter -= (mz_uint)n;
2659 }
2660 } else if (r->m_type == 3) {
2661 TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
2662 } else {
2663 if (r->m_type == 1) {
2664 mz_uint8 *p = r->m_code_size_0;
2665 mz_uint i;
2666 r->m_table_sizes[0] = 288;
2667 r->m_table_sizes[1] = 32;
2668 TINFL_MEMSET(r->m_code_size_1, 5, 32);
2669 for (i = 0; i <= 143; ++i)
2670 *p++ = 8;
2671 for (; i <= 255; ++i)
2672 *p++ = 9;
2673 for (; i <= 279; ++i)
2674 *p++ = 7;
2675 for (; i <= 287; ++i)
2676 *p++ = 8;
2677 } else {
2678 for (counter = 0; counter < 3; counter++) {
2679 TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]);
2680 r->m_table_sizes[counter] += s_min_table_sizes[counter];
2681 }
2682 MZ_CLEAR_ARR(r->m_code_size_2);
2683 for (counter = 0; counter < r->m_table_sizes[2]; counter++) {
2684 mz_uint s;
2685 TINFL_GET_BITS(14, s, 3);
2686 r->m_code_size_2[s_length_dezigzag[counter]] = (mz_uint8)s;
2687 }
2688 r->m_table_sizes[2] = 19;
2689 }
2690 for (; (int)r->m_type >= 0; r->m_type--) {
2691 int tree_next, tree_cur;
2692 mz_int16 *pLookUp;
2693 mz_int16 *pTree;
2694 mz_uint8 *pCode_size;
2695 mz_uint i, j, used_syms, total, sym_index, next_code[17],
2696 total_syms[16];
2697 pLookUp = r->m_look_up[r->m_type];
2698 pTree = pTrees[r->m_type];
2699 pCode_size = pCode_sizes[r->m_type];
2700 MZ_CLEAR_ARR(total_syms);
2701 TINFL_MEMSET(pLookUp, 0, sizeof(r->m_look_up[0]));
2702 tinfl_clear_tree(r);
2703 for (i = 0; i < r->m_table_sizes[r->m_type]; ++i)
2704 total_syms[pCode_size[i]]++;
2705 used_syms = 0, total = 0;
2706 next_code[0] = next_code[1] = 0;
2707 for (i = 1; i <= 15; ++i) {
2708 used_syms += total_syms[i];
2709 next_code[i + 1] = (total = ((total + total_syms[i]) << 1));
2710 }
2711 if ((65536 != total) && (used_syms > 1)) {
2712 TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
2713 }
2714 for (tree_next = -1, sym_index = 0;
2715 sym_index < r->m_table_sizes[r->m_type]; ++sym_index) {
2716 mz_uint rev_code = 0, l, cur_code, code_size = pCode_size[sym_index];
2717 if (!code_size)
2718 continue;
2719 cur_code = next_code[code_size]++;
2720 for (l = code_size; l > 0; l--, cur_code >>= 1)
2721 rev_code = (rev_code << 1) | (cur_code & 1);
2722 if (code_size <= TINFL_FAST_LOOKUP_BITS) {
2723 mz_int16 k = (mz_int16)((code_size << 9) | sym_index);
2724 while (rev_code < TINFL_FAST_LOOKUP_SIZE) {
2725 pLookUp[rev_code] = k;
2726 rev_code += (1 << code_size);
2727 }
2728 continue;
2729 }
2730 if (0 ==
2731 (tree_cur = pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) {
2732 pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] =
2733 (mz_int16)tree_next;
2734 tree_cur = tree_next;
2735 tree_next -= 2;
2736 }
2737 rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
2738 for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) {
2739 tree_cur -= ((rev_code >>= 1) & 1);
2740 if (!pTree[-tree_cur - 1]) {
2741 pTree[-tree_cur - 1] = (mz_int16)tree_next;
2742 tree_cur = tree_next;
2743 tree_next -= 2;
2744 } else
2745 tree_cur = pTree[-tree_cur - 1];
2746 }
2747 tree_cur -= ((rev_code >>= 1) & 1);
2748 pTree[-tree_cur - 1] = (mz_int16)sym_index;
2749 }
2750 if (r->m_type == 2) {
2751 for (counter = 0;
2752 counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) {
2753 mz_uint s;
2754 TINFL_HUFF_DECODE(16, dist, r->m_look_up[2], r->m_tree_2);
2755 if (dist < 16) {
2756 r->m_len_codes[counter++] = (mz_uint8)dist;
2757 continue;
2758 }
2759 if ((dist == 16) && (!counter)) {
2760 TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
2761 }
2762 num_extra = "\02\03\07"[dist - 16];
2763 TINFL_GET_BITS(18, s, num_extra);
2764 s += "\03\03\013"[dist - 16];
2765 TINFL_MEMSET(r->m_len_codes + counter,
2766 (dist == 16) ? r->m_len_codes[counter - 1] : 0, s);
2767 counter += s;
2768 }
2769 if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) {
2770 TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
2771 }
2772 TINFL_MEMCPY(r->m_code_size_0, r->m_len_codes, r->m_table_sizes[0]);
2773 TINFL_MEMCPY(r->m_code_size_1, r->m_len_codes + r->m_table_sizes[0],
2774 r->m_table_sizes[1]);
2775 }
2776 }
2777 for (;;) {
2778 mz_uint8 *pSrc;
2779 for (;;) {
2780 if (((pIn_buf_end - pIn_buf_cur) < 4) ||
2781 ((pOut_buf_end - pOut_buf_cur) < 2)) {
2782 TINFL_HUFF_DECODE(23, counter, r->m_look_up[0], r->m_tree_0);
2783 if (counter >= 256)
2784 break;
2785 while (pOut_buf_cur >= pOut_buf_end) {
2786 TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT);
2787 }
2788 *pOut_buf_cur++ = (mz_uint8)counter;
2789 } else {
2790 int sym2;
2791 mz_uint code_len;
2792#if TINFL_USE_64BIT_BITBUF
2793 if (num_bits < 30) {
2794 bit_buf |=
2795 (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits);
2796 pIn_buf_cur += 4;
2797 num_bits += 32;
2798 }
2799#else
2800 if (num_bits < 15) {
2801 bit_buf |=
2802 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
2803 pIn_buf_cur += 2;
2804 num_bits += 16;
2805 }
2806#endif
2807 if ((sym2 =
2808 r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
2809 0)
2810 code_len = sym2 >> 9;
2811 else {
2812 code_len = TINFL_FAST_LOOKUP_BITS;
2813 do {
2814 sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)];
2815 } while (sym2 < 0);
2816 }
2817 counter = sym2;
2818 bit_buf >>= code_len;
2819 num_bits -= code_len;
2820 if (counter & 256)
2821 break;
2822
2823#if !TINFL_USE_64BIT_BITBUF
2824 if (num_bits < 15) {
2825 bit_buf |=
2826 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
2827 pIn_buf_cur += 2;
2828 num_bits += 16;
2829 }
2830#endif
2831 if ((sym2 =
2832 r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
2833 0)
2834 code_len = sym2 >> 9;
2835 else {
2836 code_len = TINFL_FAST_LOOKUP_BITS;
2837 do {
2838 sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)];
2839 } while (sym2 < 0);
2840 }
2841 bit_buf >>= code_len;
2842 num_bits -= code_len;
2843
2844 pOut_buf_cur[0] = (mz_uint8)counter;
2845 if (sym2 & 256) {
2846 pOut_buf_cur++;
2847 counter = sym2;
2848 break;
2849 }
2850 pOut_buf_cur[1] = (mz_uint8)sym2;
2851 pOut_buf_cur += 2;
2852 }
2853 }
2854 if ((counter &= 511) == 256)
2855 break;
2856
2857 num_extra = s_length_extra[counter - 257];
2858 counter = s_length_base[counter - 257];
2859 if (num_extra) {
2860 mz_uint extra_bits;
2861 TINFL_GET_BITS(25, extra_bits, num_extra);
2862 counter += extra_bits;
2863 }
2864
2865 TINFL_HUFF_DECODE(26, dist, r->m_look_up[1], r->m_tree_1);
2866 num_extra = s_dist_extra[dist];
2867 dist = s_dist_base[dist];
2868 if (num_extra) {
2869 mz_uint extra_bits;
2870 TINFL_GET_BITS(27, extra_bits, num_extra);
2871 dist += extra_bits;
2872 }
2873
2874 dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
2875 if ((dist == 0 || dist > dist_from_out_buf_start ||
2876 dist_from_out_buf_start == 0) &&
2877 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) {
2878 TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
2879 }
2880
2881 pSrc = pOut_buf_start +
2882 ((dist_from_out_buf_start - dist) & out_buf_size_mask);
2883
2884 if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) {
2885 while (counter--) {
2886 while (pOut_buf_cur >= pOut_buf_end) {
2887 TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT);
2888 }
2889 *pOut_buf_cur++ =
2890 pOut_buf_start[(dist_from_out_buf_start++ - dist) &
2891 out_buf_size_mask];
2892 }
2893 continue;
2894 }
2895#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
2896 else if ((counter >= 9) && (counter <= dist)) {
2897 const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
2898 do {
2899#ifdef MINIZ_UNALIGNED_USE_MEMCPY
2900 memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32) * 2);
2901#else
2902 ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
2903 ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
2904#endif
2905 pOut_buf_cur += 8;
2906 } while ((pSrc += 8) < pSrc_end);
2907 if ((counter &= 7) < 3) {
2908 if (counter) {
2909 pOut_buf_cur[0] = pSrc[0];
2910 if (counter > 1)
2911 pOut_buf_cur[1] = pSrc[1];
2912 pOut_buf_cur += counter;
2913 }
2914 continue;
2915 }
2916 }
2917#endif
2918 while (counter > 2) {
2919 pOut_buf_cur[0] = pSrc[0];
2920 pOut_buf_cur[1] = pSrc[1];
2921 pOut_buf_cur[2] = pSrc[2];
2922 pOut_buf_cur += 3;
2923 pSrc += 3;
2924 counter -= 3;
2925 }
2926 if (counter > 0) {
2927 pOut_buf_cur[0] = pSrc[0];
2928 if (counter > 1)
2929 pOut_buf_cur[1] = pSrc[1];
2930 pOut_buf_cur += counter;
2931 }
2932 }
2933 }
2934 } while (!(r->m_final & 1));
2935
2936 /* Ensure byte alignment and put back any bytes from the bitbuf if we've
2937 * looked ahead too far on gzip, or other Deflate streams followed by
2938 * arbitrary data. */
2939 /* I'm being super conservative here. A number of simplifications can be made
2940 * to the byte alignment part, and the Adler32 check shouldn't ever need to
2941 * worry about reading from the bitbuf now. */
2942 TINFL_SKIP_BITS(32, num_bits & 7);
2943 while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) {
2944 --pIn_buf_cur;
2945 num_bits -= 8;
2946 }
2947 bit_buf &= ~(~(tinfl_bit_buf_t)0 << num_bits);
2948 MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end
2949 of non-deflate/zlib streams with following data (such
2950 as gzip streams). */
2951
2952 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
2953 for (counter = 0; counter < 4; ++counter) {
2954 mz_uint s;
2955 if (num_bits)
2956 TINFL_GET_BITS(41, s, 8);
2957 else
2958 TINFL_GET_BYTE(42, s);
2959 r->m_z_adler32 = (r->m_z_adler32 << 8) | s;
2960 }
2961 }
2962 TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
2963
2964 TINFL_CR_FINISH
2965
2966common_exit:
2967 /* As long as we aren't telling the caller that we NEED more input to make
2968 * forward progress: */
2969 /* Put back any bytes from the bitbuf in case we've looked ahead too far on
2970 * gzip, or other Deflate streams followed by arbitrary data. */
2971 /* We need to be very careful here to NOT push back any bytes we definitely
2972 * know we need to make forward progress, though, or we'll lock the caller up
2973 * into an inf loop. */
2974 if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) &&
2975 (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) {
2976 while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) {
2977 --pIn_buf_cur;
2978 num_bits -= 8;
2979 }
2980 }
2981 r->m_num_bits = num_bits;
2982 r->m_bit_buf = bit_buf & ~(~(tinfl_bit_buf_t)0 << num_bits);
2983 r->m_dist = dist;
2984 r->m_counter = counter;
2985 r->m_num_extra = num_extra;
2986 r->m_dist_from_out_buf_start = dist_from_out_buf_start;
2987 *pIn_buf_size = pIn_buf_cur - pIn_buf_next;
2988 *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
2989 if ((decomp_flags &
2990 (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) &&
2991 (status >= 0)) {
2992 const mz_uint8 *ptr = pOut_buf_next;
2993 size_t buf_len = *pOut_buf_size;
2994 mz_uint32 i, s1 = r->m_check_adler32 & 0xffff,
2995 s2 = r->m_check_adler32 >> 16;
2996 size_t block_len = buf_len % 5552;
2997 while (buf_len) {
2998 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
2999 s1 += ptr[0], s2 += s1;
3000 s1 += ptr[1], s2 += s1;
3001 s1 += ptr[2], s2 += s1;
3002 s1 += ptr[3], s2 += s1;
3003 s1 += ptr[4], s2 += s1;
3004 s1 += ptr[5], s2 += s1;
3005 s1 += ptr[6], s2 += s1;
3006 s1 += ptr[7], s2 += s1;
3007 }
3008 for (; i < block_len; ++i)
3009 s1 += *ptr++, s2 += s1;
3010 s1 %= 65521U, s2 %= 65521U;
3011 buf_len -= block_len;
3012 block_len = 5552;
3013 }
3014 r->m_check_adler32 = (s2 << 16) + s1;
3015 if ((status == TINFL_STATUS_DONE) &&
3016 (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) &&
3017 (r->m_check_adler32 != r->m_z_adler32))
3018 status = TINFL_STATUS_ADLER32_MISMATCH;
3019 }
3020 return status;
3021}
3022
3023/* Higher level helper functions. */
3024void *tinfl_decompress_mem_to_heap(const void *pSrc_buf,
3025 size_t src_buf_len,
3026 size_t *pOut_len,
3027 int flags) {
3028 tinfl_decompressor decomp;
3029 void *pBuf = NULL, *pNew_buf;
3030 size_t src_buf_ofs = 0, out_buf_capacity = 0;
3031 *pOut_len = 0;
3032 tinfl_init(&decomp);
3033 for (;;) {
3034 size_t src_buf_size = src_buf_len - src_buf_ofs,
3035 dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
3036 tinfl_status status = tinfl_decompress(
3037 &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
3038 (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
3039 &dst_buf_size,
3040 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
3041 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
3042 if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
3043 MZ_FREE(pBuf);
3044 *pOut_len = 0;
3045 return NULL;
3046 }
3047 src_buf_ofs += src_buf_size;
3048 *pOut_len += dst_buf_size;
3049 if (status == TINFL_STATUS_DONE)
3050 break;
3051 new_out_buf_capacity = out_buf_capacity * 2;
3052 if (new_out_buf_capacity < 128)
3053 new_out_buf_capacity = 128;
3054 pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
3055 if (!pNew_buf) {
3056 MZ_FREE(pBuf);
3057 *pOut_len = 0;
3058 return NULL;
3059 }
3060 pBuf = pNew_buf;
3061 out_buf_capacity = new_out_buf_capacity;
3062 }
3063 return pBuf;
3064}
3065
3066size_t tinfl_decompress_mem_to_mem(void *pOut_buf,
3067 size_t out_buf_len,
3068 const void *pSrc_buf,
3069 size_t src_buf_len,
3070 int flags) {
3071 tinfl_decompressor decomp;
3072 tinfl_status status;
3073 tinfl_init(&decomp);
3074 status =
3075 tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len,
3076 (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len,
3077 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
3078 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
3079 return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED
3080 : out_buf_len;
3081}
3082
3083int tinfl_decompress_mem_to_callback(const void *pIn_buf,
3084 size_t *pIn_buf_size,
3085 tinfl_put_buf_func_ptr pPut_buf_func,
3086 void *pPut_buf_user,
3087 int flags) {
3088 int result = 0;
3089 tinfl_decompressor decomp;
3090 mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE);
3091 size_t in_buf_ofs = 0, dict_ofs = 0;
3092 if (!pDict)
3093 return TINFL_STATUS_FAILED;
3094 memset(pDict, 0, TINFL_LZ_DICT_SIZE);
3095 tinfl_init(&decomp);
3096 for (;;) {
3097 size_t in_buf_size = *pIn_buf_size - in_buf_ofs,
3098 dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
3099 tinfl_status status =
3100 tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs,
3101 &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
3102 (flags & ~(TINFL_FLAG_HAS_MORE_INPUT |
3103 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
3104 in_buf_ofs += in_buf_size;
3105 if ((dst_buf_size) &&
3106 (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
3107 break;
3108 if (status != TINFL_STATUS_HAS_MORE_OUTPUT) {
3109 result = (status == TINFL_STATUS_DONE);
3110 break;
3111 }
3112 dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
3113 }
3114 MZ_FREE(pDict);
3115 *pIn_buf_size = in_buf_ofs;
3116 return result;
3117}
3118
3119#ifndef MINIZ_NO_MALLOC
3120tinfl_decompressor *tinfl_decompressor_alloc(void) {
3121 tinfl_decompressor *pDecomp =
3122 (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor));
3123 if (pDecomp)
3124 tinfl_init(pDecomp);
3125 return pDecomp;
3126}
3127
3128void tinfl_decompressor_free(tinfl_decompressor *pDecomp) {
3129 MZ_FREE(pDecomp);
3130}
3131#endif
3132
3133#ifdef __cplusplus
3134}
3135#endif
3136
3137#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/
3138/**************************************************************************
3139 *
3140 * Copyright 2013-2014 RAD Game Tools and Valve Software
3141 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
3142 * Copyright 2016 Martin Raiber
3143 * All Rights Reserved.
3144 *
3145 * Permission is hereby granted, free of charge, to any person obtaining a copy
3146 * of this software and associated documentation files (the "Software"), to deal
3147 * in the Software without restriction, including without limitation the rights
3148 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3149 * copies of the Software, and to permit persons to whom the Software is
3150 * furnished to do so, subject to the following conditions:
3151 *
3152 * The above copyright notice and this permission notice shall be included in
3153 * all copies or substantial portions of the Software.
3154 *
3155 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3156 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3157 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3158 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3159 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3160 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3161 * THE SOFTWARE.
3162 *
3163 **************************************************************************/
3164
3165#ifndef MINIZ_NO_ARCHIVE_APIS
3166
3167#ifdef __cplusplus
3168extern "C" {
3169#endif
3170
3171/* ------------------- .ZIP archive reading */
3172
3173#ifdef MINIZ_NO_STDIO
3174#define MZ_FILE void *
3175#else
3176#include <sys/stat.h>
3177
3178#if defined(_MSC_VER) || defined(__MINGW64__)
3179
3180#define WIN32_LEAN_AND_MEAN
3181#include <windows.h>
3182
3183static WCHAR *mz_utf8z_to_widechar(const char *str) {
3184 int reqChars = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
3185 WCHAR *wStr = (WCHAR *)malloc(reqChars * sizeof(WCHAR));
3186 MultiByteToWideChar(CP_UTF8, 0, str, -1, wStr, sizeof(WCHAR) * reqChars);
3187 return wStr;
3188}
3189
3190static FILE *mz_fopen(const char *pFilename, const char *pMode) {
3191 WCHAR *wFilename = mz_utf8z_to_widechar(pFilename);
3192 WCHAR *wMode = mz_utf8z_to_widechar(pMode);
3193 FILE *pFile = NULL;
3194 errno_t err = _wfopen_s(&pFile, wFilename, wMode);
3195 free(wFilename);
3196 free(wMode);
3197 return err ? NULL : pFile;
3198}
3199
3200static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) {
3201 WCHAR *wPath = mz_utf8z_to_widechar(pPath);
3202 WCHAR *wMode = mz_utf8z_to_widechar(pMode);
3203 FILE *pFile = NULL;
3204 errno_t err = _wfreopen_s(&pFile, wPath, wMode, pStream);
3205 free(wPath);
3206 free(wMode);
3207 return err ? NULL : pFile;
3208}
3209
3210static int mz_stat64(const char *path, struct __stat64 *buffer) {
3211 WCHAR *wPath = mz_utf8z_to_widechar(path);
3212 int res = _wstat64(wPath, buffer);
3213 free(wPath);
3214 return res;
3215}
3216
3217#ifndef MINIZ_NO_TIME
3218#include <sys/utime.h>
3219#endif
3220#define MZ_FOPEN mz_fopen
3221#define MZ_FCLOSE fclose
3222#define MZ_FREAD fread
3223#define MZ_FWRITE fwrite
3224#define MZ_FTELL64 _ftelli64
3225#define MZ_FSEEK64 _fseeki64
3226#define MZ_FILE_STAT_STRUCT _stat64
3227#define MZ_FILE_STAT mz_stat64
3228#define MZ_FFLUSH fflush
3229#define MZ_FREOPEN mz_freopen
3230#define MZ_DELETE_FILE remove
3231
3232#elif defined(__MINGW32__) || defined(__WATCOMC__)
3233#ifndef MINIZ_NO_TIME
3234#include <sys/utime.h>
3235#endif
3236#define MZ_FOPEN(f, m) fopen(f, m)
3237#define MZ_FCLOSE fclose
3238#define MZ_FREAD fread
3239#define MZ_FWRITE fwrite
3240#define MZ_FTELL64 _ftelli64
3241#define MZ_FSEEK64 _fseeki64
3242#define MZ_FILE_STAT_STRUCT stat
3243#define MZ_FILE_STAT stat
3244#define MZ_FFLUSH fflush
3245#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
3246#define MZ_DELETE_FILE remove
3247
3248#elif defined(__TINYC__)
3249#ifndef MINIZ_NO_TIME
3250#include <sys/utime.h>
3251#endif
3252#define MZ_FOPEN(f, m) fopen(f, m)
3253#define MZ_FCLOSE fclose
3254#define MZ_FREAD fread
3255#define MZ_FWRITE fwrite
3256#define MZ_FTELL64 ftell
3257#define MZ_FSEEK64 fseek
3258#define MZ_FILE_STAT_STRUCT stat
3259#define MZ_FILE_STAT stat
3260#define MZ_FFLUSH fflush
3261#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
3262#define MZ_DELETE_FILE remove
3263
3264#elif defined(__USE_LARGEFILE64) /* gcc, clang */
3265#ifndef MINIZ_NO_TIME
3266#include <utime.h>
3267#endif
3268#define MZ_FOPEN(f, m) fopen64(f, m)
3269#define MZ_FCLOSE fclose
3270#define MZ_FREAD fread
3271#define MZ_FWRITE fwrite
3272#define MZ_FTELL64 ftello64
3273#define MZ_FSEEK64 fseeko64
3274#define MZ_FILE_STAT_STRUCT stat64
3275#define MZ_FILE_STAT stat64
3276#define MZ_FFLUSH fflush
3277#define MZ_FREOPEN(p, m, s) freopen64(p, m, s)
3278#define MZ_DELETE_FILE remove
3279
3280#elif defined(__APPLE__) || defined(__FreeBSD__)
3281#ifndef MINIZ_NO_TIME
3282#include <utime.h>
3283#endif
3284#define MZ_FOPEN(f, m) fopen(f, m)
3285#define MZ_FCLOSE fclose
3286#define MZ_FREAD fread
3287#define MZ_FWRITE fwrite
3288#define MZ_FTELL64 ftello
3289#define MZ_FSEEK64 fseeko
3290#define MZ_FILE_STAT_STRUCT stat
3291#define MZ_FILE_STAT stat
3292#define MZ_FFLUSH fflush
3293#define MZ_FREOPEN(p, m, s) freopen(p, m, s)
3294#define MZ_DELETE_FILE remove
3295
3296#else
3297#pragma message( \
3298 "Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.")
3299#ifndef MINIZ_NO_TIME
3300#include <utime.h>
3301#endif
3302#define MZ_FOPEN(f, m) fopen(f, m)
3303#define MZ_FCLOSE fclose
3304#define MZ_FREAD fread
3305#define MZ_FWRITE fwrite
3306#ifdef __STRICT_ANSI__
3307#define MZ_FTELL64 ftell
3308#define MZ_FSEEK64 fseek
3309#else
3310#define MZ_FTELL64 ftello
3311#define MZ_FSEEK64 fseeko
3312#endif
3313#define MZ_FILE_STAT_STRUCT stat
3314#define MZ_FILE_STAT stat
3315#define MZ_FFLUSH fflush
3316#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
3317#define MZ_DELETE_FILE remove
3318#endif /* #ifdef _MSC_VER */
3319#endif /* #ifdef MINIZ_NO_STDIO */
3320
3321#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
3322
3323/* Various ZIP archive enums. To completely avoid cross platform compiler
3324 * alignment and platform endian issues, miniz.c doesn't use structs for any of
3325 * this stuff. */
3326enum {
3327 /* ZIP archive identifiers and record sizes */
3328 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50,
3329 MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50,
3330 MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
3331 MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
3332 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
3333 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
3334
3335 /* ZIP64 archive identifier and record sizes */
3336 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,
3337 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,
3338 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,
3339 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,
3340 MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,
3341 MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,
3342 MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,
3343 MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,
3344
3345 /* Central directory header record offsets */
3346 MZ_ZIP_CDH_SIG_OFS = 0,
3347 MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
3348 MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6,
3349 MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
3350 MZ_ZIP_CDH_METHOD_OFS = 10,
3351 MZ_ZIP_CDH_FILE_TIME_OFS = 12,
3352 MZ_ZIP_CDH_FILE_DATE_OFS = 14,
3353 MZ_ZIP_CDH_CRC32_OFS = 16,
3354 MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20,
3355 MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24,
3356 MZ_ZIP_CDH_FILENAME_LEN_OFS = 28,
3357 MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
3358 MZ_ZIP_CDH_COMMENT_LEN_OFS = 32,
3359 MZ_ZIP_CDH_DISK_START_OFS = 34,
3360 MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36,
3361 MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38,
3362 MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
3363
3364 /* Local directory header offsets */
3365 MZ_ZIP_LDH_SIG_OFS = 0,
3366 MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4,
3367 MZ_ZIP_LDH_BIT_FLAG_OFS = 6,
3368 MZ_ZIP_LDH_METHOD_OFS = 8,
3369 MZ_ZIP_LDH_FILE_TIME_OFS = 10,
3370 MZ_ZIP_LDH_FILE_DATE_OFS = 12,
3371 MZ_ZIP_LDH_CRC32_OFS = 14,
3372 MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18,
3373 MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
3374 MZ_ZIP_LDH_FILENAME_LEN_OFS = 26,
3375 MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
3376 MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3,
3377
3378 /* End of central directory offsets */
3379 MZ_ZIP_ECDH_SIG_OFS = 0,
3380 MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4,
3381 MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6,
3382 MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
3383 MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10,
3384 MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
3385 MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
3386 MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
3387
3388 /* ZIP64 End of central directory locator offsets */
3389 MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */
3390 MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */
3391 MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */
3392 MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */
3393
3394 /* ZIP64 End of central directory header offsets */
3395 MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */
3396 MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */
3397 MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */
3398 MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */
3399 MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */
3400 MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */
3401 MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */
3402 MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */
3403 MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */
3404 MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */
3405 MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,
3406 MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,
3407 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,
3408 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,
3409 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,
3410 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,
3411 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11
3412};
3413
3414typedef struct {
3415 void *m_p;
3416 size_t m_size, m_capacity;
3417 mz_uint m_element_size;
3418} mz_zip_array;
3419
3420struct mz_zip_internal_state_tag {
3421 mz_zip_array m_central_dir;
3422 mz_zip_array m_central_dir_offsets;
3423 mz_zip_array m_sorted_central_dir_offsets;
3424
3425 /* The flags passed in when the archive is initially opened. */
3426 mz_uint32 m_init_flags;
3427
3428 /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc.
3429 */
3430 mz_bool m_zip64;
3431
3432 /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64
3433 * will also be slammed to true too, even if we didn't find a zip64 end of
3434 * central dir header, etc.) */
3435 mz_bool m_zip64_has_extended_info_fields;
3436
3437 /* These fields are used by the file, FILE, memory, and memory/heap read/write
3438 * helpers. */
3439 MZ_FILE *m_pFile;
3440 mz_uint64 m_file_archive_start_ofs;
3441
3442 void *m_pMem;
3443 size_t m_mem_size;
3444 size_t m_mem_capacity;
3445};
3446
3447#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \
3448 (array_ptr)->m_element_size = element_size
3449
3450#if defined(DEBUG) || defined(_DEBUG)
3451static MZ_FORCEINLINE mz_uint
3452mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) {
3453 MZ_ASSERT(index < pArray->m_size);
3454 return index;
3455}
3456#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \
3457 ((element_type *)((array_ptr) \
3458 ->m_p))[mz_zip_array_range_check(array_ptr, index)]
3459#else
3460#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \
3461 ((element_type *)((array_ptr)->m_p))[index]
3462#endif
3463
3464static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray,
3465 mz_uint32 element_size) {
3466 memset(pArray, 0, sizeof(mz_zip_array));
3467 pArray->m_element_size = element_size;
3468}
3469
3470static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip,
3471 mz_zip_array *pArray) {
3472 pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
3473 memset(pArray, 0, sizeof(mz_zip_array));
3474}
3475
3476static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip,
3477 mz_zip_array *pArray,
3478 size_t min_new_capacity,
3479 mz_uint growing) {
3480 void *pNew_p;
3481 size_t new_capacity = min_new_capacity;
3482 MZ_ASSERT(pArray->m_element_size);
3483 if (pArray->m_capacity >= min_new_capacity)
3484 return MZ_TRUE;
3485 if (growing) {
3486 new_capacity = MZ_MAX(1, pArray->m_capacity);
3487 while (new_capacity < min_new_capacity)
3488 new_capacity *= 2;
3489 }
3490 if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p,
3491 pArray->m_element_size, new_capacity)))
3492 return MZ_FALSE;
3493 pArray->m_p = pNew_p;
3494 pArray->m_capacity = new_capacity;
3495 return MZ_TRUE;
3496}
3497
3498static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip,
3499 mz_zip_array *pArray,
3500 size_t new_capacity,
3501 mz_uint growing) {
3502 if (new_capacity > pArray->m_capacity) {
3503 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))
3504 return MZ_FALSE;
3505 }
3506 return MZ_TRUE;
3507}
3508
3509static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip,
3510 mz_zip_array *pArray,
3511 size_t new_size,
3512 mz_uint growing) {
3513 if (new_size > pArray->m_capacity) {
3514 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))
3515 return MZ_FALSE;
3516 }
3517 pArray->m_size = new_size;
3518 return MZ_TRUE;
3519}
3520
3521static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip,
3522 mz_zip_array *pArray,
3523 size_t n) {
3524 return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
3525}
3526
3527static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip,
3528 mz_zip_array *pArray,
3529 const void *pElements,
3530 size_t n) {
3531 size_t orig_size = pArray->m_size;
3532 if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE))
3533 return MZ_FALSE;
3534 if (n > 0)
3535 memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size,
3536 pElements, n * pArray->m_element_size);
3537 return MZ_TRUE;
3538}
3539
3540#ifndef MINIZ_NO_TIME
3541static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) {
3542 struct tm tm;
3543 memset(&tm, 0, sizeof(tm));
3544 tm.tm_isdst = -1;
3545 tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900;
3546 tm.tm_mon = ((dos_date >> 5) & 15) - 1;
3547 tm.tm_mday = dos_date & 31;
3548 tm.tm_hour = (dos_time >> 11) & 31;
3549 tm.tm_min = (dos_time >> 5) & 63;
3550 tm.tm_sec = (dos_time << 1) & 62;
3551 return mktime(&tm);
3552}
3553
3554#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
3555static void mz_zip_time_t_to_dos_time(MZ_TIME_T time,
3556 mz_uint16 *pDOS_time,
3557 mz_uint16 *pDOS_date) {
3558#ifdef _MSC_VER
3559 struct tm tm_struct;
3560 struct tm *tm = &tm_struct;
3561 errno_t err = localtime_s(tm, &time);
3562 if (err) {
3563 *pDOS_date = 0;
3564 *pDOS_time = 0;
3565 return;
3566 }
3567#else
3568 struct tm *tm = localtime(&time);
3569#endif /* #ifdef _MSC_VER */
3570
3571 *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) +
3572 ((tm->tm_sec) >> 1));
3573 *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) +
3574 ((tm->tm_mon + 1) << 5) + tm->tm_mday);
3575}
3576#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */
3577
3578#ifndef MINIZ_NO_STDIO
3579#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
3580static mz_bool mz_zip_get_file_modified_time(const char *pFilename,
3581 MZ_TIME_T *pTime) {
3582 struct MZ_FILE_STAT_STRUCT file_stat;
3583
3584 /* On Linux with x86 glibc, this call will fail on large files (I think >=
3585 * 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */
3586 if (MZ_FILE_STAT(pFilename, &file_stat) != 0)
3587 return MZ_FALSE;
3588
3589 *pTime = file_stat.st_mtime;
3590
3591 return MZ_TRUE;
3592}
3593#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/
3594
3595static mz_bool mz_zip_set_file_times(const char *pFilename,
3596 MZ_TIME_T access_time,
3597 MZ_TIME_T modified_time) {
3598 struct utimbuf t;
3599
3600 memset(&t, 0, sizeof(t));
3601 t.actime = access_time;
3602 t.modtime = modified_time;
3603
3604 return !utime(pFilename, &t);
3605}
3606#endif /* #ifndef MINIZ_NO_STDIO */
3607#endif /* #ifndef MINIZ_NO_TIME */
3608
3609static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip,
3610 mz_zip_error err_num) {
3611 if (pZip)
3612 pZip->m_last_error = err_num;
3613 return MZ_FALSE;
3614}
3615
3616static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
3617 mz_uint flags) {
3618 (void)flags;
3619 if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
3620 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
3621
3622 if (!pZip->m_pAlloc)
3623 pZip->m_pAlloc = miniz_def_alloc_func;
3624 if (!pZip->m_pFree)
3625 pZip->m_pFree = miniz_def_free_func;
3626 if (!pZip->m_pRealloc)
3627 pZip->m_pRealloc = miniz_def_realloc_func;
3628
3629 pZip->m_archive_size = 0;
3630 pZip->m_central_directory_file_ofs = 0;
3631 pZip->m_total_files = 0;
3632 pZip->m_last_error = MZ_ZIP_NO_ERROR;
3633
3634 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
3635 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
3636 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3637
3638 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
3639 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
3640 sizeof(mz_uint8));
3641 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
3642 sizeof(mz_uint32));
3643 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
3644 sizeof(mz_uint32));
3645 pZip->m_pState->m_init_flags = flags;
3646 pZip->m_pState->m_zip64 = MZ_FALSE;
3647 pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE;
3648
3649 pZip->m_zip_mode = MZ_ZIP_MODE_READING;
3650
3651 return MZ_TRUE;
3652}
3653
3654static MZ_FORCEINLINE mz_bool
3655mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array,
3656 const mz_zip_array *pCentral_dir_offsets,
3657 mz_uint l_index,
3658 mz_uint r_index) {
3659 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
3660 pCentral_dir_array, mz_uint8,
3661 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
3662 l_index)),
3663 *pE;
3664 const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(
3665 pCentral_dir_array, mz_uint8,
3666 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
3667 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS),
3668 r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);
3669 mz_uint8 l = 0, r = 0;
3670 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
3671 pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
3672 pE = pL + MZ_MIN(l_len, r_len);
3673 while (pL < pE) {
3674 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
3675 break;
3676 pL++;
3677 pR++;
3678 }
3679 return (pL == pE) ? (l_len < r_len) : (l < r);
3680}
3681
3682#define MZ_SWAP_UINT32(a, b) \
3683 do { \
3684 mz_uint32 t = a; \
3685 a = b; \
3686 b = t; \
3687 } \
3688 MZ_MACRO_END
3689
3690/* Heap sort of lowercased filenames, used to help accelerate plain central
3691 * directory searches by mz_zip_reader_locate_file(). (Could also use qsort(),
3692 * but it could allocate memory.) */
3693static void mz_zip_reader_sort_central_dir_offsets_by_filename(
3694 mz_zip_archive *pZip) {
3695 mz_zip_internal_state *pState = pZip->m_pState;
3696 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
3697 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
3698 mz_uint32 *pIndices;
3699 mz_uint32 start, end;
3700 const mz_uint32 size = pZip->m_total_files;
3701
3702 if (size <= 1U)
3703 return;
3704
3705 pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets,
3706 mz_uint32, 0);
3707
3708 start = (size - 2U) >> 1U;
3709 for (;;) {
3710 mz_uint64 child, root = start;
3711 for (;;) {
3712 if ((child = (root << 1U) + 1U) >= size)
3713 break;
3714 child += (((child + 1U) < size) &&
3715 (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
3716 pIndices[child],
3717 pIndices[child + 1U])));
3718 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
3719 pIndices[root], pIndices[child]))
3720 break;
3721 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
3722 root = child;
3723 }
3724 if (!start)
3725 break;
3726 start--;
3727 }
3728
3729 end = size - 1;
3730 while (end > 0) {
3731 mz_uint64 child, root = 0;
3732 MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
3733 for (;;) {
3734 if ((child = (root << 1U) + 1U) >= end)
3735 break;
3736 child +=
3737 (((child + 1U) < end) &&
3738 mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
3739 pIndices[child], pIndices[child + 1U]));
3740 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
3741 pIndices[root], pIndices[child]))
3742 break;
3743 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
3744 root = child;
3745 }
3746 end--;
3747 }
3748}
3749
3750static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip,
3751 mz_uint32 record_sig,
3752 mz_uint32 record_size,
3753 mz_int64 *pOfs) {
3754 mz_int64 cur_file_ofs;
3755 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
3756 mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
3757
3758 /* Basic sanity checks - reject files which are too small */
3759 if (pZip->m_archive_size < record_size)
3760 return MZ_FALSE;
3761
3762 /* Find the record by scanning the file from the end towards the beginning. */
3763 cur_file_ofs =
3764 MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
3765 for (;;) {
3766 int i,
3767 n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
3768
3769 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
3770 return MZ_FALSE;
3771
3772 for (i = n - 4; i >= 0; --i) {
3773 mz_uint s = MZ_READ_LE32(pBuf + i);
3774 if (s == record_sig) {
3775 if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)
3776 break;
3777 }
3778 }
3779
3780 if (i >= 0) {
3781 cur_file_ofs += i;
3782 break;
3783 }
3784
3785 /* Give up if we've searched the entire file, or we've gone back "too far"
3786 * (~64kb) */
3787 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
3788 (MZ_UINT16_MAX + record_size)))
3789 return MZ_FALSE;
3790
3791 cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
3792 }
3793
3794 *pOfs = cur_file_ofs;
3795 return MZ_TRUE;
3796}
3797
3798static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
3799 mz_uint flags) {
3800 mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0,
3801 cdir_disk_index = 0;
3802 mz_uint64 cdir_ofs = 0;
3803 mz_int64 cur_file_ofs = 0;
3804 const mz_uint8 *p;
3805
3806 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
3807 mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
3808 mz_bool sort_central_dir =
3809 ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
3810 mz_uint32 zip64_end_of_central_dir_locator_u32
3811 [(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) /
3812 sizeof(mz_uint32)];
3813 mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;
3814
3815 mz_uint32 zip64_end_of_central_dir_header_u32
3816 [(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
3817 sizeof(mz_uint32)];
3818 mz_uint8 *pZip64_end_of_central_dir =
3819 (mz_uint8 *)zip64_end_of_central_dir_header_u32;
3820
3821 mz_uint64 zip64_end_of_central_dir_ofs = 0;
3822
3823 /* Basic sanity checks - reject files which are too small, and check the first
3824 * 4 bytes of the file to make sure a local header is there. */
3825 if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
3826 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
3827
3828 if (!mz_zip_reader_locate_header_sig(
3829 pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG,
3830 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))
3831 return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);
3832
3833 /* Read and verify the end of central directory record. */
3834 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
3835 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
3836 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
3837 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
3838
3839 if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
3840 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
3841 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
3842
3843 if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE +
3844 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) {
3845 if (pZip->m_pRead(pZip->m_pIO_opaque,
3846 cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE,
3847 pZip64_locator,
3848 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ==
3849 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) {
3850 if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) ==
3851 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) {
3852 zip64_end_of_central_dir_ofs = MZ_READ_LE64(
3853 pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);
3854 if (zip64_end_of_central_dir_ofs >
3855 (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
3856 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
3857
3858 if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs,
3859 pZip64_end_of_central_dir,
3860 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ==
3861 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) {
3862 if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) ==
3863 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) {
3864 pZip->m_pState->m_zip64 = MZ_TRUE;
3865 }
3866 }
3867 }
3868 }
3869 }
3870
3871 pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);
3872 cdir_entries_on_this_disk =
3873 MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
3874 num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
3875 cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
3876 cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);
3877 cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
3878
3879 if (pZip->m_pState->m_zip64) {
3880 mz_uint32 zip64_total_num_of_disks =
3881 MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);
3882 mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(
3883 pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);
3884 mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(
3885 pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
3886 mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(
3887 pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);
3888 mz_uint64 zip64_size_of_central_directory =
3889 MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);
3890
3891 if (zip64_size_of_end_of_central_dir_record <
3892 (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))
3893 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
3894
3895 if (zip64_total_num_of_disks != 1U)
3896 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
3897
3898 /* Check for miniz's practical limits */
3899 if (zip64_cdir_total_entries > MZ_UINT32_MAX)
3900 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
3901
3902 pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;
3903
3904 if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)
3905 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
3906
3907 cdir_entries_on_this_disk =
3908 (mz_uint32)zip64_cdir_total_entries_on_this_disk;
3909
3910 /* Check for miniz's current practical limits (sorry, this should be enough
3911 * for millions of files) */
3912 if (zip64_size_of_central_directory > MZ_UINT32_MAX)
3913 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
3914
3915 cdir_size = (mz_uint32)zip64_size_of_central_directory;
3916
3917 num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir +
3918 MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);
3919
3920 cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir +
3921 MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);
3922
3923 cdir_ofs =
3924 MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);
3925 }
3926
3927 if (pZip->m_total_files != cdir_entries_on_this_disk)
3928 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
3929
3930 if (((num_this_disk | cdir_disk_index) != 0) &&
3931 ((num_this_disk != 1) || (cdir_disk_index != 1)))
3932 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
3933
3934 if (cdir_size <
3935 (mz_uint64)pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
3936 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
3937
3938 if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
3939 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
3940
3941 pZip->m_central_directory_file_ofs = cdir_ofs;
3942
3943 if (pZip->m_total_files) {
3944 mz_uint i, n;
3945 /* Read the entire central directory into a heap block, and allocate another
3946 * heap block to hold the unsorted central dir file record offsets, and
3947 * possibly another to hold the sorted indices. */
3948 if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
3949 MZ_FALSE)) ||
3950 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
3951 pZip->m_total_files, MZ_FALSE)))
3952 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3953
3954 if (sort_central_dir) {
3955 if (!mz_zip_array_resize(pZip,
3956 &pZip->m_pState->m_sorted_central_dir_offsets,
3957 pZip->m_total_files, MZ_FALSE))
3958 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3959 }
3960
3961 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
3962 pZip->m_pState->m_central_dir.m_p,
3963 cdir_size) != cdir_size)
3964 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
3965
3966 /* Now create an index into the central directory file records, do some
3967 * basic sanity checking on each record */
3968 p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
3969 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
3970 mz_uint total_header_size, disk_index, bit_flags, filename_size,
3971 ext_data_size;
3972 mz_uint64 comp_size, decomp_size, local_header_ofs;
3973
3974 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
3975 (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
3976 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
3977
3978 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
3979 i) =
3980 (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
3981
3982 if (sort_central_dir)
3983 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
3984 mz_uint32, i) = i;
3985
3986 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
3987 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
3988 local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
3989 filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
3990 ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
3991
3992 if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&
3993 (ext_data_size) &&
3994 (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) ==
3995 MZ_UINT32_MAX)) {
3996 /* Attempt to find zip64 extended information field in the entry's extra
3997 * data */
3998 mz_uint32 extra_size_remaining = ext_data_size;
3999
4000 if (extra_size_remaining) {
4001 const mz_uint8 *pExtra_data;
4002 void *buf = NULL;
4003
4004 if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size >
4005 n) {
4006 buf = MZ_MALLOC(ext_data_size);
4007 if (buf == NULL)
4008 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4009
4010 if (pZip->m_pRead(
4011 pZip->m_pIO_opaque,
4012 cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size,
4013 buf, ext_data_size) != ext_data_size) {
4014 MZ_FREE(buf);
4015 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
4016 }
4017
4018 pExtra_data = (mz_uint8 *)buf;
4019 } else {
4020 pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
4021 }
4022
4023 do {
4024 mz_uint32 field_id;
4025 mz_uint32 field_data_size;
4026
4027 if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
4028 MZ_FREE(buf);
4029 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4030 }
4031
4032 field_id = MZ_READ_LE16(pExtra_data);
4033 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
4034
4035 if ((field_data_size + sizeof(mz_uint16) * 2) >
4036 extra_size_remaining) {
4037 MZ_FREE(buf);
4038 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4039 }
4040
4041 if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
4042 /* Ok, the archive didn't have any zip64 headers but it uses a
4043 * zip64 extended information field so mark it as zip64 anyway
4044 * (this can occur with infozip's zip util when it reads
4045 * compresses files from stdin). */
4046 pZip->m_pState->m_zip64 = MZ_TRUE;
4047 pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;
4048 break;
4049 }
4050
4051 pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
4052 extra_size_remaining =
4053 extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
4054 } while (extra_size_remaining);
4055
4056 MZ_FREE(buf);
4057 }
4058 }
4059
4060 /* I've seen archives that aren't marked as zip64 that uses zip64 ext
4061 * data, argh */
4062 if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) {
4063 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
4064 (decomp_size != comp_size)) ||
4065 (decomp_size && !comp_size))
4066 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4067 }
4068
4069 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
4070 if ((disk_index == MZ_UINT16_MAX) ||
4071 ((disk_index != num_this_disk) && (disk_index != 1)))
4072 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
4073
4074 if (comp_size != MZ_UINT32_MAX) {
4075 if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
4076 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
4077 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4078 }
4079
4080 bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
4081 if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)
4082 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
4083
4084 if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
4085 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
4086 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
4087 MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
4088 n)
4089 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4090
4091 n -= total_header_size;
4092 p += total_header_size;
4093 }
4094 }
4095
4096 if (sort_central_dir)
4097 mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
4098
4099 return MZ_TRUE;
4100}
4101
4102void mz_zip_zero_struct(mz_zip_archive *pZip) {
4103 if (pZip)
4104 MZ_CLEAR_PTR(pZip);
4105}
4106
4107static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip,
4108 mz_bool set_last_error) {
4109 mz_bool status = MZ_TRUE;
4110
4111 if (!pZip)
4112 return MZ_FALSE;
4113
4114 if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
4115 (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) {
4116 if (set_last_error)
4117 pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER;
4118
4119 return MZ_FALSE;
4120 }
4121
4122 if (pZip->m_pState) {
4123 mz_zip_internal_state *pState = pZip->m_pState;
4124 pZip->m_pState = NULL;
4125
4126 mz_zip_array_clear(pZip, &pState->m_central_dir);
4127 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
4128 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
4129
4130#ifndef MINIZ_NO_STDIO
4131 if (pState->m_pFile) {
4132 if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) {
4133 if (MZ_FCLOSE(pState->m_pFile) == EOF) {
4134 if (set_last_error)
4135 pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED;
4136 status = MZ_FALSE;
4137 }
4138 }
4139 pState->m_pFile = NULL;
4140 }
4141#endif /* #ifndef MINIZ_NO_STDIO */
4142
4143 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
4144 }
4145 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
4146
4147 return status;
4148}
4149
4150mz_bool mz_zip_reader_end(mz_zip_archive *pZip) {
4151 return mz_zip_reader_end_internal(pZip, MZ_TRUE);
4152}
4153mz_bool mz_zip_reader_init(mz_zip_archive *pZip,
4154 mz_uint64 size,
4155 mz_uint flags) {
4156 if ((!pZip) || (!pZip->m_pRead))
4157 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4158
4159 if (!mz_zip_reader_init_internal(pZip, flags))
4160 return MZ_FALSE;
4161
4162 pZip->m_zip_type = MZ_ZIP_TYPE_USER;
4163 pZip->m_archive_size = size;
4164
4165 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
4166 mz_zip_reader_end_internal(pZip, MZ_FALSE);
4167 return MZ_FALSE;
4168 }
4169
4170 return MZ_TRUE;
4171}
4172
4173static size_t mz_zip_mem_read_func(void *pOpaque,
4174 mz_uint64 file_ofs,
4175 void *pBuf,
4176 size_t n) {
4177 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
4178 size_t s = (file_ofs >= pZip->m_archive_size)
4179 ? 0
4180 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
4181 memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
4182 return s;
4183}
4184
4185mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip,
4186 const void *pMem,
4187 size_t size,
4188 mz_uint flags) {
4189 if (!pMem)
4190 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4191
4192 if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
4193 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
4194
4195 if (!mz_zip_reader_init_internal(pZip, flags))
4196 return MZ_FALSE;
4197
4198 pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY;
4199 pZip->m_archive_size = size;
4200 pZip->m_pRead = mz_zip_mem_read_func;
4201 pZip->m_pIO_opaque = pZip;
4202 pZip->m_pNeeds_keepalive = NULL;
4203
4204#ifdef __cplusplus
4205 pZip->m_pState->m_pMem = const_cast<void *>(pMem);
4206#else
4207 pZip->m_pState->m_pMem = (void *)pMem;
4208#endif
4209
4210 pZip->m_pState->m_mem_size = size;
4211
4212 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
4213 mz_zip_reader_end_internal(pZip, MZ_FALSE);
4214 return MZ_FALSE;
4215 }
4216
4217 return MZ_TRUE;
4218}
4219
4220#ifndef MINIZ_NO_STDIO
4221static size_t mz_zip_file_read_func(void *pOpaque,
4222 mz_uint64 file_ofs,
4223 void *pBuf,
4224 size_t n) {
4225 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
4226 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
4227
4228 file_ofs += pZip->m_pState->m_file_archive_start_ofs;
4229
4230 if (((mz_int64)file_ofs < 0) ||
4231 (((cur_ofs != (mz_int64)file_ofs)) &&
4232 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
4233 return 0;
4234
4235 return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
4236}
4237
4238mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip,
4239 const char *pFilename,
4240 mz_uint32 flags) {
4241 return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0);
4242}
4243
4244mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip,
4245 const char *pFilename,
4246 mz_uint flags,
4247 mz_uint64 file_start_ofs,
4248 mz_uint64 archive_size) {
4249 mz_uint64 file_size;
4250 MZ_FILE *pFile;
4251
4252 if ((!pZip) || (!pFilename) ||
4253 ((archive_size) &&
4254 (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
4255 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4256
4257 pFile = MZ_FOPEN(pFilename, "rb");
4258 if (!pFile)
4259 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
4260
4261 file_size = archive_size;
4262 if (!file_size) {
4263 if (MZ_FSEEK64(pFile, 0, SEEK_END)) {
4264 MZ_FCLOSE(pFile);
4265 return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
4266 }
4267
4268 file_size = MZ_FTELL64(pFile);
4269 }
4270
4271 /* TODO: Better sanity check archive_size and the # of actual remaining bytes
4272 */
4273
4274 if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) {
4275 MZ_FCLOSE(pFile);
4276 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
4277 }
4278
4279 if (!mz_zip_reader_init_internal(pZip, flags)) {
4280 MZ_FCLOSE(pFile);
4281 return MZ_FALSE;
4282 }
4283
4284 pZip->m_zip_type = MZ_ZIP_TYPE_FILE;
4285 pZip->m_pRead = mz_zip_file_read_func;
4286 pZip->m_pIO_opaque = pZip;
4287 pZip->m_pState->m_pFile = pFile;
4288 pZip->m_archive_size = file_size;
4289 pZip->m_pState->m_file_archive_start_ofs = file_start_ofs;
4290
4291 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
4292 mz_zip_reader_end_internal(pZip, MZ_FALSE);
4293 return MZ_FALSE;
4294 }
4295
4296 return MZ_TRUE;
4297}
4298
4299mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip,
4300 MZ_FILE *pFile,
4301 mz_uint64 archive_size,
4302 mz_uint flags) {
4303 mz_uint64 cur_file_ofs;
4304
4305 if ((!pZip) || (!pFile))
4306 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
4307
4308 cur_file_ofs = MZ_FTELL64(pFile);
4309
4310 if (!archive_size) {
4311 if (MZ_FSEEK64(pFile, 0, SEEK_END))
4312 return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
4313
4314 archive_size = MZ_FTELL64(pFile) - cur_file_ofs;
4315
4316 if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
4317 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
4318 }
4319
4320 if (!mz_zip_reader_init_internal(pZip, flags))
4321 return MZ_FALSE;
4322
4323 pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;
4324 pZip->m_pRead = mz_zip_file_read_func;
4325
4326 pZip->m_pIO_opaque = pZip;
4327 pZip->m_pState->m_pFile = pFile;
4328 pZip->m_archive_size = archive_size;
4329 pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs;
4330
4331 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
4332 mz_zip_reader_end_internal(pZip, MZ_FALSE);
4333 return MZ_FALSE;
4334 }
4335
4336 return MZ_TRUE;
4337}
4338
4339#endif /* #ifndef MINIZ_NO_STDIO */
4340
4341static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip,
4342 mz_uint file_index) {
4343 if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files))
4344 return NULL;
4345 return &MZ_ZIP_ARRAY_ELEMENT(
4346 &pZip->m_pState->m_central_dir, mz_uint8,
4347 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
4348 file_index));
4349}
4350
4351mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
4352 mz_uint file_index) {
4353 mz_uint m_bit_flag;
4354 const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
4355 if (!p) {
4356 mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4357 return MZ_FALSE;
4358 }
4359
4360 m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
4361 return (m_bit_flag &
4362 (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED |
4363 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0;
4364}
4365
4366mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip,
4367 mz_uint file_index) {
4368 mz_uint bit_flag;
4369 mz_uint method;
4370
4371 const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
4372 if (!p) {
4373 mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4374 return MZ_FALSE;
4375 }
4376
4377 method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
4378 bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
4379
4380 if ((method != 0) && (method != MZ_DEFLATED)) {
4381 mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
4382 return MZ_FALSE;
4383 }
4384
4385 if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED |
4386 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) {
4387 mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
4388 return MZ_FALSE;
4389 }
4390
4391 if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) {
4392 mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
4393 return MZ_FALSE;
4394 }
4395
4396 return MZ_TRUE;
4397}
4398
4399mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
4400 mz_uint file_index) {
4401 mz_uint filename_len, attribute_mapping_id, external_attr;
4402 const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
4403 if (!p) {
4404 mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4405 return MZ_FALSE;
4406 }
4407
4408 filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
4409 if (filename_len) {
4410 if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
4411 return MZ_TRUE;
4412 }
4413
4414 /* Bugfix: This code was also checking if the internal attribute was non-zero,
4415 * which wasn't correct. */
4416 /* Most/all zip writers (hopefully) set DOS file/directory attributes in the
4417 * low 16-bits, so check for the DOS directory flag and ignore the source OS
4418 * ID in the created by field. */
4419 /* FIXME: Remove this check? Is it necessary - we already check the filename.
4420 */
4421 attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8;
4422 (void)attribute_mapping_id;
4423
4424 external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
4425 if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) {
4426 return MZ_TRUE;
4427 }
4428
4429 return MZ_FALSE;
4430}
4431
4432static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip,
4433 mz_uint file_index,
4434 const mz_uint8 *pCentral_dir_header,
4435 mz_zip_archive_file_stat *pStat,
4436 mz_bool *pFound_zip64_extra_data) {
4437 mz_uint n;
4438 const mz_uint8 *p = pCentral_dir_header;
4439
4440 if (pFound_zip64_extra_data)
4441 *pFound_zip64_extra_data = MZ_FALSE;
4442
4443 if ((!p) || (!pStat))
4444 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4445
4446 /* Extract fields from the central directory record. */
4447 pStat->m_file_index = file_index;
4448 pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(
4449 &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
4450 pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
4451 pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
4452 pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
4453 pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
4454#ifndef MINIZ_NO_TIME
4455 pStat->m_time =
4456 mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS),
4457 MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));
4458#endif
4459 pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
4460 pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
4461 pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
4462 pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
4463 pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
4464 pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
4465
4466 /* Copy as much of the filename and comment as possible. */
4467 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
4468 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
4469 memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
4470 pStat->m_filename[n] = '\0';
4471
4472 n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
4473 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
4474 pStat->m_comment_size = n;
4475 memcpy(pStat->m_comment,
4476 p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
4477 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
4478 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
4479 n);
4480 pStat->m_comment[n] = '\0';
4481
4482 /* Set some flags for convienance */
4483 pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index);
4484 pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index);
4485 pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index);
4486
4487 /* See if we need to read any zip64 extended information fields. */
4488 /* Confusingly, these zip64 fields can be present even on non-zip64 archives
4489 * (Debian zip on a huge files from stdin piped to stdout creates them). */
4490 if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size),
4491 pStat->m_local_header_ofs) == MZ_UINT32_MAX) {
4492 /* Attempt to find zip64 extended information field in the entry's extra
4493 * data */
4494 mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
4495
4496 if (extra_size_remaining) {
4497 const mz_uint8 *pExtra_data =
4498 p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
4499 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
4500
4501 do {
4502 mz_uint32 field_id;
4503 mz_uint32 field_data_size;
4504
4505 if (extra_size_remaining < (sizeof(mz_uint16) * 2))
4506 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4507
4508 field_id = MZ_READ_LE16(pExtra_data);
4509 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
4510
4511 if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)
4512 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4513
4514 if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
4515 const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2;
4516 mz_uint32 field_data_remaining = field_data_size;
4517
4518 if (pFound_zip64_extra_data)
4519 *pFound_zip64_extra_data = MZ_TRUE;
4520
4521 if (pStat->m_uncomp_size == MZ_UINT32_MAX) {
4522 if (field_data_remaining < sizeof(mz_uint64))
4523 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4524
4525 pStat->m_uncomp_size = MZ_READ_LE64(pField_data);
4526 pField_data += sizeof(mz_uint64);
4527 field_data_remaining -= sizeof(mz_uint64);
4528 }
4529
4530 if (pStat->m_comp_size == MZ_UINT32_MAX) {
4531 if (field_data_remaining < sizeof(mz_uint64))
4532 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4533
4534 pStat->m_comp_size = MZ_READ_LE64(pField_data);
4535 pField_data += sizeof(mz_uint64);
4536 field_data_remaining -= sizeof(mz_uint64);
4537 }
4538
4539 if (pStat->m_local_header_ofs == MZ_UINT32_MAX) {
4540 if (field_data_remaining < sizeof(mz_uint64))
4541 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4542
4543 pStat->m_local_header_ofs = MZ_READ_LE64(pField_data);
4544 pField_data += sizeof(mz_uint64);
4545 field_data_remaining -= sizeof(mz_uint64);
4546 }
4547
4548 break;
4549 }
4550
4551 pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
4552 extra_size_remaining =
4553 extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
4554 } while (extra_size_remaining);
4555 }
4556 }
4557
4558 return MZ_TRUE;
4559}
4560
4561static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA,
4562 const char *pB,
4563 mz_uint len,
4564 mz_uint flags) {
4565 mz_uint i;
4566 if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE)
4567 return 0 == memcmp(pA, pB, len);
4568 for (i = 0; i < len; ++i)
4569 if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i]))
4570 return MZ_FALSE;
4571 return MZ_TRUE;
4572}
4573
4574static MZ_FORCEINLINE int mz_zip_filename_compare(
4575 const mz_zip_array *pCentral_dir_array,
4576 const mz_zip_array *pCentral_dir_offsets,
4577 mz_uint l_index,
4578 const char *pR,
4579 mz_uint r_len) {
4580 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
4581 pCentral_dir_array, mz_uint8,
4582 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
4583 l_index)),
4584 *pE;
4585 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
4586 mz_uint8 l = 0, r = 0;
4587 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
4588 pE = pL + MZ_MIN(l_len, r_len);
4589 while (pL < pE) {
4590 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
4591 break;
4592 pL++;
4593 pR++;
4594 }
4595 return (pL == pE) ? (int)(l_len - r_len) : (l - r);
4596}
4597
4598static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip,
4599 const char *pFilename,
4600 mz_uint32 *pIndex) {
4601 mz_zip_internal_state *pState = pZip->m_pState;
4602 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
4603 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
4604 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
4605 &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
4606 const mz_uint32 size = pZip->m_total_files;
4607 const mz_uint filename_len = (mz_uint)strlen(pFilename);
4608
4609 if (pIndex)
4610 *pIndex = 0;
4611
4612 if (size) {
4613 /* yes I could use uint32_t's, but then we would have to add some special
4614 * case checks in the loop, argh, and */
4615 /* honestly the major expense here on 32-bit CPU's will still be the
4616 * filename compare */
4617 mz_int64 l = 0, h = (mz_int64)size - 1;
4618
4619 while (l <= h) {
4620 mz_int64 m = l + ((h - l) >> 1);
4621 mz_uint32 file_index = pIndices[(mz_uint32)m];
4622
4623 int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets,
4624 file_index, pFilename, filename_len);
4625 if (!comp) {
4626 if (pIndex)
4627 *pIndex = file_index;
4628 return MZ_TRUE;
4629 } else if (comp < 0)
4630 l = m + 1;
4631 else
4632 h = m - 1;
4633 }
4634 }
4635
4636 return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);
4637}
4638
4639int mz_zip_reader_locate_file(mz_zip_archive *pZip,
4640 const char *pName,
4641 const char *pComment,
4642 mz_uint flags) {
4643 mz_uint32 index;
4644 if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index))
4645 return -1;
4646 else
4647 return (int)index;
4648}
4649
4650mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip,
4651 const char *pName,
4652 const char *pComment,
4653 mz_uint flags,
4654 mz_uint32 *pIndex) {
4655 mz_uint file_index;
4656 size_t name_len, comment_len;
4657
4658 if (pIndex)
4659 *pIndex = 0;
4660
4661 if ((!pZip) || (!pZip->m_pState) || (!pName))
4662 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4663
4664 /* See if we can use a binary search */
4665 if (((pZip->m_pState->m_init_flags &
4666 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) &&
4667 (pZip->m_zip_mode == MZ_ZIP_MODE_READING) &&
4668 ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) &&
4669 (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) {
4670 return mz_zip_locate_file_binary_search(pZip, pName, pIndex);
4671 }
4672
4673 /* Locate the entry by scanning the entire central directory */
4674 name_len = strlen(pName);
4675 if (name_len > MZ_UINT16_MAX)
4676 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4677
4678 comment_len = pComment ? strlen(pComment) : 0;
4679 if (comment_len > MZ_UINT16_MAX)
4680 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4681
4682 for (file_index = 0; file_index < pZip->m_total_files; file_index++) {
4683 const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(
4684 &pZip->m_pState->m_central_dir, mz_uint8,
4685 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
4686 file_index));
4687 mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
4688 const char *pFilename =
4689 (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
4690 if (filename_len < name_len)
4691 continue;
4692 if (comment_len) {
4693 mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS),
4694 file_comment_len =
4695 MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);
4696 const char *pFile_comment = pFilename + filename_len + file_extra_len;
4697 if ((file_comment_len != comment_len) ||
4698 (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len,
4699 flags)))
4700 continue;
4701 }
4702 if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) {
4703 int ofs = filename_len - 1;
4704 do {
4705 if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') ||
4706 (pFilename[ofs] == ':'))
4707 break;
4708 } while (--ofs >= 0);
4709 ofs++;
4710 pFilename += ofs;
4711 filename_len -= ofs;
4712 }
4713 if ((filename_len == name_len) &&
4714 (mz_zip_string_equal(pName, pFilename, filename_len, flags))) {
4715 if (pIndex)
4716 *pIndex = file_index;
4717 return MZ_TRUE;
4718 }
4719 }
4720
4721 return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);
4722}
4723
4724static mz_bool mz_zip_reader_extract_to_mem_no_alloc1(
4725 mz_zip_archive *pZip,
4726 mz_uint file_index,
4727 void *pBuf,
4728 size_t buf_size,
4729 mz_uint flags,
4730 void *pUser_read_buf,
4731 size_t user_read_buf_size,
4732 const mz_zip_archive_file_stat *st) {
4733 int status = TINFL_STATUS_DONE;
4734 mz_uint64 needed_size, cur_file_ofs, comp_remaining,
4735 out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
4736 mz_zip_archive_file_stat file_stat;
4737 void *pRead_buf;
4738 mz_uint32
4739 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
4740 sizeof(mz_uint32)];
4741 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
4742 tinfl_decompressor inflator;
4743
4744 if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) ||
4745 ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead))
4746 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4747
4748 if (st) {
4749 file_stat = *st;
4750 } else if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
4751 return MZ_FALSE;
4752
4753 /* A directory or zero length file */
4754 if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))
4755 return MZ_TRUE;
4756
4757 /* Encryption and patch files are not supported. */
4758 if (file_stat.m_bit_flag &
4759 (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED |
4760 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION |
4761 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))
4762 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
4763
4764 /* This function only supports decompressing stored and deflate. */
4765 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
4766 (file_stat.m_method != MZ_DEFLATED))
4767 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
4768
4769 /* Ensure supplied output buffer is large enough. */
4770 needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size
4771 : file_stat.m_uncomp_size;
4772 if (buf_size < needed_size)
4773 return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL);
4774
4775 /* Read and parse the local directory entry. */
4776 cur_file_ofs = file_stat.m_local_header_ofs;
4777 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
4778 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
4779 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
4780 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
4781
4782 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
4783 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4784
4785 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
4786 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
4787 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
4788 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
4789 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4790
4791 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
4792 /* The file is stored or the caller has requested the compressed data. */
4793 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
4794 (size_t)needed_size) != needed_size)
4795 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
4796
4797#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
4798 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) {
4799 if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
4800 (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)
4801 return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);
4802 }
4803#endif
4804
4805 return MZ_TRUE;
4806 }
4807
4808 /* Decompress the file either directly from memory or from a file input
4809 * buffer. */
4810 tinfl_init(&inflator);
4811
4812 if (pZip->m_pState->m_pMem) {
4813 /* Read directly from the archive in memory. */
4814 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
4815 read_buf_size = read_buf_avail = file_stat.m_comp_size;
4816 comp_remaining = 0;
4817 } else if (pUser_read_buf) {
4818 /* Use a user provided read buffer. */
4819 if (!user_read_buf_size)
4820 return MZ_FALSE;
4821 pRead_buf = (mz_uint8 *)pUser_read_buf;
4822 read_buf_size = user_read_buf_size;
4823 read_buf_avail = 0;
4824 comp_remaining = file_stat.m_comp_size;
4825 } else {
4826 /* Temporarily allocate a read buffer. */
4827 read_buf_size =
4828 MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
4829 if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
4830 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
4831
4832 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
4833 (size_t)read_buf_size)))
4834 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4835
4836 read_buf_avail = 0;
4837 comp_remaining = file_stat.m_comp_size;
4838 }
4839
4840 do {
4841 /* The size_t cast here should be OK because we've verified that the output
4842 * buffer is >= file_stat.m_uncomp_size above */
4843 size_t in_buf_size,
4844 out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
4845 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
4846 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
4847 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
4848 (size_t)read_buf_avail) != read_buf_avail) {
4849 status = TINFL_STATUS_FAILED;
4850 mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
4851 break;
4852 }
4853 cur_file_ofs += read_buf_avail;
4854 comp_remaining -= read_buf_avail;
4855 read_buf_ofs = 0;
4856 }
4857 in_buf_size = (size_t)read_buf_avail;
4858 status = tinfl_decompress(
4859 &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
4860 (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size,
4861 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF |
4862 (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));
4863 read_buf_avail -= in_buf_size;
4864 read_buf_ofs += in_buf_size;
4865 out_buf_ofs += out_buf_size;
4866 } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
4867
4868 if (status == TINFL_STATUS_DONE) {
4869 /* Make sure the entire file was decompressed, and check its CRC. */
4870 if (out_buf_ofs != file_stat.m_uncomp_size) {
4871 mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);
4872 status = TINFL_STATUS_FAILED;
4873 }
4874#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
4875 else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
4876 (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) {
4877 mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);
4878 status = TINFL_STATUS_FAILED;
4879 }
4880#endif
4881 }
4882
4883 if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
4884 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
4885
4886 return status == TINFL_STATUS_DONE;
4887}
4888
4889mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
4890 mz_uint file_index,
4891 void *pBuf,
4892 size_t buf_size,
4893 mz_uint flags,
4894 void *pUser_read_buf,
4895 size_t user_read_buf_size) {
4896 return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf,
4897 buf_size, flags, pUser_read_buf,
4898 user_read_buf_size, NULL);
4899}
4900
4901mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip,
4902 const char *pFilename,
4903 void *pBuf,
4904 size_t buf_size,
4905 mz_uint flags,
4906 void *pUser_read_buf,
4907 size_t user_read_buf_size) {
4908 mz_uint32 file_index;
4909 if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
4910 return MZ_FALSE;
4911 return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf,
4912 buf_size, flags, pUser_read_buf,
4913 user_read_buf_size, NULL);
4914}
4915
4916mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip,
4917 mz_uint file_index,
4918 void *pBuf,
4919 size_t buf_size,
4920 mz_uint flags) {
4921 return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf,
4922 buf_size, flags, NULL, 0, NULL);
4923}
4924
4925mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
4926 const char *pFilename,
4927 void *pBuf,
4928 size_t buf_size,
4929 mz_uint flags) {
4930 return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf,
4931 buf_size, flags, NULL, 0);
4932}
4933
4934void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip,
4935 mz_uint file_index,
4936 size_t *pSize,
4937 mz_uint flags) {
4938 mz_zip_archive_file_stat file_stat;
4939 mz_uint64 alloc_size;
4940 void *pBuf;
4941
4942 if (pSize)
4943 *pSize = 0;
4944
4945 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
4946 return NULL;
4947
4948 alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size
4949 : file_stat.m_uncomp_size;
4950 if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) {
4951 mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
4952 return NULL;
4953 }
4954
4955 if (NULL ==
4956 (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) {
4957 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4958 return NULL;
4959 }
4960
4961 if (!mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf,
4962 (size_t)alloc_size, flags, NULL,
4963 0, &file_stat)) {
4964 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4965 return NULL;
4966 }
4967
4968 if (pSize)
4969 *pSize = (size_t)alloc_size;
4970 return pBuf;
4971}
4972
4973void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
4974 const char *pFilename,
4975 size_t *pSize,
4976 mz_uint flags) {
4977 mz_uint32 file_index;
4978 if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags,
4979 &file_index)) {
4980 if (pSize)
4981 *pSize = 0;
4982 return MZ_FALSE;
4983 }
4984 return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
4985}
4986
4987mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
4988 mz_uint file_index,
4989 mz_file_write_func pCallback,
4990 void *pOpaque,
4991 mz_uint flags) {
4992 int status = TINFL_STATUS_DONE;
4993#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
4994 mz_uint file_crc32 = MZ_CRC32_INIT;
4995#endif
4996 mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining,
4997 out_buf_ofs = 0, cur_file_ofs;
4998 mz_zip_archive_file_stat file_stat;
4999 void *pRead_buf = NULL;
5000 void *pWrite_buf = NULL;
5001 mz_uint32
5002 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5003 sizeof(mz_uint32)];
5004 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
5005
5006 if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead))
5007 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
5008
5009 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
5010 return MZ_FALSE;
5011
5012 /* A directory or zero length file */
5013 if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))
5014 return MZ_TRUE;
5015
5016 /* Encryption and patch files are not supported. */
5017 if (file_stat.m_bit_flag &
5018 (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED |
5019 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION |
5020 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))
5021 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
5022
5023 /* This function only supports decompressing stored and deflate. */
5024 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
5025 (file_stat.m_method != MZ_DEFLATED))
5026 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
5027
5028 /* Read and do some minimal validation of the local directory entry (this
5029 * doesn't crack the zip64 stuff, which we already have from the central dir)
5030 */
5031 cur_file_ofs = file_stat.m_local_header_ofs;
5032 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
5033 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
5034 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
5035 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
5036
5037 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
5038 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5039
5040 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5041 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
5042 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
5043 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
5044 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5045
5046 /* Decompress the file either directly from memory or from a file input
5047 * buffer. */
5048 if (pZip->m_pState->m_pMem) {
5049 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
5050 read_buf_size = read_buf_avail = file_stat.m_comp_size;
5051 comp_remaining = 0;
5052 } else {
5053 read_buf_size =
5054 MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
5055 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5056 (size_t)read_buf_size)))
5057 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
5058
5059 read_buf_avail = 0;
5060 comp_remaining = file_stat.m_comp_size;
5061 }
5062
5063 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
5064 /* The file is stored or the caller has requested the compressed data. */
5065 if (pZip->m_pState->m_pMem) {
5066 if (((sizeof(size_t) == sizeof(mz_uint32))) &&
5067 (file_stat.m_comp_size > MZ_UINT32_MAX))
5068 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
5069
5070 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
5071 (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) {
5072 mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
5073 status = TINFL_STATUS_FAILED;
5074 } else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
5075#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
5076 file_crc32 =
5077 (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf,
5078 (size_t)file_stat.m_comp_size);
5079#endif
5080 }
5081
5082 cur_file_ofs += file_stat.m_comp_size;
5083 out_buf_ofs += file_stat.m_comp_size;
5084 comp_remaining = 0;
5085 } else {
5086 while (comp_remaining) {
5087 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5088 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5089 (size_t)read_buf_avail) != read_buf_avail) {
5090 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
5091 status = TINFL_STATUS_FAILED;
5092 break;
5093 }
5094
5095#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
5096 if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
5097 file_crc32 = (mz_uint32)mz_crc32(
5098 file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
5099 }
5100#endif
5101
5102 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
5103 (size_t)read_buf_avail) != read_buf_avail) {
5104 mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
5105 status = TINFL_STATUS_FAILED;
5106 break;
5107 }
5108
5109 cur_file_ofs += read_buf_avail;
5110 out_buf_ofs += read_buf_avail;
5111 comp_remaining -= read_buf_avail;
5112 }
5113 }
5114 } else {
5115 tinfl_decompressor inflator;
5116 tinfl_init(&inflator);
5117
5118 if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5119 TINFL_LZ_DICT_SIZE))) {
5120 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
5121 status = TINFL_STATUS_FAILED;
5122 } else {
5123 do {
5124 mz_uint8 *pWrite_buf_cur =
5125 (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5126 size_t in_buf_size,
5127 out_buf_size =
5128 TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5129 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
5130 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5131 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5132 (size_t)read_buf_avail) != read_buf_avail) {
5133 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
5134 status = TINFL_STATUS_FAILED;
5135 break;
5136 }
5137 cur_file_ofs += read_buf_avail;
5138 comp_remaining -= read_buf_avail;
5139 read_buf_ofs = 0;
5140 }
5141
5142 in_buf_size = (size_t)read_buf_avail;
5143 status = tinfl_decompress(
5144 &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
5145 (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size,
5146 comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
5147 read_buf_avail -= in_buf_size;
5148 read_buf_ofs += in_buf_size;
5149
5150 if (out_buf_size) {
5151 if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) !=
5152 out_buf_size) {
5153 mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
5154 status = TINFL_STATUS_FAILED;
5155 break;
5156 }
5157
5158#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
5159 file_crc32 =
5160 (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
5161#endif
5162 if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) {
5163 mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
5164 status = TINFL_STATUS_FAILED;
5165 break;
5166 }
5167 }
5168 } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) ||
5169 (status == TINFL_STATUS_HAS_MORE_OUTPUT));
5170 }
5171 }
5172
5173 if ((status == TINFL_STATUS_DONE) &&
5174 (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) {
5175 /* Make sure the entire file was decompressed, and check its CRC. */
5176 if (out_buf_ofs != file_stat.m_uncomp_size) {
5177 mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);
5178 status = TINFL_STATUS_FAILED;
5179 }
5180#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
5181 else if (file_crc32 != file_stat.m_crc32) {
5182 mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
5183 status = TINFL_STATUS_FAILED;
5184 }
5185#endif
5186 }
5187
5188 if (!pZip->m_pState->m_pMem)
5189 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
5190
5191 if (pWrite_buf)
5192 pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
5193
5194 return status == TINFL_STATUS_DONE;
5195}
5196
5197mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
5198 const char *pFilename,
5199 mz_file_write_func pCallback,
5200 void *pOpaque,
5201 mz_uint flags) {
5202 mz_uint32 file_index;
5203 if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
5204 return MZ_FALSE;
5205
5206 return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque,
5207 flags);
5208}
5209
5210mz_zip_reader_extract_iter_state *mz_zip_reader_extract_iter_new(
5211 mz_zip_archive *pZip,
5212 mz_uint file_index,
5213 mz_uint flags) {
5214 mz_zip_reader_extract_iter_state *pState;
5215 mz_uint32
5216 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5217 sizeof(mz_uint32)];
5218 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
5219
5220 /* Argument sanity check */
5221 if ((!pZip) || (!pZip->m_pState))
5222 return NULL;
5223
5224 /* Allocate an iterator status structure */
5225 pState = (mz_zip_reader_extract_iter_state *)pZip->m_pAlloc(
5226 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state));
5227 if (!pState) {
5228 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
5229 return NULL;
5230 }
5231
5232 /* Fetch file details */
5233 if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) {
5234 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5235 return NULL;
5236 }
5237
5238 /* Encryption and patch files are not supported. */
5239 if (pState->file_stat.m_bit_flag &
5240 (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED |
5241 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION |
5242 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) {
5243 mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
5244 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5245 return NULL;
5246 }
5247
5248 /* This function only supports decompressing stored and deflate. */
5249 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) &&
5250 (pState->file_stat.m_method != 0) &&
5251 (pState->file_stat.m_method != MZ_DEFLATED)) {
5252 mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
5253 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5254 return NULL;
5255 }
5256
5257 /* Init state - save args */
5258 pState->pZip = pZip;
5259 pState->flags = flags;
5260
5261 /* Init state - reset variables to defaults */
5262 pState->status = TINFL_STATUS_DONE;
5263#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
5264 pState->file_crc32 = MZ_CRC32_INIT;
5265#endif
5266 pState->read_buf_ofs = 0;
5267 pState->out_buf_ofs = 0;
5268 pState->pRead_buf = NULL;
5269 pState->pWrite_buf = NULL;
5270 pState->out_blk_remain = 0;
5271
5272 /* Read and parse the local directory entry. */
5273 pState->cur_file_ofs = pState->file_stat.m_local_header_ofs;
5274 if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header,
5275 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
5276 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) {
5277 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
5278 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5279 return NULL;
5280 }
5281
5282 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) {
5283 mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5284 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5285 return NULL;
5286 }
5287
5288 pState->cur_file_ofs +=
5289 MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5290 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
5291 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
5292 if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) >
5293 pZip->m_archive_size) {
5294 mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5295 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5296 return NULL;
5297 }
5298
5299 /* Decompress the file either directly from memory or from a file input
5300 * buffer. */
5301 if (pZip->m_pState->m_pMem) {
5302 pState->pRead_buf =
5303 (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs;
5304 pState->read_buf_size = pState->read_buf_avail =
5305 pState->file_stat.m_comp_size;
5306 pState->comp_remaining = pState->file_stat.m_comp_size;
5307 } else {
5308 if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ||
5309 (!pState->file_stat.m_method))) {
5310 /* Decompression required, therefore intermediate read buffer required */
5311 pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size,
5312 (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
5313 if (NULL ==
5314 (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5315 (size_t)pState->read_buf_size))) {
5316 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
5317 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5318 return NULL;
5319 }
5320 } else {
5321 /* Decompression not required - we will be reading directly into user
5322 * buffer, no temp buf required */
5323 pState->read_buf_size = 0;
5324 }
5325 pState->read_buf_avail = 0;
5326 pState->comp_remaining = pState->file_stat.m_comp_size;
5327 }
5328
5329 if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ||
5330 (!pState->file_stat.m_method))) {
5331 /* Decompression required, init decompressor */
5332 tinfl_init(&pState->inflator);
5333
5334 /* Allocate write buffer */
5335 if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5336 TINFL_LZ_DICT_SIZE))) {
5337 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
5338 if (pState->pRead_buf)
5339 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf);
5340 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5341 return NULL;
5342 }
5343 }
5344
5345 return pState;
5346}
5347
5348mz_zip_reader_extract_iter_state *mz_zip_reader_extract_file_iter_new(
5349 mz_zip_archive *pZip,
5350 const char *pFilename,
5351 mz_uint flags) {
5352 mz_uint32 file_index;
5353
5354 /* Locate file index by name */
5355 if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
5356 return NULL;
5357
5358 /* Construct iterator */
5359 return mz_zip_reader_extract_iter_new(pZip, file_index, flags);
5360}
5361
5362size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state *pState,
5363 void *pvBuf,
5364 size_t buf_size) {
5365 size_t copied_to_caller = 0;
5366
5367 /* Argument sanity check */
5368 if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf))
5369 return 0;
5370
5371 if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ||
5372 (!pState->file_stat.m_method)) {
5373 /* The file is stored or the caller has requested the compressed data, calc
5374 * amount to return. */
5375 copied_to_caller = (size_t)MZ_MIN(buf_size, pState->comp_remaining);
5376
5377 /* Zip is in memory....or requires reading from a file? */
5378 if (pState->pZip->m_pState->m_pMem) {
5379 /* Copy data to caller's buffer */
5380 memcpy(pvBuf, pState->pRead_buf, copied_to_caller);
5381 pState->pRead_buf = ((mz_uint8 *)pState->pRead_buf) + copied_to_caller;
5382 } else {
5383 /* Read directly into caller's buffer */
5384 if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque,
5385 pState->cur_file_ofs, pvBuf,
5386 copied_to_caller) != copied_to_caller) {
5387 /* Failed to read all that was asked for, flag failure and alert user */
5388 mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED);
5389 pState->status = TINFL_STATUS_FAILED;
5390 copied_to_caller = 0;
5391 }
5392 }
5393
5394#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
5395 /* Compute CRC if not returning compressed data only */
5396 if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
5397 pState->file_crc32 = (mz_uint32)mz_crc32(
5398 pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller);
5399#endif
5400
5401 /* Advance offsets, dec counters */
5402 pState->cur_file_ofs += copied_to_caller;
5403 pState->out_buf_ofs += copied_to_caller;
5404 pState->comp_remaining -= copied_to_caller;
5405 } else {
5406 do {
5407 /* Calc ptr to write buffer - given current output pos and block size */
5408 mz_uint8 *pWrite_buf_cur =
5409 (mz_uint8 *)pState->pWrite_buf +
5410 (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5411
5412 /* Calc max output size - given current output pos and block size */
5413 size_t in_buf_size,
5414 out_buf_size = TINFL_LZ_DICT_SIZE -
5415 (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5416
5417 if (!pState->out_blk_remain) {
5418 /* Read more data from file if none available (and reading from file) */
5419 if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) {
5420 /* Calc read size */
5421 pState->read_buf_avail =
5422 MZ_MIN(pState->read_buf_size, pState->comp_remaining);
5423 if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque,
5424 pState->cur_file_ofs, pState->pRead_buf,
5425 (size_t)pState->read_buf_avail) !=
5426 pState->read_buf_avail) {
5427 mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED);
5428 pState->status = TINFL_STATUS_FAILED;
5429 break;
5430 }
5431
5432 /* Advance offsets, dec counters */
5433 pState->cur_file_ofs += pState->read_buf_avail;
5434 pState->comp_remaining -= pState->read_buf_avail;
5435 pState->read_buf_ofs = 0;
5436 }
5437
5438 /* Perform decompression */
5439 in_buf_size = (size_t)pState->read_buf_avail;
5440 pState->status = tinfl_decompress(
5441 &pState->inflator,
5442 (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs,
5443 &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur,
5444 &out_buf_size,
5445 pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
5446 pState->read_buf_avail -= in_buf_size;
5447 pState->read_buf_ofs += in_buf_size;
5448
5449 /* Update current output block size remaining */
5450 pState->out_blk_remain = out_buf_size;
5451 }
5452
5453 if (pState->out_blk_remain) {
5454 /* Calc amount to return. */
5455 size_t to_copy =
5456 MZ_MIN((buf_size - copied_to_caller), pState->out_blk_remain);
5457
5458 /* Copy data to caller's buffer */
5459 memcpy((mz_uint8 *)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy);
5460
5461#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
5462 /* Perform CRC */
5463 pState->file_crc32 =
5464 (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy);
5465#endif
5466
5467 /* Decrement data consumed from block */
5468 pState->out_blk_remain -= to_copy;
5469
5470 /* Inc output offset, while performing sanity check */
5471 if ((pState->out_buf_ofs += to_copy) >
5472 pState->file_stat.m_uncomp_size) {
5473 mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED);
5474 pState->status = TINFL_STATUS_FAILED;
5475 break;
5476 }
5477
5478 /* Increment counter of data copied to caller */
5479 copied_to_caller += to_copy;
5480 }
5481 } while ((copied_to_caller < buf_size) &&
5482 ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) ||
5483 (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)));
5484 }
5485
5486 /* Return how many bytes were copied into user buffer */
5487 return copied_to_caller;
5488}
5489
5490mz_bool mz_zip_reader_extract_iter_free(
5491 mz_zip_reader_extract_iter_state *pState) {
5492 int status;
5493
5494 /* Argument sanity check */
5495 if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState))
5496 return MZ_FALSE;
5497
5498 /* Was decompression completed and requested? */
5499 if ((pState->status == TINFL_STATUS_DONE) &&
5500 (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) {
5501 /* Make sure the entire file was decompressed, and check its CRC. */
5502 if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) {
5503 mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);
5504 pState->status = TINFL_STATUS_FAILED;
5505 }
5506#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
5507 else if (pState->file_crc32 != pState->file_stat.m_crc32) {
5508 mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED);
5509 pState->status = TINFL_STATUS_FAILED;
5510 }
5511#endif
5512 }
5513
5514 /* Free buffers */
5515 if (!pState->pZip->m_pState->m_pMem)
5516 pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf);
5517 if (pState->pWrite_buf)
5518 pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf);
5519
5520 /* Save status */
5521 status = pState->status;
5522
5523 /* Free context */
5524 pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState);
5525
5526 return status == TINFL_STATUS_DONE;
5527}
5528
5529#ifndef MINIZ_NO_STDIO
5530static size_t mz_zip_file_write_callback(void *pOpaque,
5531 mz_uint64 ofs,
5532 const void *pBuf,
5533 size_t n) {
5534 (void)ofs;
5535
5536 return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque);
5537}
5538
5539mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip,
5540 mz_uint file_index,
5541 const char *pDst_filename,
5542 mz_uint flags) {
5543 mz_bool status;
5544 mz_zip_archive_file_stat file_stat;
5545 MZ_FILE *pFile;
5546
5547 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
5548 return MZ_FALSE;
5549
5550 if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))
5551 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
5552
5553 pFile = MZ_FOPEN(pDst_filename, "wb");
5554 if (!pFile)
5555 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
5556
5557 status = mz_zip_reader_extract_to_callback(
5558 pZip, file_index, mz_zip_file_write_callback, pFile, flags);
5559
5560 if (MZ_FCLOSE(pFile) == EOF) {
5561 if (status)
5562 mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
5563
5564 status = MZ_FALSE;
5565 }
5566
5567#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)
5568 if (status)
5569 mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
5570#endif
5571
5572 return status;
5573}
5574
5575mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
5576 const char *pArchive_filename,
5577 const char *pDst_filename,
5578 mz_uint flags) {
5579 mz_uint32 file_index;
5580 if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags,
5581 &file_index))
5582 return MZ_FALSE;
5583
5584 return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
5585}
5586
5587mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip,
5588 mz_uint file_index,
5589 MZ_FILE *pFile,
5590 mz_uint flags) {
5591 mz_zip_archive_file_stat file_stat;
5592
5593 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
5594 return MZ_FALSE;
5595
5596 if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))
5597 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
5598
5599 return mz_zip_reader_extract_to_callback(
5600 pZip, file_index, mz_zip_file_write_callback, pFile, flags);
5601}
5602
5603mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip,
5604 const char *pArchive_filename,
5605 MZ_FILE *pFile,
5606 mz_uint flags) {
5607 mz_uint32 file_index;
5608 if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags,
5609 &file_index))
5610 return MZ_FALSE;
5611
5612 return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags);
5613}
5614#endif /* #ifndef MINIZ_NO_STDIO */
5615
5616static size_t mz_zip_compute_crc32_callback(void *pOpaque,
5617 mz_uint64 file_ofs,
5618 const void *pBuf,
5619 size_t n) {
5620 mz_uint32 *p = (mz_uint32 *)pOpaque;
5621 (void)file_ofs;
5622 *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n);
5623 return n;
5624}
5625
5626mz_bool mz_zip_validate_file(mz_zip_archive *pZip,
5627 mz_uint file_index,
5628 mz_uint flags) {
5629 mz_zip_archive_file_stat file_stat;
5630 mz_zip_internal_state *pState;
5631 const mz_uint8 *pCentral_dir_header;
5632 mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE;
5633 mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;
5634 mz_uint32
5635 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5636 sizeof(mz_uint32)];
5637 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
5638 mz_uint64 local_header_ofs = 0;
5639 mz_uint32 local_header_filename_len, local_header_extra_len,
5640 local_header_crc32;
5641 mz_uint64 local_header_comp_size, local_header_uncomp_size;
5642 mz_uint32 uncomp_crc32 = MZ_CRC32_INIT;
5643 mz_bool has_data_descriptor;
5644 mz_uint32 local_header_bit_flags;
5645
5646 mz_zip_array file_data_array;
5647 mz_zip_array_init(&file_data_array, 1);
5648
5649 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
5650 (!pZip->m_pRead))
5651 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
5652
5653 if (file_index > pZip->m_total_files)
5654 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
5655
5656 pState = pZip->m_pState;
5657
5658 pCentral_dir_header = mz_zip_get_cdh(pZip, file_index);
5659
5660 if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header,
5661 &file_stat, &found_zip64_ext_data_in_cdir))
5662 return MZ_FALSE;
5663
5664 /* A directory or zero length file */
5665 if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size))
5666 return MZ_TRUE;
5667
5668 /* Encryption and patch files are not supported. */
5669 if (file_stat.m_is_encrypted)
5670 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
5671
5672 /* This function only supports stored and deflate. */
5673 if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
5674 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
5675
5676 if (!file_stat.m_is_supported)
5677 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
5678
5679 /* Read and parse the local directory entry. */
5680 local_header_ofs = file_stat.m_local_header_ofs;
5681 if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header,
5682 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
5683 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
5684 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
5685
5686 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
5687 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5688
5689 local_header_filename_len =
5690 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);
5691 local_header_extra_len =
5692 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
5693 local_header_comp_size =
5694 MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);
5695 local_header_uncomp_size =
5696 MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);
5697 local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS);
5698 local_header_bit_flags =
5699 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
5700 has_data_descriptor = (local_header_bit_flags & 8) != 0;
5701
5702 if (local_header_filename_len != strlen(file_stat.m_filename))
5703 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5704
5705 if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5706 local_header_filename_len + local_header_extra_len +
5707 file_stat.m_comp_size) > pZip->m_archive_size)
5708 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5709
5710 if (!mz_zip_array_resize(
5711 pZip, &file_data_array,
5712 MZ_MAX(local_header_filename_len, local_header_extra_len),
5713 MZ_FALSE)) {
5714 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
5715 goto handle_failure;
5716 }
5717
5718 if (local_header_filename_len) {
5719 if (pZip->m_pRead(pZip->m_pIO_opaque,
5720 local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE,
5721 file_data_array.m_p,
5722 local_header_filename_len) != local_header_filename_len) {
5723 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
5724 goto handle_failure;
5725 }
5726
5727 /* I've seen 1 archive that had the same pathname, but used backslashes in
5728 * the local dir and forward slashes in the central dir. Do we care about
5729 * this? For now, this case will fail validation. */
5730 if (memcmp(file_stat.m_filename, file_data_array.m_p,
5731 local_header_filename_len) != 0) {
5732 mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
5733 goto handle_failure;
5734 }
5735 }
5736
5737 if ((local_header_extra_len) &&
5738 ((local_header_comp_size == MZ_UINT32_MAX) ||
5739 (local_header_uncomp_size == MZ_UINT32_MAX))) {
5740 mz_uint32 extra_size_remaining = local_header_extra_len;
5741 const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p;
5742
5743 if (pZip->m_pRead(pZip->m_pIO_opaque,
5744 local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5745 local_header_filename_len,
5746 file_data_array.m_p,
5747 local_header_extra_len) != local_header_extra_len) {
5748 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
5749 goto handle_failure;
5750 }
5751
5752 do {
5753 mz_uint32 field_id, field_data_size, field_total_size;
5754
5755 if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
5756 mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5757 goto handle_failure;
5758 }
5759
5760 field_id = MZ_READ_LE16(pExtra_data);
5761 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
5762 field_total_size = field_data_size + sizeof(mz_uint16) * 2;
5763
5764 if (field_total_size > extra_size_remaining) {
5765 mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5766 goto handle_failure;
5767 }
5768
5769 if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
5770 const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);
5771
5772 if (field_data_size < sizeof(mz_uint64) * 2) {
5773 mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5774 goto handle_failure;
5775 }
5776
5777 local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);
5778 local_header_comp_size =
5779 MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64));
5780
5781 found_zip64_ext_data_in_ldir = MZ_TRUE;
5782 break;
5783 }
5784
5785 pExtra_data += field_total_size;
5786 extra_size_remaining -= field_total_size;
5787 } while (extra_size_remaining);
5788 }
5789
5790 /* TODO: parse local header extra data when local_header_comp_size is
5791 * 0xFFFFFFFF! (big_descriptor.zip) */
5792 /* I've seen zips in the wild with the data descriptor bit set, but proper
5793 * local header values and bogus data descriptors */
5794 if ((has_data_descriptor) && (!local_header_comp_size) &&
5795 (!local_header_crc32)) {
5796 mz_uint8 descriptor_buf[32];
5797 mz_bool has_id;
5798 const mz_uint8 *pSrc;
5799 mz_uint32 file_crc32;
5800 mz_uint64 comp_size = 0, uncomp_size = 0;
5801
5802 mz_uint32 num_descriptor_uint32s =
5803 ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4;
5804
5805 if (pZip->m_pRead(pZip->m_pIO_opaque,
5806 local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5807 local_header_filename_len + local_header_extra_len +
5808 file_stat.m_comp_size,
5809 descriptor_buf,
5810 sizeof(mz_uint32) * num_descriptor_uint32s) !=
5811 (sizeof(mz_uint32) * num_descriptor_uint32s)) {
5812 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
5813 goto handle_failure;
5814 }
5815
5816 has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID);
5817 pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf;
5818
5819 file_crc32 = MZ_READ_LE32(pSrc);
5820
5821 if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) {
5822 comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32));
5823 uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64));
5824 } else {
5825 comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32));
5826 uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32));
5827 }
5828
5829 if ((file_crc32 != file_stat.m_crc32) ||
5830 (comp_size != file_stat.m_comp_size) ||
5831 (uncomp_size != file_stat.m_uncomp_size)) {
5832 mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
5833 goto handle_failure;
5834 }
5835 } else {
5836 if ((local_header_crc32 != file_stat.m_crc32) ||
5837 (local_header_comp_size != file_stat.m_comp_size) ||
5838 (local_header_uncomp_size != file_stat.m_uncomp_size)) {
5839 mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
5840 goto handle_failure;
5841 }
5842 }
5843
5844 mz_zip_array_clear(pZip, &file_data_array);
5845
5846 if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) {
5847 if (!mz_zip_reader_extract_to_callback(
5848 pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0))
5849 return MZ_FALSE;
5850
5851 /* 1 more check to be sure, although the extract checks too. */
5852 if (uncomp_crc32 != file_stat.m_crc32) {
5853 mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
5854 return MZ_FALSE;
5855 }
5856 }
5857
5858 return MZ_TRUE;
5859
5860handle_failure:
5861 mz_zip_array_clear(pZip, &file_data_array);
5862 return MZ_FALSE;
5863}
5864
5865mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) {
5866 mz_zip_internal_state *pState;
5867 mz_uint32 i;
5868
5869 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
5870 (!pZip->m_pRead))
5871 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
5872
5873 pState = pZip->m_pState;
5874
5875 /* Basic sanity checks */
5876 if (!pState->m_zip64) {
5877 if (pZip->m_total_files > MZ_UINT16_MAX)
5878 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
5879
5880 if (pZip->m_archive_size > MZ_UINT32_MAX)
5881 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
5882 } else {
5883 if (pState->m_central_dir.m_size >= MZ_UINT32_MAX)
5884 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
5885 }
5886
5887 for (i = 0; i < pZip->m_total_files; i++) {
5888 if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) {
5889 mz_uint32 found_index;
5890 mz_zip_archive_file_stat stat;
5891
5892 if (!mz_zip_reader_file_stat(pZip, i, &stat))
5893 return MZ_FALSE;
5894
5895 if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0,
5896 &found_index))
5897 return MZ_FALSE;
5898
5899 /* This check can fail if there are duplicate filenames in the archive
5900 * (which we don't check for when writing - that's up to the user) */
5901 if (found_index != i)
5902 return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
5903 }
5904
5905 if (!mz_zip_validate_file(pZip, i, flags))
5906 return MZ_FALSE;
5907 }
5908
5909 return MZ_TRUE;
5910}
5911
5912mz_bool mz_zip_validate_mem_archive(const void *pMem,
5913 size_t size,
5914 mz_uint flags,
5915 mz_zip_error *pErr) {
5916 mz_bool success = MZ_TRUE;
5917 mz_zip_archive zip;
5918 mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
5919
5920 if ((!pMem) || (!size)) {
5921 if (pErr)
5922 *pErr = MZ_ZIP_INVALID_PARAMETER;
5923 return MZ_FALSE;
5924 }
5925
5926 mz_zip_zero_struct(&zip);
5927
5928 if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) {
5929 if (pErr)
5930 *pErr = zip.m_last_error;
5931 return MZ_FALSE;
5932 }
5933
5934 if (!mz_zip_validate_archive(&zip, flags)) {
5935 actual_err = zip.m_last_error;
5936 success = MZ_FALSE;
5937 }
5938
5939 if (!mz_zip_reader_end_internal(&zip, success)) {
5940 if (!actual_err)
5941 actual_err = zip.m_last_error;
5942 success = MZ_FALSE;
5943 }
5944
5945 if (pErr)
5946 *pErr = actual_err;
5947
5948 return success;
5949}
5950
5951#ifndef MINIZ_NO_STDIO
5952mz_bool mz_zip_validate_file_archive(const char *pFilename,
5953 mz_uint flags,
5954 mz_zip_error *pErr) {
5955 mz_bool success = MZ_TRUE;
5956 mz_zip_archive zip;
5957 mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
5958
5959 if (!pFilename) {
5960 if (pErr)
5961 *pErr = MZ_ZIP_INVALID_PARAMETER;
5962 return MZ_FALSE;
5963 }
5964
5965 mz_zip_zero_struct(&zip);
5966
5967 if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) {
5968 if (pErr)
5969 *pErr = zip.m_last_error;
5970 return MZ_FALSE;
5971 }
5972
5973 if (!mz_zip_validate_archive(&zip, flags)) {
5974 actual_err = zip.m_last_error;
5975 success = MZ_FALSE;
5976 }
5977
5978 if (!mz_zip_reader_end_internal(&zip, success)) {
5979 if (!actual_err)
5980 actual_err = zip.m_last_error;
5981 success = MZ_FALSE;
5982 }
5983
5984 if (pErr)
5985 *pErr = actual_err;
5986
5987 return success;
5988}
5989#endif /* #ifndef MINIZ_NO_STDIO */
5990
5991/* ------------------- .ZIP archive writing */
5992
5993#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
5994
5995static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) {
5996 p[0] = (mz_uint8)v;
5997 p[1] = (mz_uint8)(v >> 8);
5998}
5999static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) {
6000 p[0] = (mz_uint8)v;
6001 p[1] = (mz_uint8)(v >> 8);
6002 p[2] = (mz_uint8)(v >> 16);
6003 p[3] = (mz_uint8)(v >> 24);
6004}
6005static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) {
6006 mz_write_le32(p, (mz_uint32)v);
6007 mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32));
6008}
6009
6010#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
6011#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
6012#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v))
6013
6014static size_t mz_zip_heap_write_func(void *pOpaque,
6015 mz_uint64 file_ofs,
6016 const void *pBuf,
6017 size_t n) {
6018 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
6019 mz_zip_internal_state *pState = pZip->m_pState;
6020 mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
6021
6022 if (!n)
6023 return 0;
6024
6025 /* An allocation this big is likely to just fail on 32-bit systems, so don't
6026 * even go there. */
6027 if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) {
6028 mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
6029 return 0;
6030 }
6031
6032 if (new_size > pState->m_mem_capacity) {
6033 void *pNew_block;
6034 size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity);
6035
6036 while (new_capacity < new_size)
6037 new_capacity *= 2;
6038
6039 if (NULL == (pNew_block = pZip->m_pRealloc(
6040 pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) {
6041 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6042 return 0;
6043 }
6044
6045 pState->m_pMem = pNew_block;
6046 pState->m_mem_capacity = new_capacity;
6047 }
6048 memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
6049 pState->m_mem_size = (size_t)new_size;
6050 return n;
6051}
6052
6053static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip,
6054 mz_bool set_last_error) {
6055 mz_zip_internal_state *pState;
6056 mz_bool status = MZ_TRUE;
6057
6058 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
6059 ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) &&
6060 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) {
6061 if (set_last_error)
6062 mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6063 return MZ_FALSE;
6064 }
6065
6066 pState = pZip->m_pState;
6067 pZip->m_pState = NULL;
6068 mz_zip_array_clear(pZip, &pState->m_central_dir);
6069 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
6070 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
6071
6072#ifndef MINIZ_NO_STDIO
6073 if (pState->m_pFile) {
6074 if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) {
6075 if (MZ_FCLOSE(pState->m_pFile) == EOF) {
6076 if (set_last_error)
6077 mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
6078 status = MZ_FALSE;
6079 }
6080 }
6081
6082 pState->m_pFile = NULL;
6083 }
6084#endif /* #ifndef MINIZ_NO_STDIO */
6085
6086 if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) {
6087 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
6088 pState->m_pMem = NULL;
6089 }
6090
6091 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
6092 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
6093 return status;
6094}
6095
6096mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip,
6097 mz_uint64 existing_size,
6098 mz_uint flags) {
6099 mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0;
6100
6101 if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) ||
6102 (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
6103 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6104
6105 if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) {
6106 if (!pZip->m_pRead)
6107 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6108 }
6109
6110 if (pZip->m_file_offset_alignment) {
6111 /* Ensure user specified file offset alignment is a power of 2. */
6112 if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
6113 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6114 }
6115
6116 if (!pZip->m_pAlloc)
6117 pZip->m_pAlloc = miniz_def_alloc_func;
6118 if (!pZip->m_pFree)
6119 pZip->m_pFree = miniz_def_free_func;
6120 if (!pZip->m_pRealloc)
6121 pZip->m_pRealloc = miniz_def_realloc_func;
6122
6123 pZip->m_archive_size = existing_size;
6124 pZip->m_central_directory_file_ofs = 0;
6125 pZip->m_total_files = 0;
6126
6127 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
6128 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
6129 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6130
6131 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
6132
6133 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
6134 sizeof(mz_uint8));
6135 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
6136 sizeof(mz_uint32));
6137 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
6138 sizeof(mz_uint32));
6139
6140 pZip->m_pState->m_zip64 = zip64;
6141 pZip->m_pState->m_zip64_has_extended_info_fields = zip64;
6142
6143 pZip->m_zip_type = MZ_ZIP_TYPE_USER;
6144 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
6145
6146 return MZ_TRUE;
6147}
6148
6149mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) {
6150 return mz_zip_writer_init_v2(pZip, existing_size, 0);
6151}
6152
6153mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip,
6154 size_t size_to_reserve_at_beginning,
6155 size_t initial_allocation_size,
6156 mz_uint flags) {
6157 pZip->m_pWrite = mz_zip_heap_write_func;
6158 pZip->m_pNeeds_keepalive = NULL;
6159
6160 if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
6161 pZip->m_pRead = mz_zip_mem_read_func;
6162
6163 pZip->m_pIO_opaque = pZip;
6164
6165 if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))
6166 return MZ_FALSE;
6167
6168 pZip->m_zip_type = MZ_ZIP_TYPE_HEAP;
6169
6170 if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size,
6171 size_to_reserve_at_beginning))) {
6172 if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(
6173 pZip->m_pAlloc_opaque, 1, initial_allocation_size))) {
6174 mz_zip_writer_end_internal(pZip, MZ_FALSE);
6175 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6176 }
6177 pZip->m_pState->m_mem_capacity = initial_allocation_size;
6178 }
6179
6180 return MZ_TRUE;
6181}
6182
6183mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
6184 size_t size_to_reserve_at_beginning,
6185 size_t initial_allocation_size) {
6186 return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning,
6187 initial_allocation_size, 0);
6188}
6189
6190#ifndef MINIZ_NO_STDIO
6191static size_t mz_zip_file_write_func(void *pOpaque,
6192 mz_uint64 file_ofs,
6193 const void *pBuf,
6194 size_t n) {
6195 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
6196 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
6197
6198 file_ofs += pZip->m_pState->m_file_archive_start_ofs;
6199
6200 if (((mz_int64)file_ofs < 0) ||
6201 (((cur_ofs != (mz_int64)file_ofs)) &&
6202 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) {
6203 mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
6204 return 0;
6205 }
6206
6207 return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
6208}
6209
6210mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip,
6211 const char *pFilename,
6212 mz_uint64 size_to_reserve_at_beginning) {
6213 return mz_zip_writer_init_file_v2(pZip, pFilename,
6214 size_to_reserve_at_beginning, 0);
6215}
6216
6217mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip,
6218 const char *pFilename,
6219 mz_uint64 size_to_reserve_at_beginning,
6220 mz_uint flags) {
6221 MZ_FILE *pFile;
6222
6223 pZip->m_pWrite = mz_zip_file_write_func;
6224 pZip->m_pNeeds_keepalive = NULL;
6225
6226 if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
6227 pZip->m_pRead = mz_zip_file_read_func;
6228
6229 pZip->m_pIO_opaque = pZip;
6230
6231 if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))
6232 return MZ_FALSE;
6233
6234 if (NULL == (pFile = MZ_FOPEN(
6235 pFilename,
6236 (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) {
6237 mz_zip_writer_end(pZip);
6238 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
6239 }
6240
6241 pZip->m_pState->m_pFile = pFile;
6242 pZip->m_zip_type = MZ_ZIP_TYPE_FILE;
6243
6244 if (size_to_reserve_at_beginning) {
6245 mz_uint64 cur_ofs = 0;
6246 char buf[4096];
6247
6248 MZ_CLEAR_ARR(buf);
6249
6250 do {
6251 size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
6252 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) {
6253 mz_zip_writer_end(pZip);
6254 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6255 }
6256 cur_ofs += n;
6257 size_to_reserve_at_beginning -= n;
6258 } while (size_to_reserve_at_beginning);
6259 }
6260
6261 return MZ_TRUE;
6262}
6263
6264mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip,
6265 MZ_FILE *pFile,
6266 mz_uint flags) {
6267 pZip->m_pWrite = mz_zip_file_write_func;
6268 pZip->m_pNeeds_keepalive = NULL;
6269
6270 if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
6271 pZip->m_pRead = mz_zip_file_read_func;
6272
6273 pZip->m_pIO_opaque = pZip;
6274
6275 if (!mz_zip_writer_init_v2(pZip, 0, flags))
6276 return MZ_FALSE;
6277
6278 pZip->m_pState->m_pFile = pFile;
6279 pZip->m_pState->m_file_archive_start_ofs =
6280 MZ_FTELL64(pZip->m_pState->m_pFile);
6281 pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;
6282
6283 return MZ_TRUE;
6284}
6285#endif /* #ifndef MINIZ_NO_STDIO */
6286
6287mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip,
6288 const char *pFilename,
6289 mz_uint flags) {
6290 mz_zip_internal_state *pState;
6291
6292 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
6293 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6294
6295 if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) {
6296 /* We don't support converting a non-zip64 file to zip64 - this seems like
6297 * more trouble than it's worth. (What about the existing 32-bit data
6298 * descriptors that could follow the compressed data?) */
6299 if (!pZip->m_pState->m_zip64)
6300 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6301 }
6302
6303 /* No sense in trying to write to an archive that's already at the support max
6304 * size */
6305 if (pZip->m_pState->m_zip64) {
6306 if (pZip->m_total_files == MZ_UINT32_MAX)
6307 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
6308 } else {
6309 if (pZip->m_total_files == MZ_UINT16_MAX)
6310 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
6311
6312 if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6313 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)
6314 return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
6315 }
6316
6317 pState = pZip->m_pState;
6318
6319 if (pState->m_pFile) {
6320#ifdef MINIZ_NO_STDIO
6321 (void)pFilename;
6322 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6323#else
6324 if (pZip->m_pIO_opaque != pZip)
6325 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6326
6327 if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) {
6328 if (!pFilename)
6329 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6330
6331 /* Archive is being read from stdio and was originally opened only for
6332 * reading. Try to reopen as writable. */
6333 if (NULL ==
6334 (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) {
6335 /* The mz_zip_archive is now in a bogus state because pState->m_pFile is
6336 * NULL, so just close it. */
6337 mz_zip_reader_end_internal(pZip, MZ_FALSE);
6338 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
6339 }
6340 }
6341
6342 pZip->m_pWrite = mz_zip_file_write_func;
6343 pZip->m_pNeeds_keepalive = NULL;
6344#endif /* #ifdef MINIZ_NO_STDIO */
6345 } else if (pState->m_pMem) {
6346 /* Archive lives in a memory block. Assume it's from the heap that we can
6347 * resize using the realloc callback. */
6348 if (pZip->m_pIO_opaque != pZip)
6349 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6350
6351 pState->m_mem_capacity = pState->m_mem_size;
6352 pZip->m_pWrite = mz_zip_heap_write_func;
6353 pZip->m_pNeeds_keepalive = NULL;
6354 }
6355 /* Archive is being read via a user provided read function - make sure the
6356 user has specified a write function too. */
6357 else if (!pZip->m_pWrite)
6358 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6359
6360 /* Start writing new files at the archive's current central directory
6361 * location. */
6362 /* TODO: We could add a flag that lets the user start writing immediately
6363 * AFTER the existing central dir - this would be safer. */
6364 pZip->m_archive_size = pZip->m_central_directory_file_ofs;
6365 pZip->m_central_directory_file_ofs = 0;
6366
6367 /* Clear the sorted central dir offsets, they aren't useful or maintained now.
6368 */
6369 /* Even though we're now in write mode, files can still be extracted and
6370 * verified, but file locates will be slow. */
6371 /* TODO: We could easily maintain the sorted central directory offsets. */
6372 mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets);
6373
6374 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
6375
6376 return MZ_TRUE;
6377}
6378
6379mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
6380 const char *pFilename) {
6381 return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0);
6382}
6383
6384/* TODO: pArchive_name is a terrible name here! */
6385mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip,
6386 const char *pArchive_name,
6387 const void *pBuf,
6388 size_t buf_size,
6389 mz_uint level_and_flags) {
6390 return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0,
6391 level_and_flags, 0, 0);
6392}
6393
6394typedef struct {
6395 mz_zip_archive *m_pZip;
6396 mz_uint64 m_cur_archive_file_ofs;
6397 mz_uint64 m_comp_size;
6398} mz_zip_writer_add_state;
6399
6400static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf,
6401 int len,
6402 void *pUser) {
6403 mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
6404 if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque,
6405 pState->m_cur_archive_file_ofs, pBuf,
6406 len) != len)
6407 return MZ_FALSE;
6408
6409 pState->m_cur_archive_file_ofs += len;
6410 pState->m_comp_size += len;
6411 return MZ_TRUE;
6412}
6413
6414#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE \
6415 (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2)
6416#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE \
6417 (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3)
6418static mz_uint32 mz_zip_writer_create_zip64_extra_data(
6419 mz_uint8 *pBuf,
6420 mz_uint64 *pUncomp_size,
6421 mz_uint64 *pComp_size,
6422 mz_uint64 *pLocal_header_ofs) {
6423 mz_uint8 *pDst = pBuf;
6424 mz_uint32 field_size = 0;
6425
6426 MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);
6427 MZ_WRITE_LE16(pDst + 2, 0);
6428 pDst += sizeof(mz_uint16) * 2;
6429
6430 if (pUncomp_size) {
6431 MZ_WRITE_LE64(pDst, *pUncomp_size);
6432 pDst += sizeof(mz_uint64);
6433 field_size += sizeof(mz_uint64);
6434 }
6435
6436 if (pComp_size) {
6437 MZ_WRITE_LE64(pDst, *pComp_size);
6438 pDst += sizeof(mz_uint64);
6439 field_size += sizeof(mz_uint64);
6440 }
6441
6442 if (pLocal_header_ofs) {
6443 MZ_WRITE_LE64(pDst, *pLocal_header_ofs);
6444 pDst += sizeof(mz_uint64);
6445 field_size += sizeof(mz_uint64);
6446 }
6447
6448 MZ_WRITE_LE16(pBuf + 2, field_size);
6449
6450 return (mz_uint32)(pDst - pBuf);
6451}
6452
6453static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip,
6454 mz_uint8 *pDst,
6455 mz_uint16 filename_size,
6456 mz_uint16 extra_size,
6457 mz_uint64 uncomp_size,
6458 mz_uint64 comp_size,
6459 mz_uint32 uncomp_crc32,
6460 mz_uint16 method,
6461 mz_uint16 bit_flags,
6462 mz_uint16 dos_time,
6463 mz_uint16 dos_date) {
6464 (void)pZip;
6465 memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
6466 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
6467 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
6468 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
6469 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
6470 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
6471 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
6472 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
6473 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS,
6474 MZ_MIN(comp_size, MZ_UINT32_MAX));
6475 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS,
6476 MZ_MIN(uncomp_size, MZ_UINT32_MAX));
6477 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
6478 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
6479 return MZ_TRUE;
6480}
6481
6482static mz_bool mz_zip_writer_create_central_dir_header(
6483 mz_zip_archive *pZip,
6484 mz_uint8 *pDst,
6485 mz_uint16 filename_size,
6486 mz_uint16 extra_size,
6487 mz_uint16 comment_size,
6488 mz_uint64 uncomp_size,
6489 mz_uint64 comp_size,
6490 mz_uint32 uncomp_crc32,
6491 mz_uint16 method,
6492 mz_uint16 bit_flags,
6493 mz_uint16 dos_time,
6494 mz_uint16 dos_date,
6495 mz_uint64 local_header_ofs,
6496 mz_uint32 ext_attributes) {
6497 (void)pZip;
6498 memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
6499 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
6500 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
6501 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
6502 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
6503 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
6504 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
6505 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
6506 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS,
6507 MZ_MIN(comp_size, MZ_UINT32_MAX));
6508 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS,
6509 MZ_MIN(uncomp_size, MZ_UINT32_MAX));
6510 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
6511 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
6512 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
6513 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
6514 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS,
6515 MZ_MIN(local_header_ofs, MZ_UINT32_MAX));
6516 return MZ_TRUE;
6517}
6518
6519static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip,
6520 const char *pFilename,
6521 mz_uint16 filename_size,
6522 const void *pExtra,
6523 mz_uint16 extra_size,
6524 const void *pComment,
6525 mz_uint16 comment_size,
6526 mz_uint64 uncomp_size,
6527 mz_uint64 comp_size,
6528 mz_uint32 uncomp_crc32,
6529 mz_uint16 method,
6530 mz_uint16 bit_flags,
6531 mz_uint16 dos_time,
6532 mz_uint16 dos_date,
6533 mz_uint64 local_header_ofs,
6534 mz_uint32 ext_attributes,
6535 const char *user_extra_data,
6536 mz_uint user_extra_data_len) {
6537 mz_zip_internal_state *pState = pZip->m_pState;
6538 mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
6539 size_t orig_central_dir_size = pState->m_central_dir.m_size;
6540 mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
6541
6542 if (!pZip->m_pState->m_zip64) {
6543 if (local_header_ofs > 0xFFFFFFFF)
6544 return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
6545 }
6546
6547 /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
6548 if (((mz_uint64)pState->m_central_dir.m_size +
6549 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size +
6550 user_extra_data_len + comment_size) >= MZ_UINT32_MAX)
6551 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
6552
6553 if (!mz_zip_writer_create_central_dir_header(
6554 pZip, central_dir_header, filename_size,
6555 (mz_uint16)(extra_size + user_extra_data_len), comment_size,
6556 uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time,
6557 dos_date, local_header_ofs, ext_attributes))
6558 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
6559
6560 if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header,
6561 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
6562 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename,
6563 filename_size)) ||
6564 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra,
6565 extra_size)) ||
6566 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data,
6567 user_extra_data_len)) ||
6568 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment,
6569 comment_size)) ||
6570 (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets,
6571 &central_dir_ofs, 1))) {
6572 /* Try to resize the central directory array back into its original state.
6573 */
6574 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6575 MZ_FALSE);
6576 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6577 }
6578
6579 return MZ_TRUE;
6580}
6581
6582static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) {
6583 /* Basic ZIP archive filename validity checks: Valid filenames cannot start
6584 * with a forward slash, cannot contain a drive letter, and cannot use
6585 * DOS-style backward slashes. */
6586 if (*pArchive_name == '/')
6587 return MZ_FALSE;
6588
6589 /* Making sure the name does not contain drive letters or DOS style backward
6590 * slashes is the responsibility of the program using miniz*/
6591
6592 return MZ_TRUE;
6593}
6594
6595static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(
6596 mz_zip_archive *pZip) {
6597 mz_uint32 n;
6598 if (!pZip->m_file_offset_alignment)
6599 return 0;
6600 n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
6601 return (mz_uint)((pZip->m_file_offset_alignment - n) &
6602 (pZip->m_file_offset_alignment - 1));
6603}
6604
6605static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip,
6606 mz_uint64 cur_file_ofs,
6607 mz_uint32 n) {
6608 char buf[4096];
6609 memset(buf, 0, MZ_MIN(sizeof(buf), n));
6610 while (n) {
6611 mz_uint32 s = MZ_MIN(sizeof(buf), n);
6612 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
6613 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6614
6615 cur_file_ofs += s;
6616 n -= s;
6617 }
6618 return MZ_TRUE;
6619}
6620
6621mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
6622 const char *pArchive_name,
6623 const void *pBuf,
6624 size_t buf_size,
6625 const void *pComment,
6626 mz_uint16 comment_size,
6627 mz_uint level_and_flags,
6628 mz_uint64 uncomp_size,
6629 mz_uint32 uncomp_crc32) {
6630 return mz_zip_writer_add_mem_ex_v2(
6631 pZip, pArchive_name, pBuf, buf_size, pComment, comment_size,
6632 level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0);
6633}
6634
6635mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip,
6636 const char *pArchive_name,
6637 const void *pBuf,
6638 size_t buf_size,
6639 const void *pComment,
6640 mz_uint16 comment_size,
6641 mz_uint level_and_flags,
6642 mz_uint64 uncomp_size,
6643 mz_uint32 uncomp_crc32,
6644 MZ_TIME_T *last_modified,
6645 const char *user_extra_data,
6646 mz_uint user_extra_data_len,
6647 const char *user_extra_data_central,
6648 mz_uint user_extra_data_central_len) {
6649 mz_uint16 method = 0, dos_time = 0, dos_date = 0;
6650 mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
6651 mz_uint64 local_dir_header_ofs = pZip->m_archive_size,
6652 cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
6653 size_t archive_name_size;
6654 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
6655 tdefl_compressor *pComp = NULL;
6656 mz_bool store_data_uncompressed;
6657 mz_zip_internal_state *pState;
6658 mz_uint8 *pExtra_data = NULL;
6659 mz_uint32 extra_size = 0;
6660 mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];
6661 mz_uint16 bit_flags = 0;
6662
6663 if ((int)level_and_flags < 0)
6664 level_and_flags = MZ_DEFAULT_LEVEL;
6665
6666 if (uncomp_size ||
6667 (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
6668 bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;
6669
6670 if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))
6671 bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;
6672
6673 level = level_and_flags & 0xF;
6674 store_data_uncompressed =
6675 ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
6676
6677 if ((!pZip) || (!pZip->m_pState) ||
6678 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) ||
6679 (!pArchive_name) || ((comment_size) && (!pComment)) ||
6680 (level > MZ_UBER_COMPRESSION))
6681 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6682
6683 pState = pZip->m_pState;
6684
6685 if (pState->m_zip64) {
6686 if (pZip->m_total_files == MZ_UINT32_MAX)
6687 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
6688 } else {
6689 if (pZip->m_total_files == MZ_UINT16_MAX) {
6690 pState->m_zip64 = MZ_TRUE;
6691 /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */
6692 }
6693 if (((mz_uint64)buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) {
6694 pState->m_zip64 = MZ_TRUE;
6695 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
6696 }
6697 }
6698
6699 if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
6700 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6701
6702 if (!mz_zip_writer_validate_archive_name(pArchive_name))
6703 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
6704
6705#ifndef MINIZ_NO_TIME
6706 if (last_modified != NULL) {
6707 mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date);
6708 } else {
6709 MZ_TIME_T cur_time;
6710 time(&cur_time);
6711 mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date);
6712 }
6713#endif /* #ifndef MINIZ_NO_TIME */
6714
6715 if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
6716 uncomp_crc32 =
6717 (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
6718 uncomp_size = buf_size;
6719 if (uncomp_size <= 3) {
6720 level = 0;
6721 store_data_uncompressed = MZ_TRUE;
6722 }
6723 }
6724
6725 archive_name_size = strlen(pArchive_name);
6726 if (archive_name_size > MZ_UINT16_MAX)
6727 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
6728
6729 num_alignment_padding_bytes =
6730 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6731
6732 /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
6733 if (((mz_uint64)pState->m_central_dir.m_size +
6734 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size +
6735 MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX)
6736 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
6737
6738 if (!pState->m_zip64) {
6739 /* Bail early if the archive would obviously become too large */
6740 if ((pZip->m_archive_size + num_alignment_padding_bytes +
6741 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size +
6742 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size +
6743 user_extra_data_len + pState->m_central_dir.m_size +
6744 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len +
6745 MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) {
6746 pState->m_zip64 = MZ_TRUE;
6747 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
6748 }
6749 }
6750
6751 if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) {
6752 /* Set DOS Subdirectory attribute bit. */
6753 ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG;
6754
6755 /* Subdirectories cannot contain data. */
6756 if ((buf_size) || (uncomp_size))
6757 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6758 }
6759
6760 /* Try to do any allocations before writing to the archive, so if an
6761 * allocation fails the file remains unmodified. (A good idea if we're doing
6762 * an in-place modification.) */
6763 if ((!mz_zip_array_ensure_room(
6764 pZip, &pState->m_central_dir,
6765 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size +
6766 (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) ||
6767 (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))
6768 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6769
6770 if ((!store_data_uncompressed) && (buf_size)) {
6771 if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(
6772 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
6773 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6774 }
6775
6776 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs,
6777 num_alignment_padding_bytes)) {
6778 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6779 return MZ_FALSE;
6780 }
6781
6782 local_dir_header_ofs += num_alignment_padding_bytes;
6783 if (pZip->m_file_offset_alignment) {
6784 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6785 0);
6786 }
6787 cur_archive_file_ofs += num_alignment_padding_bytes;
6788
6789 MZ_CLEAR_ARR(local_dir_header);
6790
6791 if (!store_data_uncompressed ||
6792 (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
6793 method = MZ_DEFLATED;
6794 }
6795
6796 if (pState->m_zip64) {
6797 if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) {
6798 pExtra_data = extra_data;
6799 extra_size = mz_zip_writer_create_zip64_extra_data(
6800 extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
6801 (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL,
6802 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs
6803 : NULL);
6804 }
6805
6806 if (!mz_zip_writer_create_local_dir_header(
6807 pZip, local_dir_header, (mz_uint16)archive_name_size,
6808 (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method,
6809 bit_flags, dos_time, dos_date))
6810 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
6811
6812 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs,
6813 local_dir_header,
6814 sizeof(local_dir_header)) != sizeof(local_dir_header))
6815 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6816
6817 cur_archive_file_ofs += sizeof(local_dir_header);
6818
6819 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
6820 archive_name_size) != archive_name_size) {
6821 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6822 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6823 }
6824 cur_archive_file_ofs += archive_name_size;
6825
6826 if (pExtra_data != NULL) {
6827 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data,
6828 extra_size) != extra_size)
6829 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6830
6831 cur_archive_file_ofs += extra_size;
6832 }
6833 } else {
6834 if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))
6835 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
6836 if (!mz_zip_writer_create_local_dir_header(
6837 pZip, local_dir_header, (mz_uint16)archive_name_size,
6838 (mz_uint16)user_extra_data_len, 0, 0, 0, method, bit_flags,
6839 dos_time, dos_date))
6840 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
6841
6842 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs,
6843 local_dir_header,
6844 sizeof(local_dir_header)) != sizeof(local_dir_header))
6845 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6846
6847 cur_archive_file_ofs += sizeof(local_dir_header);
6848
6849 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
6850 archive_name_size) != archive_name_size) {
6851 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6852 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6853 }
6854 cur_archive_file_ofs += archive_name_size;
6855 }
6856
6857 if (user_extra_data_len > 0) {
6858 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
6859 user_extra_data,
6860 user_extra_data_len) != user_extra_data_len)
6861 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6862
6863 cur_archive_file_ofs += user_extra_data_len;
6864 }
6865
6866 if (store_data_uncompressed) {
6867 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf,
6868 buf_size) != buf_size) {
6869 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6870 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6871 }
6872
6873 cur_archive_file_ofs += buf_size;
6874 comp_size = buf_size;
6875 } else if (buf_size) {
6876 mz_zip_writer_add_state state;
6877
6878 state.m_pZip = pZip;
6879 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
6880 state.m_comp_size = 0;
6881
6882 if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
6883 tdefl_create_comp_flags_from_zip_params(
6884 level, -15, MZ_DEFAULT_STRATEGY)) !=
6885 TDEFL_STATUS_OKAY) ||
6886 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) !=
6887 TDEFL_STATUS_DONE)) {
6888 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6889 return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);
6890 }
6891
6892 comp_size = state.m_comp_size;
6893 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
6894 }
6895
6896 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6897 pComp = NULL;
6898
6899 if (uncomp_size) {
6900 mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];
6901 mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;
6902
6903 MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR);
6904
6905 MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);
6906 MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);
6907 if (pExtra_data == NULL) {
6908 if (comp_size > MZ_UINT32_MAX)
6909 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
6910
6911 MZ_WRITE_LE32(local_dir_footer + 8, comp_size);
6912 MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);
6913 } else {
6914 MZ_WRITE_LE64(local_dir_footer + 8, comp_size);
6915 MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);
6916 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;
6917 }
6918
6919 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
6920 local_dir_footer,
6921 local_dir_footer_size) != local_dir_footer_size)
6922 return MZ_FALSE;
6923
6924 cur_archive_file_ofs += local_dir_footer_size;
6925 }
6926
6927 if (pExtra_data != NULL) {
6928 extra_size = mz_zip_writer_create_zip64_extra_data(
6929 extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
6930 (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL,
6931 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
6932 }
6933
6934 if (!mz_zip_writer_add_to_central_dir(
6935 pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data,
6936 (mz_uint16)extra_size, pComment, comment_size, uncomp_size, comp_size,
6937 uncomp_crc32, method, bit_flags, dos_time, dos_date,
6938 local_dir_header_ofs, ext_attributes, user_extra_data_central,
6939 user_extra_data_central_len))
6940 return MZ_FALSE;
6941
6942 pZip->m_total_files++;
6943 pZip->m_archive_size = cur_archive_file_ofs;
6944
6945 return MZ_TRUE;
6946}
6947
6948mz_bool mz_zip_writer_add_read_buf_callback(
6949 mz_zip_archive *pZip,
6950 const char *pArchive_name,
6951 mz_file_read_func read_callback,
6952 void *callback_opaque,
6953 mz_uint64 max_size,
6954 const MZ_TIME_T *pFile_time,
6955 const void *pComment,
6956 mz_uint16 comment_size,
6957 mz_uint level_and_flags,
6958 const char *user_extra_data,
6959 mz_uint user_extra_data_len,
6960 const char *user_extra_data_central,
6961 mz_uint user_extra_data_central_len) {
6962 mz_uint16 gen_flags;
6963 mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
6964 mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
6965 mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size,
6966 uncomp_size = 0, comp_size = 0;
6967 size_t archive_name_size;
6968 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
6969 mz_uint8 *pExtra_data = NULL;
6970 mz_uint32 extra_size = 0;
6971 mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];
6972 mz_zip_internal_state *pState;
6973 mz_uint64 file_ofs = 0, cur_archive_header_file_ofs;
6974
6975 if ((int)level_and_flags < 0)
6976 level_and_flags = MZ_DEFAULT_LEVEL;
6977 level = level_and_flags & 0xF;
6978
6979 gen_flags = (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE)
6980 ? 0
6981 : MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;
6982
6983 if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))
6984 gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;
6985
6986 /* Sanity checks */
6987 if ((!pZip) || (!pZip->m_pState) ||
6988 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) ||
6989 ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
6990 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6991
6992 pState = pZip->m_pState;
6993
6994 if ((!pState->m_zip64) && (max_size > MZ_UINT32_MAX)) {
6995 /* Source file is too large for non-zip64 */
6996 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
6997 pState->m_zip64 = MZ_TRUE;
6998 }
6999
7000 /* We could support this, but why? */
7001 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
7002 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7003
7004 if (!mz_zip_writer_validate_archive_name(pArchive_name))
7005 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
7006
7007 if (pState->m_zip64) {
7008 if (pZip->m_total_files == MZ_UINT32_MAX)
7009 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
7010 } else {
7011 if (pZip->m_total_files == MZ_UINT16_MAX) {
7012 pState->m_zip64 = MZ_TRUE;
7013 /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */
7014 }
7015 }
7016
7017 archive_name_size = strlen(pArchive_name);
7018 if (archive_name_size > MZ_UINT16_MAX)
7019 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
7020
7021 num_alignment_padding_bytes =
7022 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
7023
7024 /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
7025 if (((mz_uint64)pState->m_central_dir.m_size +
7026 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size +
7027 MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX)
7028 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
7029
7030 if (!pState->m_zip64) {
7031 /* Bail early if the archive would obviously become too large */
7032 if ((pZip->m_archive_size + num_alignment_padding_bytes +
7033 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size +
7034 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size +
7035 user_extra_data_len + pState->m_central_dir.m_size +
7036 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 +
7037 MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) >
7038 0xFFFFFFFF) {
7039 pState->m_zip64 = MZ_TRUE;
7040 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
7041 }
7042 }
7043
7044#ifndef MINIZ_NO_TIME
7045 if (pFile_time) {
7046 mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date);
7047 }
7048#endif
7049
7050 if (max_size <= 3)
7051 level = 0;
7052
7053 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs,
7054 num_alignment_padding_bytes)) {
7055 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7056 }
7057
7058 cur_archive_file_ofs += num_alignment_padding_bytes;
7059 local_dir_header_ofs = cur_archive_file_ofs;
7060
7061 if (pZip->m_file_offset_alignment) {
7062 MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) ==
7063 0);
7064 }
7065
7066 if (max_size && level) {
7067 method = MZ_DEFLATED;
7068 }
7069
7070 MZ_CLEAR_ARR(local_dir_header);
7071 if (pState->m_zip64) {
7072 if (max_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) {
7073 pExtra_data = extra_data;
7074 if (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE)
7075 extra_size = mz_zip_writer_create_zip64_extra_data(
7076 extra_data, (max_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
7077 (max_size >= MZ_UINT32_MAX) ? &comp_size : NULL,
7078 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs
7079 : NULL);
7080 else
7081 extra_size = mz_zip_writer_create_zip64_extra_data(
7082 extra_data, NULL, NULL,
7083 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs
7084 : NULL);
7085 }
7086
7087 if (!mz_zip_writer_create_local_dir_header(
7088 pZip, local_dir_header, (mz_uint16)archive_name_size,
7089 (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method,
7090 gen_flags, dos_time, dos_date))
7091 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
7092
7093 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
7094 local_dir_header,
7095 sizeof(local_dir_header)) != sizeof(local_dir_header))
7096 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7097
7098 cur_archive_file_ofs += sizeof(local_dir_header);
7099
7100 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
7101 archive_name_size) != archive_name_size) {
7102 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7103 }
7104
7105 cur_archive_file_ofs += archive_name_size;
7106
7107 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data,
7108 extra_size) != extra_size)
7109 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7110
7111 cur_archive_file_ofs += extra_size;
7112 } else {
7113 if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))
7114 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
7115 if (!mz_zip_writer_create_local_dir_header(
7116 pZip, local_dir_header, (mz_uint16)archive_name_size,
7117 (mz_uint16)user_extra_data_len, 0, 0, 0, method, gen_flags,
7118 dos_time, dos_date))
7119 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
7120
7121 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
7122 local_dir_header,
7123 sizeof(local_dir_header)) != sizeof(local_dir_header))
7124 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7125
7126 cur_archive_file_ofs += sizeof(local_dir_header);
7127
7128 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
7129 archive_name_size) != archive_name_size) {
7130 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7131 }
7132
7133 cur_archive_file_ofs += archive_name_size;
7134 }
7135
7136 if (user_extra_data_len > 0) {
7137 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
7138 user_extra_data,
7139 user_extra_data_len) != user_extra_data_len)
7140 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7141
7142 cur_archive_file_ofs += user_extra_data_len;
7143 }
7144
7145 if (max_size) {
7146 void *pRead_buf =
7147 pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
7148 if (!pRead_buf) {
7149 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7150 }
7151
7152 if (!level) {
7153 while (1) {
7154 size_t n = read_callback(callback_opaque, file_ofs, pRead_buf,
7155 MZ_ZIP_MAX_IO_BUF_SIZE);
7156 if (n == 0)
7157 break;
7158
7159 if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) {
7160 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
7161 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7162 }
7163 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf,
7164 n) != n) {
7165 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
7166 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7167 }
7168 file_ofs += n;
7169 uncomp_crc32 =
7170 (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
7171 cur_archive_file_ofs += n;
7172 }
7173 uncomp_size = file_ofs;
7174 comp_size = uncomp_size;
7175 } else {
7176 mz_bool result = MZ_FALSE;
7177 mz_zip_writer_add_state state;
7178 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(
7179 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
7180 if (!pComp) {
7181 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
7182 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7183 }
7184
7185 state.m_pZip = pZip;
7186 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
7187 state.m_comp_size = 0;
7188
7189 if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
7190 tdefl_create_comp_flags_from_zip_params(
7191 level, -15, MZ_DEFAULT_STRATEGY)) !=
7192 TDEFL_STATUS_OKAY) {
7193 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
7194 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
7195 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
7196 }
7197
7198 for (;;) {
7199 tdefl_status status;
7200 tdefl_flush flush = TDEFL_NO_FLUSH;
7201
7202 size_t n = read_callback(callback_opaque, file_ofs, pRead_buf,
7203 MZ_ZIP_MAX_IO_BUF_SIZE);
7204 if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) {
7205 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7206 break;
7207 }
7208
7209 file_ofs += n;
7210 uncomp_crc32 =
7211 (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
7212
7213 if (pZip->m_pNeeds_keepalive != NULL &&
7214 pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque))
7215 flush = TDEFL_FULL_FLUSH;
7216
7217 if (n == 0)
7218 flush = TDEFL_FINISH;
7219
7220 status = tdefl_compress_buffer(pComp, pRead_buf, n, flush);
7221 if (status == TDEFL_STATUS_DONE) {
7222 result = MZ_TRUE;
7223 break;
7224 } else if (status != TDEFL_STATUS_OKAY) {
7225 mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);
7226 break;
7227 }
7228 }
7229
7230 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
7231
7232 if (!result) {
7233 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
7234 return MZ_FALSE;
7235 }
7236
7237 uncomp_size = file_ofs;
7238 comp_size = state.m_comp_size;
7239 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
7240 }
7241
7242 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
7243 }
7244
7245 if (!(level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE)) {
7246 mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];
7247 mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;
7248
7249 MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);
7250 MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);
7251 if (pExtra_data == NULL) {
7252 if (comp_size > MZ_UINT32_MAX)
7253 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
7254
7255 MZ_WRITE_LE32(local_dir_footer + 8, comp_size);
7256 MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);
7257 } else {
7258 MZ_WRITE_LE64(local_dir_footer + 8, comp_size);
7259 MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);
7260 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;
7261 }
7262
7263 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
7264 local_dir_footer,
7265 local_dir_footer_size) != local_dir_footer_size)
7266 return MZ_FALSE;
7267
7268 cur_archive_file_ofs += local_dir_footer_size;
7269 }
7270
7271 if (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) {
7272 if (pExtra_data != NULL) {
7273 extra_size = mz_zip_writer_create_zip64_extra_data(
7274 extra_data, (max_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
7275 (max_size >= MZ_UINT32_MAX) ? &comp_size : NULL,
7276 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs
7277 : NULL);
7278 }
7279
7280 if (!mz_zip_writer_create_local_dir_header(
7281 pZip, local_dir_header, (mz_uint16)archive_name_size,
7282 (mz_uint16)(extra_size + user_extra_data_len),
7283 (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : uncomp_size,
7284 (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : comp_size,
7285 uncomp_crc32, method, gen_flags, dos_time, dos_date))
7286 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
7287
7288 cur_archive_header_file_ofs = local_dir_header_ofs;
7289
7290 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs,
7291 local_dir_header,
7292 sizeof(local_dir_header)) != sizeof(local_dir_header))
7293 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7294
7295 if (pExtra_data != NULL) {
7296 cur_archive_header_file_ofs += sizeof(local_dir_header);
7297
7298 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs,
7299 pArchive_name,
7300 archive_name_size) != archive_name_size) {
7301 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7302 }
7303
7304 cur_archive_header_file_ofs += archive_name_size;
7305
7306 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs,
7307 extra_data, extra_size) != extra_size)
7308 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7309
7310 cur_archive_header_file_ofs += extra_size;
7311 }
7312 }
7313
7314 if (pExtra_data != NULL) {
7315 extra_size = mz_zip_writer_create_zip64_extra_data(
7316 extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
7317 (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL,
7318 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
7319 }
7320
7321 if (!mz_zip_writer_add_to_central_dir(
7322 pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data,
7323 (mz_uint16)extra_size, pComment, comment_size, uncomp_size, comp_size,
7324 uncomp_crc32, method, gen_flags, dos_time, dos_date,
7325 local_dir_header_ofs, ext_attributes, user_extra_data_central,
7326 user_extra_data_central_len))
7327 return MZ_FALSE;
7328
7329 pZip->m_total_files++;
7330 pZip->m_archive_size = cur_archive_file_ofs;
7331
7332 return MZ_TRUE;
7333}
7334
7335#ifndef MINIZ_NO_STDIO
7336
7337static size_t mz_file_read_func_stdio(void *pOpaque,
7338 mz_uint64 file_ofs,
7339 void *pBuf,
7340 size_t n) {
7341 MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque;
7342 mz_int64 cur_ofs = MZ_FTELL64(pSrc_file);
7343
7344 if (((mz_int64)file_ofs < 0) ||
7345 (((cur_ofs != (mz_int64)file_ofs)) &&
7346 (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET))))
7347 return 0;
7348
7349 return MZ_FREAD(pBuf, 1, n, pSrc_file);
7350}
7351
7352mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip,
7353 const char *pArchive_name,
7354 MZ_FILE *pSrc_file,
7355 mz_uint64 max_size,
7356 const MZ_TIME_T *pFile_time,
7357 const void *pComment,
7358 mz_uint16 comment_size,
7359 mz_uint level_and_flags,
7360 const char *user_extra_data,
7361 mz_uint user_extra_data_len,
7362 const char *user_extra_data_central,
7363 mz_uint user_extra_data_central_len) {
7364 return mz_zip_writer_add_read_buf_callback(
7365 pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, max_size,
7366 pFile_time, pComment, comment_size, level_and_flags, user_extra_data,
7367 user_extra_data_len, user_extra_data_central,
7368 user_extra_data_central_len);
7369}
7370
7371mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip,
7372 const char *pArchive_name,
7373 const char *pSrc_filename,
7374 const void *pComment,
7375 mz_uint16 comment_size,
7376 mz_uint level_and_flags) {
7377 MZ_FILE *pSrc_file = NULL;
7378 mz_uint64 uncomp_size = 0;
7379 MZ_TIME_T file_modified_time;
7380 MZ_TIME_T *pFile_time = NULL;
7381 mz_bool status;
7382
7383 memset(&file_modified_time, 0, sizeof(file_modified_time));
7384
7385#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)
7386 pFile_time = &file_modified_time;
7387 if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time))
7388 return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED);
7389#endif
7390
7391 pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
7392 if (!pSrc_file)
7393 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
7394
7395 MZ_FSEEK64(pSrc_file, 0, SEEK_END);
7396 uncomp_size = MZ_FTELL64(pSrc_file);
7397 MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
7398
7399 status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size,
7400 pFile_time, pComment, comment_size,
7401 level_and_flags, NULL, 0, NULL, 0);
7402
7403 MZ_FCLOSE(pSrc_file);
7404
7405 return status;
7406}
7407#endif /* #ifndef MINIZ_NO_STDIO */
7408
7409static mz_bool mz_zip_writer_update_zip64_extension_block(
7410 mz_zip_array *pNew_ext,
7411 mz_zip_archive *pZip,
7412 const mz_uint8 *pExt,
7413 mz_uint32 ext_len,
7414 mz_uint64 *pComp_size,
7415 mz_uint64 *pUncomp_size,
7416 mz_uint64 *pLocal_header_ofs,
7417 mz_uint32 *pDisk_start) {
7418 /* + 64 should be enough for any new zip64 data */
7419 if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE))
7420 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7421
7422 mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE);
7423
7424 if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) {
7425 mz_uint8 new_ext_block[64];
7426 mz_uint8 *pDst = new_ext_block;
7427 mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);
7428 mz_write_le16(pDst + sizeof(mz_uint16), 0);
7429 pDst += sizeof(mz_uint16) * 2;
7430
7431 if (pUncomp_size) {
7432 mz_write_le64(pDst, *pUncomp_size);
7433 pDst += sizeof(mz_uint64);
7434 }
7435
7436 if (pComp_size) {
7437 mz_write_le64(pDst, *pComp_size);
7438 pDst += sizeof(mz_uint64);
7439 }
7440
7441 if (pLocal_header_ofs) {
7442 mz_write_le64(pDst, *pLocal_header_ofs);
7443 pDst += sizeof(mz_uint64);
7444 }
7445
7446 if (pDisk_start) {
7447 mz_write_le32(pDst, *pDisk_start);
7448 pDst += sizeof(mz_uint32);
7449 }
7450
7451 mz_write_le16(new_ext_block + sizeof(mz_uint16),
7452 (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2));
7453
7454 if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block,
7455 pDst - new_ext_block))
7456 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7457 }
7458
7459 if ((pExt) && (ext_len)) {
7460 mz_uint32 extra_size_remaining = ext_len;
7461 const mz_uint8 *pExtra_data = pExt;
7462
7463 do {
7464 mz_uint32 field_id, field_data_size, field_total_size;
7465
7466 if (extra_size_remaining < (sizeof(mz_uint16) * 2))
7467 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7468
7469 field_id = MZ_READ_LE16(pExtra_data);
7470 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
7471 field_total_size = field_data_size + sizeof(mz_uint16) * 2;
7472
7473 if (field_total_size > extra_size_remaining)
7474 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7475
7476 if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
7477 if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data,
7478 field_total_size))
7479 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7480 }
7481
7482 pExtra_data += field_total_size;
7483 extra_size_remaining -= field_total_size;
7484 } while (extra_size_remaining);
7485 }
7486
7487 return MZ_TRUE;
7488}
7489
7490/* TODO: This func is now pretty freakin complex due to zip64, split it up? */
7491mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
7492 mz_zip_archive *pSource_zip,
7493 mz_uint src_file_index) {
7494 mz_uint n, bit_flags, num_alignment_padding_bytes,
7495 src_central_dir_following_data_size;
7496 mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs;
7497 mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
7498 mz_uint32
7499 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
7500 sizeof(mz_uint32)];
7501 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
7502 mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
7503 size_t orig_central_dir_size;
7504 mz_zip_internal_state *pState;
7505 void *pBuf;
7506 const mz_uint8 *pSrc_central_header;
7507 mz_zip_archive_file_stat src_file_stat;
7508 mz_uint32 src_filename_len, src_comment_len, src_ext_len;
7509 mz_uint32 local_header_filename_size, local_header_extra_len;
7510 mz_uint64 local_header_comp_size, local_header_uncomp_size;
7511 mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;
7512
7513 /* Sanity checks */
7514 if ((!pZip) || (!pZip->m_pState) ||
7515 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead))
7516 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7517
7518 pState = pZip->m_pState;
7519
7520 /* Don't support copying files from zip64 archives to non-zip64, even though
7521 * in some cases this is possible */
7522 if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64))
7523 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7524
7525 /* Get pointer to the source central dir header and crack it */
7526 if (NULL ==
7527 (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index)))
7528 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7529
7530 if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) !=
7531 MZ_ZIP_CENTRAL_DIR_HEADER_SIG)
7532 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7533
7534 src_filename_len =
7535 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS);
7536 src_comment_len =
7537 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
7538 src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS);
7539 src_central_dir_following_data_size =
7540 src_filename_len + src_ext_len + src_comment_len;
7541
7542 /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32
7543 * fudge factor in case we need to add more extra data) */
7544 if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
7545 src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX)
7546 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
7547
7548 num_alignment_padding_bytes =
7549 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
7550
7551 if (!pState->m_zip64) {
7552 if (pZip->m_total_files == MZ_UINT16_MAX)
7553 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
7554 } else {
7555 /* TODO: Our zip64 support still has some 32-bit limits that may not be
7556 * worth fixing. */
7557 if (pZip->m_total_files == MZ_UINT32_MAX)
7558 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
7559 }
7560
7561 if (!mz_zip_file_stat_internal(pSource_zip, src_file_index,
7562 pSrc_central_header, &src_file_stat, NULL))
7563 return MZ_FALSE;
7564
7565 cur_src_file_ofs = src_file_stat.m_local_header_ofs;
7566 cur_dst_file_ofs = pZip->m_archive_size;
7567
7568 /* Read the source archive's local dir header */
7569 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs,
7570 pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
7571 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
7572 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7573
7574 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
7575 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7576
7577 cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
7578
7579 /* Compute the total size we need to copy (filename+extra data+compressed
7580 * data) */
7581 local_header_filename_size =
7582 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);
7583 local_header_extra_len =
7584 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
7585 local_header_comp_size =
7586 MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);
7587 local_header_uncomp_size =
7588 MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);
7589 src_archive_bytes_remaining = local_header_filename_size +
7590 local_header_extra_len +
7591 src_file_stat.m_comp_size;
7592
7593 /* Try to find a zip64 extended information field */
7594 if ((local_header_extra_len) &&
7595 ((local_header_comp_size == MZ_UINT32_MAX) ||
7596 (local_header_uncomp_size == MZ_UINT32_MAX))) {
7597 mz_zip_array file_data_array;
7598 const mz_uint8 *pExtra_data;
7599 mz_uint32 extra_size_remaining = local_header_extra_len;
7600
7601 mz_zip_array_init(&file_data_array, 1);
7602 if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len,
7603 MZ_FALSE)) {
7604 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7605 }
7606
7607 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque,
7608 src_file_stat.m_local_header_ofs +
7609 MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
7610 local_header_filename_size,
7611 file_data_array.m_p, local_header_extra_len) !=
7612 local_header_extra_len) {
7613 mz_zip_array_clear(pZip, &file_data_array);
7614 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7615 }
7616
7617 pExtra_data = (const mz_uint8 *)file_data_array.m_p;
7618
7619 do {
7620 mz_uint32 field_id, field_data_size, field_total_size;
7621
7622 if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
7623 mz_zip_array_clear(pZip, &file_data_array);
7624 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7625 }
7626
7627 field_id = MZ_READ_LE16(pExtra_data);
7628 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
7629 field_total_size = field_data_size + sizeof(mz_uint16) * 2;
7630
7631 if (field_total_size > extra_size_remaining) {
7632 mz_zip_array_clear(pZip, &file_data_array);
7633 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7634 }
7635
7636 if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
7637 const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);
7638
7639 if (field_data_size < sizeof(mz_uint64) * 2) {
7640 mz_zip_array_clear(pZip, &file_data_array);
7641 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7642 }
7643
7644 local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);
7645 local_header_comp_size = MZ_READ_LE64(
7646 pSrc_field_data +
7647 sizeof(mz_uint64)); /* may be 0 if there's a descriptor */
7648
7649 found_zip64_ext_data_in_ldir = MZ_TRUE;
7650 break;
7651 }
7652
7653 pExtra_data += field_total_size;
7654 extra_size_remaining -= field_total_size;
7655 } while (extra_size_remaining);
7656
7657 mz_zip_array_clear(pZip, &file_data_array);
7658 }
7659
7660 if (!pState->m_zip64) {
7661 /* Try to detect if the new archive will most likely wind up too big and
7662 * bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which
7663 * could be present, +64 is a fudge factor). */
7664 /* We also check when the archive is finalized so this doesn't need to be
7665 * perfect. */
7666 mz_uint64 approx_new_archive_size =
7667 cur_dst_file_ofs + num_alignment_padding_bytes +
7668 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining +
7669 (sizeof(mz_uint32) * 4) + pState->m_central_dir.m_size +
7670 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size +
7671 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64;
7672
7673 if (approx_new_archive_size >= MZ_UINT32_MAX)
7674 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
7675 }
7676
7677 /* Write dest archive padding */
7678 if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs,
7679 num_alignment_padding_bytes))
7680 return MZ_FALSE;
7681
7682 cur_dst_file_ofs += num_alignment_padding_bytes;
7683
7684 local_dir_header_ofs = cur_dst_file_ofs;
7685 if (pZip->m_file_offset_alignment) {
7686 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
7687 0);
7688 }
7689
7690 /* The original zip's local header+ext block doesn't change, even with zip64,
7691 * so we can just copy it over to the dest zip */
7692 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header,
7693 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
7694 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
7695 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7696
7697 cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
7698
7699 /* Copy over the source archive bytes to the dest archive, also ensure we have
7700 * enough buf space to handle optional data descriptor */
7701 if (NULL == (pBuf = pZip->m_pAlloc(
7702 pZip->m_pAlloc_opaque, 1,
7703 (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE,
7704 src_archive_bytes_remaining)))))
7705 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7706
7707 while (src_archive_bytes_remaining) {
7708 n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE,
7709 src_archive_bytes_remaining);
7710 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
7711 n) != n) {
7712 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7713 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7714 }
7715 cur_src_file_ofs += n;
7716
7717 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
7718 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7719 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7720 }
7721 cur_dst_file_ofs += n;
7722
7723 src_archive_bytes_remaining -= n;
7724 }
7725
7726 /* Now deal with the optional data descriptor */
7727 bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
7728 if (bit_flags & 8) {
7729 /* Copy data descriptor */
7730 if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) {
7731 /* src is zip64, dest must be zip64 */
7732
7733 /* name uint32_t's */
7734 /* id 1 (optional in zip64?) */
7735 /* crc 1 */
7736 /* comp_size 2 */
7737 /* uncomp_size 2 */
7738 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs,
7739 pBuf, (sizeof(mz_uint32) * 6)) !=
7740 (sizeof(mz_uint32) * 6)) {
7741 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7742 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7743 }
7744
7745 n = sizeof(mz_uint32) *
7746 ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5);
7747 } else {
7748 /* src is NOT zip64 */
7749 mz_bool has_id;
7750
7751 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs,
7752 pBuf, sizeof(mz_uint32) * 4) !=
7753 sizeof(mz_uint32) * 4) {
7754 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7755 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7756 }
7757
7758 has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID);
7759
7760 if (pZip->m_pState->m_zip64) {
7761 /* dest is zip64, so upgrade the data descriptor */
7762 const mz_uint8 *pSrc_descriptor =
7763 (const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0);
7764 const mz_uint32 src_crc32 = MZ_READ_LE32(pSrc_descriptor);
7765 const mz_uint64 src_comp_size =
7766 MZ_READ_LE32(pSrc_descriptor + sizeof(mz_uint32));
7767 const mz_uint64 src_uncomp_size =
7768 MZ_READ_LE32(pSrc_descriptor + 2 * sizeof(mz_uint32));
7769
7770 mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID);
7771 mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32);
7772 mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size);
7773 mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4,
7774 src_uncomp_size);
7775
7776 n = sizeof(mz_uint32) * 6;
7777 } else {
7778 /* dest is NOT zip64, just copy it as-is */
7779 n = sizeof(mz_uint32) * (has_id ? 4 : 3);
7780 }
7781 }
7782
7783 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
7784 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7785 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7786 }
7787
7788 cur_src_file_ofs += n;
7789 cur_dst_file_ofs += n;
7790 }
7791 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7792
7793 /* Finally, add the new central dir header */
7794 orig_central_dir_size = pState->m_central_dir.m_size;
7795
7796 memcpy(new_central_header, pSrc_central_header,
7797 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
7798
7799 if (pState->m_zip64) {
7800 /* This is the painful part: We need to write a new central dir header + ext
7801 * block with updated zip64 fields, and ensure the old fields (if any) are
7802 * not included. */
7803 const mz_uint8 *pSrc_ext =
7804 pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len;
7805 mz_zip_array new_ext_block;
7806
7807 mz_zip_array_init(&new_ext_block, sizeof(mz_uint8));
7808
7809 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS,
7810 MZ_UINT32_MAX);
7811 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS,
7812 MZ_UINT32_MAX);
7813 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS,
7814 MZ_UINT32_MAX);
7815
7816 if (!mz_zip_writer_update_zip64_extension_block(
7817 &new_ext_block, pZip, pSrc_ext, src_ext_len,
7818 &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size,
7819 &local_dir_header_ofs, NULL)) {
7820 mz_zip_array_clear(pZip, &new_ext_block);
7821 return MZ_FALSE;
7822 }
7823
7824 MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS,
7825 new_ext_block.m_size);
7826
7827 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir,
7828 new_central_header,
7829 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) {
7830 mz_zip_array_clear(pZip, &new_ext_block);
7831 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7832 }
7833
7834 if (!mz_zip_array_push_back(
7835 pZip, &pState->m_central_dir,
7836 pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE,
7837 src_filename_len)) {
7838 mz_zip_array_clear(pZip, &new_ext_block);
7839 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
7840 MZ_FALSE);
7841 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7842 }
7843
7844 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p,
7845 new_ext_block.m_size)) {
7846 mz_zip_array_clear(pZip, &new_ext_block);
7847 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
7848 MZ_FALSE);
7849 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7850 }
7851
7852 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir,
7853 pSrc_central_header +
7854 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
7855 src_filename_len + src_ext_len,
7856 src_comment_len)) {
7857 mz_zip_array_clear(pZip, &new_ext_block);
7858 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
7859 MZ_FALSE);
7860 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7861 }
7862
7863 mz_zip_array_clear(pZip, &new_ext_block);
7864 } else {
7865 /* sanity checks */
7866 if (cur_dst_file_ofs > MZ_UINT32_MAX)
7867 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
7868
7869 if (local_dir_header_ofs >= MZ_UINT32_MAX)
7870 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
7871
7872 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS,
7873 local_dir_header_ofs);
7874
7875 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir,
7876 new_central_header,
7877 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
7878 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7879
7880 if (!mz_zip_array_push_back(
7881 pZip, &pState->m_central_dir,
7882 pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE,
7883 src_central_dir_following_data_size)) {
7884 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
7885 MZ_FALSE);
7886 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7887 }
7888 }
7889
7890 /* This shouldn't trigger unless we screwed up during the initial sanity
7891 * checks */
7892 if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) {
7893 /* TODO: Support central dirs >= 32-bits in size */
7894 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
7895 MZ_FALSE);
7896 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
7897 }
7898
7899 n = (mz_uint32)orig_central_dir_size;
7900 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) {
7901 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
7902 MZ_FALSE);
7903 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7904 }
7905
7906 pZip->m_total_files++;
7907 pZip->m_archive_size = cur_dst_file_ofs;
7908
7909 return MZ_TRUE;
7910}
7911
7912mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) {
7913 mz_zip_internal_state *pState;
7914 mz_uint64 central_dir_ofs, central_dir_size;
7915 mz_uint8 hdr[256];
7916
7917 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
7918 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7919
7920 pState = pZip->m_pState;
7921
7922 if (pState->m_zip64) {
7923 if ((mz_uint64)pState->m_central_dir.m_size >= MZ_UINT32_MAX)
7924 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
7925 } else {
7926 if ((pZip->m_total_files > MZ_UINT16_MAX) ||
7927 ((pZip->m_archive_size + pState->m_central_dir.m_size +
7928 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX))
7929 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
7930 }
7931
7932 central_dir_ofs = 0;
7933 central_dir_size = 0;
7934 if (pZip->m_total_files) {
7935 /* Write central directory */
7936 central_dir_ofs = pZip->m_archive_size;
7937 central_dir_size = pState->m_central_dir.m_size;
7938 pZip->m_central_directory_file_ofs = central_dir_ofs;
7939 if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs,
7940 pState->m_central_dir.m_p,
7941 (size_t)central_dir_size) != central_dir_size)
7942 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7943
7944 pZip->m_archive_size += central_dir_size;
7945 }
7946
7947 if (pState->m_zip64) {
7948 /* Write zip64 end of central directory header */
7949 mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size;
7950
7951 MZ_CLEAR_ARR(hdr);
7952 MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS,
7953 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG);
7954 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS,
7955 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) -
7956 sizeof(mz_uint64));
7957 MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS,
7958 0x031E); /* TODO: always Unix */
7959 MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D);
7960 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS,
7961 pZip->m_total_files);
7962 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS,
7963 pZip->m_total_files);
7964 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size);
7965 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs);
7966 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr,
7967 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
7968 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)
7969 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7970
7971 pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE;
7972
7973 /* Write zip64 end of central directory locator */
7974 MZ_CLEAR_ARR(hdr);
7975 MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS,
7976 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG);
7977 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS,
7978 rel_ofs_to_zip64_ecdr);
7979 MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1);
7980 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr,
7981 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) !=
7982 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE)
7983 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7984
7985 pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE;
7986 }
7987
7988 /* Write end of central directory record */
7989 MZ_CLEAR_ARR(hdr);
7990 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS,
7991 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
7992 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS,
7993 MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));
7994 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS,
7995 MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));
7996 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS,
7997 MZ_MIN(MZ_UINT32_MAX, central_dir_size));
7998 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS,
7999 MZ_MIN(MZ_UINT32_MAX, central_dir_ofs));
8000
8001 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr,
8002 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
8003 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
8004 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8005
8006#ifndef MINIZ_NO_STDIO
8007 if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))
8008 return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
8009#endif /* #ifndef MINIZ_NO_STDIO */
8010
8011 pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE;
8012
8013 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
8014 return MZ_TRUE;
8015}
8016
8017mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip,
8018 void **ppBuf,
8019 size_t *pSize) {
8020 if ((!ppBuf) || (!pSize))
8021 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8022
8023 *ppBuf = NULL;
8024 *pSize = 0;
8025
8026 if ((!pZip) || (!pZip->m_pState))
8027 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8028
8029 if (pZip->m_pWrite != mz_zip_heap_write_func)
8030 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8031
8032 if (!mz_zip_writer_finalize_archive(pZip))
8033 return MZ_FALSE;
8034
8035 *ppBuf = pZip->m_pState->m_pMem;
8036 *pSize = pZip->m_pState->m_mem_size;
8037 pZip->m_pState->m_pMem = NULL;
8038 pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
8039
8040 return MZ_TRUE;
8041}
8042
8043mz_bool mz_zip_writer_end(mz_zip_archive *pZip) {
8044 return mz_zip_writer_end_internal(pZip, MZ_TRUE);
8045}
8046
8047#ifndef MINIZ_NO_STDIO
8048mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename,
8049 const char *pArchive_name,
8050 const void *pBuf,
8051 size_t buf_size,
8052 const void *pComment,
8053 mz_uint16 comment_size,
8054 mz_uint level_and_flags) {
8055 return mz_zip_add_mem_to_archive_file_in_place_v2(
8056 pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size,
8057 level_and_flags, NULL);
8058}
8059
8060mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename,
8061 const char *pArchive_name,
8062 const void *pBuf,
8063 size_t buf_size,
8064 const void *pComment,
8065 mz_uint16 comment_size,
8066 mz_uint level_and_flags,
8067 mz_zip_error *pErr) {
8068 mz_bool status, created_new_archive = MZ_FALSE;
8069 mz_zip_archive zip_archive;
8070 struct MZ_FILE_STAT_STRUCT file_stat;
8071 mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
8072
8073 mz_zip_zero_struct(&zip_archive);
8074 if ((int)level_and_flags < 0)
8075 level_and_flags = MZ_DEFAULT_LEVEL;
8076
8077 if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) ||
8078 ((comment_size) && (!pComment)) ||
8079 ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) {
8080 if (pErr)
8081 *pErr = MZ_ZIP_INVALID_PARAMETER;
8082 return MZ_FALSE;
8083 }
8084
8085 if (!mz_zip_writer_validate_archive_name(pArchive_name)) {
8086 if (pErr)
8087 *pErr = MZ_ZIP_INVALID_FILENAME;
8088 return MZ_FALSE;
8089 }
8090
8091 /* Important: The regular non-64 bit version of stat() can fail here if the
8092 * file is very large, which could cause the archive to be overwritten. */
8093 /* So be sure to compile with _LARGEFILE64_SOURCE 1 */
8094 if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) {
8095 /* Create a new archive. */
8096 if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0,
8097 level_and_flags)) {
8098 if (pErr)
8099 *pErr = zip_archive.m_last_error;
8100 return MZ_FALSE;
8101 }
8102
8103 created_new_archive = MZ_TRUE;
8104 } else {
8105 /* Append to an existing archive. */
8106 if (!mz_zip_reader_init_file_v2(
8107 &zip_archive, pZip_filename,
8108 level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0,
8109 0)) {
8110 if (pErr)
8111 *pErr = zip_archive.m_last_error;
8112 return MZ_FALSE;
8113 }
8114
8115 if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename,
8116 level_and_flags)) {
8117 if (pErr)
8118 *pErr = zip_archive.m_last_error;
8119
8120 mz_zip_reader_end_internal(&zip_archive, MZ_FALSE);
8121
8122 return MZ_FALSE;
8123 }
8124 }
8125
8126 status =
8127 mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size,
8128 pComment, comment_size, level_and_flags, 0, 0);
8129 actual_err = zip_archive.m_last_error;
8130
8131 /* Always finalize, even if adding failed for some reason, so we have a valid
8132 * central directory. (This may not always succeed, but we can try.) */
8133 if (!mz_zip_writer_finalize_archive(&zip_archive)) {
8134 if (!actual_err)
8135 actual_err = zip_archive.m_last_error;
8136
8137 status = MZ_FALSE;
8138 }
8139
8140 if (!mz_zip_writer_end_internal(&zip_archive, status)) {
8141 if (!actual_err)
8142 actual_err = zip_archive.m_last_error;
8143
8144 status = MZ_FALSE;
8145 }
8146
8147 if ((!status) && (created_new_archive)) {
8148 /* It's a new archive and something went wrong, so just delete it. */
8149 int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
8150 (void)ignoredStatus;
8151 }
8152
8153 if (pErr)
8154 *pErr = actual_err;
8155
8156 return status;
8157}
8158
8159void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename,
8160 const char *pArchive_name,
8161 const char *pComment,
8162 size_t *pSize,
8163 mz_uint flags,
8164 mz_zip_error *pErr) {
8165 mz_uint32 file_index;
8166 mz_zip_archive zip_archive;
8167 void *p = NULL;
8168
8169 if (pSize)
8170 *pSize = 0;
8171
8172 if ((!pZip_filename) || (!pArchive_name)) {
8173 if (pErr)
8174 *pErr = MZ_ZIP_INVALID_PARAMETER;
8175
8176 return NULL;
8177 }
8178
8179 mz_zip_zero_struct(&zip_archive);
8180 if (!mz_zip_reader_init_file_v2(
8181 &zip_archive, pZip_filename,
8182 flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) {
8183 if (pErr)
8184 *pErr = zip_archive.m_last_error;
8185
8186 return NULL;
8187 }
8188
8189 if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags,
8190 &file_index)) {
8191 p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
8192 }
8193
8194 mz_zip_reader_end_internal(&zip_archive, p != NULL);
8195
8196 if (pErr)
8197 *pErr = zip_archive.m_last_error;
8198
8199 return p;
8200}
8201
8202void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
8203 const char *pArchive_name,
8204 size_t *pSize,
8205 mz_uint flags) {
8206 return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name,
8207 NULL, pSize, flags, NULL);
8208}
8209
8210#endif /* #ifndef MINIZ_NO_STDIO */
8211
8212#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */
8213
8214/* ------------------- Misc utils */
8215
8216mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) {
8217 return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID;
8218}
8219
8220mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) {
8221 return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID;
8222}
8223
8224mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) {
8225 mz_zip_error prev_err;
8226
8227 if (!pZip)
8228 return MZ_ZIP_INVALID_PARAMETER;
8229
8230 prev_err = pZip->m_last_error;
8231
8232 pZip->m_last_error = err_num;
8233 return prev_err;
8234}
8235
8236mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) {
8237 if (!pZip)
8238 return MZ_ZIP_INVALID_PARAMETER;
8239
8240 return pZip->m_last_error;
8241}
8242
8243mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) {
8244 return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR);
8245}
8246
8247mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) {
8248 mz_zip_error prev_err;
8249
8250 if (!pZip)
8251 return MZ_ZIP_INVALID_PARAMETER;
8252
8253 prev_err = pZip->m_last_error;
8254
8255 pZip->m_last_error = MZ_ZIP_NO_ERROR;
8256 return prev_err;
8257}
8258
8259const char *mz_zip_get_error_string(mz_zip_error mz_err) {
8260 switch (mz_err) {
8261 case MZ_ZIP_NO_ERROR:
8262 return "no error";
8263 case MZ_ZIP_UNDEFINED_ERROR:
8264 return "undefined error";
8265 case MZ_ZIP_TOO_MANY_FILES:
8266 return "too many files";
8267 case MZ_ZIP_FILE_TOO_LARGE:
8268 return "file too large";
8269 case MZ_ZIP_UNSUPPORTED_METHOD:
8270 return "unsupported method";
8271 case MZ_ZIP_UNSUPPORTED_ENCRYPTION:
8272 return "unsupported encryption";
8273 case MZ_ZIP_UNSUPPORTED_FEATURE:
8274 return "unsupported feature";
8275 case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:
8276 return "failed finding central directory";
8277 case MZ_ZIP_NOT_AN_ARCHIVE:
8278 return "not a ZIP archive";
8279 case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:
8280 return "invalid header or archive is corrupted";
8281 case MZ_ZIP_UNSUPPORTED_MULTIDISK:
8282 return "unsupported multidisk archive";
8283 case MZ_ZIP_DECOMPRESSION_FAILED:
8284 return "decompression failed or archive is corrupted";
8285 case MZ_ZIP_COMPRESSION_FAILED:
8286 return "compression failed";
8287 case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:
8288 return "unexpected decompressed size";
8289 case MZ_ZIP_CRC_CHECK_FAILED:
8290 return "CRC-32 check failed";
8291 case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:
8292 return "unsupported central directory size";
8293 case MZ_ZIP_ALLOC_FAILED:
8294 return "allocation failed";
8295 case MZ_ZIP_FILE_OPEN_FAILED:
8296 return "file open failed";
8297 case MZ_ZIP_FILE_CREATE_FAILED:
8298 return "file create failed";
8299 case MZ_ZIP_FILE_WRITE_FAILED:
8300 return "file write failed";
8301 case MZ_ZIP_FILE_READ_FAILED:
8302 return "file read failed";
8303 case MZ_ZIP_FILE_CLOSE_FAILED:
8304 return "file close failed";
8305 case MZ_ZIP_FILE_SEEK_FAILED:
8306 return "file seek failed";
8307 case MZ_ZIP_FILE_STAT_FAILED:
8308 return "file stat failed";
8309 case MZ_ZIP_INVALID_PARAMETER:
8310 return "invalid parameter";
8311 case MZ_ZIP_INVALID_FILENAME:
8312 return "invalid filename";
8313 case MZ_ZIP_BUF_TOO_SMALL:
8314 return "buffer too small";
8315 case MZ_ZIP_INTERNAL_ERROR:
8316 return "internal error";
8317 case MZ_ZIP_FILE_NOT_FOUND:
8318 return "file not found";
8319 case MZ_ZIP_ARCHIVE_TOO_LARGE:
8320 return "archive is too large";
8321 case MZ_ZIP_VALIDATION_FAILED:
8322 return "validation failed";
8323 case MZ_ZIP_WRITE_CALLBACK_FAILED:
8324 return "write callback failed";
8325 case MZ_ZIP_TOTAL_ERRORS:
8326 return "total errors";
8327 default:
8328 break;
8329 }
8330
8331 return "unknown error";
8332}
8333
8334/* Note: Just because the archive is not zip64 doesn't necessarily mean it
8335 * doesn't have Zip64 extended information extra field, argh. */
8336mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) {
8337 if ((!pZip) || (!pZip->m_pState))
8338 return MZ_FALSE;
8339
8340 return pZip->m_pState->m_zip64;
8341}
8342
8343size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) {
8344 if ((!pZip) || (!pZip->m_pState))
8345 return 0;
8346
8347 return pZip->m_pState->m_central_dir.m_size;
8348}
8349
8350mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) {
8351 return pZip ? pZip->m_total_files : 0;
8352}
8353
8354mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) {
8355 if (!pZip)
8356 return 0;
8357 return pZip->m_archive_size;
8358}
8359
8360mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) {
8361 if ((!pZip) || (!pZip->m_pState))
8362 return 0;
8363 return pZip->m_pState->m_file_archive_start_ofs;
8364}
8365
8366MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) {
8367 if ((!pZip) || (!pZip->m_pState))
8368 return 0;
8369 return pZip->m_pState->m_pFile;
8370}
8371
8372size_t mz_zip_read_archive_data(mz_zip_archive *pZip,
8373 mz_uint64 file_ofs,
8374 void *pBuf,
8375 size_t n) {
8376 if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead))
8377 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8378
8379 return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n);
8380}
8381
8382mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip,
8383 mz_uint file_index,
8384 char *pFilename,
8385 mz_uint filename_buf_size) {
8386 mz_uint n;
8387 const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
8388 if (!p) {
8389 if (filename_buf_size)
8390 pFilename[0] = '\0';
8391 mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8392 return 0;
8393 }
8394 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
8395 if (filename_buf_size) {
8396 n = MZ_MIN(n, filename_buf_size - 1);
8397 memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
8398 pFilename[n] = '\0';
8399 }
8400 return n + 1;
8401}
8402
8403mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip,
8404 mz_uint file_index,
8405 mz_zip_archive_file_stat *pStat) {
8406 return mz_zip_file_stat_internal(
8407 pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL);
8408}
8409
8410mz_bool mz_zip_end(mz_zip_archive *pZip) {
8411 if (!pZip)
8412 return MZ_FALSE;
8413
8414 if (pZip->m_zip_mode == MZ_ZIP_MODE_READING)
8415 return mz_zip_reader_end(pZip);
8416#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
8417 else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) ||
8418 (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))
8419 return mz_zip_writer_end(pZip);
8420#endif
8421
8422 return MZ_FALSE;
8423}
8424
8425#ifdef __cplusplus
8426}
8427#endif
8428
8429#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/
8430