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