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