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