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