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