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