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