xref: /aosp_15_r20/external/pytorch/third_party/miniz-2.1.0/miniz.c (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
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, &central_dir_ofs, 1)))
6181     {
6182         /* Try to resize the central directory array back into its original state. */
6183         mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
6184         return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6185     }
6186 
6187     return MZ_TRUE;
6188 }
6189 
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