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