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