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