1 /* miniz.c v1.14 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing
2 See "unlicense" statement at the end of this file.
3 Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2012
4 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
5 
6 Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define
7 MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros).
8 
9 * Change History
10 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include <time.h> (thanks fermtect).
11 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit.
12 Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files.
13 Eliminated a bunch of warnings when compiling with GCC 32-bit/64.
14 Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly
15 "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning).
16 Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64.
17 Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test.
18 Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives.
19 Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.)
20 Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself).
21 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's.
22 level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson <bruced@valvesoftware.com> for the feedback/bug report.
23 5/28/11 v1.11 - Added statement from unlicense.org
24 5/27/11 v1.10 - Substantial compressor optimizations:
25 Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a
26 Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86).
27 Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types.
28 Refactored the compression code for better readability and maintainability.
29 Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large
30 drop in throughput on some files).
31 5/15/11 v1.09 - Initial stable release.
32 
33 * Low-level Deflate/Inflate implementation notes:
34 
35 Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or
36 greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses
37 approximately as well as zlib.
38 
39 Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function
40 coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory
41 block large enough to hold the entire file.
42 
43 The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation.
44 
45 * zlib-style API notes:
46 
47 miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in
48 zlib replacement in many apps:
49 The z_stream struct, optional memory allocation callbacks
50 deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
51 inflateInit/inflateInit2/inflate/inflateEnd
52 compress, compress2, compressBound, uncompress
53 CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines.
54 Supports raw deflate streams or standard zlib streams with adler-32 checking.
55 
56 Limitations:
57 The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries.
58 I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but
59 there are no guarantees that miniz.c pulls this off perfectly.
60 
61 * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by
62 Alex Evans. Supports 1-4 bytes/pixel images.
63 
64 * ZIP archive API notes:
65 
66 The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to
67 get the job done with minimal fuss. There are simple API's to retrieve file information, read files from
68 existing archives, create new archives, append new files to existing archives, or clone archive data from
69 one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h),
70 or you can specify custom file read/write callbacks.
71 
72 - Archive reading: Just call this function to read a single file from a disk archive:
73 
74 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name,
75 size_t *pSize, mz_uint zip_flags);
76 
77 For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central
78 directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files.
79 
80 - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file:
81 
82 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
83 
84 The locate operation can optionally check file comments too, which (as one example) can be used to identify
85 multiple versions of the same file in an archive. This function uses a simple linear search through the central
86 directory, so it's not very fast.
87 
88 Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and
89 retrieve detailed info on each file by calling mz_zip_reader_file_stat().
90 
91 - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data
92 to disk and builds an exact image of the central directory in memory. The central directory image is written
93 all at once at the end of the archive file when the archive is finalized.
94 
95 The archive writer can optionally align each file's local header and file data to any power of 2 alignment,
96 which can be useful when the archive will be read from optical media. Also, the writer supports placing
97 arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still
98 readable by any ZIP tool.
99 
100 - Archive appending: The simple way to add a single file to an archive is to call this function:
101 
102 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name,
103 const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
104 
105 The archive will be created if it doesn't already exist, otherwise it'll be appended to.
106 Note the appending is done in-place and is not an atomic operation, so if something goes wrong
107 during the operation it's possible the archive could be left without a central directory (although the local
108 file headers and file data will be fine, so the archive will be recoverable).
109 
110 For more complex archive modification scenarios:
111 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to
112 preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the
113 compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and
114 you're done. This is safe but requires a bunch of temporary disk space or heap memory.
115 
116 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(),
117 append new files as needed, then finalize the archive which will write an updated central directory to the
118 original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a
119 possibility that the archive's central directory could be lost with this method if anything goes wrong, though.
120 
121 - ZIP archive support limitations:
122 No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files.
123 Requires streams capable of seeking.
124 
125 * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the
126 below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it.
127 
128 * Important: For best perf. be sure to customize the below macros for your target platform:
129 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
130 #define MINIZ_LITTLE_ENDIAN 1
131 #define MINIZ_HAS_64BIT_REGISTERS 1
132 */
133 #include "Miniz.h"
134 
135 // ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
136 #ifndef MINIZ_HEADER_FILE_ONLY
137 
138 typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];
139 typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];
140 typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
141 
142 #include <string.h>
143 #include <assert.h>
144 
145 #define MZ_ASSERT(x) assert(x)
146 
147 #ifdef MINIZ_NO_MALLOC
148 #define MZ_MALLOC(x) NULL
149 #define MZ_FREE(x) (void)x, ((void)0)
150 #define MZ_REALLOC(p, x) NULL
151 #else
152 #define MZ_MALLOC(x) malloc(x)
153 #define MZ_FREE(x) free(x)
154 #define MZ_REALLOC(p, x) realloc(p, x)
155 #endif
156 
157 #define MZ_MAX(a,b) (((a)>(b))?(a):(b))
158 #define MZ_MIN(a,b) (((a)<(b))?(a):(b))
159 #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
160 
161 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
162 #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
163 #define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
164 #else
165 #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
166 #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
167 #endif
168 
169 #ifdef _MSC_VER
170 #define MZ_FORCEINLINE __forceinline
171 #elif defined(__GNUC__)
172 #define MZ_FORCEINLINE inline __attribute__((__always_inline__))
173 #else
174 #define MZ_FORCEINLINE
175 #endif
176 
177 #ifdef __cplusplus
178 extern "C" {
179 #endif
180 
181     // ------------------- zlib-style API's
182 
mz_adler32(mz_ulong adler,const unsigned char * ptr,size_t buf_len)183     mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len)
184     {
185         mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552;
186         if (!ptr) return MZ_ADLER32_INIT;
187         while (buf_len) {
188             for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
189                 s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
190                 s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
191             }
192             for (; i < block_len; ++i) s1 += *ptr++, s2 += s1;
193             s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
194         }
195         return (s2 << 16) + s1;
196     }
197 
198     // 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/
mz_crc32(mz_ulong crc,const mz_uint8 * ptr,size_t buf_len)199     mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
200     {
201         static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
202             0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
203         mz_uint32 crcu32 = (mz_uint32)crc;
204         if (!ptr) return MZ_CRC32_INIT;
205         crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; }
206         return ~crcu32;
207     }
208 
mz_free(void * p)209     void mz_free(void *p)
210     {
211         MZ_FREE(p);
212     }
213 
214 #ifndef MINIZ_NO_ZLIB_APIS
215 
def_alloc_func(void * opaque,size_t items,size_t size)216     static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); }
def_free_func(void * opaque,void * address)217     static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); }
def_realloc_func(void * opaque,void * address,size_t items,size_t size)218     static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); }
219 
mz_version(void)220     const char *mz_version(void)
221     {
222         return MZ_VERSION;
223     }
224 
mz_deflateInit(mz_streamp pStream,int level)225     int mz_deflateInit(mz_streamp pStream, int level)
226     {
227         return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY);
228     }
229 
mz_deflateInit2(mz_streamp pStream,int level,int method,int window_bits,int mem_level,int strategy)230     int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy)
231     {
232         tdefl_compressor *pComp;
233         mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
234 
235         if (!pStream) return MZ_STREAM_ERROR;
236         if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR;
237 
238         pStream->data_type = 0;
239         pStream->adler = MZ_ADLER32_INIT;
240         pStream->msg = NULL;
241         pStream->reserved = 0;
242         pStream->total_in = 0;
243         pStream->total_out = 0;
244         if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
245         if (!pStream->zfree) pStream->zfree = def_free_func;
246 
247         pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor));
248         if (!pComp)
249             return MZ_MEM_ERROR;
250 
251         pStream->state = (struct mz_internal_state *)pComp;
252 
253         if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY)
254         {
255             mz_deflateEnd(pStream);
256             return MZ_PARAM_ERROR;
257         }
258 
259         return MZ_OK;
260     }
261 
mz_deflateReset(mz_streamp pStream)262     int mz_deflateReset(mz_streamp pStream)
263     {
264         if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR;
265         pStream->total_in = pStream->total_out = 0;
266         tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags);
267         return MZ_OK;
268     }
269 
mz_deflate(mz_streamp pStream,int flush)270     int mz_deflate(mz_streamp pStream, int flush)
271     {
272         size_t in_bytes, out_bytes;
273         mz_ulong orig_total_in, orig_total_out;
274         int mz_status = MZ_OK;
275 
276         if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR;
277         if (!pStream->avail_out) return MZ_BUF_ERROR;
278 
279         if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
280 
281         if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE)
282             return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
283 
284         orig_total_in = pStream->total_in; orig_total_out = pStream->total_out;
285         for (;;)
286         {
287             tdefl_status defl_status;
288             in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
289 
290             defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush);
291             pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
292             pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state);
293 
294             pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes;
295             pStream->total_out += (mz_uint)out_bytes;
296 
297             if (defl_status < 0)
298             {
299                 mz_status = MZ_STREAM_ERROR;
300                 break;
301             }
302             else if (defl_status == TDEFL_STATUS_DONE)
303             {
304                 mz_status = MZ_STREAM_END;
305                 break;
306             }
307             else if (!pStream->avail_out)
308                 break;
309             else if ((!pStream->avail_in) && (flush != MZ_FINISH))
310             {
311                 if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out))
312                     break;
313                 return MZ_BUF_ERROR; // Can't make forward progress without some input.
314             }
315         }
316         return mz_status;
317     }
318 
mz_deflateEnd(mz_streamp pStream)319     int mz_deflateEnd(mz_streamp pStream)
320     {
321         if (!pStream) return MZ_STREAM_ERROR;
322         if (pStream->state)
323         {
324             pStream->zfree(pStream->opaque, pStream->state);
325             pStream->state = NULL;
326         }
327         return MZ_OK;
328     }
329 
mz_deflateBound(mz_streamp pStream,mz_ulong source_len)330     mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len)
331     {
332         (void)pStream;
333         // 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.)
334         return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
335     }
336 
mz_compress2(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len,int level)337     int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level)
338     {
339         int status;
340         mz_stream stream;
341         memset(&stream, 0, sizeof(stream));
342 
343         // In case mz_ulong is 64-bits (argh I hate longs).
344         if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
345 
346         stream.next_in = pSource;
347         stream.avail_in = (mz_uint32)source_len;
348         stream.next_out = pDest;
349         stream.avail_out = (mz_uint32)*pDest_len;
350 
351         status = mz_deflateInit(&stream, level);
352         if (status != MZ_OK) return status;
353 
354         status = mz_deflate(&stream, MZ_FINISH);
355         if (status != MZ_STREAM_END)
356         {
357             mz_deflateEnd(&stream);
358             return (status == MZ_OK) ? MZ_BUF_ERROR : status;
359         }
360 
361         *pDest_len = stream.total_out;
362         return mz_deflateEnd(&stream);
363     }
364 
mz_compress(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len)365     int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
366     {
367         return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION);
368     }
369 
mz_compressBound(mz_ulong source_len)370     mz_ulong mz_compressBound(mz_ulong source_len)
371     {
372         return mz_deflateBound(NULL, source_len);
373     }
374 
375     typedef struct
376     {
377         tinfl_decompressor m_decomp;
378         mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits;
379         mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
380         tinfl_status m_last_status;
381     } inflate_state;
382 
mz_inflateInit2(mz_streamp pStream,int window_bits)383     int mz_inflateInit2(mz_streamp pStream, int window_bits)
384     {
385         inflate_state *pDecomp;
386         if (!pStream) return MZ_STREAM_ERROR;
387         if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR;
388 
389         pStream->data_type = 0;
390         pStream->adler = 0;
391         pStream->msg = NULL;
392         pStream->total_in = 0;
393         pStream->total_out = 0;
394         pStream->reserved = 0;
395         if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
396         if (!pStream->zfree) pStream->zfree = def_free_func;
397 
398         pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));
399         if (!pDecomp) return MZ_MEM_ERROR;
400 
401         pStream->state = (struct mz_internal_state *)pDecomp;
402 
403         tinfl_init(&pDecomp->m_decomp);
404         pDecomp->m_dict_ofs = 0;
405         pDecomp->m_dict_avail = 0;
406         pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
407         pDecomp->m_first_call = 1;
408         pDecomp->m_has_flushed = 0;
409         pDecomp->m_window_bits = window_bits;
410 
411         return MZ_OK;
412     }
413 
mz_inflateInit(mz_streamp pStream)414     int mz_inflateInit(mz_streamp pStream)
415     {
416         return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
417     }
418 
mz_inflate(mz_streamp pStream,int flush)419     int mz_inflate(mz_streamp pStream, int flush)
420     {
421         inflate_state* pState;
422         mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
423         size_t in_bytes, out_bytes, orig_avail_in;
424         tinfl_status status;
425 
426         if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
427         if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
428         if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
429 
430         pState = (inflate_state*)pStream->state;
431         if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
432         orig_avail_in = pStream->avail_in;
433 
434         first_call = pState->m_first_call; pState->m_first_call = 0;
435         if (pState->m_last_status < 0) return MZ_DATA_ERROR;
436 
437         if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
438         pState->m_has_flushed |= (flush == MZ_FINISH);
439 
440         if ((flush == MZ_FINISH) && (first_call))
441         {
442             // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file.
443             decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
444             in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
445             status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);
446             pState->m_last_status = status;
447             pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes;
448             pStream->adler = tinfl_get_adler32(&pState->m_decomp);
449             pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes;
450 
451             if (status < 0)
452                 return MZ_DATA_ERROR;
453             else if (status != TINFL_STATUS_DONE)
454             {
455                 pState->m_last_status = TINFL_STATUS_FAILED;
456                 return MZ_BUF_ERROR;
457             }
458             return MZ_STREAM_END;
459         }
460         // flush != MZ_FINISH then we must assume there's more input.
461         if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
462 
463         if (pState->m_dict_avail)
464         {
465             n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
466             memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
467             pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
468             pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
469             return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
470         }
471 
472         for (;;)
473         {
474             in_bytes = pStream->avail_in;
475             out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
476 
477             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);
478             pState->m_last_status = status;
479 
480             pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
481             pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp);
482 
483             pState->m_dict_avail = (mz_uint)out_bytes;
484 
485             n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
486             memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
487             pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
488             pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
489 
490             if (status < 0)
491                 return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well).
492             else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
493                 return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH.
494             else if (flush == MZ_FINISH)
495             {
496                 // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH.
497                 if (status == TINFL_STATUS_DONE)
498                     return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
499                 // 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.
500                 else if (!pStream->avail_out)
501                     return MZ_BUF_ERROR;
502             }
503             else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))
504                 break;
505         }
506 
507         return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
508     }
509 
mz_inflateEnd(mz_streamp pStream)510     int mz_inflateEnd(mz_streamp pStream)
511     {
512         if (!pStream)
513             return MZ_STREAM_ERROR;
514         if (pStream->state)
515         {
516             pStream->zfree(pStream->opaque, pStream->state);
517             pStream->state = NULL;
518         }
519         return MZ_OK;
520     }
521 
mz_uncompress(unsigned char * pDest,mz_ulong * pDest_len,const unsigned char * pSource,mz_ulong source_len)522     int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
523     {
524         mz_stream stream;
525         int status;
526         memset(&stream, 0, sizeof(stream));
527 
528         // In case mz_ulong is 64-bits (argh I hate longs).
529         //~ if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
530 
531         stream.next_in = pSource;
532         stream.avail_in = (mz_uint32)source_len;
533         stream.next_out = pDest;
534         stream.avail_out = (mz_uint32)*pDest_len;
535 
536         status = mz_inflateInit(&stream);
537         if (status != MZ_OK)
538             return status;
539 
540         status = mz_inflate(&stream, MZ_FINISH);
541         if (status != MZ_STREAM_END)
542         {
543             mz_inflateEnd(&stream);
544             return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status;
545         }
546         *pDest_len = stream.total_out;
547 
548         return mz_inflateEnd(&stream);
549     }
550 
mz_error(int err)551     const char *mz_error(int err)
552     {
553         static struct { int m_err; const char *m_pDesc; } s_error_descs[] =
554         {
555             { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" },
556             { 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" }
557         };
558         mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc;
559         return NULL;
560     }
561 
562 #endif //MINIZ_NO_ZLIB_APIS
563 
564     // ------------------- Low-level Decompression (completely independent from all compression API's)
565 
566 #define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
567 #define TINFL_MEMSET(p, c, l) memset(p, c, l)
568 
569 #define TINFL_CR_BEGIN switch(r->m_state) { case 0:
570 #define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
571 #define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
572 #define TINFL_CR_FINISH }
573 
574     // TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never
575     // reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
576 #define TINFL_GET_BYTE(state_index, c) do { \
577   if (pIn_buf_cur >= pIn_buf_end) { \
578     for ( ; ; ) { \
579       if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
580         TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
581         if (pIn_buf_cur < pIn_buf_end) { \
582           c = *pIn_buf_cur++; \
583           break; \
584                                 } \
585                         } else { \
586         c = 0; \
587         break; \
588                         } \
589                 } \
590         } else c = *pIn_buf_cur++; } MZ_MACRO_END
591 
592 #define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
593 #define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
594 #define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
595 
596     // TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
597     // 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
598     // 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
599     // bit buffer contains >=15 bits (deflate's max. Huffman code size).
600 #define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
601   do { \
602     temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
603     if (temp >= 0) { \
604       code_len = temp >> 9; \
605       if ((code_len) && (num_bits >= code_len)) \
606       break; \
607                 } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
608        code_len = TINFL_FAST_LOOKUP_BITS; \
609        do { \
610           temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
611                             } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
612                 } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
613         } while (num_bits < 15);
614 
615     // 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
616     // 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
617     // 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.
618     // The slow path is only executed at the very end of the input buffer.
619 #define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
620   int temp; mz_uint code_len, c; \
621   if (num_bits < 15) { \
622     if ((pIn_buf_end - pIn_buf_cur) < 2) { \
623        TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
624                 } else { \
625        bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
626                 } \
627         } \
628   if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
629     code_len = temp >> 9, temp &= 511; \
630                 else { \
631     code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
632               } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
633 
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)634     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)
635     {
636         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 };
637         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 };
638         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 };
639         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 };
640         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 };
641         static const int s_min_table_sizes[3] = { 257, 1, 4 };
642 
643         tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
644         const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
645         mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
646         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;
647 
648         // 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).
649         if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
650 
651         num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
652         TINFL_CR_BEGIN
653 
654             bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
655         if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
656         {
657             TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
658             counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
659             if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
660             if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
661         }
662 
663         do
664         {
665             TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
666             if (r->m_type == 0)
667             {
668                 TINFL_SKIP_BITS(5, num_bits & 7);
669                 for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
670                 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)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
671                 while ((counter) && (num_bits))
672                 {
673                     TINFL_GET_BITS(51, dist, 8);
674                     while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
675                     *pOut_buf_cur++ = (mz_uint8)dist;
676                     counter--;
677                 }
678                 while (counter)
679                 {
680                     size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
681                     while (pIn_buf_cur >= pIn_buf_end)
682                     {
683                         if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
684                         {
685                             TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
686                         }
687                         else
688                         {
689                             TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
690                         }
691                     }
692                     n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
693                     TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
694                 }
695             }
696             else if (r->m_type == 3)
697             {
698                 TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
699             }
700             else
701             {
702                 if (r->m_type == 1)
703                 {
704                     mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
705                     r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
706                     for (i = 0; i <= 143; ++i) *p++ = 8; for (; i <= 255; ++i) *p++ = 9; for (; i <= 279; ++i) *p++ = 7; for (; i <= 287; ++i) *p++ = 8;
707                 }
708                 else
709                 {
710                     for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
711                     MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
712                     r->m_table_sizes[2] = 19;
713                 }
714                 for (; (int)r->m_type >= 0; r->m_type--)
715                 {
716                     int tree_next, tree_cur; tinfl_huff_table *pTable;
717                     mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
718                     for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
719                     used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
720                     for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
721                     if ((65536 != total) && (used_syms > 1))
722                     {
723                         TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
724                     }
725                     for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
726                     {
727                         mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
728                         cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
729                         if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
730                         if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
731                         rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
732                         for (j = code_size; j >(TINFL_FAST_LOOKUP_BITS + 1); j--)
733                         {
734                             tree_cur -= ((rev_code >>= 1) & 1);
735                             if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
736                             else tree_cur = pTable->m_tree[-tree_cur - 1];
737                         }
738                         tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
739                     }
740                     if (r->m_type == 2)
741                     {
742                         for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);)
743                         {
744                             mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
745                             if ((dist == 16) && (!counter))
746                             {
747                                 TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
748                             }
749                             num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
750                             TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
751                         }
752                         if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
753                         {
754                             TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
755                         }
756                         TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
757                     }
758                 }
759                 for (;;)
760                 {
761                     mz_uint8 *pSrc;
762                     for (;;)
763                     {
764                         if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
765                         {
766                             TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
767                             if (counter >= 256)
768                                 break;
769                             while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
770                             *pOut_buf_cur++ = (mz_uint8)counter;
771                         }
772                         else
773                         {
774                             int sym2; mz_uint code_len;
775 #if TINFL_USE_64BIT_BITBUF
776                             if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
777 #else
778                             if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
779 #endif
780                             if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
781                                 code_len = sym2 >> 9;
782                             else
783                             {
784                                 code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
785                             }
786                             counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
787                             if (counter & 256)
788                                 break;
789 
790 #if !TINFL_USE_64BIT_BITBUF
791                             if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
792 #endif
793                             if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
794                                 code_len = sym2 >> 9;
795                             else
796                             {
797                                 code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
798                             }
799                             bit_buf >>= code_len; num_bits -= code_len;
800 
801                             pOut_buf_cur[0] = (mz_uint8)counter;
802                             if (sym2 & 256)
803                             {
804                                 pOut_buf_cur++;
805                                 counter = sym2;
806                                 break;
807                             }
808                             pOut_buf_cur[1] = (mz_uint8)sym2;
809                             pOut_buf_cur += 2;
810                         }
811                     }
812                     if ((counter &= 511) == 256) break;
813 
814                     num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
815                     if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
816 
817                     TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
818                     num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
819                     if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
820 
821                     dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
822                     if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
823                     {
824                         TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
825                     }
826 
827                     pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
828 
829                     if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
830                     {
831                         while (counter--)
832                         {
833                             while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
834                             *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
835                         }
836                         continue;
837                     }
838 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
839                     else if ((counter >= 9) && (counter <= dist))
840                     {
841                         const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
842                         do
843                         {
844                             ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
845                             ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
846                             pOut_buf_cur += 8;
847                         } while ((pSrc += 8) < pSrc_end);
848                         if ((counter &= 7) < 3)
849                         {
850                             if (counter)
851                             {
852                                 pOut_buf_cur[0] = pSrc[0];
853                                 if (counter > 1)
854                                     pOut_buf_cur[1] = pSrc[1];
855                                 pOut_buf_cur += counter;
856                             }
857                             continue;
858                         }
859                     }
860 #endif
861                     do
862                     {
863                         pOut_buf_cur[0] = pSrc[0];
864                         pOut_buf_cur[1] = pSrc[1];
865                         pOut_buf_cur[2] = pSrc[2];
866                         pOut_buf_cur += 3; pSrc += 3;
867                     } while ((int)(counter -= 3) > 2);
868                     if ((int)counter > 0)
869                     {
870                         pOut_buf_cur[0] = pSrc[0];
871                         if ((int)counter > 1)
872                             pOut_buf_cur[1] = pSrc[1];
873                         pOut_buf_cur += counter;
874                     }
875                 }
876             }
877         } while (!(r->m_final & 1));
878         if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
879         {
880             TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
881         }
882         TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
883         TINFL_CR_FINISH
884 
885         common_exit :
886         r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
887         *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
888         if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
889         {
890             const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
891             mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
892             while (buf_len)
893             {
894                 for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
895                 {
896                     s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
897                     s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
898                 }
899                 for (; i < block_len; ++i) s1 += *ptr++, s2 += s1;
900                 s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
901             }
902             r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
903         }
904         return status;
905     }
906 
907     // Higher level helper functions.
tinfl_decompress_mem_to_heap(const void * pSrc_buf,size_t src_buf_len,size_t * pOut_len,int flags)908     void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
909     {
910         tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
911         *pOut_len = 0;
912         tinfl_init(&decomp);
913         for (;;)
914         {
915             size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
916             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,
917                 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
918             if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
919             {
920                 MZ_FREE(pBuf); *pOut_len = 0; return NULL;
921             }
922             src_buf_ofs += src_buf_size;
923             *pOut_len += dst_buf_size;
924             if (status == TINFL_STATUS_DONE) break;
925             new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
926             pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
927             if (!pNew_buf)
928             {
929                 MZ_FREE(pBuf); *pOut_len = 0; return NULL;
930             }
931             pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
932         }
933         return pBuf;
934     }
935 
tinfl_decompress_mem_to_mem(void * pOut_buf,size_t out_buf_len,const void * pSrc_buf,size_t src_buf_len,int flags)936     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)
937     {
938         tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
939         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);
940         return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
941     }
942 
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)943     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)
944     {
945         int result = 0;
946         tinfl_decompressor decomp;
947         mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
948         if (!pDict)
949             return TINFL_STATUS_FAILED;
950         tinfl_init(&decomp);
951         for (;;)
952         {
953             size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
954             tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
955                 (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
956             in_buf_ofs += in_buf_size;
957             if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
958                 break;
959             if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
960             {
961                 result = (status == TINFL_STATUS_DONE);
962                 break;
963             }
964             dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
965         }
966         MZ_FREE(pDict);
967         *pIn_buf_size = in_buf_ofs;
968         return result;
969     }
970 
971     // ------------------- Low-level Compression (independent from all decompression API's)
972 
973     // Purposely making these tables static for faster init and thread safety.
974     static const mz_uint16 s_tdefl_len_sym[256] = {
975         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,
976         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,
977         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,
978         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,
979         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,
980         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,
981         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,
982         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 };
983 
984     static const mz_uint8 s_tdefl_len_extra[256] = {
985         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,
986         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,
987         5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
988         5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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 };
989 
990     static const mz_uint8 s_tdefl_small_dist_sym[512] = {
991         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,
992         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,
993         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,
994         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,
995         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,
996         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,
997         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,
998         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,
999         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,
1000         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,
1001         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,
1002         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 };
1003 
1004     static const mz_uint8 s_tdefl_small_dist_extra[512] = {
1005         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,
1006         5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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,
1007         6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
1008         6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 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,
1009         7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
1010         7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
1011         7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
1012         7, 7, 7, 7, 7, 7, 7, 7 };
1013 
1014     static const mz_uint8 s_tdefl_large_dist_sym[128] = {
1015         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,
1016         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,
1017         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 };
1018 
1019     static const mz_uint8 s_tdefl_large_dist_extra[128] = {
1020         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,
1021         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,
1022         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 };
1023 
1024     // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values.
1025     typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq;
tdefl_radix_sort_syms(mz_uint num_syms,tdefl_sym_freq * pSyms0,tdefl_sym_freq * pSyms1)1026     static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1)
1027     {
1028         mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist);
1029         for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; }
1030         while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--;
1031         for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8)
1032         {
1033             const mz_uint32* pHist = &hist[pass << 8];
1034             mz_uint offsets[256], cur_ofs = 0;
1035             for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; }
1036             for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i];
1037             { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; }
1038         }
1039         return pCur_syms;
1040     }
1041 
1042     // tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
tdefl_calculate_minimum_redundancy(tdefl_sym_freq * A,int n)1043     static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n)
1044     {
1045         int root, leaf, next, avbl, used, dpth;
1046         if (n == 0) return; else if (n == 1) { A[0].m_key = 1; return; }
1047         A[0].m_key += A[1].m_key; root = 0; leaf = 2;
1048         for (next = 1; next < n - 1; next++)
1049         {
1050             if (leaf >= n || A[root].m_key<A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = (mz_uint16)next; }
1051             else A[next].m_key = A[leaf++].m_key;
1052             if (leaf >= n || (root<next && A[root].m_key<A[leaf].m_key)) { A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); A[root++].m_key = (mz_uint16)next; }
1053             else A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
1054         }
1055         A[n - 2].m_key = 0; for (next = n - 3; next >= 0; next--) A[next].m_key = A[A[next].m_key].m_key + 1;
1056         avbl = 1; used = dpth = 0; root = n - 2; next = n - 1;
1057         while (avbl>0)
1058         {
1059             while (root >= 0 && (int)A[root].m_key == dpth) { used++; root--; }
1060             while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; }
1061             avbl = 2 * used; dpth++; used = 0;
1062         }
1063     }
1064 
1065     // Limits canonical Huffman code table's max code size.
1066     enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
tdefl_huffman_enforce_max_code_size(int * pNum_codes,int code_list_len,int max_code_size)1067     static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size)
1068     {
1069         int i; mz_uint32 total = 0; if (code_list_len <= 1) return;
1070         for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i];
1071         for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
1072         while (total != (1UL << max_code_size))
1073         {
1074             pNum_codes[max_code_size]--;
1075             for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; }
1076             total--;
1077         }
1078     }
1079 
tdefl_optimize_huffman_table(tdefl_compressor * d,int table_num,int table_len,int code_size_limit,int static_table)1080     static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table)
1081     {
1082         int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes);
1083         if (static_table)
1084         {
1085             for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++;
1086         }
1087         else
1088         {
1089             tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms;
1090             int num_used_syms = 0;
1091             const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
1092             for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; }
1093 
1094             pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
1095 
1096             for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++;
1097 
1098             tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit);
1099 
1100             MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);
1101             for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
1102                 for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
1103         }
1104 
1105         next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1);
1106 
1107         for (i = 0; i < table_len; i++)
1108         {
1109             mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue;
1110             code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1);
1111             d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
1112         }
1113     }
1114 
1115 #define TDEFL_PUT_BITS(b, l) do { \
1116   mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \
1117   d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \
1118         while (d->m_bits_in >= 8) { \
1119     if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
1120       *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
1121       d->m_bit_buffer >>= 8; \
1122       d->m_bits_in -= 8; \
1123                     } \
1124             } MZ_MACRO_END
1125 
1126 #define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \
1127   if (rle_repeat_count < 3) { \
1128     d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \
1129                 while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
1130         } else { \
1131     d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \
1132       } rle_repeat_count = 0; } }
1133 
1134 #define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \
1135   if (rle_z_count < 3) { \
1136     d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \
1137         } else if (rle_z_count <= 10) { \
1138     d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \
1139               } else { \
1140     d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \
1141             } rle_z_count = 0; } }
1142 
1143     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 };
1144 
tdefl_start_dynamic_block(tdefl_compressor * d)1145     static void tdefl_start_dynamic_block(tdefl_compressor *d)
1146     {
1147         int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index;
1148         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;
1149 
1150         d->m_huff_count[0][256] = 1;
1151 
1152         tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
1153         tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
1154 
1155         for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break;
1156         for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break;
1157 
1158         memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
1159         memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes);
1160         total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0;
1161 
1162         memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
1163         for (i = 0; i < total_code_sizes_to_pack; i++)
1164         {
1165             mz_uint8 code_size = code_sizes_to_pack[i];
1166             if (!code_size)
1167             {
1168                 TDEFL_RLE_PREV_CODE_SIZE();
1169                 if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); }
1170             }
1171             else
1172             {
1173                 TDEFL_RLE_ZERO_CODE_SIZE();
1174                 if (code_size != prev_code_size)
1175                 {
1176                     TDEFL_RLE_PREV_CODE_SIZE();
1177                     d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size;
1178                 }
1179                 else if (++rle_repeat_count == 6)
1180                 {
1181                     TDEFL_RLE_PREV_CODE_SIZE();
1182                 }
1183             }
1184             prev_code_size = code_size;
1185         }
1186         if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); }
1187         else { TDEFL_RLE_ZERO_CODE_SIZE(); }
1188 
1189         tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
1190 
1191         TDEFL_PUT_BITS(2, 2);
1192 
1193         TDEFL_PUT_BITS(num_lit_codes - 257, 5);
1194         TDEFL_PUT_BITS(num_dist_codes - 1, 5);
1195 
1196         for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break;
1197         num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
1198         for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
1199 
1200         for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;)
1201         {
1202             mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
1203             TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
1204             if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]);
1205         }
1206     }
1207 
tdefl_start_static_block(tdefl_compressor * d)1208     static void tdefl_start_static_block(tdefl_compressor *d)
1209     {
1210         mz_uint i;
1211         mz_uint8 *p = &d->m_huff_code_sizes[0][0];
1212 
1213         for (i = 0; i <= 143; ++i) *p++ = 8;
1214         for (; i <= 255; ++i) *p++ = 9;
1215         for (; i <= 279; ++i) *p++ = 7;
1216         for (; i <= 287; ++i) *p++ = 8;
1217 
1218         memset(d->m_huff_code_sizes[1], 5, 32);
1219 
1220         tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
1221         tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
1222 
1223         TDEFL_PUT_BITS(1, 2);
1224     }
1225 
1226     static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
1227 
1228 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
tdefl_compress_lz_codes(tdefl_compressor * d)1229     static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
1230     {
1231         mz_uint flags;
1232         mz_uint8 *pLZ_codes;
1233         mz_uint8 *pOutput_buf = d->m_pOutput_buf;
1234         mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
1235         mz_uint64 bit_buffer = d->m_bit_buffer;
1236         mz_uint bits_in = d->m_bits_in;
1237 
1238 #define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); }
1239 
1240         flags = 1;
1241         for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1)
1242         {
1243             if (flags == 1)
1244                 flags = *pLZ_codes++ | 0x100;
1245 
1246             if (flags & 1)
1247             {
1248                 mz_uint s0, s1, n0, n1, sym, num_extra_bits;
1249                 mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3;
1250 
1251                 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
1252                 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]]);
1253                 TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
1254 
1255                 // This sequence coaxes MSVC into using cmov's vs. jmp's.
1256                 s0 = s_tdefl_small_dist_sym[match_dist & 511];
1257                 n0 = s_tdefl_small_dist_extra[match_dist & 511];
1258                 s1 = s_tdefl_large_dist_sym[match_dist >> 8];
1259                 n1 = s_tdefl_large_dist_extra[match_dist >> 8];
1260                 sym = (match_dist < 512) ? s0 : s1;
1261                 num_extra_bits = (match_dist < 512) ? n0 : n1;
1262 
1263                 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
1264                 TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
1265                 TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
1266             }
1267             else
1268             {
1269                 mz_uint lit = *pLZ_codes++;
1270                 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1271                 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
1272 
1273                 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
1274                 {
1275                     flags >>= 1;
1276                     lit = *pLZ_codes++;
1277                     MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1278                     TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
1279 
1280                     if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
1281                     {
1282                         flags >>= 1;
1283                         lit = *pLZ_codes++;
1284                         MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1285                         TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
1286                     }
1287                 }
1288             }
1289 
1290             if (pOutput_buf >= d->m_pOutput_buf_end)
1291                 return MZ_FALSE;
1292 
1293             *(mz_uint64*)pOutput_buf = bit_buffer;
1294             pOutput_buf += (bits_in >> 3);
1295             bit_buffer >>= (bits_in & ~7);
1296             bits_in &= 7;
1297         }
1298 
1299 #undef TDEFL_PUT_BITS_FAST
1300 
1301         d->m_pOutput_buf = pOutput_buf;
1302         d->m_bits_in = 0;
1303         d->m_bit_buffer = 0;
1304 
1305         while (bits_in)
1306         {
1307             mz_uint32 n = MZ_MIN(bits_in, 16);
1308             TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
1309             bit_buffer >>= n;
1310             bits_in -= n;
1311         }
1312 
1313         TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
1314 
1315         return (d->m_pOutput_buf < d->m_pOutput_buf_end);
1316     }
1317 #else
tdefl_compress_lz_codes(tdefl_compressor * d)1318     static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
1319     {
1320         mz_uint flags;
1321         mz_uint8 *pLZ_codes;
1322 
1323         flags = 1;
1324         for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1)
1325         {
1326             if (flags == 1)
1327                 flags = *pLZ_codes++ | 0x100;
1328             if (flags & 1)
1329             {
1330                 mz_uint sym, num_extra_bits;
1331                 mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3;
1332 
1333                 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
1334                 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]]);
1335                 TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
1336 
1337                 if (match_dist < 512)
1338                 {
1339                     sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist];
1340                 }
1341                 else
1342                 {
1343                     sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
1344                 }
1345                 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
1346                 TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
1347                 TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
1348             }
1349             else
1350             {
1351                 mz_uint lit = *pLZ_codes++;
1352                 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1353                 TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
1354             }
1355         }
1356 
1357         TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
1358 
1359         return (d->m_pOutput_buf < d->m_pOutput_buf_end);
1360     }
1361 #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
1362 
tdefl_compress_block(tdefl_compressor * d,mz_bool static_block)1363     static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block)
1364     {
1365         if (static_block)
1366             tdefl_start_static_block(d);
1367         else
1368             tdefl_start_dynamic_block(d);
1369         return tdefl_compress_lz_codes(d);
1370     }
1371 
tdefl_flush_block(tdefl_compressor * d,int flush)1372     static int tdefl_flush_block(tdefl_compressor *d, int flush)
1373     {
1374         mz_uint saved_bit_buf, saved_bits_in;
1375         mz_uint8 *pSaved_output_buf;
1376         mz_bool comp_block_succeeded = MZ_FALSE;
1377         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;
1378         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;
1379 
1380         d->m_pOutput_buf = pOutput_buf_start;
1381         d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
1382 
1383         MZ_ASSERT(!d->m_output_flush_remaining);
1384         d->m_output_flush_ofs = 0;
1385         d->m_output_flush_remaining = 0;
1386 
1387         *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
1388         d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
1389 
1390         if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index))
1391         {
1392             TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8);
1393         }
1394 
1395         TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
1396 
1397         pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in;
1398 
1399         if (!use_raw_block)
1400             comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48));
1401 
1402         // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead.
1403         if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) &&
1404             ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size))
1405         {
1406             mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
1407             TDEFL_PUT_BITS(0, 2);
1408             if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); }
1409             for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF)
1410             {
1411                 TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
1412             }
1413             for (i = 0; i < d->m_total_lz_bytes; ++i)
1414             {
1415                 TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8);
1416             }
1417         }
1418         // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes.
1419         else if (!comp_block_succeeded)
1420         {
1421             d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
1422             tdefl_compress_block(d, MZ_TRUE);
1423         }
1424 
1425         if (flush)
1426         {
1427             if (flush == TDEFL_FINISH)
1428             {
1429                 if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); }
1430                 if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } }
1431             }
1432             else
1433             {
1434                 mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); }
1435             }
1436         }
1437 
1438         MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
1439 
1440         memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
1441         memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
1442 
1443         d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++;
1444 
1445         if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0)
1446         {
1447             if (d->m_pPut_buf_func)
1448             {
1449                 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
1450                 if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
1451                     return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
1452             }
1453             else if (pOutput_buf_start == d->m_output_buf)
1454             {
1455                 int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
1456                 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy);
1457                 d->m_out_buf_ofs += bytes_to_copy;
1458                 if ((n -= bytes_to_copy) != 0)
1459                 {
1460                     d->m_output_flush_ofs = bytes_to_copy;
1461                     d->m_output_flush_remaining = n;
1462                 }
1463             }
1464             else
1465             {
1466                 d->m_out_buf_ofs += n;
1467             }
1468         }
1469 
1470         return d->m_output_flush_remaining;
1471     }
1472 
1473 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
1474 #define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p)
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)1475     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)
1476     {
1477         mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
1478         mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
1479         const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q;
1480         mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s);
1481         MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return;
1482         for (;;)
1483         {
1484             for (;;)
1485             {
1486                 if (--num_probes_left == 0) return;
1487 #define TDEFL_PROBE \
1488         next_probe_pos = d->m_next[probe_pos]; \
1489         if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \
1490         probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
1491         if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break;
1492                 TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE;
1493             }
1494             if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32;
1495             do {} while ((TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
1496                 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0));
1497             if (!probe_len)
1498             {
1499                 *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break;
1500             }
1501             else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len)
1502             {
1503                 *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break;
1504                 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
1505             }
1506         }
1507     }
1508 #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)1509     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)
1510     {
1511         mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
1512         mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
1513         const mz_uint8 *s = d->m_dict + pos, *p, *q;
1514         mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
1515         MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return;
1516         for (;;)
1517         {
1518             for (;;)
1519             {
1520                 if (--num_probes_left == 0) return;
1521 #define TDEFL_PROBE \
1522         next_probe_pos = d->m_next[probe_pos]; \
1523         if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \
1524         probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
1525         if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break;
1526                 TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE;
1527             }
1528             if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break;
1529             if (probe_len > match_len)
1530             {
1531                 *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return;
1532                 c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1];
1533             }
1534         }
1535     }
1536 #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
1537 
1538 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
tdefl_compress_fast(tdefl_compressor * d)1539     static mz_bool tdefl_compress_fast(tdefl_compressor *d)
1540     {
1541         // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio.
1542         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;
1543         mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
1544         mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
1545 
1546         while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size)))
1547         {
1548             const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
1549             mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
1550             mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
1551             d->m_src_buf_left -= num_bytes_to_process;
1552             lookahead_size += num_bytes_to_process;
1553 
1554             while (num_bytes_to_process)
1555             {
1556                 mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
1557                 memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
1558                 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
1559                     memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
1560                 d->m_pSrc += n;
1561                 dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
1562                 num_bytes_to_process -= n;
1563             }
1564 
1565             dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
1566             if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break;
1567 
1568             while (lookahead_size >= 4)
1569             {
1570                 mz_uint cur_match_dist, cur_match_len = 1;
1571                 mz_uint8 *pCur_dict = d->m_dict + cur_pos;
1572                 mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF;
1573                 mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK;
1574                 mz_uint probe_pos = d->m_hash[hash];
1575                 d->m_hash[hash] = (mz_uint16)lookahead_pos;
1576 
1577                 if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram))
1578                 {
1579                     const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
1580                     const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
1581                     mz_uint32 probe_len = 32;
1582                     do {} while ((TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
1583                         (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0));
1584                     cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
1585                     if (!probe_len)
1586                         cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
1587 
1588                     if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)))
1589                     {
1590                         cur_match_len = 1;
1591                         *pLZ_code_buf++ = (mz_uint8)first_trigram;
1592                         *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
1593                         d->m_huff_count[0][(mz_uint8)first_trigram]++;
1594                     }
1595                     else
1596                     {
1597                         mz_uint32 s0, s1;
1598                         cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
1599 
1600                         MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
1601 
1602                         cur_match_dist--;
1603 
1604                         pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
1605                         *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
1606                         pLZ_code_buf += 3;
1607                         *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
1608 
1609                         s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
1610                         s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
1611                         d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
1612 
1613                         d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++;
1614                     }
1615                 }
1616                 else
1617                 {
1618                     *pLZ_code_buf++ = (mz_uint8)first_trigram;
1619                     *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
1620                     d->m_huff_count[0][(mz_uint8)first_trigram]++;
1621                 }
1622 
1623                 if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; }
1624 
1625                 total_lz_bytes += cur_match_len;
1626                 lookahead_pos += cur_match_len;
1627                 dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE);
1628                 cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
1629                 MZ_ASSERT(lookahead_size >= cur_match_len);
1630                 lookahead_size -= cur_match_len;
1631 
1632                 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
1633                 {
1634                     int n;
1635                     d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
1636                     d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
1637                     if ((n = tdefl_flush_block(d, 0)) != 0)
1638                         return (n < 0) ? MZ_FALSE : MZ_TRUE;
1639                     total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left;
1640                 }
1641             }
1642 
1643             while (lookahead_size)
1644             {
1645                 mz_uint8 lit = d->m_dict[cur_pos];
1646 
1647                 total_lz_bytes++;
1648                 *pLZ_code_buf++ = lit;
1649                 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
1650                 if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; }
1651 
1652                 d->m_huff_count[0][lit]++;
1653 
1654                 lookahead_pos++;
1655                 dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE);
1656                 cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
1657                 lookahead_size--;
1658 
1659                 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
1660                 {
1661                     int n;
1662                     d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
1663                     d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
1664                     if ((n = tdefl_flush_block(d, 0)) != 0)
1665                         return (n < 0) ? MZ_FALSE : MZ_TRUE;
1666                     total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left;
1667                 }
1668             }
1669         }
1670 
1671         d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
1672         d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
1673         return MZ_TRUE;
1674     }
1675 #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1676 
tdefl_record_literal(tdefl_compressor * d,mz_uint8 lit)1677     static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit)
1678     {
1679         d->m_total_lz_bytes++;
1680         *d->m_pLZ_code_buf++ = lit;
1681         *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; }
1682         d->m_huff_count[0][lit]++;
1683     }
1684 
tdefl_record_match(tdefl_compressor * d,mz_uint match_len,mz_uint match_dist)1685     static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist)
1686     {
1687         mz_uint32 s0, s1;
1688 
1689         MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE));
1690 
1691         d->m_total_lz_bytes += match_len;
1692 
1693         d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
1694 
1695         match_dist -= 1;
1696         d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
1697         d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3;
1698 
1699         *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; }
1700 
1701         s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
1702         d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
1703 
1704         if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
1705     }
1706 
tdefl_compress_normal(tdefl_compressor * d)1707     static mz_bool tdefl_compress_normal(tdefl_compressor *d)
1708     {
1709         const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left;
1710         tdefl_flush flush = d->m_flush;
1711 
1712         while ((src_buf_left) || ((flush) && (d->m_lookahead_size)))
1713         {
1714             mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
1715             // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN.
1716             if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1))
1717             {
1718                 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;
1719                 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];
1720                 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
1721                 const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
1722                 src_buf_left -= num_bytes_to_process;
1723                 d->m_lookahead_size += num_bytes_to_process;
1724                 while (pSrc != pSrc_end)
1725                 {
1726                     mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
1727                     hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
1728                     d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos);
1729                     dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++;
1730                 }
1731             }
1732             else
1733             {
1734                 while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
1735                 {
1736                     mz_uint8 c = *pSrc++;
1737                     mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
1738                     src_buf_left--;
1739                     d->m_dict[dst_pos] = c;
1740                     if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
1741                         d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
1742                     if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN)
1743                     {
1744                         mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
1745                         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);
1746                         d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos);
1747                     }
1748                 }
1749             }
1750             d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
1751             if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
1752                 break;
1753 
1754             // Simple lazy/greedy parsing state machine.
1755             len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
1756             if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS))
1757             {
1758                 if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))
1759                 {
1760                     mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
1761                     cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; }
1762                     if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1;
1763                 }
1764             }
1765             else
1766             {
1767                 tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len);
1768             }
1769             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)))
1770             {
1771                 cur_match_dist = cur_match_len = 0;
1772             }
1773             if (d->m_saved_match_len)
1774             {
1775                 if (cur_match_len > d->m_saved_match_len)
1776                 {
1777                     tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
1778                     if (cur_match_len >= 128)
1779                     {
1780                         tdefl_record_match(d, cur_match_len, cur_match_dist);
1781                         d->m_saved_match_len = 0; len_to_move = cur_match_len;
1782                     }
1783                     else
1784                     {
1785                         d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len;
1786                     }
1787                 }
1788                 else
1789                 {
1790                     tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
1791                     len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0;
1792                 }
1793             }
1794             else if (!cur_match_dist)
1795                 tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
1796             else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128))
1797             {
1798                 tdefl_record_match(d, cur_match_len, cur_match_dist);
1799                 len_to_move = cur_match_len;
1800             }
1801             else
1802             {
1803                 d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len;
1804             }
1805             // Move the lookahead forward by len_to_move bytes.
1806             d->m_lookahead_pos += len_to_move;
1807             MZ_ASSERT(d->m_lookahead_size >= len_to_move);
1808             d->m_lookahead_size -= len_to_move;
1809             d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE);
1810             // Check if it's time to flush the current LZ codes to the internal output buffer.
1811             if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
1812                 ((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))))
1813             {
1814                 int n;
1815                 d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left;
1816                 if ((n = tdefl_flush_block(d, 0)) != 0)
1817                     return (n < 0) ? MZ_FALSE : MZ_TRUE;
1818             }
1819         }
1820 
1821         d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left;
1822         return MZ_TRUE;
1823     }
1824 
tdefl_flush_output_buffer(tdefl_compressor * d)1825     static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d)
1826     {
1827         if (d->m_pIn_buf_size)
1828         {
1829             *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
1830         }
1831 
1832         if (d->m_pOut_buf_size)
1833         {
1834             size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining);
1835             memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n);
1836             d->m_output_flush_ofs += (mz_uint)n;
1837             d->m_output_flush_remaining -= (mz_uint)n;
1838             d->m_out_buf_ofs += n;
1839 
1840             *d->m_pOut_buf_size = d->m_out_buf_ofs;
1841         }
1842 
1843         return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY;
1844     }
1845 
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)1846     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)
1847     {
1848         if (!d)
1849         {
1850             if (pIn_buf_size) *pIn_buf_size = 0;
1851             if (pOut_buf_size) *pOut_buf_size = 0;
1852             return TDEFL_STATUS_BAD_PARAM;
1853         }
1854 
1855         d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size;
1856         d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size;
1857         d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
1858         d->m_out_buf_ofs = 0;
1859         d->m_flush = flush;
1860 
1861         if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
1862             (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf))
1863         {
1864             if (pIn_buf_size) *pIn_buf_size = 0;
1865             if (pOut_buf_size) *pOut_buf_size = 0;
1866             return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
1867         }
1868         d->m_wants_to_finish |= (flush == TDEFL_FINISH);
1869 
1870         if ((d->m_output_flush_remaining) || (d->m_finished))
1871             return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
1872 
1873 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1874         if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
1875             ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
1876             ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0))
1877         {
1878             if (!tdefl_compress_fast(d))
1879                 return d->m_prev_return_status;
1880         }
1881         else
1882 #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1883         {
1884             if (!tdefl_compress_normal(d))
1885                 return d->m_prev_return_status;
1886         }
1887 
1888         if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf))
1889             d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf);
1890 
1891         if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining))
1892         {
1893             if (tdefl_flush_block(d, flush) < 0)
1894                 return d->m_prev_return_status;
1895             d->m_finished = (flush == TDEFL_FINISH);
1896             if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; }
1897         }
1898 
1899         return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
1900     }
1901 
tdefl_compress_buffer(tdefl_compressor * d,const void * pIn_buf,size_t in_buf_size,tdefl_flush flush)1902     tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush)
1903     {
1904         MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
1905     }
1906 
tdefl_init(tdefl_compressor * d,tdefl_put_buf_func_ptr pPut_buf_func,void * pPut_buf_user,int flags)1907     tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
1908     {
1909         d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user;
1910         d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
1911         d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
1912         if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash);
1913         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;
1914         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;
1915         d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8;
1916         d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY;
1917         d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1;
1918         d->m_pIn_buf = NULL; d->m_pOut_buf = NULL;
1919         d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL;
1920         d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0;
1921         memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
1922         memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
1923         return TDEFL_STATUS_OKAY;
1924     }
1925 
tdefl_get_prev_return_status(tdefl_compressor * d)1926     tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d)
1927     {
1928         return d->m_prev_return_status;
1929     }
1930 
tdefl_get_adler32(tdefl_compressor * d)1931     mz_uint32 tdefl_get_adler32(tdefl_compressor *d)
1932     {
1933         return d->m_adler32;
1934     }
1935 
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)1936     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)
1937     {
1938         tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE;
1939         pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE;
1940         succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY);
1941         succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE);
1942         MZ_FREE(pComp); return succeeded;
1943     }
1944 
1945     typedef struct
1946     {
1947         size_t m_size, m_capacity;
1948         mz_uint8 *m_pBuf;
1949         mz_bool m_expandable;
1950     } tdefl_output_buffer;
1951 
tdefl_output_buffer_putter(const void * pBuf,int len,void * pUser)1952     static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser)
1953     {
1954         tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
1955         size_t new_size = p->m_size + len;
1956         if (new_size > p->m_capacity)
1957         {
1958             size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE;
1959             do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity);
1960             pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE;
1961             p->m_pBuf = pNew_buf; p->m_capacity = new_capacity;
1962         }
1963         memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size;
1964         return MZ_TRUE;
1965     }
1966 
tdefl_compress_mem_to_heap(const void * pSrc_buf,size_t src_buf_len,size_t * pOut_len,int flags)1967     void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
1968     {
1969         tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf);
1970         if (!pOut_len) return MZ_FALSE; else *pOut_len = 0;
1971         out_buf.m_expandable = MZ_TRUE;
1972         if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL;
1973         *pOut_len = out_buf.m_size; return out_buf.m_pBuf;
1974     }
1975 
tdefl_compress_mem_to_mem(void * pOut_buf,size_t out_buf_len,const void * pSrc_buf,size_t src_buf_len,int flags)1976     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)
1977     {
1978         tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf);
1979         if (!pOut_buf) return 0;
1980         out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len;
1981         if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0;
1982         return out_buf.m_size;
1983     }
1984 
1985 #ifndef MINIZ_NO_ZLIB_APIS
1986     static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };
1987 
1988     // 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)1989     mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy)
1990     {
1991         mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
1992         if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
1993 
1994         if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
1995         else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES;
1996         else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK;
1997         else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
1998         else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES;
1999 
2000         return comp_flags;
2001     }
2002 #endif //MINIZ_NO_ZLIB_APIS
2003 
2004 #ifdef _MSC_VER
2005 #pragma warning (push)
2006 #pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal)
2007 #endif
2008 
2009     // Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at
2010     // http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
tdefl_write_image_to_png_file_in_memory(const void * pImage,int w,int h,int num_chans,size_t * pLen_out)2011     void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out)
2012     {
2013         tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0;
2014         if (!pComp) return NULL;
2015         MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; }
2016         // write dummy header
2017         for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf);
2018         // compress image data
2019         tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, TDEFL_DEFAULT_MAX_PROBES | TDEFL_WRITE_ZLIB_HEADER);
2020         for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + y * bpl, bpl, TDEFL_NO_FLUSH); }
2021         if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
2022         // write real header
2023         *pLen_out = out_buf.m_size - 41;
2024         {
2025             mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
2026                 0, 0, (mz_uint8)(w >> 8), (mz_uint8)w, 0, 0, (mz_uint8)(h >> 8), (mz_uint8)h, 8, static_cast<mz_uint8>("\0\0\04\02\06"[num_chans]), 0, 0, 0, 0, 0, 0, 0,
2027                 (mz_uint8)(*pLen_out >> 24), (mz_uint8)(*pLen_out >> 16), (mz_uint8)(*pLen_out >> 8), (mz_uint8)*pLen_out, 0x49, 0x44, 0x41, 0x54 };
2028             c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); for (i = 0; i<4; ++i, c <<= 8) ((mz_uint8*)(pnghdr + 29))[i] = (mz_uint8)(c >> 24);
2029             memcpy(out_buf.m_pBuf, pnghdr, 41);
2030         }
2031         // write footer (IDAT CRC-32, followed by IEND chunk)
2032         if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
2033         c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); for (i = 0; i<4; ++i, c <<= 8) (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24);
2034         // compute final size of file, grab compressed data buffer and return
2035         *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf;
2036     }
2037 
2038 #ifdef _MSC_VER
2039 #pragma warning (pop)
2040 #endif
2041 
2042     // ------------------- .ZIP archive reading
2043 
2044 #ifndef MINIZ_NO_ARCHIVE_APIS
2045 
2046 #ifdef MINIZ_NO_STDIO
2047 #define MZ_FILE void *
2048 #else
2049 #include <stdio.h>
2050 #include <sys/stat.h>
2051 
2052 #if defined(_MSC_VER)
mz_fopen(const char * pFilename,const char * pMode)2053     static FILE *mz_fopen(const char *pFilename, const char *pMode)
2054     {
2055         FILE* pFile = NULL;
2056         fopen_s(&pFile, pFilename, pMode);
2057         return pFile;
2058     }
mz_freopen(const char * pPath,const char * pMode,FILE * pStream)2059     static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream)
2060     {
2061         FILE* pFile = NULL;
2062         if (freopen_s(&pFile, pPath, pMode, pStream))
2063             return NULL;
2064         return pFile;
2065     }
2066 #else
mz_fopen(const char * pFilename,const char * pMode)2067     static FILE *mz_fopen(const char *pFilename, const char *pMode)
2068     {
2069         return fopen(pFilename, pMode);
2070     }
mz_freopen(const char * pPath,const char * pMode,FILE * pStream)2071     static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream)
2072     {
2073         return freopen(pPath, pMode, pStream);
2074     }
2075 #endif // #if defined(_MSC_VER)
2076 
2077 #if defined(_MSC_VER) || defined(__MINGW64__)
2078 #ifndef MINIZ_NO_TIME
2079 #include <sys/utime.h>
2080 #endif
2081 #define MZ_FILE FILE
2082 #define MZ_FOPEN mz_fopen
2083 #define MZ_FCLOSE fclose
2084 #define MZ_FREAD fread
2085 #define MZ_FWRITE fwrite
2086 #define MZ_FTELL64 _ftelli64
2087 #define MZ_FSEEK64 _fseeki64
2088 #define MZ_FILE_STAT_STRUCT _stat
2089 #define MZ_FILE_STAT _stat
2090 #define MZ_FFLUSH fflush
2091 #define MZ_FREOPEN mz_freopen
2092 #define MZ_DELETE_FILE remove
2093 #elif defined(__MINGW32__)
2094 #ifndef MINIZ_NO_TIME
2095 #include <sys/utime.h>
2096 #endif
2097 #define MZ_FILE FILE
2098 #define MZ_FOPEN mz_fopen
2099 #define MZ_FCLOSE fclose
2100 #define MZ_FREAD fread
2101 #define MZ_FWRITE fwrite
2102 #define MZ_FTELL64 ftello64
2103 #define MZ_FSEEK64 fseeko64
2104 #define MZ_FILE_STAT_STRUCT _stat
2105 #define MZ_FILE_STAT _stat
2106 #define MZ_FFLUSH fflush
2107 #define MZ_FREOPEN mz_freopen
2108 #define MZ_DELETE_FILE remove
2109 #elif defined(__TINYC__)
2110 #ifndef MINIZ_NO_TIME
2111 #include <sys\utime.h>
2112 #endif
2113 #define MZ_FILE FILE
2114 #define MZ_FOPEN mz_fopen
2115 #define MZ_FCLOSE fclose
2116 #define MZ_FREAD fread
2117 #define MZ_FWRITE fwrite
2118 #define MZ_FTELL64 ftell
2119 #define MZ_FSEEK64 fseek
2120 #define MZ_FILE_STAT_STRUCT stat
2121 #define MZ_FILE_STAT stat
2122 #define MZ_FFLUSH fflush
2123 #define MZ_FREOPEN mz_freopen
2124 #define MZ_DELETE_FILE remove
2125 #else
2126 #ifndef MINIZ_NO_TIME
2127 #include <utime.h>
2128 #endif
2129 #define MZ_FILE FILE
2130 #define MZ_FOPEN mz_fopen
2131 #define MZ_FCLOSE fclose
2132 #define MZ_FREAD fread
2133 #define MZ_FWRITE fwrite
2134 #define MZ_FTELL64 ftello
2135 #define MZ_FSEEK64 fseeko
2136 #define MZ_FILE_STAT_STRUCT stat
2137 #define MZ_FILE_STAT stat
2138 #define MZ_FFLUSH fflush
2139 #define MZ_FREOPEN mz_freopen
2140 #define MZ_DELETE_FILE remove
2141 #endif // #ifdef _MSC_VER
2142 #endif // #ifdef MINIZ_NO_STDIO
2143 
2144 #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
2145 
2146     // 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.
2147     enum
2148     {
2149         // ZIP archive identifiers and record sizes
2150         MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
2151         MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
2152         // Central directory header record offsets
2153         MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
2154         MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16,
2155         MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
2156         MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
2157         // Local directory header offsets
2158         MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10,
2159         MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
2160         MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
2161         // End of central directory offsets
2162         MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
2163         MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
2164     };
2165 
2166     typedef struct
2167     {
2168         void *m_p;
2169         size_t m_size, m_capacity;
2170         mz_uint m_element_size;
2171     } mz_zip_array;
2172 
2173     struct mz_zip_internal_state_tag
2174     {
2175         mz_zip_array m_central_dir;
2176         mz_zip_array m_central_dir_offsets;
2177         mz_zip_array m_sorted_central_dir_offsets;
2178         MZ_FILE *m_pFile;
2179         void *m_pMem;
2180         size_t m_mem_size;
2181         size_t m_mem_capacity;
2182     };
2183 
2184 #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size
2185 #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index]
2186 
mz_zip_array_clear(mz_zip_archive * pZip,mz_zip_array * pArray)2187     static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)
2188     {
2189         pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
2190         memset(pArray, 0, sizeof(mz_zip_array));
2191     }
2192 
mz_zip_array_ensure_capacity(mz_zip_archive * pZip,mz_zip_array * pArray,size_t min_new_capacity,mz_uint growing)2193     static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing)
2194     {
2195         void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE;
2196         if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; }
2197         if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE;
2198         pArray->m_p = pNew_p; pArray->m_capacity = new_capacity;
2199         return MZ_TRUE;
2200     }
2201 
mz_zip_array_reserve(mz_zip_archive * pZip,mz_zip_array * pArray,size_t new_capacity,mz_uint growing)2202     static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing)
2203     {
2204         if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; }
2205         return MZ_TRUE;
2206     }
2207 
mz_zip_array_resize(mz_zip_archive * pZip,mz_zip_array * pArray,size_t new_size,mz_uint growing)2208     static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)
2209     {
2210         if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; }
2211         pArray->m_size = new_size;
2212         return MZ_TRUE;
2213     }
2214 
mz_zip_array_ensure_room(mz_zip_archive * pZip,mz_zip_array * pArray,size_t n)2215     static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n)
2216     {
2217         return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
2218     }
2219 
mz_zip_array_push_back(mz_zip_archive * pZip,mz_zip_array * pArray,const void * pElements,size_t n)2220     static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n)
2221     {
2222         size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE;
2223         memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size);
2224         return MZ_TRUE;
2225     }
2226 
2227 #ifndef MINIZ_NO_TIME
mz_zip_dos_to_time_t(int dos_time,int dos_date)2228     static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date)
2229     {
2230         struct tm tm;
2231         memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1;
2232         tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31;
2233         tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62;
2234         return mktime(&tm);
2235     }
2236 
mz_zip_time_to_dos_time(time_t time,mz_uint16 * pDOS_time,mz_uint16 * pDOS_date)2237     static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)
2238     {
2239 #ifdef _MSC_VER
2240         struct tm tm_struct;
2241         struct tm *tm = &tm_struct;
2242         errno_t err = localtime_s(tm, &time);
2243         if (err)
2244         {
2245             *pDOS_date = 0; *pDOS_time = 0;
2246             return;
2247         }
2248 #else
2249         struct tm *tm = localtime(&time);
2250 #endif
2251         *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1));
2252         *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday);
2253     }
2254 #endif
2255 
2256 #ifndef MINIZ_NO_STDIO
mz_zip_get_file_modified_time(const char * pFilename,mz_uint16 * pDOS_time,mz_uint16 * pDOS_date)2257     static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)
2258     {
2259 #ifdef MINIZ_NO_TIME
2260         (void)pFilename; *pDOS_date = *pDOS_time = 0;
2261 #else
2262         struct MZ_FILE_STAT_STRUCT file_stat; if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE;
2263         mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date);
2264 #endif // #ifdef MINIZ_NO_TIME
2265         return MZ_TRUE;
2266     }
2267 
mz_zip_set_file_times(const char * pFilename,time_t access_time,time_t modified_time)2268     static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time)
2269     {
2270 #ifndef MINIZ_NO_TIME
2271         struct utimbuf t; t.actime = access_time; t.modtime = modified_time;
2272         return !utime(pFilename, &t);
2273 #else
2274         (void)pFilename, (void)access_time, (void)modified_time;
2275         return MZ_TRUE;
2276 #endif // #ifndef MINIZ_NO_TIME
2277     }
2278 #endif
2279 
mz_zip_reader_init_internal(mz_zip_archive * pZip,mz_uint32 flags)2280     static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags)
2281     {
2282         (void)flags;
2283         if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
2284             return MZ_FALSE;
2285 
2286         if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
2287         if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
2288         if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
2289 
2290         pZip->m_zip_mode = MZ_ZIP_MODE_READING;
2291         pZip->m_archive_size = 0;
2292         pZip->m_central_directory_file_ofs = 0;
2293         pZip->m_total_files = 0;
2294 
2295         if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
2296             return MZ_FALSE;
2297         memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
2298         MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
2299         MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
2300         MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
2301         return MZ_TRUE;
2302     }
2303 
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)2304     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)
2305     {
2306         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;
2307         const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
2308         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);
2309         mz_uint8 l = 0, r = 0;
2310         pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
2311         pE = pL + MZ_MIN(l_len, r_len);
2312         while (pL < pE)
2313         {
2314             if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
2315                 break;
2316             pL++; pR++;
2317         }
2318         return (pL == pE) ? (l_len < r_len) : (l < r);
2319     }
2320 
2321 #define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END
2322 
2323     // 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)2324     static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip)
2325     {
2326         mz_zip_internal_state *pState = pZip->m_pState;
2327         const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
2328         const mz_zip_array *pCentral_dir = &pState->m_central_dir;
2329         mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
2330         const int size = pZip->m_total_files;
2331         int start = (size - 2) >> 1, end;
2332         while (start >= 0)
2333         {
2334             int child, root = start;
2335             for (;;)
2336             {
2337                 if ((child = (root << 1) + 1) >= size)
2338                     break;
2339                 child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])));
2340                 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
2341                     break;
2342                 MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child;
2343             }
2344             start--;
2345         }
2346 
2347         end = size - 1;
2348         while (end > 0)
2349         {
2350             int child, root = 0;
2351             MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
2352             for (;;)
2353             {
2354                 if ((child = (root << 1) + 1) >= end)
2355                     break;
2356                 child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]));
2357                 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
2358                     break;
2359                 MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child;
2360             }
2361             end--;
2362         }
2363     }
2364 
mz_zip_reader_read_central_dir(mz_zip_archive * pZip,mz_uint32 flags)2365     static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags)
2366     {
2367         mz_uint cdir_size, num_this_disk, cdir_disk_index;
2368         mz_uint64 cdir_ofs;
2369         mz_int64 cur_file_ofs;
2370         const mz_uint8 *p;
2371         mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
2372         // 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.
2373         if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
2374             return MZ_FALSE;
2375         // Find the end of central directory record by scanning the file from the end towards the beginning.
2376         cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
2377         for (;;)
2378         {
2379             int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
2380             if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
2381                 return MZ_FALSE;
2382             for (i = n - 4; i >= 0; --i)
2383                 if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
2384                     break;
2385             if (i >= 0)
2386             {
2387                 cur_file_ofs += i;
2388                 break;
2389             }
2390             if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
2391                 return MZ_FALSE;
2392             cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
2393         }
2394         // Read and verify the end of central directory record.
2395         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)
2396             return MZ_FALSE;
2397         if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
2398             ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
2399             return MZ_FALSE;
2400 
2401         num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
2402         cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
2403         if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1)))
2404             return MZ_FALSE;
2405 
2406         if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
2407             return MZ_FALSE;
2408 
2409         cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
2410         if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
2411             return MZ_FALSE;
2412 
2413         pZip->m_central_directory_file_ofs = cdir_ofs;
2414 
2415         if (pZip->m_total_files)
2416         {
2417             mz_uint i, n;
2418             // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices.
2419             if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) ||
2420                 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) ||
2421                 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)))
2422                 return MZ_FALSE;
2423             if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size)
2424                 return MZ_FALSE;
2425 
2426             // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported).
2427             p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
2428             for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i)
2429             {
2430                 mz_uint total_header_size, comp_size, decomp_size, disk_index;
2431                 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
2432                     return MZ_FALSE;
2433                 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);
2434                 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i;
2435                 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
2436                 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
2437                 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF))
2438                     return MZ_FALSE;
2439                 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
2440                 if ((disk_index != num_this_disk) && (disk_index != 1))
2441                     return MZ_FALSE;
2442                 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)
2443                     return MZ_FALSE;
2444                 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)
2445                     return MZ_FALSE;
2446                 n -= total_header_size; p += total_header_size;
2447             }
2448         }
2449 
2450         if ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0)
2451             mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
2452 
2453         return MZ_TRUE;
2454     }
2455 
mz_zip_reader_init(mz_zip_archive * pZip,mz_uint64 size,mz_uint32 flags)2456     mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags)
2457     {
2458         if ((!pZip) || (!pZip->m_pRead))
2459             return MZ_FALSE;
2460         if (!mz_zip_reader_init_internal(pZip, flags))
2461             return MZ_FALSE;
2462         pZip->m_archive_size = size;
2463         if (!mz_zip_reader_read_central_dir(pZip, flags))
2464         {
2465             mz_zip_reader_end(pZip);
2466             return MZ_FALSE;
2467         }
2468         return MZ_TRUE;
2469     }
2470 
mz_zip_mem_read_func(void * pOpaque,mz_uint64 file_ofs,void * pBuf,size_t n)2471     static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
2472     {
2473         mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
2474         size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
2475         memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
2476         return s;
2477     }
2478 
mz_zip_reader_init_mem(mz_zip_archive * pZip,const void * pMem,size_t size,mz_uint32 flags)2479     mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags)
2480     {
2481         if (!mz_zip_reader_init_internal(pZip, flags))
2482             return MZ_FALSE;
2483         pZip->m_archive_size = size;
2484         pZip->m_pRead = mz_zip_mem_read_func;
2485         pZip->m_pIO_opaque = pZip;
2486         pZip->m_pState->m_pMem = (void *)pMem;
2487         pZip->m_pState->m_mem_size = size;
2488         if (!mz_zip_reader_read_central_dir(pZip, flags))
2489         {
2490             mz_zip_reader_end(pZip);
2491             return MZ_FALSE;
2492         }
2493         return MZ_TRUE;
2494     }
2495 
2496 #ifndef MINIZ_NO_STDIO
mz_zip_file_read_func(void * pOpaque,mz_uint64 file_ofs,void * pBuf,size_t n)2497     static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
2498     {
2499         mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
2500         mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
2501         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))))
2502             return 0;
2503         return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
2504     }
2505 
mz_zip_reader_init_file(mz_zip_archive * pZip,const char * pFilename,mz_uint32 flags)2506     mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags)
2507     {
2508         mz_uint64 file_size;
2509         MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb");
2510         if (!pFile)
2511             return MZ_FALSE;
2512         if (MZ_FSEEK64(pFile, 0, SEEK_END))
2513             return MZ_FALSE;
2514         file_size = MZ_FTELL64(pFile);
2515         if (!mz_zip_reader_init_internal(pZip, flags))
2516         {
2517             MZ_FCLOSE(pFile);
2518             return MZ_FALSE;
2519         }
2520         pZip->m_pRead = mz_zip_file_read_func;
2521         pZip->m_pIO_opaque = pZip;
2522         pZip->m_pState->m_pFile = pFile;
2523         pZip->m_archive_size = file_size;
2524         if (!mz_zip_reader_read_central_dir(pZip, flags))
2525         {
2526             mz_zip_reader_end(pZip);
2527             return MZ_FALSE;
2528         }
2529         return MZ_TRUE;
2530     }
2531 #endif // #ifndef MINIZ_NO_STDIO
2532 
mz_zip_reader_get_num_files(mz_zip_archive * pZip)2533     mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip)
2534     {
2535         return pZip ? pZip->m_total_files : 0;
2536     }
2537 
mz_zip_reader_get_cdh(mz_zip_archive * pZip,mz_uint file_index)2538     static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index)
2539     {
2540         if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
2541             return NULL;
2542         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));
2543     }
2544 
mz_zip_reader_is_file_encrypted(mz_zip_archive * pZip,mz_uint file_index)2545     mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index)
2546     {
2547         mz_uint m_bit_flag;
2548         const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
2549         if (!p)
2550             return MZ_FALSE;
2551         m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
2552         return (m_bit_flag & 1);
2553     }
2554 
mz_zip_reader_is_file_a_directory(mz_zip_archive * pZip,mz_uint file_index)2555     mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index)
2556     {
2557         mz_uint filename_len, internal_attr, external_attr;
2558         const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
2559         if (!p)
2560             return MZ_FALSE;
2561 
2562         internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
2563         external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
2564         if ((!internal_attr) && ((external_attr & 0x10) != 0))
2565             return MZ_TRUE;
2566 
2567         filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
2568         if (filename_len)
2569         {
2570             if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
2571                 return MZ_TRUE;
2572         }
2573 
2574         return MZ_FALSE;
2575     }
2576 
mz_zip_reader_file_stat(mz_zip_archive * pZip,mz_uint file_index,mz_zip_archive_file_stat * pStat)2577     mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat)
2578     {
2579         mz_uint n;
2580         const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
2581         if ((!p) || (!pStat))
2582             return MZ_FALSE;
2583 
2584         // Unpack the central directory record.
2585         pStat->m_file_index = file_index;
2586         pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
2587         pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
2588         pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
2589         pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
2590         pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
2591 #ifndef MINIZ_NO_TIME
2592         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));
2593 #endif
2594         pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
2595         pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
2596         pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
2597         pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
2598         pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
2599         pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
2600 
2601         // Copy as much of the filename and comment as possible.
2602         n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
2603         memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0';
2604 
2605         n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
2606         pStat->m_comment_size = n;
2607         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); pStat->m_comment[n] = '\0';
2608 
2609         return MZ_TRUE;
2610     }
2611 
mz_zip_reader_get_filename(mz_zip_archive * pZip,mz_uint file_index,char * pFilename,mz_uint filename_buf_size)2612     mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size)
2613     {
2614         mz_uint n;
2615         const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
2616         if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; }
2617         n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
2618         if (filename_buf_size)
2619         {
2620             n = MZ_MIN(n, filename_buf_size - 1);
2621             memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
2622             pFilename[n] = '\0';
2623         }
2624         return n + 1;
2625     }
2626 
mz_zip_reader_string_equal(const char * pA,const char * pB,mz_uint len,mz_uint flags)2627     static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags)
2628     {
2629         mz_uint i;
2630         if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE)
2631             return 0 == memcmp(pA, pB, len);
2632         for (i = 0; i < len; ++i)
2633             if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i]))
2634                 return MZ_FALSE;
2635         return MZ_TRUE;
2636     }
2637 
mz_zip_reader_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)2638     static MZ_FORCEINLINE int mz_zip_reader_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)
2639     {
2640         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;
2641         mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
2642         mz_uint8 l = 0, r = 0;
2643         pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
2644         pE = pL + MZ_MIN(l_len, r_len);
2645         while (pL < pE)
2646         {
2647             if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
2648                 break;
2649             pL++; pR++;
2650         }
2651         return (pL == pE) ? (int)(l_len - r_len) : (l - r);
2652     }
2653 
mz_zip_reader_locate_file_binary_search(mz_zip_archive * pZip,const char * pFilename)2654     static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename)
2655     {
2656         mz_zip_internal_state *pState = pZip->m_pState;
2657         const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
2658         const mz_zip_array *pCentral_dir = &pState->m_central_dir;
2659         mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
2660         const int size = pZip->m_total_files;
2661         const mz_uint filename_len = (mz_uint)strlen(pFilename);
2662         int l = 0, h = size - 1;
2663         while (l <= h)
2664         {
2665             int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len);
2666             if (!comp)
2667                 return file_index;
2668             else if (comp < 0)
2669                 l = m + 1;
2670             else
2671                 h = m - 1;
2672         }
2673         return -1;
2674     }
2675 
mz_zip_reader_locate_file(mz_zip_archive * pZip,const char * pName,const char * pComment,mz_uint flags)2676     int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags)
2677     {
2678         mz_uint file_index; size_t name_len, comment_len;
2679         if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
2680             return -1;
2681         if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_p))
2682             return mz_zip_reader_locate_file_binary_search(pZip, pName);
2683         name_len = strlen(pName); if (name_len > 0xFFFF) return -1;
2684         comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1;
2685         for (file_index = 0; file_index < pZip->m_total_files; file_index++)
2686         {
2687             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));
2688             mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
2689             const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
2690             if (filename_len < name_len)
2691                 continue;
2692             if (comment_len)
2693             {
2694                 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);
2695                 const char *pFile_comment = pFilename + filename_len + file_extra_len;
2696                 if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags)))
2697                     continue;
2698             }
2699             if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len))
2700             {
2701                 int ofs = filename_len - 1;
2702                 do
2703                 {
2704                     if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':'))
2705                         break;
2706                 } while (--ofs >= 0);
2707                 ofs++;
2708                 pFilename += ofs; filename_len -= ofs;
2709             }
2710             if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags)))
2711                 return file_index;
2712         }
2713         return -1;
2714     }
2715 
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)2716     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)
2717     {
2718         int status = TINFL_STATUS_DONE;
2719         mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
2720         mz_zip_archive_file_stat file_stat;
2721         void *pRead_buf;
2722         mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
2723         tinfl_decompressor inflator;
2724 
2725         if ((buf_size) && (!pBuf))
2726             return MZ_FALSE;
2727 
2728         if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
2729             return MZ_FALSE;
2730 
2731         if (!file_stat.m_comp_size)
2732             return MZ_TRUE;
2733 
2734         // Encryption and patch files are not supported.
2735         if (file_stat.m_bit_flag & (1 | 32))
2736             return MZ_FALSE;
2737 
2738         // This function only supports stored and deflate.
2739         if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
2740             return MZ_FALSE;
2741 
2742         // Ensure supplied output buffer is large enough.
2743         needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size;
2744         if (buf_size < needed_size)
2745             return MZ_FALSE;
2746 
2747         // Read and parse the local directory entry.
2748         cur_file_ofs = file_stat.m_local_header_ofs;
2749         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)
2750             return MZ_FALSE;
2751         if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
2752             return MZ_FALSE;
2753 
2754         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);
2755         if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
2756             return MZ_FALSE;
2757 
2758         if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
2759         {
2760             // The file is stored or the caller has requested the compressed data.
2761             if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size)
2762                 return MZ_FALSE;
2763             return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32);
2764         }
2765 
2766         // Decompress the file either directly from memory or from a file input buffer.
2767         tinfl_init(&inflator);
2768 
2769         if (pZip->m_pState->m_pMem)
2770         {
2771             // Read directly from the archive in memory.
2772             pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
2773             read_buf_size = read_buf_avail = file_stat.m_comp_size;
2774             comp_remaining = 0;
2775         }
2776         else if (pUser_read_buf)
2777         {
2778             // Use a user provided read buffer.
2779             if (!user_read_buf_size)
2780                 return MZ_FALSE;
2781             pRead_buf = (mz_uint8 *)pUser_read_buf;
2782             read_buf_size = user_read_buf_size;
2783             read_buf_avail = 0;
2784             comp_remaining = file_stat.m_uncomp_size;
2785         }
2786         else
2787         {
2788             // Temporarily allocate a read buffer.
2789             read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);
2790 #ifdef _MSC_VER
2791             if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
2792 #else
2793             if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
2794 #endif
2795                 return MZ_FALSE;
2796             if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
2797                 return MZ_FALSE;
2798             read_buf_avail = 0;
2799             comp_remaining = file_stat.m_comp_size;
2800         }
2801 
2802         do
2803         {
2804             size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
2805             if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
2806             {
2807                 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
2808                 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
2809                 {
2810                     status = TINFL_STATUS_FAILED;
2811                     break;
2812                 }
2813                 cur_file_ofs += read_buf_avail;
2814                 comp_remaining -= read_buf_avail;
2815                 read_buf_ofs = 0;
2816             }
2817             in_buf_size = (size_t)read_buf_avail;
2818             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));
2819             read_buf_avail -= in_buf_size;
2820             read_buf_ofs += in_buf_size;
2821             out_buf_ofs += out_buf_size;
2822         } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
2823 
2824         if (status == TINFL_STATUS_DONE)
2825         {
2826             // Make sure the entire file was decompressed, and check its CRC.
2827             if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32))
2828                 status = TINFL_STATUS_FAILED;
2829         }
2830 
2831         if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
2832             pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
2833 
2834         return status == TINFL_STATUS_DONE;
2835     }
2836 
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)2837     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)
2838     {
2839         int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
2840         if (file_index < 0)
2841             return MZ_FALSE;
2842         return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size);
2843     }
2844 
mz_zip_reader_extract_to_mem(mz_zip_archive * pZip,mz_uint file_index,void * pBuf,size_t buf_size,mz_uint flags)2845     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)
2846     {
2847         return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0);
2848     }
2849 
mz_zip_reader_extract_file_to_mem(mz_zip_archive * pZip,const char * pFilename,void * pBuf,size_t buf_size,mz_uint flags)2850     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)
2851     {
2852         return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0);
2853     }
2854 
mz_zip_reader_extract_to_heap(mz_zip_archive * pZip,mz_uint file_index,size_t * pSize,mz_uint flags)2855     void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags)
2856     {
2857         mz_uint64 comp_size, uncomp_size, alloc_size;
2858         const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
2859         void *pBuf;
2860 
2861         if (pSize)
2862             *pSize = 0;
2863         if (!p)
2864             return NULL;
2865 
2866         comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
2867         uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
2868 
2869         alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
2870 #ifdef _MSC_VER
2871         if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
2872 #else
2873         if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
2874 #endif
2875             return NULL;
2876         if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))
2877             return NULL;
2878 
2879         if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags))
2880         {
2881             pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
2882             return NULL;
2883         }
2884 
2885         if (pSize) *pSize = (size_t)alloc_size;
2886         return pBuf;
2887     }
2888 
mz_zip_reader_extract_file_to_heap(mz_zip_archive * pZip,const char * pFilename,size_t * pSize,mz_uint flags)2889     void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags)
2890     {
2891         int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
2892         if (file_index < 0)
2893         {
2894             if (pSize) *pSize = 0;
2895             return MZ_FALSE;
2896         }
2897         return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
2898     }
2899 
mz_zip_reader_extract_to_callback(mz_zip_archive * pZip,mz_uint file_index,mz_file_write_func pCallback,void * pOpaque,mz_uint flags)2900     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)
2901     {
2902         int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT;
2903         mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs;
2904         mz_zip_archive_file_stat file_stat;
2905         void *pRead_buf = NULL; void *pWrite_buf = NULL;
2906         mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
2907 
2908         if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
2909             return MZ_FALSE;
2910 
2911         if (!file_stat.m_comp_size)
2912             return MZ_TRUE;
2913 
2914         // Encryption and patch files are not supported.
2915         if (file_stat.m_bit_flag & (1 | 32))
2916             return MZ_FALSE;
2917 
2918         // This function only supports stored and deflate.
2919         if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
2920             return MZ_FALSE;
2921 
2922         // Read and parse the local directory entry.
2923         cur_file_ofs = file_stat.m_local_header_ofs;
2924         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)
2925             return MZ_FALSE;
2926         if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
2927             return MZ_FALSE;
2928 
2929         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);
2930         if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
2931             return MZ_FALSE;
2932 
2933         // Decompress the file either directly from memory or from a file input buffer.
2934         if (pZip->m_pState->m_pMem)
2935         {
2936             pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
2937             read_buf_size = read_buf_avail = file_stat.m_comp_size;
2938             comp_remaining = 0;
2939         }
2940         else
2941         {
2942             read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);
2943             if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
2944                 return MZ_FALSE;
2945             read_buf_avail = 0;
2946             comp_remaining = file_stat.m_comp_size;
2947         }
2948 
2949         if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
2950         {
2951             // The file is stored or the caller has requested the compressed data.
2952             if (pZip->m_pState->m_pMem)
2953             {
2954 #ifdef _MSC_VER
2955                 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF))
2956 #else
2957                 if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF))
2958 #endif
2959                     return MZ_FALSE;
2960                 if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)
2961                     status = TINFL_STATUS_FAILED;
2962                 else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
2963                     file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size);
2964                 cur_file_ofs += file_stat.m_comp_size;
2965                 out_buf_ofs += file_stat.m_comp_size;
2966                 comp_remaining = 0;
2967             }
2968             else
2969             {
2970                 while (comp_remaining)
2971                 {
2972                     read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
2973                     if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
2974                     {
2975                         status = TINFL_STATUS_FAILED;
2976                         break;
2977                     }
2978 
2979                     if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
2980                         file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
2981 
2982                     if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
2983                     {
2984                         status = TINFL_STATUS_FAILED;
2985                         break;
2986                     }
2987                     cur_file_ofs += read_buf_avail;
2988                     out_buf_ofs += read_buf_avail;
2989                     comp_remaining -= read_buf_avail;
2990                 }
2991             }
2992         }
2993         else
2994         {
2995             tinfl_decompressor inflator;
2996             tinfl_init(&inflator);
2997 
2998             if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE)))
2999                 status = TINFL_STATUS_FAILED;
3000             else
3001             {
3002                 do
3003                 {
3004                     mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
3005                     size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
3006                     if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
3007                     {
3008                         read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
3009                         if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
3010                         {
3011                             status = TINFL_STATUS_FAILED;
3012                             break;
3013                         }
3014                         cur_file_ofs += read_buf_avail;
3015                         comp_remaining -= read_buf_avail;
3016                         read_buf_ofs = 0;
3017                     }
3018 
3019                     in_buf_size = (size_t)read_buf_avail;
3020                     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);
3021                     read_buf_avail -= in_buf_size;
3022                     read_buf_ofs += in_buf_size;
3023 
3024                     if (out_buf_size)
3025                     {
3026                         if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size)
3027                         {
3028                             status = TINFL_STATUS_FAILED;
3029                             break;
3030                         }
3031                         file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
3032                         if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size)
3033                         {
3034                             status = TINFL_STATUS_FAILED;
3035                             break;
3036                         }
3037                     }
3038                 } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT));
3039             }
3040         }
3041 
3042         if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
3043         {
3044             // Make sure the entire file was decompressed, and check its CRC.
3045             if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32))
3046                 status = TINFL_STATUS_FAILED;
3047         }
3048 
3049         if (!pZip->m_pState->m_pMem)
3050             pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3051         if (pWrite_buf)
3052             pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
3053 
3054         return status == TINFL_STATUS_DONE;
3055     }
3056 
mz_zip_reader_extract_file_to_callback(mz_zip_archive * pZip,const char * pFilename,mz_file_write_func pCallback,void * pOpaque,mz_uint flags)3057     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)
3058     {
3059         int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
3060         if (file_index < 0)
3061             return MZ_FALSE;
3062         return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags);
3063     }
3064 
3065 #ifndef MINIZ_NO_STDIO
mz_zip_file_write_callback(void * pOpaque,mz_uint64 ofs,const void * pBuf,size_t n)3066     static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n)
3067     {
3068         (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque);
3069     }
3070 
mz_zip_reader_extract_to_file(mz_zip_archive * pZip,mz_uint file_index,const char * pDst_filename,mz_uint flags)3071     mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags)
3072     {
3073         mz_bool status;
3074         mz_zip_archive_file_stat file_stat;
3075         MZ_FILE *pFile;
3076         if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
3077             return MZ_FALSE;
3078         pFile = MZ_FOPEN(pDst_filename, "wb");
3079         if (!pFile)
3080             return MZ_FALSE;
3081         status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);
3082         if (MZ_FCLOSE(pFile) == EOF)
3083             return MZ_FALSE;
3084 #ifndef MINIZ_NO_TIME
3085         if (status)
3086             mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
3087 #endif
3088         return status;
3089     }
3090 #endif // #ifndef MINIZ_NO_STDIO
3091 
mz_zip_reader_end(mz_zip_archive * pZip)3092     mz_bool mz_zip_reader_end(mz_zip_archive *pZip)
3093     {
3094         if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
3095             return MZ_FALSE;
3096 
3097         if (pZip->m_pState)
3098         {
3099             mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL;
3100             mz_zip_array_clear(pZip, &pState->m_central_dir);
3101             mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
3102             mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
3103 
3104 #ifndef MINIZ_NO_STDIO
3105             if (pState->m_pFile)
3106             {
3107                 MZ_FCLOSE(pState->m_pFile);
3108                 pState->m_pFile = NULL;
3109             }
3110 #endif // #ifndef MINIZ_NO_STDIO
3111 
3112             pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
3113         }
3114         pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
3115 
3116         return MZ_TRUE;
3117     }
3118 
3119 #ifndef MINIZ_NO_STDIO
mz_zip_reader_extract_file_to_file(mz_zip_archive * pZip,const char * pArchive_filename,const char * pDst_filename,mz_uint flags)3120     mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags)
3121     {
3122         int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags);
3123         if (file_index < 0)
3124             return MZ_FALSE;
3125         return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
3126     }
3127 #endif
3128 
3129     // ------------------- .ZIP archive writing
3130 
3131 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
3132 
mz_write_le16(mz_uint8 * p,mz_uint16 v)3133     static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); }
mz_write_le32(mz_uint8 * p,mz_uint32 v)3134     static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); }
3135 #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
3136 #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
3137 
mz_zip_writer_init(mz_zip_archive * pZip,mz_uint64 existing_size)3138     mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size)
3139     {
3140         if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
3141             return MZ_FALSE;
3142 
3143         if (pZip->m_file_offset_alignment)
3144         {
3145             // Ensure user specified file offset alignment is a power of 2.
3146             if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
3147                 return MZ_FALSE;
3148         }
3149 
3150         if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
3151         if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
3152         if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
3153 
3154         pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
3155         pZip->m_archive_size = existing_size;
3156         pZip->m_central_directory_file_ofs = 0;
3157         pZip->m_total_files = 0;
3158 
3159         if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
3160             return MZ_FALSE;
3161         memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
3162         MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
3163         MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
3164         MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
3165         return MZ_TRUE;
3166     }
3167 
mz_zip_heap_write_func(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)3168     static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
3169     {
3170         mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
3171         mz_zip_internal_state *pState = pZip->m_pState;
3172         mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
3173 #ifdef _MSC_VER
3174         if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
3175 #else
3176         if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
3177 #endif
3178             return 0;
3179         if (new_size > pState->m_mem_capacity)
3180         {
3181             void *pNew_block;
3182             size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2;
3183             if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))
3184                 return 0;
3185             pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity;
3186         }
3187         memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
3188         pState->m_mem_size = (size_t)new_size;
3189         return n;
3190     }
3191 
mz_zip_writer_init_heap(mz_zip_archive * pZip,size_t size_to_reserve_at_beginning,size_t initial_allocation_size)3192     mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size)
3193     {
3194         pZip->m_pWrite = mz_zip_heap_write_func;
3195         pZip->m_pIO_opaque = pZip;
3196         if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning))
3197             return MZ_FALSE;
3198         if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning)))
3199         {
3200             if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size)))
3201             {
3202                 mz_zip_writer_end(pZip);
3203                 return MZ_FALSE;
3204             }
3205             pZip->m_pState->m_mem_capacity = initial_allocation_size;
3206         }
3207         return MZ_TRUE;
3208     }
3209 
3210 #ifndef MINIZ_NO_STDIO
mz_zip_file_write_func(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)3211     static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
3212     {
3213         mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
3214         mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
3215         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))))
3216             return 0;
3217         return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
3218     }
3219 
mz_zip_writer_init_file(mz_zip_archive * pZip,const char * pFilename,mz_uint64 size_to_reserve_at_beginning)3220     mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning)
3221     {
3222         MZ_FILE *pFile;
3223         pZip->m_pWrite = mz_zip_file_write_func;
3224         pZip->m_pIO_opaque = pZip;
3225         if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning))
3226             return MZ_FALSE;
3227         if (NULL == (pFile = MZ_FOPEN(pFilename, "wb")))
3228         {
3229             mz_zip_writer_end(pZip);
3230             return MZ_FALSE;
3231         }
3232         pZip->m_pState->m_pFile = pFile;
3233         if (size_to_reserve_at_beginning)
3234         {
3235             mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf);
3236             do
3237             {
3238                 size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
3239                 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n)
3240                 {
3241                     mz_zip_writer_end(pZip);
3242                     return MZ_FALSE;
3243                 }
3244                 cur_ofs += n; size_to_reserve_at_beginning -= n;
3245             } while (size_to_reserve_at_beginning);
3246         }
3247         return MZ_TRUE;
3248     }
3249 #endif // #ifndef MINIZ_NO_STDIO
3250 
mz_zip_writer_init_from_reader(mz_zip_archive * pZip,const char * pFilename)3251     mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename)
3252     {
3253         mz_zip_internal_state *pState;
3254         if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
3255             return MZ_FALSE;
3256         // No sense in trying to write to an archive that's already at the support max size
3257         if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
3258             return MZ_FALSE;
3259 
3260         pState = pZip->m_pState;
3261 
3262         if (pState->m_pFile)
3263         {
3264 #ifdef MINIZ_NO_STDIO
3265             pFilename; return MZ_FALSE;
3266 #else
3267             // Archive is being read from stdio - try to reopen as writable.
3268             if (pZip->m_pIO_opaque != pZip)
3269                 return MZ_FALSE;
3270             if (!pFilename)
3271                 return MZ_FALSE;
3272             pZip->m_pWrite = mz_zip_file_write_func;
3273             if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile)))
3274             {
3275                 // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it.
3276                 mz_zip_reader_end(pZip);
3277                 return MZ_FALSE;
3278             }
3279 #endif // #ifdef MINIZ_NO_STDIO
3280         }
3281         else if (pState->m_pMem)
3282         {
3283             // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback.
3284             if (pZip->m_pIO_opaque != pZip)
3285                 return MZ_FALSE;
3286             pState->m_mem_capacity = pState->m_mem_size;
3287             pZip->m_pWrite = mz_zip_heap_write_func;
3288         }
3289         // Archive is being read via a user provided read function - make sure the user has specified a write function too.
3290         else if (!pZip->m_pWrite)
3291             return MZ_FALSE;
3292 
3293         // Start writing new files at the archive's current central directory location.
3294         pZip->m_archive_size = pZip->m_central_directory_file_ofs;
3295         pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
3296         pZip->m_central_directory_file_ofs = 0;
3297 
3298         return MZ_TRUE;
3299     }
3300 
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)3301     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)
3302     {
3303         return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0);
3304     }
3305 
3306     typedef struct
3307     {
3308         mz_zip_archive *m_pZip;
3309         mz_uint64 m_cur_archive_file_ofs;
3310         mz_uint64 m_comp_size;
3311     } mz_zip_writer_add_state;
3312 
mz_zip_writer_add_put_buf_callback(const void * pBuf,int len,void * pUser)3313     static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser)
3314     {
3315         mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
3316         if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len)
3317             return MZ_FALSE;
3318         pState->m_cur_archive_file_ofs += len;
3319         pState->m_comp_size += len;
3320         return MZ_TRUE;
3321     }
3322 
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)3323     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)
3324     {
3325         (void)pZip;
3326         memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
3327         MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
3328         MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
3329         MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
3330         MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
3331         MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
3332         MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
3333         MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
3334         MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size);
3335         MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
3336         MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
3337         MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
3338         return MZ_TRUE;
3339     }
3340 
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)3341     static mz_bool 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)
3342     {
3343         (void)pZip;
3344         memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
3345         MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
3346         MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
3347         MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
3348         MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
3349         MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
3350         MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
3351         MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
3352         MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size);
3353         MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
3354         MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
3355         MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
3356         MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
3357         MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
3358         MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs);
3359         return MZ_TRUE;
3360     }
3361 
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)3362     static mz_bool 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)
3363     {
3364         mz_zip_internal_state *pState = pZip->m_pState;
3365         mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
3366         size_t orig_central_dir_size = pState->m_central_dir.m_size;
3367         mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
3368 
3369         // No zip64 support yet
3370         if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF))
3371             return MZ_FALSE;
3372 
3373         if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes))
3374             return MZ_FALSE;
3375 
3376         if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
3377             (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) ||
3378             (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) ||
3379             (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) ||
3380             (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &central_dir_ofs, 1)))
3381         {
3382             // Try to push the central directory array back into its original state.
3383             mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
3384             return MZ_FALSE;
3385         }
3386 
3387         return MZ_TRUE;
3388     }
3389 
mz_zip_writer_validate_archive_name(const char * pArchive_name)3390     static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name)
3391     {
3392         // 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.
3393         if (*pArchive_name == '/')
3394             return MZ_FALSE;
3395         while (*pArchive_name)
3396         {
3397             if ((*pArchive_name == '\\') || (*pArchive_name == ':'))
3398                 return MZ_FALSE;
3399             pArchive_name++;
3400         }
3401         return MZ_TRUE;
3402     }
3403 
mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive * pZip)3404     static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip)
3405     {
3406         mz_uint32 n;
3407         if (!pZip->m_file_offset_alignment)
3408             return 0;
3409         n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
3410         return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1);
3411     }
3412 
mz_zip_writer_write_zeros(mz_zip_archive * pZip,mz_uint64 cur_file_ofs,mz_uint32 n)3413     static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n)
3414     {
3415         char buf[4096];
3416         memset(buf, 0, MZ_MIN(sizeof(buf), n));
3417         while (n)
3418         {
3419             mz_uint32 s = MZ_MIN(sizeof(buf), n);
3420             if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
3421                 return MZ_FALSE;
3422             cur_file_ofs += s; n -= s;
3423         }
3424         return MZ_TRUE;
3425     }
3426 
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)3427     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, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32)
3428     {
3429         mz_uint16 method = 0, dos_time = 0, dos_date = 0;
3430         mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
3431         mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
3432         size_t archive_name_size;
3433         mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
3434         tdefl_compressor *pComp = NULL;
3435         mz_bool store_data_uncompressed;
3436         mz_zip_internal_state *pState;
3437 
3438         if ((int)level_and_flags < 0)
3439             level_and_flags = MZ_DEFAULT_LEVEL;
3440         level = level_and_flags & 0xF;
3441         store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
3442 
3443         if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION))
3444             return MZ_FALSE;
3445 
3446         pState = pZip->m_pState;
3447 
3448         if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
3449             return MZ_FALSE;
3450         // No zip64 support yet
3451         if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF))
3452             return MZ_FALSE;
3453         if (!mz_zip_writer_validate_archive_name(pArchive_name))
3454             return MZ_FALSE;
3455 
3456 #ifndef MINIZ_NO_TIME
3457         {
3458             time_t cur_time; time(&cur_time);
3459             mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date);
3460         }
3461 #endif // #ifndef MINIZ_NO_TIME
3462 
3463         archive_name_size = strlen(pArchive_name);
3464         if (archive_name_size > 0xFFFF)
3465             return MZ_FALSE;
3466 
3467         num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
3468 
3469         // no zip64 support yet
3470         if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF))
3471             return MZ_FALSE;
3472 
3473         if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/'))
3474         {
3475             // Set DOS Subdirectory attribute bit.
3476             ext_attributes |= 0x10;
3477             // Subdirectories cannot contain data.
3478             if ((buf_size) || (uncomp_size))
3479                 return MZ_FALSE;
3480         }
3481 
3482         // 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.)
3483         if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))
3484             return MZ_FALSE;
3485 
3486         if ((!store_data_uncompressed) && (buf_size))
3487         {
3488             if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
3489                 return MZ_FALSE;
3490         }
3491 
3492         if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header)))
3493         {
3494             pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3495             return MZ_FALSE;
3496         }
3497         local_dir_header_ofs += num_alignment_padding_bytes;
3498         if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
3499         cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header);
3500 
3501         MZ_CLEAR_OBJ(local_dir_header);
3502         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
3503         {
3504             pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3505             return MZ_FALSE;
3506         }
3507         cur_archive_file_ofs += archive_name_size;
3508 
3509         if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
3510         {
3511             uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size);
3512             uncomp_size = buf_size;
3513             if (uncomp_size <= 3)
3514             {
3515                 level = 0;
3516                 store_data_uncompressed = MZ_TRUE;
3517             }
3518         }
3519 
3520         if (store_data_uncompressed)
3521         {
3522             if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size)
3523             {
3524                 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3525                 return MZ_FALSE;
3526             }
3527 
3528             cur_archive_file_ofs += buf_size;
3529             comp_size = buf_size;
3530 
3531             if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
3532                 method = MZ_DEFLATED;
3533         }
3534         else if (buf_size)
3535         {
3536             mz_zip_writer_add_state state;
3537 
3538             state.m_pZip = pZip;
3539             state.m_cur_archive_file_ofs = cur_archive_file_ofs;
3540             state.m_comp_size = 0;
3541 
3542             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) ||
3543                 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE))
3544             {
3545                 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3546                 return MZ_FALSE;
3547             }
3548 
3549             comp_size = state.m_comp_size;
3550             cur_archive_file_ofs = state.m_cur_archive_file_ofs;
3551 
3552             method = MZ_DEFLATED;
3553         }
3554 
3555         pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3556         pComp = NULL;
3557 
3558         // no zip64 support yet
3559         if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
3560             return MZ_FALSE;
3561 
3562         if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
3563             return MZ_FALSE;
3564 
3565         if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
3566             return MZ_FALSE;
3567 
3568         if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes))
3569             return MZ_FALSE;
3570 
3571         pZip->m_total_files++;
3572         pZip->m_archive_size = cur_archive_file_ofs;
3573 
3574         return MZ_TRUE;
3575     }
3576 
3577 #ifndef MINIZ_NO_STDIO
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)3578     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)
3579     {
3580         mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
3581         mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
3582         mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0;
3583         size_t archive_name_size;
3584         mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
3585         MZ_FILE *pSrc_file = NULL;
3586 
3587         if ((int)level_and_flags < 0)
3588             level_and_flags = MZ_DEFAULT_LEVEL;
3589         level = level_and_flags & 0xF;
3590 
3591         if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
3592             return MZ_FALSE;
3593         if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
3594             return MZ_FALSE;
3595         if (!mz_zip_writer_validate_archive_name(pArchive_name))
3596             return MZ_FALSE;
3597 
3598         archive_name_size = strlen(pArchive_name);
3599         if (archive_name_size > 0xFFFF)
3600             return MZ_FALSE;
3601 
3602         num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
3603 
3604         // no zip64 support yet
3605         if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF))
3606             return MZ_FALSE;
3607 
3608         if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date))
3609             return MZ_FALSE;
3610 
3611         pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
3612         if (!pSrc_file)
3613             return MZ_FALSE;
3614         MZ_FSEEK64(pSrc_file, 0, SEEK_END);
3615         uncomp_size = MZ_FTELL64(pSrc_file);
3616         MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
3617 
3618         if (uncomp_size > 0xFFFFFFFF)
3619         {
3620             // No zip64 support yet
3621             MZ_FCLOSE(pSrc_file);
3622             return MZ_FALSE;
3623         }
3624         if (uncomp_size <= 3)
3625             level = 0;
3626 
3627         if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header)))
3628             return MZ_FALSE;
3629         local_dir_header_ofs += num_alignment_padding_bytes;
3630         if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
3631         cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header);
3632 
3633         MZ_CLEAR_OBJ(local_dir_header);
3634         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
3635         {
3636             MZ_FCLOSE(pSrc_file);
3637             return MZ_FALSE;
3638         }
3639         cur_archive_file_ofs += archive_name_size;
3640 
3641         if (uncomp_size)
3642         {
3643             mz_uint64 uncomp_remaining = uncomp_size;
3644             void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
3645             if (!pRead_buf)
3646             {
3647                 MZ_FCLOSE(pSrc_file);
3648                 return MZ_FALSE;
3649             }
3650 
3651             if (!level)
3652             {
3653                 while (uncomp_remaining)
3654                 {
3655                     mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
3656                     if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n))
3657                     {
3658                         pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3659                         MZ_FCLOSE(pSrc_file);
3660                         return MZ_FALSE;
3661                     }
3662                     uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
3663                     uncomp_remaining -= n;
3664                     cur_archive_file_ofs += n;
3665                 }
3666                 comp_size = uncomp_size;
3667             }
3668             else
3669             {
3670                 mz_bool result = MZ_FALSE;
3671                 mz_zip_writer_add_state state;
3672                 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
3673                 if (!pComp)
3674                 {
3675                     pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3676                     MZ_FCLOSE(pSrc_file);
3677                     return MZ_FALSE;
3678                 }
3679 
3680                 state.m_pZip = pZip;
3681                 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
3682                 state.m_comp_size = 0;
3683 
3684                 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)
3685                 {
3686                     pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3687                     pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3688                     MZ_FCLOSE(pSrc_file);
3689                     return MZ_FALSE;
3690                 }
3691 
3692                 for (;;)
3693                 {
3694                     size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE);
3695                     tdefl_status status;
3696 
3697                     if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size)
3698                         break;
3699 
3700                     uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
3701                     uncomp_remaining -= in_buf_size;
3702 
3703                     status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH);
3704                     if (status == TDEFL_STATUS_DONE)
3705                     {
3706                         result = MZ_TRUE;
3707                         break;
3708                     }
3709                     else if (status != TDEFL_STATUS_OKAY)
3710                         break;
3711                 }
3712 
3713                 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3714 
3715                 if (!result)
3716                 {
3717                     pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3718                     MZ_FCLOSE(pSrc_file);
3719                     return MZ_FALSE;
3720                 }
3721 
3722                 comp_size = state.m_comp_size;
3723                 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
3724 
3725                 method = MZ_DEFLATED;
3726             }
3727 
3728             pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3729         }
3730 
3731         MZ_FCLOSE(pSrc_file); pSrc_file = NULL;
3732 
3733         // no zip64 support yet
3734         if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
3735             return MZ_FALSE;
3736 
3737         if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
3738             return MZ_FALSE;
3739 
3740         if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
3741             return MZ_FALSE;
3742 
3743         if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes))
3744             return MZ_FALSE;
3745 
3746         pZip->m_total_files++;
3747         pZip->m_archive_size = cur_archive_file_ofs;
3748 
3749         return MZ_TRUE;
3750     }
3751 #endif // #ifndef MINIZ_NO_STDIO
3752 
mz_zip_writer_add_from_zip_reader(mz_zip_archive * pZip,mz_zip_archive * pSource_zip,mz_uint file_index)3753     mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index)
3754     {
3755         mz_uint n, bit_flags, num_alignment_padding_bytes;
3756         mz_uint64 comp_bytes_remaining, local_dir_header_ofs;
3757         mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
3758         mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
3759         mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
3760         size_t orig_central_dir_size;
3761         mz_zip_internal_state *pState;
3762         void *pBuf; const mz_uint8 *pSrc_central_header;
3763 
3764         if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
3765             return MZ_FALSE;
3766         if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index)))
3767             return MZ_FALSE;
3768         pState = pZip->m_pState;
3769 
3770         num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
3771 
3772         // no zip64 support yet
3773         if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
3774             return MZ_FALSE;
3775 
3776         cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
3777         cur_dst_file_ofs = pZip->m_archive_size;
3778 
3779         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)
3780             return MZ_FALSE;
3781         if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
3782             return MZ_FALSE;
3783         cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
3784 
3785         if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes))
3786             return MZ_FALSE;
3787         cur_dst_file_ofs += num_alignment_padding_bytes;
3788         local_dir_header_ofs = cur_dst_file_ofs;
3789         if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
3790 
3791         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)
3792             return MZ_FALSE;
3793         cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
3794 
3795         n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
3796         comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
3797 
3798         if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining)))))
3799             return MZ_FALSE;
3800 
3801         while (comp_bytes_remaining)
3802         {
3803             n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining);
3804             if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n)
3805             {
3806                 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
3807                 return MZ_FALSE;
3808             }
3809             cur_src_file_ofs += n;
3810 
3811             if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
3812             {
3813                 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
3814                 return MZ_FALSE;
3815             }
3816             cur_dst_file_ofs += n;
3817 
3818             comp_bytes_remaining -= n;
3819         }
3820 
3821         bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
3822         if (bit_flags & 8)
3823         {
3824             // Copy data descriptor
3825             if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4)
3826             {
3827                 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
3828                 return MZ_FALSE;
3829             }
3830 
3831             n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3);
3832             if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
3833             {
3834                 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
3835                 return MZ_FALSE;
3836             }
3837 
3838             cur_src_file_ofs += n;
3839             cur_dst_file_ofs += n;
3840         }
3841         pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
3842 
3843         // no zip64 support yet
3844         if (cur_dst_file_ofs > 0xFFFFFFFF)
3845             return MZ_FALSE;
3846 
3847         orig_central_dir_size = pState->m_central_dir.m_size;
3848 
3849         memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
3850         MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs);
3851         if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
3852             return MZ_FALSE;
3853 
3854         n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
3855         if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n))
3856         {
3857             mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
3858             return MZ_FALSE;
3859         }
3860 
3861         if (pState->m_central_dir.m_size > 0xFFFFFFFF)
3862             return MZ_FALSE;
3863         n = (mz_uint32)pState->m_central_dir.m_size;
3864         if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1))
3865         {
3866             mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
3867             return MZ_FALSE;
3868         }
3869 
3870         pZip->m_total_files++;
3871         pZip->m_archive_size = cur_dst_file_ofs;
3872 
3873         return MZ_TRUE;
3874     }
3875 
mz_zip_writer_finalize_archive(mz_zip_archive * pZip)3876     mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip)
3877     {
3878         mz_zip_internal_state *pState;
3879         mz_uint64 central_dir_ofs, central_dir_size;
3880         mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE];
3881 
3882         if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
3883             return MZ_FALSE;
3884 
3885         pState = pZip->m_pState;
3886 
3887         // no zip64 support yet
3888         if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
3889             return MZ_FALSE;
3890 
3891         central_dir_ofs = 0;
3892         central_dir_size = 0;
3893         if (pZip->m_total_files)
3894         {
3895             // Write central directory
3896             central_dir_ofs = pZip->m_archive_size;
3897             central_dir_size = pState->m_central_dir.m_size;
3898             pZip->m_central_directory_file_ofs = central_dir_ofs;
3899             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)
3900                 return MZ_FALSE;
3901             pZip->m_archive_size += central_dir_size;
3902         }
3903 
3904         // Write end of central directory record
3905         MZ_CLEAR_OBJ(hdr);
3906         MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
3907         MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files);
3908         MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
3909         MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size);
3910         MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs);
3911 
3912         if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr))
3913             return MZ_FALSE;
3914 #ifndef MINIZ_NO_STDIO
3915         if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))
3916             return MZ_FALSE;
3917 #endif // #ifndef MINIZ_NO_STDIO
3918 
3919         pZip->m_archive_size += sizeof(hdr);
3920 
3921         pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
3922         return MZ_TRUE;
3923     }
3924 
mz_zip_writer_finalize_heap_archive(mz_zip_archive * pZip,void ** pBuf,size_t * pSize)3925     mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize)
3926     {
3927         if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize))
3928             return MZ_FALSE;
3929         if (pZip->m_pWrite != mz_zip_heap_write_func)
3930             return MZ_FALSE;
3931         if (!mz_zip_writer_finalize_archive(pZip))
3932             return MZ_FALSE;
3933 
3934         *pBuf = pZip->m_pState->m_pMem;
3935         *pSize = pZip->m_pState->m_mem_size;
3936         pZip->m_pState->m_pMem = NULL;
3937         pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
3938         return MZ_TRUE;
3939     }
3940 
mz_zip_writer_end(mz_zip_archive * pZip)3941     mz_bool mz_zip_writer_end(mz_zip_archive *pZip)
3942     {
3943         mz_zip_internal_state *pState;
3944         mz_bool status = MZ_TRUE;
3945         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)))
3946             return MZ_FALSE;
3947 
3948         pState = pZip->m_pState;
3949         pZip->m_pState = NULL;
3950         mz_zip_array_clear(pZip, &pState->m_central_dir);
3951         mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
3952         mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
3953 
3954 #ifndef MINIZ_NO_STDIO
3955         if (pState->m_pFile)
3956         {
3957             MZ_FCLOSE(pState->m_pFile);
3958             pState->m_pFile = NULL;
3959         }
3960 #endif // #ifndef MINIZ_NO_STDIO
3961 
3962         if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem))
3963         {
3964             pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
3965             pState->m_pMem = NULL;
3966         }
3967 
3968         pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
3969         pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
3970         return status;
3971     }
3972 
3973 #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)3974     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)
3975     {
3976         mz_bool status, created_new_archive = MZ_FALSE;
3977         mz_zip_archive zip_archive;
3978         struct MZ_FILE_STAT_STRUCT file_stat;
3979         MZ_CLEAR_OBJ(zip_archive);
3980         if ((int)level_and_flags < 0)
3981             level_and_flags = MZ_DEFAULT_LEVEL;
3982         if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
3983             return MZ_FALSE;
3984         if (!mz_zip_writer_validate_archive_name(pArchive_name))
3985             return MZ_FALSE;
3986         if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0)
3987         {
3988             // Create a new archive.
3989             if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0))
3990                 return MZ_FALSE;
3991             created_new_archive = MZ_TRUE;
3992         }
3993         else
3994         {
3995             // Append to an existing archive.
3996             if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
3997                 return MZ_FALSE;
3998             if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename))
3999             {
4000                 mz_zip_reader_end(&zip_archive);
4001                 return MZ_FALSE;
4002             }
4003         }
4004         status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0);
4005         // 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.)
4006         if (!mz_zip_writer_finalize_archive(&zip_archive))
4007             status = MZ_FALSE;
4008         if (!mz_zip_writer_end(&zip_archive))
4009             status = MZ_FALSE;
4010         if ((!status) && (created_new_archive))
4011         {
4012             // It's a new archive and something went wrong, so just delete it.
4013             int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
4014             (void)ignoredStatus;
4015         }
4016         return status;
4017     }
4018 
mz_zip_extract_archive_file_to_heap(const char * pZip_filename,const char * pArchive_name,size_t * pSize,mz_uint flags)4019     void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags)
4020     {
4021         int file_index;
4022         mz_zip_archive zip_archive;
4023         void *p = NULL;
4024 
4025         if (pSize)
4026             *pSize = 0;
4027 
4028         if ((!pZip_filename) || (!pArchive_name))
4029             return NULL;
4030 
4031         MZ_CLEAR_OBJ(zip_archive);
4032         if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
4033             return NULL;
4034 
4035         if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0)
4036             p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
4037 
4038         mz_zip_reader_end(&zip_archive);
4039         return p;
4040     }
4041 
4042 #endif // #ifndef MINIZ_NO_STDIO
4043 
4044 #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
4045 
4046 #endif // #ifndef MINIZ_NO_ARCHIVE_APIS
4047 
4048 #ifdef __cplusplus
4049 }
4050 #endif
4051 
4052 #endif // MINIZ_HEADER_FILE_ONLY
4053 
4054 /*
4055 This is free and unencumbered software released into the public domain.
4056 
4057 Anyone is free to copy, modify, publish, use, compile, sell, or
4058 distribute this software, either in source code form or as a compiled
4059 binary, for any purpose, commercial or non-commercial, and by any
4060 means.
4061 
4062 In jurisdictions that recognize copyright laws, the author or authors
4063 of this software dedicate any and all copyright interest in the
4064 software to the public domain. We make this dedication for the benefit
4065 of the public at large and to the detriment of our heirs and
4066 successors. We intend this dedication to be an overt act of
4067 relinquishment in perpetuity of all present and future rights to this
4068 software under copyright law.
4069 
4070 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4071 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4072 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
4073 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
4074 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
4075 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
4076 OTHER DEALINGS IN THE SOFTWARE.
4077 
4078 For more information, please refer to <http://unlicense.org/>
4079 */