1 /**************************************************************************
2 *
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 *
25 **************************************************************************/
26
27 #include "miniz.h"
28
29 typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];
30 typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];
31 typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
32
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36
37 /* ------------------- zlib-style API's */
38
mz_adler32(mz_ulong adler,const unsigned char * ptr,size_t buf_len)39 mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len)
40 {
41 // 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 */
91 mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len);
92 #else
93 /* Faster, but larger CPU cache footprint.
94 */
mz_crc32(mz_ulong crc,const mz_uint8 * ptr,size_t buf_len)95 mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
96 {
97 static const mz_uint32 s_crc_table[256] =
98 {
99 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
100 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
101 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
102 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
103 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
104 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
105 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
106 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
107 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
108 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
109 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB,
110 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
111 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA,
112 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE,
113 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
114 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
115 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409,
116 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
117 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739,
118 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
119 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268,
120 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0,
121 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8,
122 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
123 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
124 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
125 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,
126 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
127 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE,
128 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
129 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6,
130 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
131 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D,
132 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
133 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
134 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
135 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
136 };
137
138 mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF;
139 const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr;
140
141 while (buf_len >= 4)
142 {
143 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];
144 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF];
145 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF];
146 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF];
147 pByte_buf += 4;
148 buf_len -= 4;
149 }
150
151 while (buf_len)
152 {
153 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];
154 ++pByte_buf;
155 --buf_len;
156 }
157
158 return ~crc32;
159 }
160 #endif
161
mz_free(void * p)162 void mz_free(void *p)
163 {
164 MZ_FREE(p);
165 }
166
miniz_def_alloc_func(void * opaque,size_t items,size_t size)167 void *miniz_def_alloc_func(void *opaque, size_t items, size_t size)
168 {
169 (void)opaque, (void)items, (void)size;
170 return MZ_MALLOC(items * size);
171 }
miniz_def_free_func(void * opaque,void * address)172 void miniz_def_free_func(void *opaque, void *address)
173 {
174 (void)opaque, (void)address;
175 MZ_FREE(address);
176 }
miniz_def_realloc_func(void * opaque,void * address,size_t items,size_t size)177 void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size)
178 {
179 (void)opaque, (void)address, (void)items, (void)size;
180 return MZ_REALLOC(address, items * size);
181 }
182
mz_version(void)183 const char *mz_version(void)
184 {
185 return MZ_VERSION;
186 }
187
188 #ifndef MINIZ_NO_ZLIB_APIS
189
mz_deflateInit(mz_streamp pStream,int level)190 int mz_deflateInit(mz_streamp pStream, int level)
191 {
192 return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY);
193 }
194
mz_deflateInit2(mz_streamp pStream,int level,int method,int window_bits,int mem_level,int strategy)195 int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy)
196 {
197 // 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
mz_deflateReset(mz_streamp pStream)232 int 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
mz_deflate(mz_streamp pStream,int flush)241 int 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
mz_deflateEnd(mz_streamp pStream)302 int 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
mz_deflateBound(mz_streamp pStream,mz_ulong source_len)314 mz_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
mz_compress2(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len,int level)321 int 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
mz_compress(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len)352 int 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
mz_compressBound(mz_ulong source_len)357 mz_ulong mz_compressBound(mz_ulong source_len)
358 {
359 return mz_deflateBound(NULL, source_len);
360 }
361
362 typedef 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
mz_inflateInit2(mz_streamp pStream,int window_bits)371 int 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
mz_inflateInit(mz_streamp pStream)408 int mz_inflateInit(mz_streamp pStream)
409 {
410 return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
411 }
412
mz_inflateReset(mz_streamp pStream)413 int 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
mz_inflate(mz_streamp pStream,int flush)440 int 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
mz_inflateEnd(mz_streamp pStream)556 int 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
mz_uncompress(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len)568 int 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
mz_error(int err)599 const 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
679 extern "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. */
685 static 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
697 static 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
705 static 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
721 static 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
733 static 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
740 static 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. */
748 typedef struct
749 {
750 mz_uint16 m_key, m_sym_index;
751 } tdefl_sym_freq;
tdefl_radix_sort_syms(mz_uint num_syms,tdefl_sym_freq * pSyms0,tdefl_sym_freq * pSyms1)752 static 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. */
tdefl_calculate_minimum_redundancy(tdefl_sym_freq * A,int n)787 static 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. */
844 enum
845 {
846 TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32
847 };
tdefl_huffman_enforce_max_code_size(int * pNum_codes,int code_list_len,int max_code_size)848 static 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
tdefl_optimize_huffman_table(tdefl_compressor * d,int table_num,int table_len,int code_size_limit,int static_table)873 static 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)
994 static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
995
tdefl_start_dynamic_block(tdefl_compressor * d)996 static 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
tdefl_start_static_block(tdefl_compressor * d)1086 static 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
1109 static 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
tdefl_compress_lz_codes(tdefl_compressor * d)1112 static 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
tdefl_compress_lz_codes(tdefl_compressor * d)1206 static 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
tdefl_compress_block(tdefl_compressor * d,mz_bool static_block)1257 static 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
tdefl_flush_block(tdefl_compressor * d,int flush)1266 static 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
TDEFL_READ_UNALIGNED_WORD(const mz_uint8 * p)1409 static 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 }
TDEFL_READ_UNALIGNED_WORD2(const mz_uint16 * p)1415 static 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
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)1425 static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)
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
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)1481 static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)
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
TDEFL_READ_UNALIGNED_WORD32(const mz_uint8 * p)1528 static 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
tdefl_compress_fast(tdefl_compressor * d)1537 static 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
tdefl_record_literal(tdefl_compressor * d,mz_uint8 lit)1711 static 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
tdefl_record_match(tdefl_compressor * d,mz_uint match_len,mz_uint match_dist)1725 static 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
tdefl_compress_normal(tdefl_compressor * d)1756 static 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
tdefl_flush_output_buffer(tdefl_compressor * d)1903 static 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
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)1924 tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush)
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
tdefl_compress_buffer(tdefl_compressor * d,const void * pIn_buf,size_t in_buf_size,tdefl_flush flush)1992 tdefl_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
tdefl_init(tdefl_compressor * d,tdefl_put_buf_func_ptr pPut_buf_func,void * pPut_buf_user,int flags)1998 tdefl_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
tdefl_get_prev_return_status(tdefl_compressor * d)2033 tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d)
2034 {
2035 return d->m_prev_return_status;
2036 }
2037
tdefl_get_adler32(tdefl_compressor * d)2038 mz_uint32 tdefl_get_adler32(tdefl_compressor *d)
2039 {
2040 return d->m_adler32;
2041 }
2042
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)2043 mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
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
2060 typedef struct
2061 {
2062 size_t m_size, m_capacity;
2063 mz_uint8 *m_pBuf;
2064 mz_bool m_expandable;
2065 } tdefl_output_buffer;
2066
tdefl_output_buffer_putter(const void * pBuf,int len,void * pUser)2067 static 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
tdefl_compress_mem_to_heap(const void * pSrc_buf,size_t src_buf_len,size_t * pOut_len,int flags)2093 void *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
tdefl_compress_mem_to_mem(void * pOut_buf,size_t out_buf_len,const void * pSrc_buf,size_t src_buf_len,int flags)2108 size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
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
2121 static 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). */
tdefl_create_comp_flags_from_zip_params(int level,int window_bits,int strategy)2124 mz_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. */
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)2152 void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip)
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 }
tdefl_write_image_to_png_file_in_memory(const void * pImage,int w,int h,int num_chans,size_t * pLen_out)2233 void *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. */
tdefl_compressor_alloc(void)2243 tdefl_compressor *tdefl_compressor_alloc(void)
2244 {
2245 return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
2246 }
2247
tdefl_compressor_free(tdefl_compressor * pComp)2248 void 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
2290 extern "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
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)2434 tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
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
2875 common_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. */
tinfl_decompress_mem_to_heap(const void * pSrc_buf,size_t src_buf_len,size_t * pOut_len,int flags)2929 void *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
tinfl_decompress_mem_to_mem(void * pOut_buf,size_t out_buf_len,const void * pSrc_buf,size_t src_buf_len,int flags)2969 size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
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
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)2979 int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
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
tinfl_decompressor_alloc(void)3009 tinfl_decompressor *tinfl_decompressor_alloc(void)
3010 {
3011 tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor));
3012 if (pDecomp)
3013 tinfl_init(pDecomp);
3014 return pDecomp;
3015 }
3016
tinfl_decompressor_free(tinfl_decompressor * pDecomp)3017 void 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
3057 extern "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__)
3068 static FILE *mz_fopen(const char *pFilename, const char *pMode)
3069 {
3070 FILE *pFile = NULL;
3071 fopen_s(&pFile, pFilename, pMode);
3072 return pFile;
3073 }
3074 static 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. */
3183 enum
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
3272 typedef struct
3273 {
3274 void *m_p;
3275 size_t m_size, m_capacity;
3276 mz_uint m_element_size;
3277 } mz_zip_array;
3278
3279 struct 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)
mz_zip_array_range_check(const mz_zip_array * pArray,mz_uint index)3306 static 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
mz_zip_array_init(mz_zip_array * pArray,mz_uint32 element_size)3316 static 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
mz_zip_array_clear(mz_zip_archive * pZip,mz_zip_array * pArray)3322 static 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
mz_zip_array_ensure_capacity(mz_zip_archive * pZip,mz_zip_array * pArray,size_t min_new_capacity,mz_uint growing)3328 static 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
mz_zip_array_reserve(mz_zip_archive * pZip,mz_zip_array * pArray,size_t new_capacity,mz_uint growing)3349 static 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
mz_zip_array_resize(mz_zip_archive * pZip,mz_zip_array * pArray,size_t new_size,mz_uint growing)3359 static 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
mz_zip_array_ensure_room(mz_zip_archive * pZip,mz_zip_array * pArray,size_t n)3370 static 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
mz_zip_array_push_back(mz_zip_archive * pZip,mz_zip_array * pArray,const void * pElements,size_t n)3375 static 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
mz_zip_dos_to_time_t(int dos_time,int dos_date)3386 static 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
mz_zip_time_t_to_dos_time(MZ_TIME_T time,mz_uint16 * pDOS_time,mz_uint16 * pDOS_date)3401 static 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
mz_zip_get_file_modified_time(const char * pFilename,MZ_TIME_T * pTime)3424 static 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
mz_zip_set_file_times(const char * pFilename,MZ_TIME_T access_time,MZ_TIME_T modified_time)3438 static 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
mz_zip_set_error(mz_zip_archive * pZip,mz_zip_error err_num)3451 static 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
mz_zip_reader_init_internal(mz_zip_archive * pZip,mz_uint flags)3458 static 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
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)3492 static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index)
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.) */
mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive * pZip)3522 static 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
mz_zip_reader_locate_header_sig(mz_zip_archive * pZip,mz_uint32 record_sig,mz_uint32 record_size,mz_int64 * pOfs)3578 static 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
mz_zip_reader_read_central_dir(mz_zip_archive * pZip,mz_uint flags)3626 static 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
mz_zip_zero_struct(mz_zip_archive * pZip)3886 void mz_zip_zero_struct(mz_zip_archive *pZip)
3887 {
3888 if (pZip)
3889 MZ_CLEAR_OBJ(*pZip);
3890 }
3891
mz_zip_reader_end_internal(mz_zip_archive * pZip,mz_bool set_last_error)3892 static 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
mz_zip_reader_end(mz_zip_archive * pZip)3939 mz_bool mz_zip_reader_end(mz_zip_archive *pZip)
3940 {
3941 return mz_zip_reader_end_internal(pZip, MZ_TRUE);
3942 }
mz_zip_reader_init(mz_zip_archive * pZip,mz_uint64 size,mz_uint flags)3943 mz_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
mz_zip_mem_read_func(void * pOpaque,mz_uint64 file_ofs,void * pBuf,size_t n)3963 static 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
mz_zip_reader_init_mem(mz_zip_archive * pZip,const void * pMem,size_t size,mz_uint flags)3971 mz_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
mz_zip_file_read_func(void * pOpaque,mz_uint64 file_ofs,void * pBuf,size_t n)4006 static 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
mz_zip_reader_init_file(mz_zip_archive * pZip,const char * pFilename,mz_uint32 flags)4019 mz_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
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)4024 mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size)
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
mz_zip_reader_init_cfile(mz_zip_archive * pZip,MZ_FILE * pFile,mz_uint64 archive_size,mz_uint flags)4078 mz_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
mz_zip_get_cdh(mz_zip_archive * pZip,mz_uint file_index)4120 static 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
mz_zip_reader_is_file_encrypted(mz_zip_archive * pZip,mz_uint file_index)4127 mz_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
mz_zip_reader_is_file_supported(mz_zip_archive * pZip,mz_uint file_index)4142 mz_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
mz_zip_reader_is_file_a_directory(mz_zip_archive * pZip,mz_uint file_index)4180 mz_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
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)4213 static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data)
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
mz_zip_string_equal(const char * pA,const char * pB,mz_uint len,mz_uint flags)4338 static 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
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)4350 static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len)
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
mz_zip_locate_file_binary_search(mz_zip_archive * pZip,const char * pFilename,mz_uint32 * pIndex)4368 static 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
mz_zip_reader_locate_file(mz_zip_archive * pZip,const char * pName,const char * pComment,mz_uint flags)4408 int 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
mz_zip_reader_locate_file_v2(mz_zip_archive * pZip,const char * pName,const char * pComment,mz_uint flags,mz_uint32 * pIndex)4418 mz_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
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)4486 mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)
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
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)4632 mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)
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
mz_zip_reader_extract_to_mem(mz_zip_archive * pZip,mz_uint file_index,void * pBuf,size_t buf_size,mz_uint flags)4641 mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags)
4642 {
4643 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0);
4644 }
4645
mz_zip_reader_extract_file_to_mem(mz_zip_archive * pZip,const char * pFilename,void * pBuf,size_t buf_size,mz_uint flags)4646 mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags)
4647 {
4648 return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0);
4649 }
4650
mz_zip_reader_extract_to_heap(mz_zip_archive * pZip,mz_uint file_index,size_t * pSize,mz_uint flags)4651 void *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
mz_zip_reader_extract_file_to_heap(mz_zip_archive * pZip,const char * pFilename,size_t * pSize,mz_uint flags)4695 void *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
mz_zip_reader_extract_to_callback(mz_zip_archive * pZip,mz_uint file_index,mz_file_write_func pCallback,void * pOpaque,mz_uint flags)4708 mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)
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
mz_zip_reader_extract_file_to_callback(mz_zip_archive * pZip,const char * pFilename,mz_file_write_func pCallback,void * pOpaque,mz_uint flags)4912 mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)
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
mz_zip_reader_extract_iter_new(mz_zip_archive * pZip,mz_uint file_index,mz_uint flags)4922 mz_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
mz_zip_reader_extract_file_iter_new(mz_zip_archive * pZip,const char * pFilename,mz_uint flags)5051 mz_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
mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state * pState,void * pvBuf,size_t buf_size)5064 size_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
mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state * pState)5182 mz_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
mz_zip_file_write_callback(void * pOpaque,mz_uint64 ofs,const void * pBuf,size_t n)5225 static 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
mz_zip_reader_extract_to_file(mz_zip_archive * pZip,mz_uint file_index,const char * pDst_filename,mz_uint flags)5232 mz_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
mz_zip_reader_extract_file_to_file(mz_zip_archive * pZip,const char * pArchive_filename,const char * pDst_filename,mz_uint flags)5266 mz_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
mz_zip_reader_extract_to_cfile(mz_zip_archive * pZip,mz_uint file_index,MZ_FILE * pFile,mz_uint flags)5275 mz_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
mz_zip_reader_extract_file_to_cfile(mz_zip_archive * pZip,const char * pArchive_filename,MZ_FILE * pFile,mz_uint flags)5288 mz_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
mz_zip_compute_crc32_callback(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)5298 static 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
mz_zip_validate_file(mz_zip_archive * pZip,mz_uint file_index,mz_uint flags)5306 mz_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
5519 handle_failure:
5520 mz_zip_array_clear(pZip, &file_data_array);
5521 return MZ_FALSE;
5522 }
5523
mz_zip_validate_archive(mz_zip_archive * pZip,mz_uint flags)5524 mz_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
mz_zip_validate_mem_archive(const void * pMem,size_t size,mz_uint flags,mz_zip_error * pErr)5580 mz_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
mz_zip_validate_file_archive(const char * pFilename,mz_uint flags,mz_zip_error * pErr)5622 mz_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
mz_write_le16(mz_uint8 * p,mz_uint16 v)5668 static 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 }
mz_write_le32(mz_uint8 * p,mz_uint32 v)5673 static 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 }
mz_write_le64(mz_uint8 * p,mz_uint64 v)5680 static 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
mz_zip_heap_write_func(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)5690 static 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
mz_zip_writer_end_internal(mz_zip_archive * pZip,mz_bool set_last_error)5729 static 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
mz_zip_writer_init_v2(mz_zip_archive * pZip,mz_uint64 existing_size,mz_uint flags)5776 mz_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
mz_zip_writer_init(mz_zip_archive * pZip,mz_uint64 existing_size)5825 mz_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
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)5830 mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags)
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
mz_zip_writer_init_heap(mz_zip_archive * pZip,size_t size_to_reserve_at_beginning,size_t initial_allocation_size)5858 mz_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
mz_zip_file_write_func(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)5864 static 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
mz_zip_writer_init_file(mz_zip_archive * pZip,const char * pFilename,mz_uint64 size_to_reserve_at_beginning)5880 mz_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
mz_zip_writer_init_file_v2(mz_zip_archive * pZip,const char * pFilename,mz_uint64 size_to_reserve_at_beginning,mz_uint flags)5885 mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags)
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
mz_zip_writer_init_cfile(mz_zip_archive * pZip,MZ_FILE * pFile,mz_uint flags)5932 mz_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
mz_zip_writer_init_from_reader_v2(mz_zip_archive * pZip,const char * pFilename,mz_uint flags)5953 mz_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
mz_zip_writer_init_from_reader(mz_zip_archive * pZip,const char * pFilename)6041 mz_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! */
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)6047 mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags)
6048 {
6049 return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0);
6050 }
6051
6052 typedef 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
mz_zip_writer_add_put_buf_callback(const void * pBuf,int len,void * pUser)6059 static 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)
mz_zip_writer_create_zip64_extra_data(mz_uint8 * pBuf,mz_uint64 * pUncomp_size,mz_uint64 * pComp_size,mz_uint64 * pLocal_header_ofs)6072 static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs)
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
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)6107 static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date)
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
mz_zip_writer_create_central_dir_header(mz_zip_archive * pZip,mz_uint8 * pDst,mz_uint16 filename_size,mz_uint16 extra_size,mz_uint16 comment_size,mz_uint64 uncomp_size,mz_uint64 comp_size,mz_uint32 uncomp_crc32,mz_uint16 method,mz_uint16 bit_flags,mz_uint16 dos_time,mz_uint16 dos_date,mz_uint64 local_header_ofs,mz_uint32 ext_attributes)6125 static 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
mz_zip_writer_add_to_central_dir(mz_zip_archive * pZip,const char * pFilename,mz_uint16 filename_size,const void * pExtra,mz_uint16 extra_size,const void * pComment,mz_uint16 comment_size,mz_uint64 uncomp_size,mz_uint64 comp_size,mz_uint32 uncomp_crc32,mz_uint16 method,mz_uint16 bit_flags,mz_uint16 dos_time,mz_uint16 dos_date,mz_uint64 local_header_ofs,mz_uint32 ext_attributes,const char * user_extra_data,mz_uint user_extra_data_len)6150 static 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, ¢ral_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
mz_zip_writer_validate_archive_name(const char * pArchive_name)6190 static 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
mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive * pZip)6201 static 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
mz_zip_writer_write_zeros(mz_zip_archive * pZip,mz_uint64 cur_file_ofs,mz_uint32 n)6211 static 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
mz_zip_writer_add_mem_ex(mz_zip_archive * pZip,const char * pArchive_name,const void * pBuf,size_t buf_size,const void * pComment,mz_uint16 comment_size,mz_uint level_and_flags,mz_uint64 uncomp_size,mz_uint32 uncomp_crc32)6227 mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
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
mz_zip_writer_add_mem_ex_v2(mz_zip_archive * pZip,const char * pArchive_name,const void * pBuf,size_t buf_size,const void * pComment,mz_uint16 comment_size,mz_uint level_and_flags,mz_uint64 uncomp_size,mz_uint32 uncomp_crc32,MZ_TIME_T * last_modified,const char * user_extra_data,mz_uint user_extra_data_len,const char * user_extra_data_central,mz_uint user_extra_data_central_len)6233 mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size,
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 mz_bool write_metadata_only = buf_size && !pBuf;
6254
6255 if ((int)level_and_flags < 0)
6256 level_and_flags = MZ_DEFAULT_LEVEL;
6257
6258 if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
6259 bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;
6260
6261 if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))
6262 bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;
6263
6264 level = level_and_flags & 0xF;
6265 store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
6266
6267 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
6268 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6269
6270 pState = pZip->m_pState;
6271
6272 if (pState->m_zip64)
6273 {
6274 if (pZip->m_total_files == MZ_UINT32_MAX)
6275 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
6276 }
6277 else
6278 {
6279 if (pZip->m_total_files == MZ_UINT16_MAX)
6280 {
6281 pState->m_zip64 = MZ_TRUE;
6282 /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */
6283 }
6284 if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF))
6285 {
6286 pState->m_zip64 = MZ_TRUE;
6287 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
6288 }
6289 }
6290
6291 if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
6292 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6293
6294 if (!mz_zip_writer_validate_archive_name(pArchive_name))
6295 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
6296
6297 #ifndef MINIZ_NO_TIME
6298 if (last_modified != NULL)
6299 {
6300 mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date);
6301 }
6302 else
6303 {
6304 MZ_TIME_T cur_time;
6305 time(&cur_time);
6306 mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date);
6307 }
6308 #endif /* #ifndef MINIZ_NO_TIME */
6309
6310 if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
6311 {
6312 if (!write_metadata_only) {
6313 uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
6314 }
6315 uncomp_size = buf_size;
6316 if (uncomp_size <= 3)
6317 {
6318 level = 0;
6319 store_data_uncompressed = MZ_TRUE;
6320 }
6321 }
6322
6323 archive_name_size = strlen(pArchive_name);
6324 if (archive_name_size > MZ_UINT16_MAX)
6325 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
6326
6327 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6328
6329 /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
6330 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)
6331 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
6332
6333 if (!pState->m_zip64)
6334 {
6335 /* Bail early if the archive would obviously become too large */
6336 if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size
6337 + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len +
6338 pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len
6339 + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF)
6340 {
6341 pState->m_zip64 = MZ_TRUE;
6342 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
6343 }
6344 }
6345
6346 if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/'))
6347 {
6348 /* Set DOS Subdirectory attribute bit. */
6349 ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG;
6350
6351 /* Subdirectories cannot contain data. */
6352 if ((buf_size) || (uncomp_size))
6353 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6354 }
6355
6356 /* 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.) */
6357 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)))
6358 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6359
6360 if ((!store_data_uncompressed) && (buf_size))
6361 {
6362 if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
6363 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6364 }
6365
6366 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes))
6367 {
6368 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6369 return MZ_FALSE;
6370 }
6371
6372 local_dir_header_ofs += num_alignment_padding_bytes;
6373 if (pZip->m_file_offset_alignment)
6374 {
6375 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0);
6376 }
6377 cur_archive_file_ofs += num_alignment_padding_bytes;
6378
6379 MZ_CLEAR_OBJ(local_dir_header);
6380
6381 if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
6382 {
6383 method = MZ_DEFLATED;
6384 }
6385
6386 if (pState->m_zip64)
6387 {
6388 if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX)
6389 {
6390 pExtra_data = extra_data;
6391 extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
6392 (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
6393 }
6394
6395 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))
6396 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
6397
6398 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
6399 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6400
6401 cur_archive_file_ofs += sizeof(local_dir_header);
6402
6403 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
6404 {
6405 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6406 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6407 }
6408 cur_archive_file_ofs += archive_name_size;
6409
6410 if (pExtra_data != NULL)
6411 {
6412 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size)
6413 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6414
6415 cur_archive_file_ofs += extra_size;
6416 }
6417 }
6418 else
6419 {
6420 if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))
6421 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
6422 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))
6423 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
6424
6425 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
6426 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6427
6428 cur_archive_file_ofs += sizeof(local_dir_header);
6429
6430 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
6431 {
6432 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6433 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6434 }
6435 cur_archive_file_ofs += archive_name_size;
6436 }
6437
6438 if (user_extra_data_len > 0)
6439 {
6440 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
6441 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6442
6443 cur_archive_file_ofs += user_extra_data_len;
6444 }
6445
6446 if (store_data_uncompressed)
6447 {
6448 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size)
6449 {
6450 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6451 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6452 }
6453
6454 cur_archive_file_ofs += buf_size;
6455 comp_size = buf_size;
6456 }
6457 else if (buf_size)
6458 {
6459 mz_zip_writer_add_state state;
6460
6461 state.m_pZip = pZip;
6462 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
6463 state.m_comp_size = 0;
6464
6465 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) ||
6466 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE))
6467 {
6468 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6469 return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);
6470 }
6471
6472 comp_size = state.m_comp_size;
6473 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
6474 }
6475
6476 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6477 pComp = NULL;
6478
6479 if (uncomp_size)
6480 {
6481 mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];
6482 mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;
6483
6484 MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR);
6485
6486 MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);
6487 MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);
6488 if (pExtra_data == NULL)
6489 {
6490 if (comp_size > MZ_UINT32_MAX)
6491 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
6492
6493 MZ_WRITE_LE32(local_dir_footer + 8, comp_size);
6494 MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);
6495 }
6496 else
6497 {
6498 MZ_WRITE_LE64(local_dir_footer + 8, comp_size);
6499 MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);
6500 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;
6501 }
6502
6503 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size)
6504 return MZ_FALSE;
6505
6506 cur_archive_file_ofs += local_dir_footer_size;
6507 }
6508
6509 if (pExtra_data != NULL)
6510 {
6511 extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
6512 (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
6513 }
6514
6515 if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment,
6516 comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes,
6517 user_extra_data_central, user_extra_data_central_len))
6518 return MZ_FALSE;
6519
6520 pZip->m_total_files++;
6521 pZip->m_archive_size = cur_archive_file_ofs;
6522
6523 return MZ_TRUE;
6524 }
6525
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,const char * user_extra_data,mz_uint user_extra_data_len,const char * user_extra_data_central,mz_uint user_extra_data_central_len)6526 mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
6527 const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)
6528 {
6529 mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;
6530 mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
6531 mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
6532 mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0;
6533 size_t archive_name_size;
6534 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
6535 mz_uint8 *pExtra_data = NULL;
6536 mz_uint32 extra_size = 0;
6537 mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];
6538 mz_zip_internal_state *pState;
6539 mz_uint64 file_ofs = 0;
6540
6541 if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))
6542 gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;
6543
6544 if ((int)level_and_flags < 0)
6545 level_and_flags = MZ_DEFAULT_LEVEL;
6546 level = level_and_flags & 0xF;
6547
6548 /* Sanity checks */
6549 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
6550 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6551
6552 pState = pZip->m_pState;
6553
6554 if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX))
6555 {
6556 /* Source file is too large for non-zip64 */
6557 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
6558 pState->m_zip64 = MZ_TRUE;
6559 }
6560
6561 /* We could support this, but why? */
6562 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
6563 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6564
6565 if (!mz_zip_writer_validate_archive_name(pArchive_name))
6566 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
6567
6568 if (pState->m_zip64)
6569 {
6570 if (pZip->m_total_files == MZ_UINT32_MAX)
6571 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
6572 }
6573 else
6574 {
6575 if (pZip->m_total_files == MZ_UINT16_MAX)
6576 {
6577 pState->m_zip64 = MZ_TRUE;
6578 /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */
6579 }
6580 }
6581
6582 archive_name_size = strlen(pArchive_name);
6583 if (archive_name_size > MZ_UINT16_MAX)
6584 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
6585
6586 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6587
6588 /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
6589 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)
6590 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
6591
6592 if (!pState->m_zip64)
6593 {
6594 /* Bail early if the archive would obviously become too large */
6595 if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE
6596 + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024
6597 + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF)
6598 {
6599 pState->m_zip64 = MZ_TRUE;
6600 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
6601 }
6602 }
6603
6604 #ifndef MINIZ_NO_TIME
6605 if (pFile_time)
6606 {
6607 mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date);
6608 }
6609 #endif
6610
6611 if (uncomp_size <= 3)
6612 level = 0;
6613
6614 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes))
6615 {
6616 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6617 }
6618
6619 cur_archive_file_ofs += num_alignment_padding_bytes;
6620 local_dir_header_ofs = cur_archive_file_ofs;
6621
6622 if (pZip->m_file_offset_alignment)
6623 {
6624 MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0);
6625 }
6626
6627 if (uncomp_size && level)
6628 {
6629 method = MZ_DEFLATED;
6630 }
6631
6632 MZ_CLEAR_OBJ(local_dir_header);
6633 if (pState->m_zip64)
6634 {
6635 if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX)
6636 {
6637 pExtra_data = extra_data;
6638 extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
6639 (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
6640 }
6641
6642 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))
6643 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
6644
6645 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
6646 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6647
6648 cur_archive_file_ofs += sizeof(local_dir_header);
6649
6650 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
6651 {
6652 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6653 }
6654
6655 cur_archive_file_ofs += archive_name_size;
6656
6657 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size)
6658 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6659
6660 cur_archive_file_ofs += extra_size;
6661 }
6662 else
6663 {
6664 if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))
6665 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
6666 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))
6667 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
6668
6669 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
6670 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6671
6672 cur_archive_file_ofs += sizeof(local_dir_header);
6673
6674 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
6675 {
6676 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6677 }
6678
6679 cur_archive_file_ofs += archive_name_size;
6680 }
6681
6682 if (user_extra_data_len > 0)
6683 {
6684 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
6685 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
6686
6687 cur_archive_file_ofs += user_extra_data_len;
6688 }
6689
6690 if (uncomp_size)
6691 {
6692 mz_uint64 uncomp_remaining = uncomp_size;
6693 void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
6694 if (!pRead_buf)
6695 {
6696 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6697 }
6698
6699 if (!level)
6700 {
6701 while (uncomp_remaining)
6702 {
6703 mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
6704 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))
6705 {
6706 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6707 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
6708 }
6709 file_ofs += n;
6710 uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
6711 uncomp_remaining -= n;
6712 cur_archive_file_ofs += n;
6713 }
6714 comp_size = uncomp_size;
6715 }
6716 else
6717 {
6718 mz_bool result = MZ_FALSE;
6719 mz_zip_writer_add_state state;
6720 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
6721 if (!pComp)
6722 {
6723 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6724 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6725 }
6726
6727 state.m_pZip = pZip;
6728 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
6729 state.m_comp_size = 0;
6730
6731 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)
6732 {
6733 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6734 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6735 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
6736 }
6737
6738 for (;;)
6739 {
6740 size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
6741 tdefl_status status;
6742 tdefl_flush flush = TDEFL_NO_FLUSH;
6743
6744 if (read_callback(callback_opaque, file_ofs, pRead_buf, in_buf_size)!= in_buf_size)
6745 {
6746 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
6747 break;
6748 }
6749
6750 file_ofs += in_buf_size;
6751 uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
6752 uncomp_remaining -= in_buf_size;
6753
6754 if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque))
6755 flush = TDEFL_FULL_FLUSH;
6756
6757 status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH);
6758 if (status == TDEFL_STATUS_DONE)
6759 {
6760 result = MZ_TRUE;
6761 break;
6762 }
6763 else if (status != TDEFL_STATUS_OKAY)
6764 {
6765 mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);
6766 break;
6767 }
6768 }
6769
6770 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6771
6772 if (!result)
6773 {
6774 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6775 return MZ_FALSE;
6776 }
6777
6778 comp_size = state.m_comp_size;
6779 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
6780 }
6781
6782 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6783 }
6784
6785 {
6786 mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];
6787 mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;
6788
6789 MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);
6790 MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);
6791 if (pExtra_data == NULL)
6792 {
6793 if (comp_size > MZ_UINT32_MAX)
6794 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
6795
6796 MZ_WRITE_LE32(local_dir_footer + 8, comp_size);
6797 MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);
6798 }
6799 else
6800 {
6801 MZ_WRITE_LE64(local_dir_footer + 8, comp_size);
6802 MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);
6803 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;
6804 }
6805
6806 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size)
6807 return MZ_FALSE;
6808
6809 cur_archive_file_ofs += local_dir_footer_size;
6810 }
6811
6812 if (pExtra_data != NULL)
6813 {
6814 extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
6815 (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
6816 }
6817
6818 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,
6819 uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes,
6820 user_extra_data_central, user_extra_data_central_len))
6821 return MZ_FALSE;
6822
6823 pZip->m_total_files++;
6824 pZip->m_archive_size = cur_archive_file_ofs;
6825
6826 return MZ_TRUE;
6827 }
6828
6829 #ifndef MINIZ_NO_STDIO
6830
mz_file_read_func_stdio(void * pOpaque,mz_uint64 file_ofs,void * pBuf,size_t n)6831 static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
6832 {
6833 MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque;
6834 mz_int64 cur_ofs = MZ_FTELL64(pSrc_file);
6835
6836 if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET))))
6837 return 0;
6838
6839 return MZ_FREAD(pBuf, 1, n, pSrc_file);
6840 }
6841
mz_zip_writer_add_cfile(mz_zip_archive * pZip,const char * pArchive_name,MZ_FILE * pSrc_file,mz_uint64 size_to_add,const MZ_TIME_T * pFile_time,const void * pComment,mz_uint16 comment_size,mz_uint level_and_flags,const char * user_extra_data,mz_uint user_extra_data_len,const char * user_extra_data_central,mz_uint user_extra_data_central_len)6842 mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
6843 const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)
6844 {
6845 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,
6846 user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len);
6847 }
6848
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)6849 mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
6850 {
6851 MZ_FILE *pSrc_file = NULL;
6852 mz_uint64 uncomp_size = 0;
6853 MZ_TIME_T file_modified_time;
6854 MZ_TIME_T *pFile_time = NULL;
6855 mz_bool status;
6856
6857 memset(&file_modified_time, 0, sizeof(file_modified_time));
6858
6859 #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)
6860 pFile_time = &file_modified_time;
6861 if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time))
6862 return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED);
6863 #endif
6864
6865 pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
6866 if (!pSrc_file)
6867 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
6868
6869 MZ_FSEEK64(pSrc_file, 0, SEEK_END);
6870 uncomp_size = MZ_FTELL64(pSrc_file);
6871 MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
6872
6873 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);
6874
6875 MZ_FCLOSE(pSrc_file);
6876
6877 return status;
6878 }
6879 #endif /* #ifndef MINIZ_NO_STDIO */
6880
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)6881 static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start)
6882 {
6883 /* + 64 should be enough for any new zip64 data */
6884 if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE))
6885 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6886
6887 mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE);
6888
6889 if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start))
6890 {
6891 mz_uint8 new_ext_block[64];
6892 mz_uint8 *pDst = new_ext_block;
6893 mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);
6894 mz_write_le16(pDst + sizeof(mz_uint16), 0);
6895 pDst += sizeof(mz_uint16) * 2;
6896
6897 if (pUncomp_size)
6898 {
6899 mz_write_le64(pDst, *pUncomp_size);
6900 pDst += sizeof(mz_uint64);
6901 }
6902
6903 if (pComp_size)
6904 {
6905 mz_write_le64(pDst, *pComp_size);
6906 pDst += sizeof(mz_uint64);
6907 }
6908
6909 if (pLocal_header_ofs)
6910 {
6911 mz_write_le64(pDst, *pLocal_header_ofs);
6912 pDst += sizeof(mz_uint64);
6913 }
6914
6915 if (pDisk_start)
6916 {
6917 mz_write_le32(pDst, *pDisk_start);
6918 pDst += sizeof(mz_uint32);
6919 }
6920
6921 mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2));
6922
6923 if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block))
6924 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6925 }
6926
6927 if ((pExt) && (ext_len))
6928 {
6929 mz_uint32 extra_size_remaining = ext_len;
6930 const mz_uint8 *pExtra_data = pExt;
6931
6932 do
6933 {
6934 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
6935 mz_uint32 field_id, field_data_size, field_total_size;
6936
6937 if (extra_size_remaining < (sizeof(mz_uint16) * 2))
6938 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
6939
6940 field_id = MZ_READ_LE16(pExtra_data);
6941 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
6942 field_total_size = field_data_size + sizeof(mz_uint16) * 2;
6943
6944 if (field_total_size > extra_size_remaining)
6945 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
6946
6947 if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
6948 {
6949 if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size))
6950 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6951 }
6952
6953 pExtra_data += field_total_size;
6954 extra_size_remaining -= field_total_size;
6955 } while (extra_size_remaining);
6956 }
6957
6958 return MZ_TRUE;
6959 }
6960
6961 /* TODO: This func is now pretty freakin complex due to zip64, split it up? */
mz_zip_writer_add_from_zip_reader(mz_zip_archive * pZip,mz_zip_archive * pSource_zip,mz_uint src_file_index)6962 mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index)
6963 {
6964 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
6965 mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size;
6966 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
6967 mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs;
6968 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
6969 mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
6970 mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
6971 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
6972 mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
6973 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
6974 size_t orig_central_dir_size;
6975 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
6976 mz_zip_internal_state *pState;
6977 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
6978 void *pBuf;
6979 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
6980 const mz_uint8 *pSrc_central_header;
6981 mz_zip_archive_file_stat src_file_stat;
6982 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
6983 mz_uint32 src_filename_len, src_comment_len, src_ext_len;
6984 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
6985 mz_uint32 local_header_filename_size, local_header_extra_len;
6986 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
6987 mz_uint64 local_header_comp_size, local_header_uncomp_size;
6988 mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;
6989
6990 /* Sanity checks */
6991 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead))
6992 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6993
6994 pState = pZip->m_pState;
6995
6996 /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */
6997 if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64))
6998 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6999
7000 /* Get pointer to the source central dir header and crack it */
7001 if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index)))
7002 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7003
7004 if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)
7005 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7006
7007 src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS);
7008 src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
7009 src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS);
7010 src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len;
7011
7012 /* 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) */
7013 if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX)
7014 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
7015
7016 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
7017
7018 if (!pState->m_zip64)
7019 {
7020 if (pZip->m_total_files == MZ_UINT16_MAX)
7021 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
7022 }
7023 else
7024 {
7025 /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */
7026 if (pZip->m_total_files == MZ_UINT32_MAX)
7027 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
7028 }
7029
7030 if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL))
7031 return MZ_FALSE;
7032
7033 cur_src_file_ofs = src_file_stat.m_local_header_ofs;
7034 cur_dst_file_ofs = pZip->m_archive_size;
7035
7036 /* Read the source archive's local dir header */
7037 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)
7038 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7039
7040 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
7041 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7042
7043 cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
7044
7045 /* Compute the total size we need to copy (filename+extra data+compressed data) */
7046 local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);
7047 local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
7048 local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);
7049 local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);
7050 src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size;
7051
7052 /* Try to find a zip64 extended information field */
7053 if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX)))
7054 {
7055 mz_zip_array file_data_array;
7056 const mz_uint8 *pExtra_data;
7057 mz_uint32 extra_size_remaining = local_header_extra_len;
7058
7059 mz_zip_array_init(&file_data_array, 1);
7060 if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE))
7061 {
7062 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7063 }
7064
7065 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)
7066 {
7067 mz_zip_array_clear(pZip, &file_data_array);
7068 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7069 }
7070
7071 pExtra_data = (const mz_uint8 *)file_data_array.m_p;
7072
7073 do
7074 {
7075 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
7076 mz_uint32 field_id, field_data_size, field_total_size;
7077
7078 if (extra_size_remaining < (sizeof(mz_uint16) * 2))
7079 {
7080 mz_zip_array_clear(pZip, &file_data_array);
7081 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7082 }
7083
7084 field_id = MZ_READ_LE16(pExtra_data);
7085 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
7086 field_total_size = field_data_size + sizeof(mz_uint16) * 2;
7087
7088 if (field_total_size > extra_size_remaining)
7089 {
7090 mz_zip_array_clear(pZip, &file_data_array);
7091 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7092 }
7093
7094 if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
7095 {
7096 const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);
7097
7098 if (field_data_size < sizeof(mz_uint64) * 2)
7099 {
7100 mz_zip_array_clear(pZip, &file_data_array);
7101 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7102 }
7103
7104 // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
7105 local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);
7106 // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
7107 local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */
7108
7109 found_zip64_ext_data_in_ldir = MZ_TRUE;
7110 break;
7111 }
7112
7113 pExtra_data += field_total_size;
7114 extra_size_remaining -= field_total_size;
7115 } while (extra_size_remaining);
7116
7117 mz_zip_array_clear(pZip, &file_data_array);
7118 }
7119
7120 if (!pState->m_zip64)
7121 {
7122 /* 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). */
7123 /* We also check when the archive is finalized so this doesn't need to be perfect. */
7124 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) +
7125 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;
7126
7127 if (approx_new_archive_size >= MZ_UINT32_MAX)
7128 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
7129 }
7130
7131 /* Write dest archive padding */
7132 if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes))
7133 return MZ_FALSE;
7134
7135 cur_dst_file_ofs += num_alignment_padding_bytes;
7136
7137 local_dir_header_ofs = cur_dst_file_ofs;
7138 if (pZip->m_file_offset_alignment)
7139 {
7140 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0);
7141 }
7142
7143 /* 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 */
7144 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)
7145 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7146
7147 cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
7148
7149 /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */
7150 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)))))
7151 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7152
7153 while (src_archive_bytes_remaining)
7154 {
7155 n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining);
7156 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n)
7157 {
7158 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7159 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7160 }
7161 cur_src_file_ofs += n;
7162
7163 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
7164 {
7165 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7166 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7167 }
7168 cur_dst_file_ofs += n;
7169
7170 src_archive_bytes_remaining -= n;
7171 }
7172
7173 /* Now deal with the optional data descriptor */
7174 bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
7175 if (bit_flags & 8)
7176 {
7177 /* Copy data descriptor */
7178 if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir))
7179 {
7180 /* src is zip64, dest must be zip64 */
7181
7182 /* name uint32_t's */
7183 /* id 1 (optional in zip64?) */
7184 /* crc 1 */
7185 /* comp_size 2 */
7186 /* uncomp_size 2 */
7187 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6))
7188 {
7189 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7190 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7191 }
7192
7193 n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5);
7194 }
7195 else
7196 {
7197 /* src is NOT zip64 */
7198 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
7199 mz_bool has_id;
7200
7201 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4)
7202 {
7203 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7204 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7205 }
7206
7207 has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID);
7208
7209 if (pZip->m_pState->m_zip64)
7210 {
7211 /* dest is zip64, so upgrade the data descriptor */
7212 const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0));
7213 const mz_uint32 src_crc32 = pSrc_descriptor[0];
7214 const mz_uint64 src_comp_size = pSrc_descriptor[1];
7215 const mz_uint64 src_uncomp_size = pSrc_descriptor[2];
7216
7217 mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID);
7218 mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32);
7219 mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size);
7220 mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size);
7221
7222 n = sizeof(mz_uint32) * 6;
7223 }
7224 else
7225 {
7226 /* dest is NOT zip64, just copy it as-is */
7227 n = sizeof(mz_uint32) * (has_id ? 4 : 3);
7228 }
7229 }
7230
7231 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
7232 {
7233 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7234 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7235 }
7236
7237 // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
7238 cur_src_file_ofs += n;
7239 cur_dst_file_ofs += n;
7240 }
7241 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
7242
7243 /* Finally, add the new central dir header */
7244 orig_central_dir_size = pState->m_central_dir.m_size;
7245
7246 memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
7247
7248 if (pState->m_zip64)
7249 {
7250 /* 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. */
7251 const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len;
7252 mz_zip_array new_ext_block;
7253
7254 mz_zip_array_init(&new_ext_block, sizeof(mz_uint8));
7255
7256 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX);
7257 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX);
7258 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX);
7259
7260 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))
7261 {
7262 mz_zip_array_clear(pZip, &new_ext_block);
7263 return MZ_FALSE;
7264 }
7265
7266 MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size);
7267
7268 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
7269 {
7270 mz_zip_array_clear(pZip, &new_ext_block);
7271 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7272 }
7273
7274 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len))
7275 {
7276 mz_zip_array_clear(pZip, &new_ext_block);
7277 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
7278 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7279 }
7280
7281 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size))
7282 {
7283 mz_zip_array_clear(pZip, &new_ext_block);
7284 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
7285 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7286 }
7287
7288 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))
7289 {
7290 mz_zip_array_clear(pZip, &new_ext_block);
7291 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
7292 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7293 }
7294
7295 mz_zip_array_clear(pZip, &new_ext_block);
7296 }
7297 else
7298 {
7299 /* sanity checks */
7300 if (cur_dst_file_ofs > MZ_UINT32_MAX)
7301 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
7302
7303 if (local_dir_header_ofs >= MZ_UINT32_MAX)
7304 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
7305
7306 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs);
7307
7308 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
7309 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7310
7311 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))
7312 {
7313 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
7314 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7315 }
7316 }
7317
7318 /* This shouldn't trigger unless we screwed up during the initial sanity checks */
7319 if (pState->m_central_dir.m_size >= MZ_UINT32_MAX)
7320 {
7321 /* TODO: Support central dirs >= 32-bits in size */
7322 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
7323 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
7324 }
7325
7326 n = (mz_uint32)orig_central_dir_size;
7327 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1))
7328 {
7329 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
7330 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7331 }
7332
7333 pZip->m_total_files++;
7334 pZip->m_archive_size = cur_dst_file_ofs;
7335
7336 return MZ_TRUE;
7337 }
7338
mz_zip_writer_finalize_archive(mz_zip_archive * pZip)7339 mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip)
7340 {
7341 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
7342 mz_zip_internal_state *pState;
7343 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
7344 mz_uint64 central_dir_ofs, central_dir_size;
7345 mz_uint8 hdr[256];
7346
7347 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
7348 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7349
7350 pState = pZip->m_pState;
7351
7352 if (pState->m_zip64)
7353 {
7354 if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX))
7355 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
7356 }
7357 else
7358 {
7359 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))
7360 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
7361 }
7362
7363 central_dir_ofs = 0;
7364 central_dir_size = 0;
7365 if (pZip->m_total_files)
7366 {
7367 /* Write central directory */
7368 central_dir_ofs = pZip->m_archive_size;
7369 central_dir_size = pState->m_central_dir.m_size;
7370 pZip->m_central_directory_file_ofs = central_dir_ofs;
7371 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)
7372 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7373
7374 pZip->m_archive_size += central_dir_size;
7375 }
7376
7377 if (pState->m_zip64)
7378 {
7379 /* Write zip64 end of central directory header */
7380 mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size;
7381
7382 MZ_CLEAR_OBJ(hdr);
7383 MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG);
7384 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));
7385 MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */
7386 MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D);
7387 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files);
7388 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
7389 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size);
7390 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs);
7391 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)
7392 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7393
7394 pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE;
7395
7396 /* Write zip64 end of central directory locator */
7397 MZ_CLEAR_OBJ(hdr);
7398 MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG);
7399 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr);
7400 MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1);
7401 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)
7402 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7403
7404 pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE;
7405 }
7406
7407 /* Write end of central directory record */
7408 MZ_CLEAR_OBJ(hdr);
7409 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
7410 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));
7411 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));
7412 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size));
7413 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs));
7414
7415 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)
7416 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
7417
7418 #ifndef MINIZ_NO_STDIO
7419 if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))
7420 return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
7421 #endif /* #ifndef MINIZ_NO_STDIO */
7422
7423 pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE;
7424
7425 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
7426 return MZ_TRUE;
7427 }
7428
mz_zip_writer_finalize_heap_archive(mz_zip_archive * pZip,void ** ppBuf,size_t * pSize)7429 mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize)
7430 {
7431 if ((!ppBuf) || (!pSize))
7432 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7433
7434 *ppBuf = NULL;
7435 *pSize = 0;
7436
7437 if ((!pZip) || (!pZip->m_pState))
7438 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7439
7440 if (pZip->m_pWrite != mz_zip_heap_write_func)
7441 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7442
7443 if (!mz_zip_writer_finalize_archive(pZip))
7444 return MZ_FALSE;
7445
7446 *ppBuf = pZip->m_pState->m_pMem;
7447 *pSize = pZip->m_pState->m_mem_size;
7448 pZip->m_pState->m_pMem = NULL;
7449 pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
7450
7451 return MZ_TRUE;
7452 }
7453
mz_zip_writer_end(mz_zip_archive * pZip)7454 mz_bool mz_zip_writer_end(mz_zip_archive *pZip)
7455 {
7456 return mz_zip_writer_end_internal(pZip, MZ_TRUE);
7457 }
7458
7459 #ifndef MINIZ_NO_STDIO
mz_zip_add_mem_to_archive_file_in_place(const char * pZip_filename,const char * pArchive_name,const void * pBuf,size_t buf_size,const void * pComment,mz_uint16 comment_size,mz_uint level_and_flags)7460 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
7461 {
7462 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);
7463 }
7464
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)7465 mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr)
7466 {
7467 mz_bool status, created_new_archive = MZ_FALSE;
7468 mz_zip_archive zip_archive;
7469 struct MZ_FILE_STAT_STRUCT file_stat;
7470 mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
7471
7472 mz_zip_zero_struct(&zip_archive);
7473 if ((int)level_and_flags < 0)
7474 level_and_flags = MZ_DEFAULT_LEVEL;
7475
7476 if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
7477 {
7478 if (pErr)
7479 *pErr = MZ_ZIP_INVALID_PARAMETER;
7480 return MZ_FALSE;
7481 }
7482
7483 if (!mz_zip_writer_validate_archive_name(pArchive_name))
7484 {
7485 if (pErr)
7486 *pErr = MZ_ZIP_INVALID_FILENAME;
7487 return MZ_FALSE;
7488 }
7489
7490 /* 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. */
7491 /* So be sure to compile with _LARGEFILE64_SOURCE 1 */
7492 if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0)
7493 {
7494 /* Create a new archive. */
7495 if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags))
7496 {
7497 if (pErr)
7498 *pErr = zip_archive.m_last_error;
7499 return MZ_FALSE;
7500 }
7501
7502 created_new_archive = MZ_TRUE;
7503 }
7504 else
7505 {
7506 /* Append to an existing archive. */
7507 if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0))
7508 {
7509 if (pErr)
7510 *pErr = zip_archive.m_last_error;
7511 return MZ_FALSE;
7512 }
7513
7514 if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags))
7515 {
7516 if (pErr)
7517 *pErr = zip_archive.m_last_error;
7518
7519 mz_zip_reader_end_internal(&zip_archive, MZ_FALSE);
7520
7521 return MZ_FALSE;
7522 }
7523 }
7524
7525 status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0);
7526 actual_err = zip_archive.m_last_error;
7527
7528 /* 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.) */
7529 if (!mz_zip_writer_finalize_archive(&zip_archive))
7530 {
7531 if (!actual_err)
7532 actual_err = zip_archive.m_last_error;
7533
7534 status = MZ_FALSE;
7535 }
7536
7537 if (!mz_zip_writer_end_internal(&zip_archive, status))
7538 {
7539 if (!actual_err)
7540 actual_err = zip_archive.m_last_error;
7541
7542 status = MZ_FALSE;
7543 }
7544
7545 if ((!status) && (created_new_archive))
7546 {
7547 /* It's a new archive and something went wrong, so just delete it. */
7548 int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
7549 (void)ignoredStatus;
7550 }
7551
7552 if (pErr)
7553 *pErr = actual_err;
7554
7555 return status;
7556 }
7557
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)7558 void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr)
7559 {
7560 mz_uint32 file_index;
7561 mz_zip_archive zip_archive;
7562 void *p = NULL;
7563
7564 if (pSize)
7565 *pSize = 0;
7566
7567 if ((!pZip_filename) || (!pArchive_name))
7568 {
7569 if (pErr)
7570 *pErr = MZ_ZIP_INVALID_PARAMETER;
7571
7572 return NULL;
7573 }
7574
7575 mz_zip_zero_struct(&zip_archive);
7576 if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0))
7577 {
7578 if (pErr)
7579 *pErr = zip_archive.m_last_error;
7580
7581 return NULL;
7582 }
7583
7584 if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index))
7585 {
7586 p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
7587 }
7588
7589 mz_zip_reader_end_internal(&zip_archive, p != NULL);
7590
7591 if (pErr)
7592 *pErr = zip_archive.m_last_error;
7593
7594 return p;
7595 }
7596
mz_zip_extract_archive_file_to_heap(const char * pZip_filename,const char * pArchive_name,size_t * pSize,mz_uint flags)7597 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags)
7598 {
7599 return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL);
7600 }
7601
7602 #endif /* #ifndef MINIZ_NO_STDIO */
7603
7604 #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */
7605
7606 /* ------------------- Misc utils */
7607
mz_zip_get_mode(mz_zip_archive * pZip)7608 mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip)
7609 {
7610 return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID;
7611 }
7612
mz_zip_get_type(mz_zip_archive * pZip)7613 mz_zip_type mz_zip_get_type(mz_zip_archive *pZip)
7614 {
7615 return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID;
7616 }
7617
mz_zip_set_last_error(mz_zip_archive * pZip,mz_zip_error err_num)7618 mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num)
7619 {
7620 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
7621 mz_zip_error prev_err;
7622
7623 if (!pZip)
7624 return MZ_ZIP_INVALID_PARAMETER;
7625
7626 prev_err = pZip->m_last_error;
7627
7628 pZip->m_last_error = err_num;
7629 return prev_err;
7630 }
7631
mz_zip_peek_last_error(mz_zip_archive * pZip)7632 mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip)
7633 {
7634 if (!pZip)
7635 return MZ_ZIP_INVALID_PARAMETER;
7636
7637 return pZip->m_last_error;
7638 }
7639
mz_zip_clear_last_error(mz_zip_archive * pZip)7640 mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip)
7641 {
7642 return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR);
7643 }
7644
mz_zip_get_last_error(mz_zip_archive * pZip)7645 mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip)
7646 {
7647 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
7648 mz_zip_error prev_err;
7649
7650 if (!pZip)
7651 return MZ_ZIP_INVALID_PARAMETER;
7652
7653 prev_err = pZip->m_last_error;
7654
7655 pZip->m_last_error = MZ_ZIP_NO_ERROR;
7656 return prev_err;
7657 }
7658
mz_zip_get_error_string(mz_zip_error mz_err)7659 const char *mz_zip_get_error_string(mz_zip_error mz_err)
7660 {
7661 switch (mz_err)
7662 {
7663 case MZ_ZIP_NO_ERROR:
7664 return "no error";
7665 case MZ_ZIP_UNDEFINED_ERROR:
7666 return "undefined error";
7667 case MZ_ZIP_TOO_MANY_FILES:
7668 return "too many files";
7669 case MZ_ZIP_FILE_TOO_LARGE:
7670 return "file too large";
7671 case MZ_ZIP_UNSUPPORTED_METHOD:
7672 return "unsupported method";
7673 case MZ_ZIP_UNSUPPORTED_ENCRYPTION:
7674 return "unsupported encryption";
7675 case MZ_ZIP_UNSUPPORTED_FEATURE:
7676 return "unsupported feature";
7677 case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:
7678 return "failed finding central directory";
7679 case MZ_ZIP_NOT_AN_ARCHIVE:
7680 return "not a ZIP archive";
7681 case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:
7682 return "invalid header or archive is corrupted";
7683 case MZ_ZIP_UNSUPPORTED_MULTIDISK:
7684 return "unsupported multidisk archive";
7685 case MZ_ZIP_DECOMPRESSION_FAILED:
7686 return "decompression failed or archive is corrupted";
7687 case MZ_ZIP_COMPRESSION_FAILED:
7688 return "compression failed";
7689 case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:
7690 return "unexpected decompressed size";
7691 case MZ_ZIP_CRC_CHECK_FAILED:
7692 return "CRC-32 check failed";
7693 case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:
7694 return "unsupported central directory size";
7695 case MZ_ZIP_ALLOC_FAILED:
7696 return "allocation failed";
7697 case MZ_ZIP_FILE_OPEN_FAILED:
7698 return "file open failed";
7699 case MZ_ZIP_FILE_CREATE_FAILED:
7700 return "file create failed";
7701 case MZ_ZIP_FILE_WRITE_FAILED:
7702 return "file write failed";
7703 case MZ_ZIP_FILE_READ_FAILED:
7704 return "file read failed";
7705 case MZ_ZIP_FILE_CLOSE_FAILED:
7706 return "file close failed";
7707 case MZ_ZIP_FILE_SEEK_FAILED:
7708 return "file seek failed";
7709 case MZ_ZIP_FILE_STAT_FAILED:
7710 return "file stat failed";
7711 case MZ_ZIP_INVALID_PARAMETER:
7712 return "invalid parameter";
7713 case MZ_ZIP_INVALID_FILENAME:
7714 return "invalid filename";
7715 case MZ_ZIP_BUF_TOO_SMALL:
7716 return "buffer too small";
7717 case MZ_ZIP_INTERNAL_ERROR:
7718 return "internal error";
7719 case MZ_ZIP_FILE_NOT_FOUND:
7720 return "file not found";
7721 case MZ_ZIP_ARCHIVE_TOO_LARGE:
7722 return "archive is too large";
7723 case MZ_ZIP_VALIDATION_FAILED:
7724 return "validation failed";
7725 case MZ_ZIP_WRITE_CALLBACK_FAILED:
7726 return "write calledback failed";
7727 default:
7728 break;
7729 }
7730
7731 return "unknown error";
7732 }
7733
7734 /* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */
mz_zip_is_zip64(mz_zip_archive * pZip)7735 mz_bool mz_zip_is_zip64(mz_zip_archive *pZip)
7736 {
7737 if ((!pZip) || (!pZip->m_pState))
7738 return MZ_FALSE;
7739
7740 return pZip->m_pState->m_zip64;
7741 }
7742
mz_zip_get_central_dir_size(mz_zip_archive * pZip)7743 size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip)
7744 {
7745 if ((!pZip) || (!pZip->m_pState))
7746 return 0;
7747
7748 return pZip->m_pState->m_central_dir.m_size;
7749 }
7750
mz_zip_reader_get_num_files(mz_zip_archive * pZip)7751 mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip)
7752 {
7753 return pZip ? pZip->m_total_files : 0;
7754 }
7755
mz_zip_get_archive_size(mz_zip_archive * pZip)7756 mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip)
7757 {
7758 if (!pZip)
7759 return 0;
7760 return pZip->m_archive_size;
7761 }
7762
mz_zip_get_archive_file_start_offset(mz_zip_archive * pZip)7763 mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip)
7764 {
7765 if ((!pZip) || (!pZip->m_pState))
7766 return 0;
7767 return pZip->m_pState->m_file_archive_start_ofs;
7768 }
7769
mz_zip_get_cfile(mz_zip_archive * pZip)7770 MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip)
7771 {
7772 if ((!pZip) || (!pZip->m_pState))
7773 return 0;
7774 return pZip->m_pState->m_pFile;
7775 }
7776
mz_zip_read_archive_data(mz_zip_archive * pZip,mz_uint64 file_ofs,void * pBuf,size_t n)7777 size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n)
7778 {
7779 if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead))
7780 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7781
7782 return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n);
7783 }
7784
mz_zip_reader_get_filename(mz_zip_archive * pZip,mz_uint file_index,char * pFilename,mz_uint filename_buf_size)7785 mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size)
7786 {
7787 // NOLINTNEXTLINE(cppcoreguidelines-init-variables)
7788 mz_uint n;
7789 const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
7790 if (!p)
7791 {
7792 if (filename_buf_size)
7793 pFilename[0] = '\0';
7794 mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7795 return 0;
7796 }
7797 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
7798 if (filename_buf_size)
7799 {
7800 n = MZ_MIN(n, filename_buf_size - 1);
7801 memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
7802 pFilename[n] = '\0';
7803 }
7804 return n + 1;
7805 }
7806
mz_zip_reader_file_stat(mz_zip_archive * pZip,mz_uint file_index,mz_zip_archive_file_stat * pStat)7807 mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat)
7808 {
7809 return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL);
7810 }
7811
mz_zip_end(mz_zip_archive * pZip)7812 mz_bool mz_zip_end(mz_zip_archive *pZip)
7813 {
7814 if (!pZip)
7815 return MZ_FALSE;
7816
7817 if (pZip->m_zip_mode == MZ_ZIP_MODE_READING)
7818 return mz_zip_reader_end(pZip);
7819 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
7820 else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))
7821 return mz_zip_writer_end(pZip);
7822 #endif
7823
7824 return MZ_FALSE;
7825 }
7826
7827 #ifdef __cplusplus
7828 }
7829 #endif
7830
7831 #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/
7832