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