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