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