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