1 /* miniz.c v1.14 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing
\r
2 See "unlicense" statement at the end of this file.
\r
3 Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2012
\r
4 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
\r
6 Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define
\r
7 MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros).
\r
10 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include <time.h> (thanks fermtect).
\r
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.
\r
12 Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files.
\r
13 Eliminated a bunch of warnings when compiling with GCC 32-bit/64.
\r
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
\r
15 "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning).
\r
16 Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64.
\r
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.
\r
18 Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives.
\r
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.)
\r
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).
\r
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.
\r
22 level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson <bruced@valvesoftware.com> for the feedback/bug report.
\r
23 5/28/11 v1.11 - Added statement from unlicense.org
\r
24 5/27/11 v1.10 - Substantial compressor optimizations:
\r
25 Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a
\r
26 Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86).
\r
27 Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types.
\r
28 Refactored the compression code for better readability and maintainability.
\r
29 Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large
\r
30 drop in throughput on some files).
\r
31 5/15/11 v1.09 - Initial stable release.
\r
33 * Low-level Deflate/Inflate implementation notes:
\r
35 Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or
\r
36 greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses
\r
37 approximately as well as zlib.
\r
39 Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function
\r
40 coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory
\r
41 block large enough to hold the entire file.
\r
43 The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation.
\r
45 * zlib-style API notes:
\r
47 miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in
\r
48 zlib replacement in many apps:
\r
49 The z_stream struct, optional memory allocation callbacks
\r
50 deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
\r
51 inflateInit/inflateInit2/inflate/inflateEnd
\r
52 compress, compress2, compressBound, uncompress
\r
53 CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines.
\r
54 Supports raw deflate streams or standard zlib streams with adler-32 checking.
\r
57 The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries.
\r
58 I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but
\r
59 there are no guarantees that miniz.c pulls this off perfectly.
\r
61 * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by
\r
62 Alex Evans. Supports 1-4 bytes/pixel images.
\r
64 * ZIP archive API notes:
\r
66 The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to
\r
67 get the job done with minimal fuss. There are simple API's to retrieve file information, read files from
\r
68 existing archives, create new archives, append new files to existing archives, or clone archive data from
\r
69 one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h),
\r
70 or you can specify custom file read/write callbacks.
\r
72 - Archive reading: Just call this function to read a single file from a disk archive:
\r
74 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name,
\r
75 size_t *pSize, mz_uint zip_flags);
\r
77 For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central
\r
78 directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files.
\r
80 - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file:
\r
82 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
\r
84 The locate operation can optionally check file comments too, which (as one example) can be used to identify
\r
85 multiple versions of the same file in an archive. This function uses a simple linear search through the central
\r
86 directory, so it's not very fast.
\r
88 Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and
\r
89 retrieve detailed info on each file by calling mz_zip_reader_file_stat().
\r
91 - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data
\r
92 to disk and builds an exact image of the central directory in memory. The central directory image is written
\r
93 all at once at the end of the archive file when the archive is finalized.
\r
95 The archive writer can optionally align each file's local header and file data to any power of 2 alignment,
\r
96 which can be useful when the archive will be read from optical media. Also, the writer supports placing
\r
97 arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still
\r
98 readable by any ZIP tool.
\r
100 - Archive appending: The simple way to add a single file to an archive is to call this function:
\r
102 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name,
\r
103 const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
\r
105 The archive will be created if it doesn't already exist, otherwise it'll be appended to.
\r
106 Note the appending is done in-place and is not an atomic operation, so if something goes wrong
\r
107 during the operation it's possible the archive could be left without a central directory (although the local
\r
108 file headers and file data will be fine, so the archive will be recoverable).
\r
110 For more complex archive modification scenarios:
\r
111 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to
\r
112 preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the
\r
113 compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and
\r
114 you're done. This is safe but requires a bunch of temporary disk space or heap memory.
\r
116 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(),
\r
117 append new files as needed, then finalize the archive which will write an updated central directory to the
\r
118 original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a
\r
119 possibility that the archive's central directory could be lost with this method if anything goes wrong, though.
\r
121 - ZIP archive support limitations:
\r
122 No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files.
\r
123 Requires streams capable of seeking.
\r
125 * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the
\r
126 below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it.
\r
128 * Important: For best perf. be sure to customize the below macros for your target platform:
\r
129 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
\r
130 #define MINIZ_LITTLE_ENDIAN 1
\r
131 #define MINIZ_HAS_64BIT_REGISTERS 1
\r
134 #ifndef MINIZ_HEADER_INCLUDED
\r
135 #define MINIZ_HEADER_INCLUDED
\r
137 #include <stdlib.h>
\r
139 #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
\r
143 // Defines to completely disable specific portions of miniz.c:
\r
144 // If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl.
\r
146 // Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O.
\r
147 #define MINIZ_NO_STDIO
\r
149 // If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or
\r
150 // get/set file times.
\r
151 #define MINIZ_NO_TIME
\r
153 // Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's.
\r
154 #define MINIZ_NO_ARCHIVE_APIS
\r
156 // Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's.
\r
157 #define MINIZ_NO_ARCHIVE_WRITING_APIS
\r
159 // Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's.
\r
160 #define MINIZ_NO_ZLIB_APIS
\r
162 // Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib.
\r
163 #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
\r
165 // Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
\r
166 // Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc
\r
167 // callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user
\r
168 // functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work.
\r
169 //#define MINIZ_NO_MALLOC
\r
170 #define MINIZ_SDL_MALLOC
\r
172 #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__)
\r
173 // MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
\r
174 #define MINIZ_X86_OR_X64_CPU 1
\r
177 #if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
\r
178 // Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
\r
179 #define MINIZ_LITTLE_ENDIAN 1
\r
182 #if MINIZ_X86_OR_X64_CPU
\r
183 // Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses.
\r
184 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
\r
187 #if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__)
\r
188 // 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).
\r
189 #define MINIZ_HAS_64BIT_REGISTERS 1
\r
196 // ------------------- zlib-style API Definitions.
\r
198 // 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!
\r
199 typedef unsigned long mz_ulong;
\r
201 // Heap allocation callbacks.
\r
202 // Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long.
\r
203 typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
\r
204 typedef void (*mz_free_func)(void *opaque, void *address);
\r
205 typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size);
\r
207 #define MZ_ADLER32_INIT (1)
\r
208 // mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL.
\r
209 mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);
\r
211 #define MZ_CRC32_INIT (0)
\r
212 // mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL.
\r
213 mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);
\r
215 // Compression strategies.
\r
216 enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 };
\r
219 #define MZ_DEFLATED 8
\r
221 #ifndef MINIZ_NO_ZLIB_APIS
\r
223 #define MZ_VERSION "9.1.14"
\r
224 #define MZ_VERNUM 0x91E0
\r
225 #define MZ_VER_MAJOR 9
\r
226 #define MZ_VER_MINOR 1
\r
227 #define MZ_VER_REVISION 14
\r
228 #define MZ_VER_SUBREVISION 0
\r
230 // 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).
\r
231 enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 };
\r
233 // Return status codes. MZ_PARAM_ERROR is non-standard.
\r
234 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 };
\r
236 // 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.
\r
237 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 };
\r
240 #define MZ_DEFAULT_WINDOW_BITS 15
\r
242 struct mz_internal_state;
\r
244 // Compression/decompression stream struct.
\r
245 typedef struct mz_stream_s
\r
247 const unsigned char *next_in; // pointer to next byte to read
\r
248 unsigned int avail_in; // number of bytes available at next_in
\r
249 mz_ulong total_in; // total number of bytes consumed so far
\r
251 unsigned char *next_out; // pointer to next byte to write
\r
252 unsigned int avail_out; // number of bytes that can be written to next_out
\r
253 mz_ulong total_out; // total number of bytes produced so far
\r
255 char *msg; // error msg (unused)
\r
256 struct mz_internal_state *state; // internal state, allocated by zalloc/zfree
\r
258 mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc)
\r
259 mz_free_func zfree; // optional heap free function (defaults to free)
\r
260 void *opaque; // heap alloc function user pointer
\r
262 int data_type; // data_type (unused)
\r
263 mz_ulong adler; // adler32 of the source or uncompressed data
\r
264 mz_ulong reserved; // not used
\r
267 typedef mz_stream *mz_streamp;
\r
269 // Returns the version string of miniz.c.
\r
270 const char *mz_version(void);
\r
272 // mz_deflateInit() initializes a compressor with default options:
\r
274 // pStream must point to an initialized mz_stream struct.
\r
275 // level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION].
\r
276 // level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio.
\r
277 // (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.)
\r
279 // MZ_OK on success.
\r
280 // MZ_STREAM_ERROR if the stream is bogus.
\r
281 // MZ_PARAM_ERROR if the input parameters are bogus.
\r
282 // MZ_MEM_ERROR on out of memory.
\r
283 int mz_deflateInit(mz_streamp pStream, int level);
\r
285 // mz_deflateInit2() is like mz_deflate(), except with more control:
\r
286 // Additional parameters:
\r
287 // method must be MZ_DEFLATED
\r
288 // 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)
\r
289 // mem_level must be between [1, 9] (it's checked but ignored by miniz.c)
\r
290 int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy);
\r
292 // Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2().
\r
293 int mz_deflateReset(mz_streamp pStream);
\r
295 // mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible.
\r
297 // 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.
\r
298 // flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH.
\r
300 // 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).
\r
301 // 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.
\r
302 // MZ_STREAM_ERROR if the stream is bogus.
\r
303 // MZ_PARAM_ERROR if one of the parameters is invalid.
\r
304 // 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.)
\r
305 int mz_deflate(mz_streamp pStream, int flush);
\r
307 // mz_deflateEnd() deinitializes a compressor:
\r
309 // MZ_OK on success.
\r
310 // MZ_STREAM_ERROR if the stream is bogus.
\r
311 int mz_deflateEnd(mz_streamp pStream);
\r
313 // 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.
\r
314 mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
\r
316 // Single-call compression functions mz_compress() and mz_compress2():
\r
317 // Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure.
\r
318 int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
\r
319 int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level);
\r
321 // mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress().
\r
322 mz_ulong mz_compressBound(mz_ulong source_len);
\r
324 // Initializes a decompressor.
\r
325 int mz_inflateInit(mz_streamp pStream);
\r
327 // 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:
\r
328 // window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate).
\r
329 int mz_inflateInit2(mz_streamp pStream, int window_bits);
\r
331 // 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.
\r
333 // 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.
\r
334 // flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH.
\r
335 // 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).
\r
336 // 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.
\r
338 // 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.
\r
339 // 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.
\r
340 // MZ_STREAM_ERROR if the stream is bogus.
\r
341 // MZ_DATA_ERROR if the deflate stream is invalid.
\r
342 // MZ_PARAM_ERROR if one of the parameters is invalid.
\r
343 // 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
\r
344 // with more input data, or with more room in the output buffer (except when using single call decompression, described above).
\r
345 int mz_inflate(mz_streamp pStream, int flush);
\r
347 // Deinitializes a decompressor.
\r
348 int mz_inflateEnd(mz_streamp pStream);
\r
350 // Single-call decompression.
\r
351 // Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure.
\r
352 int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
\r
354 // Returns a string description of the specified error code, or NULL if the error code is invalid.
\r
355 const char *mz_error(int err);
\r
357 // 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.
\r
358 // Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project.
\r
359 #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
\r
360 typedef unsigned char Byte;
\r
361 typedef unsigned int uInt;
\r
362 typedef mz_ulong uLong;
\r
363 typedef Byte Bytef;
\r
364 typedef uInt uIntf;
\r
365 typedef char charf;
\r
367 typedef void *voidpf;
\r
368 typedef uLong uLongf;
\r
369 typedef void *voidp;
\r
370 typedef void *const voidpc;
\r
372 #define Z_NO_FLUSH MZ_NO_FLUSH
\r
373 #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
\r
374 #define Z_SYNC_FLUSH MZ_SYNC_FLUSH
\r
375 #define Z_FULL_FLUSH MZ_FULL_FLUSH
\r
376 #define Z_FINISH MZ_FINISH
\r
377 #define Z_BLOCK MZ_BLOCK
\r
379 #define Z_STREAM_END MZ_STREAM_END
\r
380 #define Z_NEED_DICT MZ_NEED_DICT
\r
381 #define Z_ERRNO MZ_ERRNO
\r
382 #define Z_STREAM_ERROR MZ_STREAM_ERROR
\r
383 #define Z_DATA_ERROR MZ_DATA_ERROR
\r
384 #define Z_MEM_ERROR MZ_MEM_ERROR
\r
385 #define Z_BUF_ERROR MZ_BUF_ERROR
\r
386 #define Z_VERSION_ERROR MZ_VERSION_ERROR
\r
387 #define Z_PARAM_ERROR MZ_PARAM_ERROR
\r
388 #define Z_NO_COMPRESSION MZ_NO_COMPRESSION
\r
389 #define Z_BEST_SPEED MZ_BEST_SPEED
\r
390 #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
\r
391 #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
\r
392 #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
\r
393 #define Z_FILTERED MZ_FILTERED
\r
394 #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
\r
395 #define Z_RLE MZ_RLE
\r
396 #define Z_FIXED MZ_FIXED
\r
397 #define Z_DEFLATED MZ_DEFLATED
\r
398 #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
\r
399 #define alloc_func mz_alloc_func
\r
400 #define free_func mz_free_func
\r
401 #define internal_state mz_internal_state
\r
402 #define z_stream mz_stream
\r
403 #define deflateInit mz_deflateInit
\r
404 #define deflateInit2 mz_deflateInit2
\r
405 #define deflateReset mz_deflateReset
\r
406 #define deflate mz_deflate
\r
407 #define deflateEnd mz_deflateEnd
\r
408 #define deflateBound mz_deflateBound
\r
409 #define compress mz_compress
\r
410 #define compress2 mz_compress2
\r
411 #define compressBound mz_compressBound
\r
412 #define inflateInit mz_inflateInit
\r
413 #define inflateInit2 mz_inflateInit2
\r
414 #define inflate mz_inflate
\r
415 #define inflateEnd mz_inflateEnd
\r
416 #define uncompress mz_uncompress
\r
417 #define crc32 mz_crc32
\r
418 #define adler32 mz_adler32
\r
419 #define MAX_WBITS 15
\r
420 #define MAX_MEM_LEVEL 9
\r
421 #define zError mz_error
\r
422 #define ZLIB_VERSION MZ_VERSION
\r
423 #define ZLIB_VERNUM MZ_VERNUM
\r
424 #define ZLIB_VER_MAJOR MZ_VER_MAJOR
\r
425 #define ZLIB_VER_MINOR MZ_VER_MINOR
\r
426 #define ZLIB_VER_REVISION MZ_VER_REVISION
\r
427 #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
\r
428 #define zlibVersion mz_version
\r
429 #define zlib_version mz_version()
\r
430 #endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
\r
432 #endif // MINIZ_NO_ZLIB_APIS
\r
434 // ------------------- Types and macros
\r
436 typedef unsigned char mz_uint8;
\r
437 typedef signed short mz_int16;
\r
438 typedef unsigned short mz_uint16;
\r
439 typedef unsigned int mz_uint32;
\r
440 typedef unsigned int mz_uint;
\r
441 typedef long long mz_int64;
\r
442 typedef unsigned long long mz_uint64;
\r
443 typedef int mz_bool;
\r
445 #define MZ_FALSE (0)
\r
446 #define MZ_TRUE (1)
\r
448 // Works around MSVC's spammy "warning C4127: conditional expression is constant" message.
\r
450 #define MZ_MACRO_END while (0, 0)
\r
452 #define MZ_MACRO_END while (0)
\r
455 // ------------------- ZIP archive reading/writing
\r
457 #ifndef MINIZ_NO_ARCHIVE_APIS
\r
461 MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024,
\r
462 MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
\r
463 MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
\r
468 mz_uint32 m_file_index;
\r
469 mz_uint32 m_central_dir_ofs;
\r
470 mz_uint16 m_version_made_by;
\r
471 mz_uint16 m_version_needed;
\r
472 mz_uint16 m_bit_flag;
\r
473 mz_uint16 m_method;
\r
474 #ifndef MINIZ_NO_TIME
\r
478 mz_uint64 m_comp_size;
\r
479 mz_uint64 m_uncomp_size;
\r
480 mz_uint16 m_internal_attr;
\r
481 mz_uint32 m_external_attr;
\r
482 mz_uint64 m_local_header_ofs;
\r
483 mz_uint32 m_comment_size;
\r
484 char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
\r
485 char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
\r
486 } mz_zip_archive_file_stat;
\r
488 typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n);
\r
489 typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n);
\r
491 struct mz_zip_internal_state_tag;
\r
492 typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
\r
496 MZ_ZIP_MODE_INVALID = 0,
\r
497 MZ_ZIP_MODE_READING = 1,
\r
498 MZ_ZIP_MODE_WRITING = 2,
\r
499 MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
\r
504 mz_uint64 m_archive_size;
\r
505 mz_uint64 m_central_directory_file_ofs;
\r
506 mz_uint m_total_files;
\r
507 mz_zip_mode m_zip_mode;
\r
509 mz_uint m_file_offset_alignment;
\r
511 mz_alloc_func m_pAlloc;
\r
512 mz_free_func m_pFree;
\r
513 mz_realloc_func m_pRealloc;
\r
514 void *m_pAlloc_opaque;
\r
516 mz_file_read_func m_pRead;
\r
517 mz_file_write_func m_pWrite;
\r
518 void *m_pIO_opaque;
\r
520 mz_zip_internal_state *m_pState;
\r
526 MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
\r
527 MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
\r
528 MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
\r
529 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
\r
532 // ZIP archive reading
\r
534 // Inits a ZIP archive reader.
\r
535 // These functions read and validate the archive's central directory.
\r
536 mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags);
\r
537 mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags);
\r
539 #ifndef MINIZ_NO_STDIO
\r
540 mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags);
\r
543 // Returns the total number of files in the archive.
\r
544 mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
\r
546 // Returns detailed information about an archive file entry.
\r
547 mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat);
\r
549 // Determines if an archive file entry is a directory entry.
\r
550 mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index);
\r
551 mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index);
\r
553 // Retrieves the filename of an archive file entry.
\r
554 // 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.
\r
555 mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size);
\r
557 // Attempts to locates a file in the archive's central directory.
\r
558 // Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH
\r
559 // Returns -1 if the file cannot be found.
\r
560 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
\r
562 // Extracts a archive file to a memory buffer using no memory allocation.
\r
563 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);
\r
564 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);
\r
566 // Extracts a archive file to a memory buffer.
\r
567 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);
\r
568 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);
\r
570 // Extracts a archive file to a dynamically allocated heap buffer.
\r
571 void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags);
\r
572 void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags);
\r
574 // Extracts a archive file using a callback function to output the file's data.
\r
575 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);
\r
576 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);
\r
578 #ifndef MINIZ_NO_STDIO
\r
579 // Extracts a archive file to a disk file and sets its last accessed and modified times.
\r
580 // This function only extracts files, not archive directory records.
\r
581 mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags);
\r
582 mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags);
\r
585 // Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used.
\r
586 mz_bool mz_zip_reader_end(mz_zip_archive *pZip);
\r
588 // ZIP archive writing
\r
590 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
\r
592 // Inits a ZIP archive writer.
\r
593 mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);
\r
594 mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size);
\r
596 #ifndef MINIZ_NO_STDIO
\r
597 mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning);
\r
600 // Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive.
\r
601 // 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.
\r
602 // 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).
\r
603 // Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL.
\r
604 // Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before
\r
605 // the archive is finalized the file's central directory will be hosed.
\r
606 mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename);
\r
608 // Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive.
\r
609 // To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer.
\r
610 // 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.
\r
611 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);
\r
612 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);
\r
614 #ifndef MINIZ_NO_STDIO
\r
615 // Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive.
\r
616 // 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.
\r
617 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);
\r
620 // Adds a file to an archive by fully cloning the data from another archive.
\r
621 // This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields.
\r
622 mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index);
\r
624 // Finalizes the archive by writing the central directory records followed by the end of central directory record.
\r
625 // After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end().
\r
626 // An archive must be manually finalized by calling this function for it to be valid.
\r
627 mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);
\r
628 mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize);
\r
630 // Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used.
\r
631 // Note for the archive to be valid, it must have been finalized before ending.
\r
632 mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
\r
634 // Misc. high-level helper functions:
\r
636 // mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive.
\r
637 // 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.
\r
638 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);
\r
640 // Reads a single file from an archive into a heap block.
\r
641 // Returns NULL on failure.
\r
642 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags);
\r
644 #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
\r
646 #endif // #ifndef MINIZ_NO_ARCHIVE_APIS
\r
648 // ------------------- Low-level Decompression API Definitions
\r
650 // Decompression flags used by tinfl_decompress().
\r
651 // 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.
\r
652 // 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.
\r
653 // 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).
\r
654 // TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
\r
657 TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
\r
658 TINFL_FLAG_HAS_MORE_INPUT = 2,
\r
659 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
\r
660 TINFL_FLAG_COMPUTE_ADLER32 = 8
\r
663 // High level decompression functions:
\r
664 // tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc().
\r
666 // pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress.
\r
668 // Function returns a pointer to the decompressed data, or NULL on failure.
\r
669 // *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
\r
670 // The caller must free() the returned block when it's no longer needed.
\r
671 void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
\r
673 // tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
\r
674 // Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
\r
675 #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
\r
676 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);
\r
678 // 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.
\r
679 // Returns 1 on success or 0 on failure.
\r
680 typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
\r
681 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);
\r
683 struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
\r
685 // Max size of LZ dictionary.
\r
686 #define TINFL_LZ_DICT_SIZE 32768
\r
691 TINFL_STATUS_BAD_PARAM = -3,
\r
692 TINFL_STATUS_ADLER32_MISMATCH = -2,
\r
693 TINFL_STATUS_FAILED = -1,
\r
694 TINFL_STATUS_DONE = 0,
\r
695 TINFL_STATUS_NEEDS_MORE_INPUT = 1,
\r
696 TINFL_STATUS_HAS_MORE_OUTPUT = 2
\r
699 // Initializes the decompressor to its initial state.
\r
700 #define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
\r
701 #define tinfl_get_adler32(r) (r)->m_check_adler32
\r
703 // 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.
\r
704 // 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.
\r
705 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);
\r
707 // Internal/private bits follow.
\r
710 TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
\r
711 TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
\r
716 mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
\r
717 mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
\r
718 } tinfl_huff_table;
\r
720 #if MINIZ_HAS_64BIT_REGISTERS
\r
721 #define TINFL_USE_64BIT_BITBUF 1
\r
724 #if TINFL_USE_64BIT_BITBUF
\r
725 typedef mz_uint64 tinfl_bit_buf_t;
\r
726 #define TINFL_BITBUF_SIZE (64)
\r
728 typedef mz_uint32 tinfl_bit_buf_t;
\r
729 #define TINFL_BITBUF_SIZE (32)
\r
732 struct tinfl_decompressor_tag
\r
734 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];
\r
735 tinfl_bit_buf_t m_bit_buf;
\r
736 size_t m_dist_from_out_buf_start;
\r
737 tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
\r
738 mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
\r
741 // ------------------- Low-level Compression API Definitions
\r
743 // Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently).
\r
744 #define TDEFL_LESS_MEMORY 0
\r
746 // tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search):
\r
747 // 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).
\r
750 TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF
\r
753 // 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.
\r
754 // TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers).
\r
755 // TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing.
\r
756 // 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).
\r
757 // TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1)
\r
758 // TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled.
\r
759 // TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables.
\r
760 // TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks.
\r
763 TDEFL_WRITE_ZLIB_HEADER = 0x01000,
\r
764 TDEFL_COMPUTE_ADLER32 = 0x02000,
\r
765 TDEFL_GREEDY_PARSING_FLAG = 0x04000,
\r
766 TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
\r
767 TDEFL_RLE_MATCHES = 0x10000,
\r
768 TDEFL_FILTER_MATCHES = 0x20000,
\r
769 TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
\r
770 TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
\r
773 // High level compression functions:
\r
774 // tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc().
\r
776 // pSrc_buf, src_buf_len: Pointer and size of source block to compress.
\r
777 // flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression.
\r
779 // Function returns a pointer to the compressed data, or NULL on failure.
\r
780 // *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data.
\r
781 // The caller must free() the returned block when it's no longer needed.
\r
782 void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
\r
784 // tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory.
\r
785 // Returns 0 on failure.
\r
786 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);
\r
788 // Compresses an image to a compressed PNG file in memory.
\r
790 // pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4.
\r
792 // Function returns a pointer to the compressed data, or NULL on failure.
\r
793 // *pLen_out will be set to the size of the PNG image file.
\r
794 // The caller must free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed.
\r
795 void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int bpl, int num_chans, size_t *pLen_out);
\r
797 // Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
\r
798 typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
\r
800 // tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally.
\r
801 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);
\r
803 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 };
\r
805 // TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes).
\r
806 #if TDEFL_LESS_MEMORY
\r
807 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 };
\r
809 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 };
\r
812 // 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.
\r
815 TDEFL_STATUS_BAD_PARAM = -2,
\r
816 TDEFL_STATUS_PUT_BUF_FAILED = -1,
\r
817 TDEFL_STATUS_OKAY = 0,
\r
818 TDEFL_STATUS_DONE = 1,
\r
821 // Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
\r
824 TDEFL_NO_FLUSH = 0,
\r
825 TDEFL_SYNC_FLUSH = 2,
\r
826 TDEFL_FULL_FLUSH = 3,
\r
830 // tdefl's compression state structure.
\r
833 tdefl_put_buf_func_ptr m_pPut_buf_func;
\r
834 void *m_pPut_buf_user;
\r
835 mz_uint m_flags, m_max_probes[2];
\r
836 int m_greedy_parsing;
\r
837 mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
\r
838 mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
\r
839 mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer;
\r
840 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;
\r
841 tdefl_status m_prev_return_status;
\r
842 const void *m_pIn_buf;
\r
844 size_t *m_pIn_buf_size, *m_pOut_buf_size;
\r
845 tdefl_flush m_flush;
\r
846 const mz_uint8 *m_pSrc;
\r
847 size_t m_src_buf_left, m_out_buf_ofs;
\r
848 mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
\r
849 mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
\r
850 mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
\r
851 mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
\r
852 mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
\r
853 mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
\r
854 mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
\r
855 mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
\r
856 } tdefl_compressor;
\r
858 // Initializes the compressor.
\r
859 // There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory.
\r
860 // 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.
\r
861 // If pBut_buf_func is NULL the user should always call the tdefl_compress() API.
\r
862 // flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.)
\r
863 tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
\r
865 // 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.
\r
866 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);
\r
868 // tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr.
\r
869 // tdefl_compress_buffer() always consumes the entire input buffer.
\r
870 tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush);
\r
872 tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
\r
873 mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
\r
875 // 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.
\r
876 #ifndef MINIZ_NO_ZLIB_APIS
\r
877 // Create tdefl_compress() flags given zlib-style compression parameters.
\r
878 // level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files)
\r
879 // window_bits may be -15 (raw deflate) or 15 (zlib)
\r
880 // strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED
\r
881 mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy);
\r
882 #endif // #ifndef MINIZ_NO_ZLIB_APIS
\r
888 #endif // MINIZ_HEADER_INCLUDED
\r
890 // ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
\r
892 #ifndef MINIZ_HEADER_FILE_ONLY
\r
894 typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1];
\r
895 typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1];
\r
896 typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1];
\r
898 #include <string.h>
\r
899 #include <assert.h>
\r
901 #define MZ_ASSERT(x) assert(x)
\r
903 #ifdef MINIZ_NO_MALLOC
\r
904 #define MZ_MALLOC(x) NULL
\r
905 #define MZ_FREE(x) (void)x, ((void)0)
\r
906 #define MZ_REALLOC(p, x) NULL
\r
907 #elif defined(MINIZ_SDL_MALLOC)
\r
908 #define MZ_MALLOC(x) SDL_malloc(x)
\r
909 #define MZ_FREE(x) SDL_free(x)
\r
910 #define MZ_REALLOC(p, x) SDL_realloc(p, x)
\r
912 #define MZ_MALLOC(x) malloc(x)
\r
913 #define MZ_FREE(x) free(x)
\r
914 #define MZ_REALLOC(p, x) realloc(p, x)
\r
917 #define MZ_MAX(a,b) (((a)>(b))?(a):(b))
\r
918 #define MZ_MIN(a,b) (((a)<(b))?(a):(b))
\r
919 #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
\r
921 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
\r
922 #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
\r
923 #define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
\r
925 #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
\r
926 #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))
\r
930 #define MZ_FORCEINLINE __forceinline
\r
931 #elif defined(__GNUC__)
\r
932 #define MZ_FORCEINLINE __attribute__((__always_inline__))
\r
934 #define MZ_FORCEINLINE inline
\r
941 // ------------------- zlib-style API's
\r
943 mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len)
\r
945 mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552;
\r
946 if (!ptr) return MZ_ADLER32_INIT;
\r
948 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
\r
949 s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
\r
950 s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
\r
952 for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
\r
953 s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
\r
955 return (s2 << 16) + s1;
\r
958 // 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/
\r
959 mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
\r
961 static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
\r
962 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
\r
963 mz_uint32 crcu32 = (mz_uint32)crc;
\r
964 if (!ptr) return MZ_CRC32_INIT;
\r
965 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)]; }
\r
969 #ifndef MINIZ_NO_ZLIB_APIS
\r
971 static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); }
\r
972 static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); }
\r
973 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); }
\r
975 const char *mz_version(void)
\r
980 int mz_deflateInit(mz_streamp pStream, int level)
\r
982 return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY);
\r
985 int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy)
\r
987 tdefl_compressor *pComp;
\r
988 mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
\r
990 if (!pStream) return MZ_STREAM_ERROR;
\r
991 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;
\r
993 pStream->data_type = 0;
\r
994 pStream->adler = MZ_ADLER32_INIT;
\r
995 pStream->msg = NULL;
\r
996 pStream->reserved = 0;
\r
997 pStream->total_in = 0;
\r
998 pStream->total_out = 0;
\r
999 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
\r
1000 if (!pStream->zfree) pStream->zfree = def_free_func;
\r
1002 pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor));
\r
1004 return MZ_MEM_ERROR;
\r
1006 pStream->state = (struct mz_internal_state *)pComp;
\r
1008 if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY)
\r
1010 mz_deflateEnd(pStream);
\r
1011 return MZ_PARAM_ERROR;
\r
1017 int mz_deflateReset(mz_streamp pStream)
\r
1019 if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR;
\r
1020 pStream->total_in = pStream->total_out = 0;
\r
1021 tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags);
\r
1025 int mz_deflate(mz_streamp pStream, int flush)
\r
1027 size_t in_bytes, out_bytes;
\r
1028 mz_ulong orig_total_in, orig_total_out;
\r
1029 int mz_status = MZ_OK;
\r
1031 if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR;
\r
1032 if (!pStream->avail_out) return MZ_BUF_ERROR;
\r
1034 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
\r
1036 if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE)
\r
1037 return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
\r
1039 orig_total_in = pStream->total_in; orig_total_out = pStream->total_out;
\r
1042 tdefl_status defl_status;
\r
1043 in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
\r
1045 defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush);
\r
1046 pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
\r
1047 pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state);
\r
1049 pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes;
\r
1050 pStream->total_out += (mz_uint)out_bytes;
\r
1052 if (defl_status < 0)
\r
1054 mz_status = MZ_STREAM_ERROR;
\r
1057 else if (defl_status == TDEFL_STATUS_DONE)
\r
1059 mz_status = MZ_STREAM_END;
\r
1062 else if (!pStream->avail_out)
\r
1064 else if ((!pStream->avail_in) && (flush != MZ_FINISH))
\r
1066 if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out))
\r
1068 return MZ_BUF_ERROR; // Can't make forward progress without some input.
\r
1074 int mz_deflateEnd(mz_streamp pStream)
\r
1076 if (!pStream) return MZ_STREAM_ERROR;
\r
1077 if (pStream->state)
\r
1079 pStream->zfree(pStream->opaque, pStream->state);
\r
1080 pStream->state = NULL;
\r
1085 mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len)
\r
1088 // 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.)
\r
1089 return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
\r
1092 int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level)
\r
1096 memset(&stream, 0, sizeof(stream));
\r
1098 // In case mz_ulong is 64-bits (argh I hate longs).
\r
1099 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
\r
1101 stream.next_in = pSource;
\r
1102 stream.avail_in = (mz_uint32)source_len;
\r
1103 stream.next_out = pDest;
\r
1104 stream.avail_out = (mz_uint32)*pDest_len;
\r
1106 status = mz_deflateInit(&stream, level);
\r
1107 if (status != MZ_OK) return status;
\r
1109 status = mz_deflate(&stream, MZ_FINISH);
\r
1110 if (status != MZ_STREAM_END)
\r
1112 mz_deflateEnd(&stream);
\r
1113 return (status == MZ_OK) ? MZ_BUF_ERROR : status;
\r
1116 *pDest_len = stream.total_out;
\r
1117 return mz_deflateEnd(&stream);
\r
1120 int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
\r
1122 return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION);
\r
1125 mz_ulong mz_compressBound(mz_ulong source_len)
\r
1127 return mz_deflateBound(NULL, source_len);
\r
1132 tinfl_decompressor m_decomp;
\r
1133 mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits;
\r
1134 mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
\r
1135 tinfl_status m_last_status;
\r
1138 int mz_inflateInit2(mz_streamp pStream, int window_bits)
\r
1140 inflate_state *pDecomp;
\r
1141 if (!pStream) return MZ_STREAM_ERROR;
\r
1142 if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR;
\r
1144 pStream->data_type = 0;
\r
1145 pStream->adler = 0;
\r
1146 pStream->msg = NULL;
\r
1147 pStream->total_in = 0;
\r
1148 pStream->total_out = 0;
\r
1149 pStream->reserved = 0;
\r
1150 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
\r
1151 if (!pStream->zfree) pStream->zfree = def_free_func;
\r
1153 pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));
\r
1154 if (!pDecomp) return MZ_MEM_ERROR;
\r
1156 pStream->state = (struct mz_internal_state *)pDecomp;
\r
1158 tinfl_init(&pDecomp->m_decomp);
\r
1159 pDecomp->m_dict_ofs = 0;
\r
1160 pDecomp->m_dict_avail = 0;
\r
1161 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
\r
1162 pDecomp->m_first_call = 1;
\r
1163 pDecomp->m_has_flushed = 0;
\r
1164 pDecomp->m_window_bits = window_bits;
\r
1169 int mz_inflateInit(mz_streamp pStream)
\r
1171 return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
\r
1174 int mz_inflate(mz_streamp pStream, int flush)
\r
1176 inflate_state* pState;
\r
1177 mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
\r
1178 size_t in_bytes, out_bytes, orig_avail_in;
\r
1179 tinfl_status status;
\r
1181 if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
\r
1182 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
\r
1183 if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
\r
1185 pState = (inflate_state*)pStream->state;
\r
1186 if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
\r
1187 orig_avail_in = pStream->avail_in;
\r
1189 first_call = pState->m_first_call; pState->m_first_call = 0;
\r
1190 if (pState->m_last_status < 0) return MZ_DATA_ERROR;
\r
1192 if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
\r
1193 pState->m_has_flushed |= (flush == MZ_FINISH);
\r
1195 if ((flush == MZ_FINISH) && (first_call))
\r
1197 // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file.
\r
1198 decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
\r
1199 in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
\r
1200 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);
\r
1201 pState->m_last_status = status;
\r
1202 pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes;
\r
1203 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
\r
1204 pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes;
\r
1207 return MZ_DATA_ERROR;
\r
1208 else if (status != TINFL_STATUS_DONE)
\r
1210 pState->m_last_status = TINFL_STATUS_FAILED;
\r
1211 return MZ_BUF_ERROR;
\r
1213 return MZ_STREAM_END;
\r
1215 // flush != MZ_FINISH then we must assume there's more input.
\r
1216 if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
\r
1218 if (pState->m_dict_avail)
\r
1220 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
\r
1221 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
\r
1222 pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
\r
1223 pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
\r
1224 return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
\r
1229 in_bytes = pStream->avail_in;
\r
1230 out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
\r
1232 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);
\r
1233 pState->m_last_status = status;
\r
1235 pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
\r
1236 pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp);
\r
1238 pState->m_dict_avail = (mz_uint)out_bytes;
\r
1240 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
\r
1241 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
\r
1242 pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
\r
1243 pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
\r
1246 return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well).
\r
1247 else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
\r
1248 return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH.
\r
1249 else if (flush == MZ_FINISH)
\r
1251 // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH.
\r
1252 if (status == TINFL_STATUS_DONE)
\r
1253 return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
\r
1254 // 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.
\r
1255 else if (!pStream->avail_out)
\r
1256 return MZ_BUF_ERROR;
\r
1258 else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))
\r
1262 return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
\r
1265 int mz_inflateEnd(mz_streamp pStream)
\r
1268 return MZ_STREAM_ERROR;
\r
1269 if (pStream->state)
\r
1271 pStream->zfree(pStream->opaque, pStream->state);
\r
1272 pStream->state = NULL;
\r
1277 int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
\r
1281 memset(&stream, 0, sizeof(stream));
\r
1283 // In case mz_ulong is 64-bits (argh I hate longs).
\r
1284 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
\r
1286 stream.next_in = pSource;
\r
1287 stream.avail_in = (mz_uint32)source_len;
\r
1288 stream.next_out = pDest;
\r
1289 stream.avail_out = (mz_uint32)*pDest_len;
\r
1291 status = mz_inflateInit(&stream);
\r
1292 if (status != MZ_OK)
\r
1295 status = mz_inflate(&stream, MZ_FINISH);
\r
1296 if (status != MZ_STREAM_END)
\r
1298 mz_inflateEnd(&stream);
\r
1299 return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status;
\r
1301 *pDest_len = stream.total_out;
\r
1303 return mz_inflateEnd(&stream);
\r
1306 const char *mz_error(int err)
\r
1308 static struct { int m_err; const char *m_pDesc; } s_error_descs[] =
\r
1310 { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" },
\r
1311 { 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" }
\r
1313 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;
\r
1317 #endif //MINIZ_NO_ZLIB_APIS
\r
1319 // ------------------- Low-level Decompression (completely independent from all compression API's)
\r
1321 #define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
\r
1322 #define TINFL_MEMSET(p, c, l) memset(p, c, l)
\r
1324 #define TINFL_CR_BEGIN switch(r->m_state) { case 0:
\r
1325 #define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
\r
1326 #define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
\r
1327 #define TINFL_CR_FINISH }
\r
1329 // 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
\r
1330 // reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
\r
1331 #define TINFL_GET_BYTE(state_index, c) do { \
\r
1332 if (pIn_buf_cur >= pIn_buf_end) { \
\r
1334 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
\r
1335 TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
\r
1336 if (pIn_buf_cur < pIn_buf_end) { \
\r
1337 c = *pIn_buf_cur++; \
\r
1345 } else c = *pIn_buf_cur++; } MZ_MACRO_END
\r
1347 #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))
\r
1348 #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
\r
1349 #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
\r
1351 // TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
\r
1352 // 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
\r
1353 // 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
\r
1354 // bit buffer contains >=15 bits (deflate's max. Huffman code size).
\r
1355 #define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
\r
1357 temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
\r
1358 if (temp >= 0) { \
\r
1359 code_len = temp >> 9; \
\r
1360 if ((code_len) && (num_bits >= code_len)) \
\r
1362 } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
\r
1363 code_len = TINFL_FAST_LOOKUP_BITS; \
\r
1365 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
\r
1366 } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
\r
1367 } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
\r
1368 } while (num_bits < 15);
\r
1370 // 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
\r
1371 // 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
\r
1372 // 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.
\r
1373 // The slow path is only executed at the very end of the input buffer.
\r
1374 #define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
\r
1375 int temp; mz_uint code_len, c; \
\r
1376 if (num_bits < 15) { \
\r
1377 if ((pIn_buf_end - pIn_buf_cur) < 2) { \
\r
1378 TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
\r
1380 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; \
\r
1383 if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
\r
1384 code_len = temp >> 9, temp &= 511; \
\r
1386 code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
\r
1387 } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
\r
1389 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)
\r
1391 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 };
\r
1392 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 };
\r
1393 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};
\r
1394 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};
\r
1395 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 };
\r
1396 static const int s_min_table_sizes[3] = { 257, 1, 4 };
\r
1398 tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
\r
1399 const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
\r
1400 mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
\r
1401 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;
\r
1403 // 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).
\r
1404 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; }
\r
1406 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;
\r
1409 bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
\r
1410 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
\r
1412 TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
\r
1413 counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
\r
1414 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)))));
\r
1415 if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
\r
1420 TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
\r
1421 if (r->m_type == 0)
\r
1423 TINFL_SKIP_BITS(5, num_bits & 7);
\r
1424 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]); }
\r
1425 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); }
\r
1426 while ((counter) && (num_bits))
\r
1428 TINFL_GET_BITS(51, dist, 8);
\r
1429 while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
\r
1430 *pOut_buf_cur++ = (mz_uint8)dist;
\r
1435 size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
\r
1436 while (pIn_buf_cur >= pIn_buf_end)
\r
1438 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
\r
1440 TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
\r
1444 TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
\r
1447 n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
\r
1448 TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
\r
1451 else if (r->m_type == 3)
\r
1453 TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
\r
1457 if (r->m_type == 1)
\r
1459 mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
\r
1460 r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
\r
1461 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;
\r
1465 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]; }
\r
1466 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; }
\r
1467 r->m_table_sizes[2] = 19;
\r
1469 for ( ; (int)r->m_type >= 0; r->m_type--)
\r
1471 int tree_next, tree_cur; tinfl_huff_table *pTable;
\r
1472 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);
\r
1473 for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
\r
1474 used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
\r
1475 for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
\r
1476 if ((65536 != total) && (used_syms > 1))
\r
1478 TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
\r
1480 for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
\r
1482 mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
\r
1483 cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
\r
1484 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; }
\r
1485 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; }
\r
1486 rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
\r
1487 for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
\r
1489 tree_cur -= ((rev_code >>= 1) & 1);
\r
1490 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];
\r
1492 tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
\r
1494 if (r->m_type == 2)
\r
1496 for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
\r
1498 mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
\r
1499 if ((dist == 16) && (!counter))
\r
1501 TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
\r
1503 num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
\r
1504 TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
\r
1506 if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
\r
1508 TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
\r
1510 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]);
\r
1518 if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
\r
1520 TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
\r
1521 if (counter >= 256)
\r
1523 while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
\r
1524 *pOut_buf_cur++ = (mz_uint8)counter;
\r
1528 int sym2; mz_uint code_len;
\r
1529 #if TINFL_USE_64BIT_BITBUF
\r
1530 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; }
\r
1532 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; }
\r
1534 if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
\r
1535 code_len = sym2 >> 9;
\r
1538 code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
\r
1540 counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
\r
1541 if (counter & 256)
\r
1544 #if !TINFL_USE_64BIT_BITBUF
\r
1545 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; }
\r
1547 if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
\r
1548 code_len = sym2 >> 9;
\r
1551 code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
\r
1553 bit_buf >>= code_len; num_bits -= code_len;
\r
1555 pOut_buf_cur[0] = (mz_uint8)counter;
\r
1562 pOut_buf_cur[1] = (mz_uint8)sym2;
\r
1563 pOut_buf_cur += 2;
\r
1566 if ((counter &= 511) == 256) break;
\r
1568 num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
\r
1569 if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
\r
1571 TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
\r
1572 num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
\r
1573 if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
\r
1575 dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
\r
1576 if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
\r
1578 TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
\r
1581 pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
\r
1583 if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
\r
1587 while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
\r
1588 *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
\r
1592 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
\r
1593 else if ((counter >= 9) && (counter <= dist))
\r
1595 const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
\r
1598 ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
\r
1599 ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
\r
1600 pOut_buf_cur += 8;
\r
1601 } while ((pSrc += 8) < pSrc_end);
\r
1602 if ((counter &= 7) < 3)
\r
1606 pOut_buf_cur[0] = pSrc[0];
\r
1608 pOut_buf_cur[1] = pSrc[1];
\r
1609 pOut_buf_cur += counter;
\r
1617 pOut_buf_cur[0] = pSrc[0];
\r
1618 pOut_buf_cur[1] = pSrc[1];
\r
1619 pOut_buf_cur[2] = pSrc[2];
\r
1620 pOut_buf_cur += 3; pSrc += 3;
\r
1621 } while ((int)(counter -= 3) > 2);
\r
1622 if ((int)counter > 0)
\r
1624 pOut_buf_cur[0] = pSrc[0];
\r
1625 if ((int)counter > 1)
\r
1626 pOut_buf_cur[1] = pSrc[1];
\r
1627 pOut_buf_cur += counter;
\r
1631 } while (!(r->m_final & 1));
\r
1632 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
\r
1634 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; }
\r
1636 TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
\r
1640 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;
\r
1641 *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
\r
1642 if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
\r
1644 const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
\r
1645 mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
\r
1648 for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
\r
1650 s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
\r
1651 s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
\r
1653 for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
\r
1654 s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
\r
1656 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;
\r
1661 // Higher level helper functions.
\r
1662 void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
\r
1664 tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
\r
1666 tinfl_init(&decomp);
\r
1669 size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
\r
1670 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,
\r
1671 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
\r
1672 if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
\r
1674 MZ_FREE(pBuf); *pOut_len = 0; return NULL;
\r
1676 src_buf_ofs += src_buf_size;
\r
1677 *pOut_len += dst_buf_size;
\r
1678 if (status == TINFL_STATUS_DONE) break;
\r
1679 new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
\r
1680 pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
\r
1683 MZ_FREE(pBuf); *pOut_len = 0; return NULL;
\r
1685 pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
\r
1690 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)
\r
1692 tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
\r
1693 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);
\r
1694 return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
\r
1697 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)
\r
1700 tinfl_decompressor decomp;
\r
1701 mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
\r
1703 return TINFL_STATUS_FAILED;
\r
1704 tinfl_init(&decomp);
\r
1707 size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
\r
1708 tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
\r
1709 (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
\r
1710 in_buf_ofs += in_buf_size;
\r
1711 if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
\r
1713 if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
\r
1715 result = (status == TINFL_STATUS_DONE);
\r
1718 dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
\r
1721 *pIn_buf_size = in_buf_ofs;
\r
1725 // ------------------- Low-level Compression (independent from all decompression API's)
\r
1727 // Purposely making these tables static for faster init and thread safety.
\r
1728 static const mz_uint16 s_tdefl_len_sym[256] = {
\r
1729 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,
\r
1730 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,
\r
1731 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,
\r
1732 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,
\r
1733 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,
\r
1734 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,
\r
1735 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,
\r
1736 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 };
\r
1738 static const mz_uint8 s_tdefl_len_extra[256] = {
\r
1739 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,
\r
1740 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,
\r
1741 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
\r
1742 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,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 };
\r
1744 static const mz_uint8 s_tdefl_small_dist_sym[512] = {
\r
1745 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,
\r
1746 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,
\r
1747 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,
\r
1748 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,
\r
1749 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,
\r
1750 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,
\r
1751 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,
\r
1752 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,
\r
1753 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,
\r
1754 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,
\r
1755 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,
\r
1756 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 };
\r
1758 static const mz_uint8 s_tdefl_small_dist_extra[512] = {
\r
1759 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,
\r
1760 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,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,
\r
1761 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
\r
1762 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,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,
\r
1763 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
\r
1764 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
\r
1765 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
\r
1766 7,7,7,7,7,7,7,7 };
\r
1768 static const mz_uint8 s_tdefl_large_dist_sym[128] = {
\r
1769 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,
\r
1770 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,
\r
1771 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 };
\r
1773 static const mz_uint8 s_tdefl_large_dist_extra[128] = {
\r
1774 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,
\r
1775 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,
\r
1776 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 };
\r
1778 // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values.
\r
1779 typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq;
\r
1780 static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1)
\r
1782 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);
\r
1783 for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; }
\r
1784 while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--;
\r
1785 for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8)
\r
1787 const mz_uint32* pHist = &hist[pass << 8];
\r
1788 mz_uint offsets[256], cur_ofs = 0;
\r
1789 for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; }
\r
1790 for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i];
\r
1791 { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; }
\r
1796 // tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
\r
1797 static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n)
\r
1799 int root, leaf, next, avbl, used, dpth;
\r
1800 if (n==0) return; else if (n==1) { A[0].m_key = 1; return; }
\r
1801 A[0].m_key += A[1].m_key; root = 0; leaf = 2;
\r
1802 for (next=1; next < n-1; next++)
\r
1804 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;
\r
1805 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);
\r
1807 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;
\r
1808 avbl = 1; used = dpth = 0; root = n-2; next = n-1;
\r
1811 while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; }
\r
1812 while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; }
\r
1813 avbl = 2*used; dpth++; used = 0;
\r
1817 // Limits canonical Huffman code table's max code size.
\r
1818 enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
\r
1819 static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size)
\r
1821 int i; mz_uint32 total = 0; if (code_list_len <= 1) return;
\r
1822 for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i];
\r
1823 for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
\r
1824 while (total != (1UL << max_code_size))
\r
1826 pNum_codes[max_code_size]--;
\r
1827 for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; }
\r
1832 static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table)
\r
1834 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);
\r
1837 for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++;
\r
1841 tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms;
\r
1842 int num_used_syms = 0;
\r
1843 const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
\r
1844 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; }
\r
1846 pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
\r
1848 for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++;
\r
1850 tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit);
\r
1852 MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);
\r
1853 for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
\r
1854 for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
\r
1857 next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1);
\r
1859 for (i = 0; i < table_len; i++)
\r
1861 mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue;
\r
1862 code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1);
\r
1863 d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
\r
1867 #define TDEFL_PUT_BITS(b, l) do { \
\r
1868 mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \
\r
1869 d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \
\r
1870 while (d->m_bits_in >= 8) { \
\r
1871 if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
\r
1872 *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
\r
1873 d->m_bit_buffer >>= 8; \
\r
1874 d->m_bits_in -= 8; \
\r
1878 #define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \
\r
1879 if (rle_repeat_count < 3) { \
\r
1880 d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \
\r
1881 while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
\r
1883 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); \
\r
1884 } rle_repeat_count = 0; } }
\r
1886 #define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \
\r
1887 if (rle_z_count < 3) { \
\r
1888 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; \
\r
1889 } else if (rle_z_count <= 10) { \
\r
1890 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); \
\r
1892 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); \
\r
1893 } rle_z_count = 0; } }
\r
1895 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 };
\r
1897 static void tdefl_start_dynamic_block(tdefl_compressor *d)
\r
1899 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;
\r
1900 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;
\r
1902 d->m_huff_count[0][256] = 1;
\r
1904 tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
\r
1905 tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
\r
1907 for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break;
\r
1908 for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break;
\r
1910 memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
\r
1911 memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes);
\r
1912 total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0;
\r
1914 memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
\r
1915 for (i = 0; i < total_code_sizes_to_pack; i++)
\r
1917 mz_uint8 code_size = code_sizes_to_pack[i];
\r
1920 TDEFL_RLE_PREV_CODE_SIZE();
\r
1921 if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); }
\r
1925 TDEFL_RLE_ZERO_CODE_SIZE();
\r
1926 if (code_size != prev_code_size)
\r
1928 TDEFL_RLE_PREV_CODE_SIZE();
\r
1929 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;
\r
1931 else if (++rle_repeat_count == 6)
\r
1933 TDEFL_RLE_PREV_CODE_SIZE();
\r
1936 prev_code_size = code_size;
\r
1938 if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); }
\r
1940 tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
\r
1942 TDEFL_PUT_BITS(2, 2);
\r
1944 TDEFL_PUT_BITS(num_lit_codes - 257, 5);
\r
1945 TDEFL_PUT_BITS(num_dist_codes - 1, 5);
\r
1947 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;
\r
1948 num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
\r
1949 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);
\r
1951 for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; )
\r
1953 mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
\r
1954 TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
\r
1955 if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]);
\r
1959 static void tdefl_start_static_block(tdefl_compressor *d)
\r
1962 mz_uint8 *p = &d->m_huff_code_sizes[0][0];
\r
1964 for (i = 0; i <= 143; ++i) *p++ = 8;
\r
1965 for ( ; i <= 255; ++i) *p++ = 9;
\r
1966 for ( ; i <= 279; ++i) *p++ = 7;
\r
1967 for ( ; i <= 287; ++i) *p++ = 8;
\r
1969 memset(d->m_huff_code_sizes[1], 5, 32);
\r
1971 tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
\r
1972 tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
\r
1974 TDEFL_PUT_BITS(1, 2);
\r
1977 static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
\r
1979 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
\r
1980 static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
\r
1983 mz_uint8 *pLZ_codes;
\r
1984 mz_uint8 *pOutput_buf = d->m_pOutput_buf;
\r
1985 mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
\r
1986 mz_uint64 bit_buffer = d->m_bit_buffer;
\r
1987 mz_uint bits_in = d->m_bits_in;
\r
1989 #define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); }
\r
1992 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1)
\r
1995 flags = *pLZ_codes++ | 0x100;
\r
1999 mz_uint s0, s1, n0, n1, sym, num_extra_bits;
\r
2000 mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3;
\r
2002 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
\r
2003 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]]);
\r
2004 TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
\r
2006 // This sequence coaxes MSVC into using cmov's vs. jmp's.
\r
2007 s0 = s_tdefl_small_dist_sym[match_dist & 511];
\r
2008 n0 = s_tdefl_small_dist_extra[match_dist & 511];
\r
2009 s1 = s_tdefl_large_dist_sym[match_dist >> 8];
\r
2010 n1 = s_tdefl_large_dist_extra[match_dist >> 8];
\r
2011 sym = (match_dist < 512) ? s0 : s1;
\r
2012 num_extra_bits = (match_dist < 512) ? n0 : n1;
\r
2014 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
\r
2015 TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
\r
2016 TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
\r
2020 mz_uint lit = *pLZ_codes++;
\r
2021 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
\r
2022 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
\r
2024 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
\r
2027 lit = *pLZ_codes++;
\r
2028 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
\r
2029 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
\r
2031 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
\r
2034 lit = *pLZ_codes++;
\r
2035 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
\r
2036 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
\r
2041 if (pOutput_buf >= d->m_pOutput_buf_end)
\r
2044 *(mz_uint64*)pOutput_buf = bit_buffer;
\r
2045 pOutput_buf += (bits_in >> 3);
\r
2046 bit_buffer >>= (bits_in & ~7);
\r
2050 #undef TDEFL_PUT_BITS_FAST
\r
2052 d->m_pOutput_buf = pOutput_buf;
\r
2054 d->m_bit_buffer = 0;
\r
2058 mz_uint32 n = MZ_MIN(bits_in, 16);
\r
2059 TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
\r
2064 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
\r
2066 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
\r
2069 static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
\r
2072 mz_uint8 *pLZ_codes;
\r
2075 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1)
\r
2078 flags = *pLZ_codes++ | 0x100;
\r
2081 mz_uint sym, num_extra_bits;
\r
2082 mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3;
\r
2084 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
\r
2085 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]]);
\r
2086 TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
\r
2088 if (match_dist < 512)
\r
2090 sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist];
\r
2094 sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
\r
2096 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
\r
2097 TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
\r
2098 TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
\r
2102 mz_uint lit = *pLZ_codes++;
\r
2103 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
\r
2104 TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
\r
2108 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
\r
2110 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
\r
2112 #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
\r
2114 static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block)
\r
2117 tdefl_start_static_block(d);
\r
2119 tdefl_start_dynamic_block(d);
\r
2120 return tdefl_compress_lz_codes(d);
\r
2123 static int tdefl_flush_block(tdefl_compressor *d, int flush)
\r
2125 mz_uint saved_bit_buf, saved_bits_in;
\r
2126 mz_uint8 *pSaved_output_buf;
\r
2127 mz_bool comp_block_succeeded = MZ_FALSE;
\r
2128 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;
\r
2129 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;
\r
2131 d->m_pOutput_buf = pOutput_buf_start;
\r
2132 d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
\r
2134 MZ_ASSERT(!d->m_output_flush_remaining);
\r
2135 d->m_output_flush_ofs = 0;
\r
2136 d->m_output_flush_remaining = 0;
\r
2138 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
\r
2139 d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
\r
2141 if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index))
\r
2143 TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8);
\r
2146 TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
\r
2148 pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in;
\r
2150 if (!use_raw_block)
\r
2151 comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48));
\r
2153 // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead.
\r
2154 if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) &&
\r
2155 ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) )
\r
2157 mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
\r
2158 TDEFL_PUT_BITS(0, 2);
\r
2159 if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); }
\r
2160 for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF)
\r
2162 TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
\r
2164 for (i = 0; i < d->m_total_lz_bytes; ++i)
\r
2166 TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8);
\r
2169 // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes.
\r
2170 else if (!comp_block_succeeded)
\r
2172 d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
\r
2173 tdefl_compress_block(d, MZ_TRUE);
\r
2178 if (flush == TDEFL_FINISH)
\r
2180 if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); }
\r
2181 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; } }
\r
2185 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); }
\r
2189 MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
\r
2191 memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
\r
2192 memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
\r
2194 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++;
\r
2196 if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0)
\r
2198 if (d->m_pPut_buf_func)
\r
2200 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
\r
2201 if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
\r
2202 return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
\r
2204 else if (pOutput_buf_start == d->m_output_buf)
\r
2206 int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
\r
2207 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy);
\r
2208 d->m_out_buf_ofs += bytes_to_copy;
\r
2209 if ((n -= bytes_to_copy) != 0)
\r
2211 d->m_output_flush_ofs = bytes_to_copy;
\r
2212 d->m_output_flush_remaining = n;
\r
2217 d->m_out_buf_ofs += n;
\r
2221 return d->m_output_flush_remaining;
\r
2224 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
\r
2225 #define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p)
\r
2226 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)
\r
2228 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
\r
2229 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
\r
2230 const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q;
\r
2231 mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s);
\r
2232 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return;
\r
2237 if (--num_probes_left == 0) return;
\r
2238 #define TDEFL_PROBE \
\r
2239 next_probe_pos = d->m_next[probe_pos]; \
\r
2240 if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \
\r
2241 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
\r
2242 if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break;
\r
2243 TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE;
\r
2245 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;
\r
2246 do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
\r
2247 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) );
\r
2250 *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break;
\r
2252 else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len)
\r
2254 *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break;
\r
2255 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
\r
2260 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)
\r
2262 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
\r
2263 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
\r
2264 const mz_uint8 *s = d->m_dict + pos, *p, *q;
\r
2265 mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
\r
2266 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return;
\r
2271 if (--num_probes_left == 0) return;
\r
2272 #define TDEFL_PROBE \
\r
2273 next_probe_pos = d->m_next[probe_pos]; \
\r
2274 if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \
\r
2275 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
\r
2276 if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break;
\r
2277 TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE;
\r
2279 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;
\r
2280 if (probe_len > match_len)
\r
2282 *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return;
\r
2283 c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1];
\r
2287 #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
\r
2289 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
\r
2290 static mz_bool tdefl_compress_fast(tdefl_compressor *d)
\r
2292 // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio.
\r
2293 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;
\r
2294 mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
\r
2295 mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
\r
2297 while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size)))
\r
2299 const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
\r
2300 mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
\r
2301 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
\r
2302 d->m_src_buf_left -= num_bytes_to_process;
\r
2303 lookahead_size += num_bytes_to_process;
\r
2305 while (num_bytes_to_process)
\r
2307 mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
\r
2308 memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
\r
2309 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
\r
2310 memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
\r
2312 dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
\r
2313 num_bytes_to_process -= n;
\r
2316 dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
\r
2317 if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break;
\r
2319 while (lookahead_size >= 4)
\r
2321 mz_uint cur_match_dist, cur_match_len = 1;
\r
2322 mz_uint8 *pCur_dict = d->m_dict + cur_pos;
\r
2323 mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF;
\r
2324 mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK;
\r
2325 mz_uint probe_pos = d->m_hash[hash];
\r
2326 d->m_hash[hash] = (mz_uint16)lookahead_pos;
\r
2328 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))
\r
2330 const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
\r
2331 const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
\r
2332 mz_uint32 probe_len = 32;
\r
2333 do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
\r
2334 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) );
\r
2335 cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
\r
2337 cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
\r
2339 if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)))
\r
2341 cur_match_len = 1;
\r
2342 *pLZ_code_buf++ = (mz_uint8)first_trigram;
\r
2343 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
\r
2344 d->m_huff_count[0][(mz_uint8)first_trigram]++;
\r
2349 cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
\r
2351 MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
\r
2355 pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
\r
2356 *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
\r
2357 pLZ_code_buf += 3;
\r
2358 *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
\r
2360 s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
\r
2361 s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
\r
2362 d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
\r
2364 d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++;
\r
2369 *pLZ_code_buf++ = (mz_uint8)first_trigram;
\r
2370 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
\r
2371 d->m_huff_count[0][(mz_uint8)first_trigram]++;
\r
2374 if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; }
\r
2376 total_lz_bytes += cur_match_len;
\r
2377 lookahead_pos += cur_match_len;
\r
2378 dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE);
\r
2379 cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
\r
2380 MZ_ASSERT(lookahead_size >= cur_match_len);
\r
2381 lookahead_size -= cur_match_len;
\r
2383 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
\r
2386 d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
\r
2387 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;
\r
2388 if ((n = tdefl_flush_block(d, 0)) != 0)
\r
2389 return (n < 0) ? MZ_FALSE : MZ_TRUE;
\r
2390 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;
\r
2394 while (lookahead_size)
\r
2396 mz_uint8 lit = d->m_dict[cur_pos];
\r
2399 *pLZ_code_buf++ = lit;
\r
2400 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
\r
2401 if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; }
\r
2403 d->m_huff_count[0][lit]++;
\r
2406 dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE);
\r
2407 cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
\r
2410 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
\r
2413 d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
\r
2414 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;
\r
2415 if ((n = tdefl_flush_block(d, 0)) != 0)
\r
2416 return (n < 0) ? MZ_FALSE : MZ_TRUE;
\r
2417 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;
\r
2422 d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
\r
2423 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;
\r
2426 #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
\r
2428 static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit)
\r
2430 d->m_total_lz_bytes++;
\r
2431 *d->m_pLZ_code_buf++ = lit;
\r
2432 *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++; }
\r
2433 d->m_huff_count[0][lit]++;
\r
2436 static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist)
\r
2440 MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE));
\r
2442 d->m_total_lz_bytes += match_len;
\r
2444 d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
\r
2447 d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
\r
2448 d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3;
\r
2450 *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++; }
\r
2452 s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
\r
2453 d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
\r
2455 if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
\r
2458 static mz_bool tdefl_compress_normal(tdefl_compressor *d)
\r
2460 const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left;
\r
2461 tdefl_flush flush = d->m_flush;
\r
2463 while ((src_buf_left) || ((flush) && (d->m_lookahead_size)))
\r
2465 mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
\r
2466 // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN.
\r
2467 if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1))
\r
2469 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;
\r
2470 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];
\r
2471 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
\r
2472 const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
\r
2473 src_buf_left -= num_bytes_to_process;
\r
2474 d->m_lookahead_size += num_bytes_to_process;
\r
2475 while (pSrc != pSrc_end)
\r
2477 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;
\r
2478 hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
\r
2479 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos);
\r
2480 dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++;
\r
2485 while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
\r
2487 mz_uint8 c = *pSrc++;
\r
2488 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
\r
2490 d->m_dict[dst_pos] = c;
\r
2491 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
\r
2492 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
\r
2493 if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN)
\r
2495 mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
\r
2496 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);
\r
2497 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos);
\r
2501 d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
\r
2502 if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
\r
2505 // Simple lazy/greedy parsing state machine.
\r
2506 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;
\r
2507 if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS))
\r
2509 if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))
\r
2511 mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
\r
2512 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++; }
\r
2513 if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1;
\r
2518 tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len);
\r
2520 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)))
\r
2522 cur_match_dist = cur_match_len = 0;
\r
2524 if (d->m_saved_match_len)
\r
2526 if (cur_match_len > d->m_saved_match_len)
\r
2528 tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
\r
2529 if (cur_match_len >= 128)
\r
2531 tdefl_record_match(d, cur_match_len, cur_match_dist);
\r
2532 d->m_saved_match_len = 0; len_to_move = cur_match_len;
\r
2536 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;
\r
2541 tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
\r
2542 len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0;
\r
2545 else if (!cur_match_dist)
\r
2546 tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
\r
2547 else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128))
\r
2549 tdefl_record_match(d, cur_match_len, cur_match_dist);
\r
2550 len_to_move = cur_match_len;
\r
2554 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;
\r
2556 // Move the lookahead forward by len_to_move bytes.
\r
2557 d->m_lookahead_pos += len_to_move;
\r
2558 MZ_ASSERT(d->m_lookahead_size >= len_to_move);
\r
2559 d->m_lookahead_size -= len_to_move;
\r
2560 d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE);
\r
2561 // Check if it's time to flush the current LZ codes to the internal output buffer.
\r
2562 if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
\r
2563 ( (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))) )
\r
2566 d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left;
\r
2567 if ((n = tdefl_flush_block(d, 0)) != 0)
\r
2568 return (n < 0) ? MZ_FALSE : MZ_TRUE;
\r
2572 d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left;
\r
2576 static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d)
\r
2578 if (d->m_pIn_buf_size)
\r
2580 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
\r
2583 if (d->m_pOut_buf_size)
\r
2585 size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining);
\r
2586 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n);
\r
2587 d->m_output_flush_ofs += (mz_uint)n;
\r
2588 d->m_output_flush_remaining -= (mz_uint)n;
\r
2589 d->m_out_buf_ofs += n;
\r
2591 *d->m_pOut_buf_size = d->m_out_buf_ofs;
\r
2594 return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY;
\r
2597 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)
\r
2601 if (pIn_buf_size) *pIn_buf_size = 0;
\r
2602 if (pOut_buf_size) *pOut_buf_size = 0;
\r
2603 return TDEFL_STATUS_BAD_PARAM;
\r
2606 d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size;
\r
2607 d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size;
\r
2608 d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
\r
2609 d->m_out_buf_ofs = 0;
\r
2610 d->m_flush = flush;
\r
2612 if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
\r
2613 (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) )
\r
2615 if (pIn_buf_size) *pIn_buf_size = 0;
\r
2616 if (pOut_buf_size) *pOut_buf_size = 0;
\r
2617 return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
\r
2619 d->m_wants_to_finish |= (flush == TDEFL_FINISH);
\r
2621 if ((d->m_output_flush_remaining) || (d->m_finished))
\r
2622 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
\r
2624 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
\r
2625 if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
\r
2626 ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
\r
2627 ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0))
\r
2629 if (!tdefl_compress_fast(d))
\r
2630 return d->m_prev_return_status;
\r
2633 #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
\r
2635 if (!tdefl_compress_normal(d))
\r
2636 return d->m_prev_return_status;
\r
2639 if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf))
\r
2640 d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf);
\r
2642 if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining))
\r
2644 if (tdefl_flush_block(d, flush) < 0)
\r
2645 return d->m_prev_return_status;
\r
2646 d->m_finished = (flush == TDEFL_FINISH);
\r
2647 if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; }
\r
2650 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
\r
2653 tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush)
\r
2655 MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
\r
2658 tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
\r
2660 d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user;
\r
2661 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;
\r
2662 d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
\r
2663 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash);
\r
2664 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;
\r
2665 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;
\r
2666 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;
\r
2667 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;
\r
2668 d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1;
\r
2669 d->m_pIn_buf = NULL; d->m_pOut_buf = NULL;
\r
2670 d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL;
\r
2671 d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0;
\r
2672 memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
\r
2673 memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
\r
2674 return TDEFL_STATUS_OKAY;
\r
2677 tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d)
\r
2679 return d->m_prev_return_status;
\r
2682 mz_uint32 tdefl_get_adler32(tdefl_compressor *d)
\r
2684 return d->m_adler32;
\r
2687 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)
\r
2689 tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE;
\r
2690 pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE;
\r
2691 succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY);
\r
2692 succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE);
\r
2693 MZ_FREE(pComp); return succeeded;
\r
2698 size_t m_size, m_capacity;
\r
2700 mz_bool m_expandable;
\r
2701 } tdefl_output_buffer;
\r
2703 static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser)
\r
2705 tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
\r
2706 size_t new_size = p->m_size + len;
\r
2707 if (new_size > p->m_capacity)
\r
2709 size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE;
\r
2710 do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity);
\r
2711 pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE;
\r
2712 p->m_pBuf = pNew_buf; p->m_capacity = new_capacity;
\r
2714 memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size;
\r
2718 void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
\r
2720 tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf);
\r
2721 if (!pOut_len) return MZ_FALSE; else *pOut_len = 0;
\r
2722 out_buf.m_expandable = MZ_TRUE;
\r
2723 if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL;
\r
2724 *pOut_len = out_buf.m_size; return out_buf.m_pBuf;
\r
2727 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)
\r
2729 tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf);
\r
2730 if (!pOut_buf) return 0;
\r
2731 out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len;
\r
2732 if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0;
\r
2733 return out_buf.m_size;
\r
2736 #ifndef MINIZ_NO_ZLIB_APIS
\r
2737 static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };
\r
2739 // 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).
\r
2740 mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy)
\r
2742 mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
\r
2743 if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
\r
2745 if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
\r
2746 else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES;
\r
2747 else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK;
\r
2748 else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
\r
2749 else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES;
\r
2751 return comp_flags;
\r
2753 #endif //MINIZ_NO_ZLIB_APIS
\r
2756 #pragma warning (push)
\r
2757 #pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal)
\r
2760 // Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at
\r
2761 // http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
\r
2762 void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int bpl, int num_chans, size_t *pLen_out)
\r
2764 tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, y, z; mz_uint32 c; *pLen_out = 0;
\r
2765 if (!pComp) return NULL;
\r
2766 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; }
\r
2767 // write dummy header
\r
2768 for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf);
\r
2769 // compress image data
\r
2770 tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, TDEFL_DEFAULT_MAX_PROBES | TDEFL_WRITE_ZLIB_HEADER);
\r
2771 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); }
\r
2772 if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
\r
2773 // write real header
\r
2774 *pLen_out = out_buf.m_size-41;
\r
2776 mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
\r
2777 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,
\r
2778 (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54};
\r
2779 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);
\r
2780 memcpy(out_buf.m_pBuf, pnghdr, 41);
\r
2782 // write footer (IDAT CRC-32, followed by IEND chunk)
\r
2783 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; }
\r
2784 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);
\r
2785 // compute final size of file, grab compressed data buffer and return
\r
2786 *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf;
\r
2790 #pragma warning (pop)
\r
2793 // ------------------- .ZIP archive reading
\r
2795 #ifndef MINIZ_NO_ARCHIVE_APIS
\r
2797 #ifdef MINIZ_NO_STDIO
\r
2798 #define MZ_FILE void *
\r
2800 #include <stdio.h>
\r
2801 #include <sys/stat.h>
\r
2802 #if defined(_MSC_VER) || defined(__MINGW64__)
\r
2803 #include <sys/utime.h>
\r
2804 #define MZ_FILE FILE
\r
2805 #define MZ_FOPEN fopen
\r
2806 #define MZ_FCLOSE fclose
\r
2807 #define MZ_FREAD fread
\r
2808 #define MZ_FWRITE fwrite
\r
2809 #define MZ_FTELL64 _ftelli64
\r
2810 #define MZ_FSEEK64 _fseeki64
\r
2811 #define MZ_FILE_STAT_STRUCT _stat
\r
2812 #define MZ_FILE_STAT _stat
\r
2813 #define MZ_FFLUSH fflush
\r
2814 #define MZ_FREOPEN freopen
\r
2815 #define MZ_DELETE_FILE remove
\r
2816 #elif defined(__MINGW32__)
\r
2817 #include <sys/utime.h>
\r
2818 #define MZ_FILE FILE
\r
2819 #define MZ_FOPEN fopen
\r
2820 #define MZ_FCLOSE fclose
\r
2821 #define MZ_FREAD fread
\r
2822 #define MZ_FWRITE fwrite
\r
2823 #define MZ_FTELL64 ftello64
\r
2824 #define MZ_FSEEK64 fseeko64
\r
2825 #define MZ_FILE_STAT_STRUCT _stat
\r
2826 #define MZ_FILE_STAT _stat
\r
2827 #define MZ_FFLUSH fflush
\r
2828 #define MZ_FREOPEN freopen
\r
2829 #define MZ_DELETE_FILE remove
\r
2831 #include <utime.h>
\r
2832 #define MZ_FILE FILE
\r
2833 #define MZ_FOPEN fopen
\r
2834 #define MZ_FCLOSE fclose
\r
2835 #define MZ_FREAD fread
\r
2836 #define MZ_FWRITE fwrite
\r
2837 #define MZ_FTELL64 ftello
\r
2838 #define MZ_FSEEK64 fseeko
\r
2839 #define MZ_FILE_STAT_STRUCT stat
\r
2840 #define MZ_FILE_STAT stat
\r
2841 #define MZ_FFLUSH fflush
\r
2842 #define MZ_FREOPEN freopen
\r
2843 #define MZ_DELETE_FILE remove
\r
2844 #endif // #ifdef _MSC_VER
\r
2845 #endif // #ifdef MINIZ_NO_STDIO
\r
2847 #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
\r
2849 // 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.
\r
2852 // ZIP archive identifiers and record sizes
\r
2853 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
\r
2854 MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
\r
2855 // Central directory header record offsets
\r
2856 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,
\r
2857 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,
\r
2858 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,
\r
2859 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,
\r
2860 // Local directory header offsets
\r
2861 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,
\r
2862 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,
\r
2863 MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
\r
2864 // End of central directory offsets
\r
2865 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,
\r
2866 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,
\r
2872 size_t m_size, m_capacity;
\r
2873 mz_uint m_element_size;
\r
2876 struct mz_zip_internal_state_tag
\r
2878 mz_zip_array m_central_dir;
\r
2879 mz_zip_array m_central_dir_offsets;
\r
2880 mz_zip_array m_sorted_central_dir_offsets;
\r
2883 size_t m_mem_size;
\r
2884 size_t m_mem_capacity;
\r
2887 #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size
\r
2888 #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index]
\r
2890 static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)
\r
2892 pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
\r
2893 memset(pArray, 0, sizeof(mz_zip_array));
\r
2896 static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing)
\r
2898 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;
\r
2899 if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; }
\r
2900 if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE;
\r
2901 pArray->m_p = pNew_p; pArray->m_capacity = new_capacity;
\r
2905 static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing)
\r
2907 if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; }
\r
2911 static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)
\r
2913 if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; }
\r
2914 pArray->m_size = new_size;
\r
2918 static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n)
\r
2920 return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
\r
2923 static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n)
\r
2925 size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE;
\r
2926 memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size);
\r
2930 #ifndef MINIZ_NO_TIME
\r
2931 static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date)
\r
2934 memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1;
\r
2935 tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31;
\r
2936 tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62;
\r
2937 return mktime(&tm);
\r
2940 static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)
\r
2942 struct tm *tm = localtime(&time);
\r
2943 *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1));
\r
2944 *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday);
\r
2948 #ifndef MINIZ_NO_STDIO
\r
2949 static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)
\r
2951 #ifdef MINIZ_NO_TIME
\r
2952 (void)pFilename; *pDOS_date = *pDOS_time = 0;
\r
2954 struct MZ_FILE_STAT_STRUCT file_stat; if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE;
\r
2955 mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date);
\r
2956 #endif // #ifdef MINIZ_NO_TIME
\r
2960 static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time)
\r
2962 #ifndef MINIZ_NO_TIME
\r
2963 struct utimbuf t; t.actime = access_time; t.modtime = modified_time;
\r
2964 return !utime(pFilename, &t);
\r
2966 pFilename, access_time, modified_time;
\r
2968 #endif // #ifndef MINIZ_NO_TIME
\r
2972 static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags)
\r
2975 if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
\r
2978 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
\r
2979 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
\r
2980 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
\r
2982 pZip->m_zip_mode = MZ_ZIP_MODE_READING;
\r
2983 pZip->m_archive_size = 0;
\r
2984 pZip->m_central_directory_file_ofs = 0;
\r
2985 pZip->m_total_files = 0;
\r
2987 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
\r
2989 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
\r
2990 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
\r
2991 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
\r
2992 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
\r
2996 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)
\r
2998 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;
\r
2999 const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
\r
3000 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);
\r
3001 mz_uint8 l = 0, r = 0;
\r
3002 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
\r
3003 pE = pL + MZ_MIN(l_len, r_len);
\r
3006 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
\r
3010 return (pL == pE) ? (l_len < r_len) : (l < r);
\r
3013 #define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END
\r
3015 // 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.)
\r
3016 static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip)
\r
3018 mz_zip_internal_state *pState = pZip->m_pState;
\r
3019 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
\r
3020 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
\r
3021 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
\r
3022 const int size = pZip->m_total_files;
\r
3023 int start = (size - 2) >> 1, end;
\r
3024 while (start >= 0)
\r
3026 int child, root = start;
\r
3029 if ((child = (root << 1) + 1) >= size)
\r
3031 child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])));
\r
3032 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
\r
3034 MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child;
\r
3042 int child, root = 0;
\r
3043 MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
\r
3046 if ((child = (root << 1) + 1) >= end)
\r
3048 child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]));
\r
3049 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
\r
3051 MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child;
\r
3057 static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags)
\r
3059 mz_uint cdir_size, num_this_disk, cdir_disk_index;
\r
3060 mz_uint64 cdir_ofs;
\r
3061 mz_int64 cur_file_ofs;
\r
3062 const mz_uint8 *p;
\r
3063 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
\r
3064 // 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.
\r
3065 if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
\r
3067 // Find the end of central directory record by scanning the file from the end towards the beginning.
\r
3068 cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
\r
3071 int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
\r
3072 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
\r
3074 for (i = n - 4; i >= 0; --i)
\r
3075 if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
\r
3079 cur_file_ofs += i;
\r
3082 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
\r
3084 cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
\r
3086 // Read and verify the end of central directory record.
\r
3087 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)
\r
3089 if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
\r
3090 ((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)))
\r
3093 num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
\r
3094 cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
\r
3095 if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1)))
\r
3098 if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
\r
3101 cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
\r
3102 if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
\r
3105 pZip->m_central_directory_file_ofs = cdir_ofs;
\r
3107 if (pZip->m_total_files)
\r
3110 // 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.
\r
3111 if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) ||
\r
3112 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) ||
\r
3113 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)))
\r
3115 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size)
\r
3118 // 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).
\r
3119 p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
\r
3120 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i)
\r
3122 mz_uint total_header_size, comp_size, decomp_size, disk_index;
\r
3123 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
\r
3125 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);
\r
3126 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i;
\r
3127 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
\r
3128 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
\r
3129 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF))
\r
3131 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
\r
3132 if ((disk_index != num_this_disk) && (disk_index != 1))
\r
3134 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)
\r
3136 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)
\r
3138 n -= total_header_size; p += total_header_size;
\r
3142 if ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0)
\r
3143 mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
\r
3148 mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags)
\r
3150 if ((!pZip) || (!pZip->m_pRead))
\r
3152 if (!mz_zip_reader_init_internal(pZip, flags))
\r
3154 pZip->m_archive_size = size;
\r
3155 if (!mz_zip_reader_read_central_dir(pZip, flags))
\r
3157 mz_zip_reader_end(pZip);
\r
3163 static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
\r
3165 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
\r
3166 size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
\r
3167 memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
\r
3171 mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags)
\r
3173 if (!mz_zip_reader_init_internal(pZip, flags))
\r
3175 pZip->m_archive_size = size;
\r
3176 pZip->m_pRead = mz_zip_mem_read_func;
\r
3177 pZip->m_pIO_opaque = pZip;
\r
3178 pZip->m_pState->m_pMem = (void *)pMem;
\r
3179 pZip->m_pState->m_mem_size = size;
\r
3180 if (!mz_zip_reader_read_central_dir(pZip, flags))
\r
3182 mz_zip_reader_end(pZip);
\r
3188 #ifndef MINIZ_NO_STDIO
\r
3189 static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
\r
3191 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
\r
3192 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
\r
3193 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))))
\r
3195 return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
\r
3198 mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags)
\r
3200 mz_uint64 file_size;
\r
3201 MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb");
\r
3204 if (MZ_FSEEK64(pFile, 0, SEEK_END))
\r
3206 file_size = MZ_FTELL64(pFile);
\r
3207 if (!mz_zip_reader_init_internal(pZip, flags))
\r
3212 pZip->m_pRead = mz_zip_file_read_func;
\r
3213 pZip->m_pIO_opaque = pZip;
\r
3214 pZip->m_pState->m_pFile = pFile;
\r
3215 pZip->m_archive_size = file_size;
\r
3216 if (!mz_zip_reader_read_central_dir(pZip, flags))
\r
3218 mz_zip_reader_end(pZip);
\r
3223 #endif // #ifndef MINIZ_NO_STDIO
\r
3225 mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip)
\r
3227 return pZip ? pZip->m_total_files : 0;
\r
3230 static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index)
\r
3232 if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
\r
3234 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));
\r
3237 mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index)
\r
3239 mz_uint m_bit_flag;
\r
3240 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
\r
3243 m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
\r
3244 return (m_bit_flag & 1);
\r
3247 mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index)
\r
3249 mz_uint filename_len, internal_attr, external_attr;
\r
3250 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
\r
3254 internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
\r
3255 external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
\r
3256 if ((!internal_attr) && ((external_attr & 0x10) != 0))
\r
3259 filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
\r
3262 if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
\r
3269 mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat)
\r
3272 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
\r
3273 if ((!p) || (!pStat))
\r
3276 // Unpack the central directory record.
\r
3277 pStat->m_file_index = file_index;
\r
3278 pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
\r
3279 pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
\r
3280 pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
\r
3281 pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
\r
3282 pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
\r
3283 #ifndef MINIZ_NO_TIME
\r
3284 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));
\r
3286 pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
\r
3287 pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
\r
3288 pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
\r
3289 pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
\r
3290 pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
\r
3291 pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
\r
3293 // Copy as much of the filename and comment as possible.
\r
3294 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
\r
3295 memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0';
\r
3297 n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
\r
3298 pStat->m_comment_size = n;
\r
3299 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';
\r
3304 mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size)
\r
3307 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
\r
3308 if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; }
\r
3309 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
\r
3310 if (filename_buf_size)
\r
3312 n = MZ_MIN(n, filename_buf_size - 1);
\r
3313 memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
\r
3314 pFilename[n] = '\0';
\r
3319 static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags)
\r
3322 if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE)
\r
3323 return 0 == memcmp(pA, pB, len);
\r
3324 for (i = 0; i < len; ++i)
\r
3325 if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i]))
\r
3330 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)
\r
3332 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;
\r
3333 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
\r
3334 mz_uint8 l = 0, r = 0;
\r
3335 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
\r
3336 pE = pL + MZ_MIN(l_len, r_len);
\r
3339 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
\r
3343 return (pL == pE) ? (int)(l_len - r_len) : (l - r);
\r
3346 static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename)
\r
3348 mz_zip_internal_state *pState = pZip->m_pState;
\r
3349 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
\r
3350 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
\r
3351 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
\r
3352 const int size = pZip->m_total_files;
\r
3353 const mz_uint filename_len = (mz_uint)strlen(pFilename);
\r
3354 int l = 0, h = size - 1;
\r
3357 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);
\r
3359 return file_index;
\r
3360 else if (comp < 0)
\r
3368 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags)
\r
3370 mz_uint file_index; size_t name_len, comment_len;
\r
3371 if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
\r
3373 if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_p))
\r
3374 return mz_zip_reader_locate_file_binary_search(pZip, pName);
\r
3375 name_len = strlen(pName); if (name_len > 0xFFFF) return -1;
\r
3376 comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1;
\r
3377 for (file_index = 0; file_index < pZip->m_total_files; file_index++)
\r
3379 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));
\r
3380 mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
\r
3381 const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
\r
3382 if (filename_len < name_len)
\r
3386 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);
\r
3387 const char *pFile_comment = pFilename + filename_len + file_extra_len;
\r
3388 if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags)))
\r
3391 if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len))
\r
3393 int ofs = filename_len - 1;
\r
3396 if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':'))
\r
3398 } while (--ofs >= 0);
\r
3400 pFilename += ofs; filename_len -= ofs;
\r
3402 if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags)))
\r
3403 return file_index;
\r
3408 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)
\r
3410 int status = TINFL_STATUS_DONE;
\r
3411 mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
\r
3412 mz_zip_archive_file_stat file_stat;
\r
3414 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;
\r
3415 tinfl_decompressor inflator;
\r
3417 if ((buf_size) && (!pBuf))
\r
3420 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
\r
3423 if (!file_stat.m_comp_size)
\r
3426 // Encryption and patch files are not supported.
\r
3427 if (file_stat.m_bit_flag & (1 | 32))
\r
3430 // This function only supports stored and deflate.
\r
3431 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
\r
3434 // Ensure supplied output buffer is large enough.
\r
3435 needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size;
\r
3436 if (buf_size < needed_size)
\r
3439 // Read and parse the local directory entry.
\r
3440 cur_file_ofs = file_stat.m_local_header_ofs;
\r
3441 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)
\r
3443 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
\r
3446 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);
\r
3447 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
\r
3450 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
\r
3452 // The file is stored or the caller has requested the compressed data.
\r
3453 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size)
\r
3455 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);
\r
3458 // Decompress the file either directly from memory or from a file input buffer.
\r
3459 tinfl_init(&inflator);
\r
3461 if (pZip->m_pState->m_pMem)
\r
3463 // Read directly from the archive in memory.
\r
3464 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
\r
3465 read_buf_size = read_buf_avail = file_stat.m_comp_size;
\r
3466 comp_remaining = 0;
\r
3468 else if (pUser_read_buf)
\r
3470 // Use a user provided read buffer.
\r
3471 if (!user_read_buf_size)
\r
3473 pRead_buf = (mz_uint8 *)pUser_read_buf;
\r
3474 read_buf_size = user_read_buf_size;
\r
3475 read_buf_avail = 0;
\r
3476 comp_remaining = file_stat.m_uncomp_size;
\r
3480 // Temporarily allocate a read buffer.
\r
3481 read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);
\r
3483 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
\r
3485 if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
\r
3488 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
\r
3490 read_buf_avail = 0;
\r
3491 comp_remaining = file_stat.m_comp_size;
\r
3496 size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
\r
3497 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
\r
3499 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
\r
3500 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
\r
3502 status = TINFL_STATUS_FAILED;
\r
3505 cur_file_ofs += read_buf_avail;
\r
3506 comp_remaining -= read_buf_avail;
\r
3509 in_buf_size = (size_t)read_buf_avail;
\r
3510 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));
\r
3511 read_buf_avail -= in_buf_size;
\r
3512 read_buf_ofs += in_buf_size;
\r
3513 out_buf_ofs += out_buf_size;
\r
3514 } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
\r
3516 if (status == TINFL_STATUS_DONE)
\r
3518 // Make sure the entire file was decompressed, and check its CRC.
\r
3519 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))
\r
3520 status = TINFL_STATUS_FAILED;
\r
3523 if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
\r
3524 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
\r
3526 return status == TINFL_STATUS_DONE;
\r
3529 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)
\r
3531 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
\r
3532 if (file_index < 0)
\r
3534 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size);
\r
3537 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)
\r
3539 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0);
\r
3542 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)
\r
3544 return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0);
\r
3547 void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags)
\r
3549 mz_uint64 comp_size, uncomp_size, alloc_size;
\r
3550 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
\r
3558 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
\r
3559 uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
\r
3561 alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
\r
3563 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
\r
3565 if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
\r
3568 if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))
\r
3571 if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags))
\r
3573 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
\r
3577 if (pSize) *pSize = (size_t)alloc_size;
\r
3581 void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags)
\r
3583 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
\r
3584 if (file_index < 0)
\r
3586 if (pSize) *pSize = 0;
\r
3589 return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
\r
3592 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)
\r
3594 int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT;
\r
3595 mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs;
\r
3596 mz_zip_archive_file_stat file_stat;
\r
3597 void *pRead_buf = NULL; void *pWrite_buf = NULL;
\r
3598 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;
\r
3600 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
\r
3603 if (!file_stat.m_comp_size)
\r
3606 // Encryption and patch files are not supported.
\r
3607 if (file_stat.m_bit_flag & (1 | 32))
\r
3610 // This function only supports stored and deflate.
\r
3611 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
\r
3614 // Read and parse the local directory entry.
\r
3615 cur_file_ofs = file_stat.m_local_header_ofs;
\r
3616 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)
\r
3618 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
\r
3621 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);
\r
3622 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
\r
3625 // Decompress the file either directly from memory or from a file input buffer.
\r
3626 if (pZip->m_pState->m_pMem)
\r
3628 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
\r
3629 read_buf_size = read_buf_avail = file_stat.m_comp_size;
\r
3630 comp_remaining = 0;
\r
3634 read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);
\r
3635 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
\r
3637 read_buf_avail = 0;
\r
3638 comp_remaining = file_stat.m_comp_size;
\r
3641 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
\r
3643 // The file is stored or the caller has requested the compressed data.
\r
3644 if (pZip->m_pState->m_pMem)
\r
3647 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF))
\r
3649 if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF))
\r
3652 if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)
\r
3653 status = TINFL_STATUS_FAILED;
\r
3654 else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
\r
3655 file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size);
\r
3656 cur_file_ofs += file_stat.m_comp_size;
\r
3657 out_buf_ofs += file_stat.m_comp_size;
\r
3658 comp_remaining = 0;
\r
3662 while (comp_remaining)
\r
3664 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
\r
3665 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
\r
3667 status = TINFL_STATUS_FAILED;
\r
3671 if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
\r
3672 file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
\r
3674 if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
\r
3676 status = TINFL_STATUS_FAILED;
\r
3679 cur_file_ofs += read_buf_avail;
\r
3680 out_buf_ofs += read_buf_avail;
\r
3681 comp_remaining -= read_buf_avail;
\r
3687 tinfl_decompressor inflator;
\r
3688 tinfl_init(&inflator);
\r
3690 if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE)))
\r
3691 status = TINFL_STATUS_FAILED;
\r
3696 mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
\r
3697 size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
\r
3698 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
\r
3700 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
\r
3701 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
\r
3703 status = TINFL_STATUS_FAILED;
\r
3706 cur_file_ofs += read_buf_avail;
\r
3707 comp_remaining -= read_buf_avail;
\r
3711 in_buf_size = (size_t)read_buf_avail;
\r
3712 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);
\r
3713 read_buf_avail -= in_buf_size;
\r
3714 read_buf_ofs += in_buf_size;
\r
3718 if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size)
\r
3720 status = TINFL_STATUS_FAILED;
\r
3723 file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
\r
3724 if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size)
\r
3726 status = TINFL_STATUS_FAILED;
\r
3730 } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT));
\r
3734 if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
\r
3736 // Make sure the entire file was decompressed, and check its CRC.
\r
3737 if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32))
\r
3738 status = TINFL_STATUS_FAILED;
\r
3741 if (!pZip->m_pState->m_pMem)
\r
3742 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
\r
3744 pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
\r
3746 return status == TINFL_STATUS_DONE;
\r
3749 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)
\r
3751 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
\r
3752 if (file_index < 0)
\r
3754 return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags);
\r
3757 #ifndef MINIZ_NO_STDIO
\r
3758 static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n)
\r
3760 (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque);
\r
3763 mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags)
\r
3766 mz_zip_archive_file_stat file_stat;
\r
3768 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
\r
3770 pFile = MZ_FOPEN(pDst_filename, "wb");
\r
3773 status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);
\r
3774 if (MZ_FCLOSE(pFile) == EOF)
\r
3776 #ifndef MINIZ_NO_TIME
\r
3778 mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
\r
3782 #endif // #ifndef MINIZ_NO_STDIO
\r
3784 mz_bool mz_zip_reader_end(mz_zip_archive *pZip)
\r
3786 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
\r
3789 if (pZip->m_pState)
\r
3791 mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL;
\r
3792 mz_zip_array_clear(pZip, &pState->m_central_dir);
\r
3793 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
\r
3794 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
\r
3796 #ifndef MINIZ_NO_STDIO
\r
3797 if (pState->m_pFile)
\r
3799 MZ_FCLOSE(pState->m_pFile);
\r
3800 pState->m_pFile = NULL;
\r
3802 #endif // #ifndef MINIZ_NO_STDIO
\r
3804 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
\r
3806 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
\r
3811 #ifndef MINIZ_NO_STDIO
\r
3812 mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags)
\r
3814 int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags);
\r
3815 if (file_index < 0)
\r
3817 return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
\r
3821 // ------------------- .ZIP archive writing
\r
3823 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
\r
3825 static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); }
\r
3826 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); }
\r
3827 #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
\r
3828 #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
\r
3830 mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size)
\r
3832 if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
\r
3835 if (pZip->m_file_offset_alignment)
\r
3837 // Ensure user specified file offset alignment is a power of 2.
\r
3838 if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
\r
3842 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
\r
3843 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
\r
3844 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
\r
3846 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
\r
3847 pZip->m_archive_size = existing_size;
\r
3848 pZip->m_central_directory_file_ofs = 0;
\r
3849 pZip->m_total_files = 0;
\r
3851 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
\r
3853 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
\r
3854 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
\r
3855 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
\r
3856 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
\r
3860 static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
\r
3862 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
\r
3863 mz_zip_internal_state *pState = pZip->m_pState;
\r
3864 mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
\r
3866 if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
\r
3868 if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
\r
3871 if (new_size > pState->m_mem_capacity)
\r
3874 size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2;
\r
3875 if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))
\r
3877 pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity;
\r
3879 memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
\r
3880 pState->m_mem_size = (size_t)new_size;
\r
3884 mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size)
\r
3886 pZip->m_pWrite = mz_zip_heap_write_func;
\r
3887 pZip->m_pIO_opaque = pZip;
\r
3888 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning))
\r
3890 if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning)))
\r
3892 if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size)))
\r
3894 mz_zip_writer_end(pZip);
\r
3897 pZip->m_pState->m_mem_capacity = initial_allocation_size;
\r
3902 #ifndef MINIZ_NO_STDIO
\r
3903 static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
\r
3905 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
\r
3906 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
\r
3907 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))))
\r
3909 return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
\r
3912 mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning)
\r
3915 pZip->m_pWrite = mz_zip_file_write_func;
\r
3916 pZip->m_pIO_opaque = pZip;
\r
3917 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning))
\r
3919 if (NULL == (pFile = MZ_FOPEN(pFilename, "wb")))
\r
3921 mz_zip_writer_end(pZip);
\r
3924 pZip->m_pState->m_pFile = pFile;
\r
3925 if (size_to_reserve_at_beginning)
\r
3927 mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf);
\r
3930 size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
\r
3931 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n)
\r
3933 mz_zip_writer_end(pZip);
\r
3936 cur_ofs += n; size_to_reserve_at_beginning -= n;
\r
3937 } while (size_to_reserve_at_beginning);
\r
3941 #endif // #ifndef MINIZ_NO_STDIO
\r
3943 mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename)
\r
3945 mz_zip_internal_state *pState;
\r
3946 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
\r
3948 // No sense in trying to write to an archive that's already at the support max size
\r
3949 if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
\r
3952 pState = pZip->m_pState;
\r
3954 if (pState->m_pFile)
\r
3956 #ifdef MINIZ_NO_STDIO
\r
3957 pFilename; return MZ_FALSE;
\r
3959 // Archive is being read from stdio - try to reopen as writable.
\r
3960 if (pZip->m_pIO_opaque != pZip)
\r
3964 pZip->m_pWrite = mz_zip_file_write_func;
\r
3965 if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile)))
\r
3967 // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it.
\r
3968 mz_zip_reader_end(pZip);
\r
3971 #endif // #ifdef MINIZ_NO_STDIO
\r
3973 else if (pState->m_pMem)
\r
3975 // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback.
\r
3976 if (pZip->m_pIO_opaque != pZip)
\r
3978 pState->m_mem_capacity = pState->m_mem_size;
\r
3979 pZip->m_pWrite = mz_zip_heap_write_func;
\r
3981 // Archive is being read via a user provided read function - make sure the user has specified a write function too.
\r
3982 else if (!pZip->m_pWrite)
\r
3985 // Start writing new files at the archive's current central directory location.
\r
3986 pZip->m_archive_size = pZip->m_central_directory_file_ofs;
\r
3987 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
\r
3988 pZip->m_central_directory_file_ofs = 0;
\r
3993 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)
\r
3995 return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0);
\r
4000 mz_zip_archive *m_pZip;
\r
4001 mz_uint64 m_cur_archive_file_ofs;
\r
4002 mz_uint64 m_comp_size;
\r
4003 } mz_zip_writer_add_state;
\r
4005 static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser)
\r
4007 mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
\r
4008 if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len)
\r
4010 pState->m_cur_archive_file_ofs += len;
\r
4011 pState->m_comp_size += len;
\r
4015 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)
\r
4018 memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
\r
4019 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
\r
4020 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
\r
4021 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
\r
4022 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
\r
4023 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
\r
4024 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
\r
4025 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
\r
4026 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size);
\r
4027 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
\r
4028 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
\r
4029 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
\r
4033 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)
\r
4036 memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
\r
4037 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
\r
4038 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
\r
4039 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
\r
4040 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
\r
4041 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
\r
4042 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
\r
4043 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
\r
4044 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size);
\r
4045 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
\r
4046 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
\r
4047 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
\r
4048 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
\r
4049 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
\r
4050 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs);
\r
4054 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)
\r
4056 mz_zip_internal_state *pState = pZip->m_pState;
\r
4057 mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
\r
4058 size_t orig_central_dir_size = pState->m_central_dir.m_size;
\r
4059 mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
\r
4061 // No zip64 support yet
\r
4062 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))
\r
4065 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))
\r
4068 if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
\r
4069 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) ||
\r
4070 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) ||
\r
4071 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) ||
\r
4072 (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1)))
\r
4074 // Try to push the central directory array back into its original state.
\r
4075 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
\r
4082 static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name)
\r
4084 // 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.
\r
4085 if (*pArchive_name == '/')
\r
4087 while (*pArchive_name)
\r
4089 if ((*pArchive_name == '\\') || (*pArchive_name == ':'))
\r
4096 static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip)
\r
4099 if (!pZip->m_file_offset_alignment)
\r
4101 n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
\r
4102 return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1);
\r
4105 static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n)
\r
4108 memset(buf, 0, MZ_MIN(sizeof(buf), n));
\r
4111 mz_uint32 s = MZ_MIN(sizeof(buf), n);
\r
4112 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
\r
4114 cur_file_ofs += s; n -= s;
\r
4119 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)
\r
4121 mz_uint16 method = 0, dos_time = 0, dos_date = 0;
\r
4122 mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
\r
4123 mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
\r
4124 size_t archive_name_size;
\r
4125 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
\r
4126 tdefl_compressor *pComp = NULL;
\r
4127 mz_bool store_data_uncompressed;
\r
4128 mz_zip_internal_state *pState;
\r
4130 if ((int)level_and_flags < 0)
\r
4131 level_and_flags = MZ_DEFAULT_LEVEL;
\r
4132 level = level_and_flags & 0xF;
\r
4133 store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
\r
4135 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))
\r
4138 pState = pZip->m_pState;
\r
4140 if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
\r
4142 // No zip64 support yet
\r
4143 if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF))
\r
4145 if (!mz_zip_writer_validate_archive_name(pArchive_name))
\r
4148 #ifndef MINIZ_NO_TIME
\r
4150 time_t cur_time; time(&cur_time);
\r
4151 mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date);
\r
4153 #endif // #ifndef MINIZ_NO_TIME
\r
4155 archive_name_size = strlen(pArchive_name);
\r
4156 if (archive_name_size > 0xFFFF)
\r
4159 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
\r
4161 // no zip64 support yet
\r
4162 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))
\r
4165 if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/'))
\r
4167 // Set DOS Subdirectory attribute bit.
\r
4168 ext_attributes |= 0x10;
\r
4169 // Subdirectories cannot contain data.
\r
4170 if ((buf_size) || (uncomp_size))
\r
4174 // 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.)
\r
4175 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)))
\r
4178 if ((!store_data_uncompressed) && (buf_size))
\r
4180 if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
\r
4184 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header)))
\r
4186 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
\r
4189 local_dir_header_ofs += num_alignment_padding_bytes;
\r
4190 if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
\r
4191 cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header);
\r
4193 MZ_CLEAR_OBJ(local_dir_header);
\r
4194 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
\r
4196 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
\r
4199 cur_archive_file_ofs += archive_name_size;
\r
4201 if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
\r
4203 uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size);
\r
4204 uncomp_size = buf_size;
\r
4205 if (uncomp_size <= 3)
\r
4208 store_data_uncompressed = MZ_TRUE;
\r
4212 if (store_data_uncompressed)
\r
4214 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size)
\r
4216 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
\r
4220 cur_archive_file_ofs += buf_size;
\r
4221 comp_size = buf_size;
\r
4223 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
\r
4224 method = MZ_DEFLATED;
\r
4226 else if (buf_size)
\r
4228 mz_zip_writer_add_state state;
\r
4230 state.m_pZip = pZip;
\r
4231 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
\r
4232 state.m_comp_size = 0;
\r
4234 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) ||
\r
4235 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE))
\r
4237 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
\r
4241 comp_size = state.m_comp_size;
\r
4242 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
\r
4244 method = MZ_DEFLATED;
\r
4247 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
\r
4250 // no zip64 support yet
\r
4251 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
\r
4254 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))
\r
4257 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
\r
4260 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))
\r
4263 pZip->m_total_files++;
\r
4264 pZip->m_archive_size = cur_archive_file_ofs;
\r
4269 #ifndef MINIZ_NO_STDIO
\r
4270 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)
\r
4272 mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
\r
4273 mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
\r
4274 mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0;
\r
4275 size_t archive_name_size;
\r
4276 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
\r
4277 MZ_FILE *pSrc_file = NULL;
\r
4279 if ((int)level_and_flags < 0)
\r
4280 level_and_flags = MZ_DEFAULT_LEVEL;
\r
4281 level = level_and_flags & 0xF;
\r
4283 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
\r
4285 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
\r
4287 if (!mz_zip_writer_validate_archive_name(pArchive_name))
\r
4290 archive_name_size = strlen(pArchive_name);
\r
4291 if (archive_name_size > 0xFFFF)
\r
4294 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
\r
4296 // no zip64 support yet
\r
4297 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))
\r
4300 if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date))
\r
4303 pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
\r
4306 MZ_FSEEK64(pSrc_file, 0, SEEK_END);
\r
4307 uncomp_size = MZ_FTELL64(pSrc_file);
\r
4308 MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
\r
4310 if (uncomp_size > 0xFFFFFFFF)
\r
4312 // No zip64 support yet
\r
4313 MZ_FCLOSE(pSrc_file);
\r
4316 if (uncomp_size <= 3)
\r
4319 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header)))
\r
4321 local_dir_header_ofs += num_alignment_padding_bytes;
\r
4322 if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
\r
4323 cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header);
\r
4325 MZ_CLEAR_OBJ(local_dir_header);
\r
4326 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
\r
4328 MZ_FCLOSE(pSrc_file);
\r
4331 cur_archive_file_ofs += archive_name_size;
\r
4335 mz_uint64 uncomp_remaining = uncomp_size;
\r
4336 void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
\r
4339 MZ_FCLOSE(pSrc_file);
\r
4345 while (uncomp_remaining)
\r
4347 mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
\r
4348 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))
\r
4350 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
\r
4351 MZ_FCLOSE(pSrc_file);
\r
4354 uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
\r
4355 uncomp_remaining -= n;
\r
4356 cur_archive_file_ofs += n;
\r
4358 comp_size = uncomp_size;
\r
4362 mz_bool result = MZ_FALSE;
\r
4363 mz_zip_writer_add_state state;
\r
4364 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
\r
4367 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
\r
4368 MZ_FCLOSE(pSrc_file);
\r
4372 state.m_pZip = pZip;
\r
4373 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
\r
4374 state.m_comp_size = 0;
\r
4376 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)
\r
4378 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
\r
4379 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
\r
4380 MZ_FCLOSE(pSrc_file);
\r
4386 size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE);
\r
4387 tdefl_status status;
\r
4389 if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size)
\r
4392 uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
\r
4393 uncomp_remaining -= in_buf_size;
\r
4395 status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH);
\r
4396 if (status == TDEFL_STATUS_DONE)
\r
4401 else if (status != TDEFL_STATUS_OKAY)
\r
4405 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
\r
4409 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
\r
4410 MZ_FCLOSE(pSrc_file);
\r
4414 comp_size = state.m_comp_size;
\r
4415 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
\r
4417 method = MZ_DEFLATED;
\r
4420 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
\r
4423 MZ_FCLOSE(pSrc_file); pSrc_file = NULL;
\r
4425 // no zip64 support yet
\r
4426 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
\r
4429 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))
\r
4432 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
\r
4435 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))
\r
4438 pZip->m_total_files++;
\r
4439 pZip->m_archive_size = cur_archive_file_ofs;
\r
4443 #endif // #ifndef MINIZ_NO_STDIO
\r
4445 mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index)
\r
4447 mz_uint n, bit_flags, num_alignment_padding_bytes;
\r
4448 mz_uint64 comp_bytes_remaining, local_dir_header_ofs;
\r
4449 mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
\r
4450 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;
\r
4451 mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
\r
4452 size_t orig_central_dir_size;
\r
4453 mz_zip_internal_state *pState;
\r
4454 void *pBuf; const mz_uint8 *pSrc_central_header;
\r
4456 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
\r
4458 if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index)))
\r
4460 pState = pZip->m_pState;
\r
4462 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
\r
4464 // no zip64 support yet
\r
4465 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))
\r
4468 cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
\r
4469 cur_dst_file_ofs = pZip->m_archive_size;
\r
4471 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)
\r
4473 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
\r
4475 cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
\r
4477 if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes))
\r
4479 cur_dst_file_ofs += num_alignment_padding_bytes;
\r
4480 local_dir_header_ofs = cur_dst_file_ofs;
\r
4481 if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
\r
4483 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)
\r
4485 cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
\r
4487 n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
\r
4488 comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
\r
4490 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)))))
\r
4493 while (comp_bytes_remaining)
\r
4495 n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining);
\r
4496 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n)
\r
4498 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
\r
4501 cur_src_file_ofs += n;
\r
4503 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
\r
4505 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
\r
4508 cur_dst_file_ofs += n;
\r
4510 comp_bytes_remaining -= n;
\r
4513 bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
\r
4514 if (bit_flags & 8)
\r
4516 // Copy data descriptor
\r
4517 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4)
\r
4519 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
\r
4523 n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3);
\r
4524 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
\r
4526 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
\r
4530 cur_src_file_ofs += n;
\r
4531 cur_dst_file_ofs += n;
\r
4533 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
\r
4535 // no zip64 support yet
\r
4536 if (cur_dst_file_ofs > 0xFFFFFFFF)
\r
4539 orig_central_dir_size = pState->m_central_dir.m_size;
\r
4541 memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
\r
4542 MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs);
\r
4543 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
\r
4546 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);
\r
4547 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n))
\r
4549 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
\r
4553 if (pState->m_central_dir.m_size > 0xFFFFFFFF)
\r
4555 n = (mz_uint32)pState->m_central_dir.m_size;
\r
4556 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1))
\r
4558 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
\r
4562 pZip->m_total_files++;
\r
4563 pZip->m_archive_size = cur_dst_file_ofs;
\r
4568 mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip)
\r
4570 mz_zip_internal_state *pState;
\r
4571 mz_uint64 central_dir_ofs, central_dir_size;
\r
4572 mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE];
\r
4574 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
\r
4577 pState = pZip->m_pState;
\r
4579 // no zip64 support yet
\r
4580 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))
\r
4583 central_dir_ofs = 0;
\r
4584 central_dir_size = 0;
\r
4585 if (pZip->m_total_files)
\r
4587 // Write central directory
\r
4588 central_dir_ofs = pZip->m_archive_size;
\r
4589 central_dir_size = pState->m_central_dir.m_size;
\r
4590 pZip->m_central_directory_file_ofs = central_dir_ofs;
\r
4591 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)
\r
4593 pZip->m_archive_size += central_dir_size;
\r
4596 // Write end of central directory record
\r
4597 MZ_CLEAR_OBJ(hdr);
\r
4598 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
\r
4599 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files);
\r
4600 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
\r
4601 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size);
\r
4602 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs);
\r
4604 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr))
\r
4606 #ifndef MINIZ_NO_STDIO
\r
4607 if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))
\r
4609 #endif // #ifndef MINIZ_NO_STDIO
\r
4611 pZip->m_archive_size += sizeof(hdr);
\r
4613 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
\r
4617 mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize)
\r
4619 if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize))
\r
4621 if (pZip->m_pWrite != mz_zip_heap_write_func)
\r
4623 if (!mz_zip_writer_finalize_archive(pZip))
\r
4626 *pBuf = pZip->m_pState->m_pMem;
\r
4627 *pSize = pZip->m_pState->m_mem_size;
\r
4628 pZip->m_pState->m_pMem = NULL;
\r
4629 pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
\r
4633 mz_bool mz_zip_writer_end(mz_zip_archive *pZip)
\r
4635 mz_zip_internal_state *pState;
\r
4636 mz_bool status = MZ_TRUE;
\r
4637 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)))
\r
4640 pState = pZip->m_pState;
\r
4641 pZip->m_pState = NULL;
\r
4642 mz_zip_array_clear(pZip, &pState->m_central_dir);
\r
4643 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
\r
4644 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
\r
4646 #ifndef MINIZ_NO_STDIO
\r
4647 if (pState->m_pFile)
\r
4649 MZ_FCLOSE(pState->m_pFile);
\r
4650 pState->m_pFile = NULL;
\r
4652 #endif // #ifndef MINIZ_NO_STDIO
\r
4654 if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem))
\r
4656 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
\r
4657 pState->m_pMem = NULL;
\r
4660 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
\r
4661 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
\r
4665 #ifndef MINIZ_NO_STDIO
\r
4666 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)
\r
4668 mz_bool status, created_new_archive = MZ_FALSE;
\r
4669 mz_zip_archive zip_archive;
\r
4670 struct MZ_FILE_STAT_STRUCT file_stat;
\r
4671 MZ_CLEAR_OBJ(zip_archive);
\r
4672 if ((int)level_and_flags < 0)
\r
4673 level_and_flags = MZ_DEFAULT_LEVEL;
\r
4674 if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
\r
4676 if (!mz_zip_writer_validate_archive_name(pArchive_name))
\r
4678 if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0)
\r
4680 // Create a new archive.
\r
4681 if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0))
\r
4683 created_new_archive = MZ_TRUE;
\r
4687 // Append to an existing archive.
\r
4688 if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
\r
4690 if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename))
\r
4692 mz_zip_reader_end(&zip_archive);
\r
4696 status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0);
\r
4697 // 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.)
\r
4698 if (!mz_zip_writer_finalize_archive(&zip_archive))
\r
4699 status = MZ_FALSE;
\r
4700 if (!mz_zip_writer_end(&zip_archive))
\r
4701 status = MZ_FALSE;
\r
4702 if ((!status) && (created_new_archive))
\r
4704 // It's a new archive and something went wrong, so just delete it.
\r
4705 int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
\r
4706 (void)ignoredStatus;
\r
4711 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags)
\r
4714 mz_zip_archive zip_archive;
\r
4720 if ((!pZip_filename) || (!pArchive_name))
\r
4723 MZ_CLEAR_OBJ(zip_archive);
\r
4724 if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
\r
4727 if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0)
\r
4728 p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
\r
4730 mz_zip_reader_end(&zip_archive);
\r
4734 #endif // #ifndef MINIZ_NO_STDIO
\r
4736 #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
\r
4738 #endif // #ifndef MINIZ_NO_ARCHIVE_APIS
\r
4740 #ifdef __cplusplus
\r
4744 #endif // MINIZ_HEADER_FILE_ONLY
\r
4747 This is free and unencumbered software released into the public domain.
\r
4749 Anyone is free to copy, modify, publish, use, compile, sell, or
\r
4750 distribute this software, either in source code form or as a compiled
\r
4751 binary, for any purpose, commercial or non-commercial, and by any
\r
4754 In jurisdictions that recognize copyright laws, the author or authors
\r
4755 of this software dedicate any and all copyright interest in the
\r
4756 software to the public domain. We make this dedication for the benefit
\r
4757 of the public at large and to the detriment of our heirs and
\r
4758 successors. We intend this dedication to be an overt act of
\r
4759 relinquishment in perpetuity of all present and future rights to this
\r
4760 software under copyright law.
\r
4762 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
4763 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
4764 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
\r
4765 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
\r
4766 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
\r
4767 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
\r
4768 OTHER DEALINGS IN THE SOFTWARE.
\r
4770 For more information, please refer to <http://unlicense.org/>
\r