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