libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
Loading...
Searching...
No Matches
miniz.h
1#ifndef MINIZ_EXPORT
2#define MINIZ_EXPORT
3#endif
4/* miniz.c 3.0.2 - public domain deflate/inflate, zlib-subset, ZIP
5 reading/writing/appending, PNG writing See "unlicense" statement at the end
6 of this file. Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13,
7 2013 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951:
8 http://www.ietf.org/rfc/rfc1951.txt
9
10 Most API's defined in miniz.c are optional. For example, to disable the
11 archive related functions just define MINIZ_NO_ARCHIVE_APIS, or to get rid of
12 all stdio usage define MINIZ_NO_STDIO (see the list below for more macros).
13
14 * Low-level Deflate/Inflate implementation notes:
15
16 Compression: Use the "tdefl" API's. The compressor supports raw, static,
17 and dynamic blocks, lazy or greedy parsing, match length filtering, RLE-only,
18 and Huffman-only streams. It performs and compresses approximately as well as
19 zlib.
20
21 Decompression: Use the "tinfl" API's. The entire decompressor is
22 implemented as a single function coroutine: see tinfl_decompress(). It
23 supports decompression into a 32KB (or larger power of 2) wrapping buffer, or
24 into a memory block large enough to hold the entire file.
25
26 The low-level tdefl/tinfl API's do not make any use of dynamic memory
27 allocation.
28
29 * zlib-style API notes:
30
31 miniz.c implements a fairly large subset of zlib. There's enough
32 functionality present for it to be a drop-in zlib replacement in many apps:
33 The z_stream struct, optional memory allocation callbacks
34 deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
35 inflateInit/inflateInit2/inflate/inflateReset/inflateEnd
36 compress, compress2, compressBound, uncompress
37 CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly
38 routines. Supports raw deflate streams or standard zlib streams with adler-32
39 checking.
40
41 Limitations:
42 The callback API's are not implemented yet. No support for gzip headers or
43 zlib static dictionaries. I've tried to closely emulate zlib's various
44 flavors of stream flushing and return status codes, but there are no
45 guarantees that miniz.c pulls this off perfectly.
46
47 * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function,
48 originally written by Alex Evans. Supports 1-4 bytes/pixel images.
49
50 * ZIP archive API notes:
51
52 The ZIP archive API's where designed with simplicity and efficiency in
53 mind, with just enough abstraction to get the job done with minimal fuss.
54 There are simple API's to retrieve file information, read files from existing
55 archives, create new archives, append new files to existing archives, or
56 clone archive data from one archive to another. It supports archives located
57 in memory or the heap, on disk (using stdio.h), or you can specify custom
58 file read/write callbacks.
59
60 - Archive reading: Just call this function to read a single file from a
61 disk archive:
62
63 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const
64 char *pArchive_name, size_t *pSize, mz_uint zip_flags);
65
66 For more complex cases, use the "mz_zip_reader" functions. Upon opening an
67 archive, the entire central directory is located and read as-is into memory,
68 and subsequent file access only occurs when reading individual files.
69
70 - Archives file scanning: The simple way is to use this function to scan a
71 loaded archive for a specific file:
72
73 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
74 const char *pComment, mz_uint flags);
75
76 The locate operation can optionally check file comments too, which (as one
77 example) can be used to identify multiple versions of the same file in an
78 archive. This function uses a simple linear search through the central
79 directory, so it's not very fast.
80
81 Alternately, you can iterate through all the files in an archive (using
82 mz_zip_reader_get_num_files()) and retrieve detailed info on each file by
83 calling mz_zip_reader_file_stat().
84
85 - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer
86 immediately writes compressed file data to disk and builds an exact image of
87 the central directory in memory. The central directory image is written all
88 at once at the end of the archive file when the archive is finalized.
89
90 The archive writer can optionally align each file's local header and file
91 data to any power of 2 alignment, which can be useful when the archive will
92 be read from optical media. Also, the writer supports placing arbitrary data
93 blobs at the very beginning of ZIP archives. Archives written using either
94 feature are still readable by any ZIP tool.
95
96 - Archive appending: The simple way to add a single file to an archive is
97 to call this function:
98
99 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename,
100 const char *pArchive_name, const void *pBuf, size_t buf_size, const void
101 *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
102
103 The archive will be created if it doesn't already exist, otherwise it'll be
104 appended to. Note the appending is done in-place and is not an atomic
105 operation, so if something goes wrong during the operation it's possible the
106 archive could be left without a central directory (although the local file
107 headers and file data will be fine, so the archive will be recoverable).
108
109 For more complex archive modification scenarios:
110 1. The safest way is to use a mz_zip_reader to read the existing archive,
111 cloning only those bits you want to preserve into a new archive using using
112 the mz_zip_writer_add_from_zip_reader() function (which compiles the
113 compressed file data as-is). When you're done, delete the old archive and
114 rename the newly written archive, and you're done. This is safe but requires
115 a bunch of temporary disk space or heap memory.
116
117 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using
118 mz_zip_writer_init_from_reader(), append new files as needed, then finalize
119 the archive which will write an updated central directory to the original
120 archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place()
121 does.) There's a possibility that the archive's central directory could be
122 lost with this method if anything goes wrong, though.
123
124 - ZIP archive support limitations:
125 No spanning support. Extraction functions can only handle unencrypted,
126 stored or deflated files. Requires streams capable of seeking.
127
128 * This is a header file library, like stb_image.c. To get only a header file,
129 either cut and paste the below header, or create miniz.h, #define
130 MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it.
131
132 * Important: For best perf. be sure to customize the below macros for your
133 target platform: #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define
134 MINIZ_LITTLE_ENDIAN 1 #define MINIZ_HAS_64BIT_REGISTERS 1
135
136 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before
137 including miniz.c to ensure miniz uses the 64-bit variants: fopen64(),
138 stat64(), etc. Otherwise you won't be able to process large files (i.e.
139 32-bit stat() fails for me on files > 0x7FFFFFFF bytes).
140*/
141#pragma once
142
143/* Defines to completely disable specific portions of miniz.c:
144 If all macros here are defined the only functionality remaining will be
145 CRC-32 and adler-32. */
146
147/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on
148 * stdio for file I/O. */
149/*#define MINIZ_NO_STDIO */
150
151/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able
152 * to get the current time, or */
153/* get/set file times, and the C run-time funcs that get/set times won't be
154 * called. */
155/* The current downside is the times written to your archives will be from 1979.
156 */
157/*#define MINIZ_NO_TIME */
158
159/* Define MINIZ_NO_DEFLATE_APIS to disable all compression API's. */
160/*#define MINIZ_NO_DEFLATE_APIS */
161
162/* Define MINIZ_NO_INFLATE_APIS to disable all decompression API's. */
163/*#define MINIZ_NO_INFLATE_APIS */
164
165/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */
166/*#define MINIZ_NO_ARCHIVE_APIS */
167
168/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP
169 * archive API's. */
170/*#define MINIZ_NO_ARCHIVE_WRITING_APIS */
171
172/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression
173 * API's. */
174/*#define MINIZ_NO_ZLIB_APIS */
175
176/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent
177 * conflicts against stock zlib. */
178/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */
179
180/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
181 Note if MINIZ_NO_MALLOC is defined then the user must always provide custom
182 user alloc/free/realloc callbacks to the zlib and archive API's, and a few
183 stand-alone helper API's which don't provide custom user functions (such as
184 tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work.
185 */
186/*#define MINIZ_NO_MALLOC */
187
188#ifdef MINIZ_NO_INFLATE_APIS
189#define MINIZ_NO_ARCHIVE_APIS
190#endif
191
192#ifdef MINIZ_NO_DEFLATE_APIS
193#define MINIZ_NO_ARCHIVE_WRITING_APIS
194#endif
195
196#if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
197/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc
198 * on Linux */
199#define MINIZ_NO_TIME
200#endif
201
202#include <stddef.h>
203
204#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
205#include <time.h>
206#endif
207
208#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
209 defined(__i386) || defined(__i486__) || defined(__i486) || \
210 defined(i386) || defined(__ia64__) || defined(__x86_64__)
211/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */
212#define MINIZ_X86_OR_X64_CPU 1
213#else
214#define MINIZ_X86_OR_X64_CPU 0
215#endif
216
217/* Set MINIZ_LITTLE_ENDIAN only if not set */
218#if !defined(MINIZ_LITTLE_ENDIAN)
219#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__)
220
221#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
222/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */
223#define MINIZ_LITTLE_ENDIAN 1
224#else
225#define MINIZ_LITTLE_ENDIAN 0
226#endif
227
228#else
229
230#if MINIZ_X86_OR_X64_CPU
231#define MINIZ_LITTLE_ENDIAN 1
232#else
233#define MINIZ_LITTLE_ENDIAN 0
234#endif
235
236#endif
237#endif
238
239/* Using unaligned loads and stores causes errors when using UBSan */
240#if defined(__has_feature)
241#if __has_feature(undefined_behavior_sanitizer)
242#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0
243#endif
244#endif
245
246/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */
247#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES)
248#if MINIZ_X86_OR_X64_CPU
249/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
250 * integer loads and stores from unaligned addresses. */
251#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0
252#define MINIZ_UNALIGNED_USE_MEMCPY
253#else
254#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0
255#endif
256#endif
257
258#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \
259 defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \
260 defined(__x86_64__)
261/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are
262 * reasonably fast (and don't involve compiler generated calls to helper
263 * functions). */
264#define MINIZ_HAS_64BIT_REGISTERS 1
265#else
266#define MINIZ_HAS_64BIT_REGISTERS 0
267#endif
268
269#ifdef __cplusplus
270extern "C" {
271#endif
272
273/* ------------------- zlib-style API Definitions. */
274
275/* For more compatibility with zlib, miniz.c uses unsigned long for some
276 * parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */
277typedef unsigned long mz_ulong;
278
279/* mz_free() internally uses the MZ_FREE() macro (which by default calls free()
280 * unless you've modified the MZ_MALLOC macro) to release a block allocated from
281 * the heap. */
282MINIZ_EXPORT void mz_free(void *p);
283
284#define MZ_ADLER32_INIT (1)
285/* mz_adler32() returns the initial adler-32 value to use when called with
286 * ptr==NULL. */
287MINIZ_EXPORT mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr,
288 size_t buf_len);
289
290#define MZ_CRC32_INIT (0)
291/* mz_crc32() returns the initial CRC-32 value to use when called with
292 * ptr==NULL. */
293MINIZ_EXPORT mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr,
294 size_t buf_len);
295
296/* Compression strategies. */
297enum {
298 MZ_DEFAULT_STRATEGY = 0,
299 MZ_FILTERED = 1,
300 MZ_HUFFMAN_ONLY = 2,
301 MZ_RLE = 3,
302 MZ_FIXED = 4
303};
304
305/* Method */
306#define MZ_DEFLATED 8
307
308/* Heap allocation callbacks.
309Note that mz_alloc_func parameter types purposely differ from zlib's: items/size
310is size_t, not unsigned long. */
311typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
312typedef void (*mz_free_func)(void *opaque, void *address);
313typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items,
314 size_t size);
315
316/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best
317 * possible compression (not zlib compatible, and may be very slow),
318 * MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */
319enum {
320 MZ_NO_COMPRESSION = 0,
321 MZ_BEST_SPEED = 1,
322 MZ_BEST_COMPRESSION = 9,
323 MZ_UBER_COMPRESSION = 10,
324 MZ_DEFAULT_LEVEL = 6,
325 MZ_DEFAULT_COMPRESSION = -1
326};
327
328#define MZ_VERSION "11.0.2"
329#define MZ_VERNUM 0xB002
330#define MZ_VER_MAJOR 11
331#define MZ_VER_MINOR 2
332#define MZ_VER_REVISION 0
333#define MZ_VER_SUBREVISION 0
334
335#ifndef MINIZ_NO_ZLIB_APIS
336
337/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The
338 * other values are for advanced use (refer to the zlib docs). */
339enum {
340 MZ_NO_FLUSH = 0,
341 MZ_PARTIAL_FLUSH = 1,
342 MZ_SYNC_FLUSH = 2,
343 MZ_FULL_FLUSH = 3,
344 MZ_FINISH = 4,
345 MZ_BLOCK = 5
346};
347
348/* Return status codes. MZ_PARAM_ERROR is non-standard. */
349enum {
350 MZ_OK = 0,
351 MZ_STREAM_END = 1,
352 MZ_NEED_DICT = 2,
353 MZ_ERRNO = -1,
354 MZ_STREAM_ERROR = -2,
355 MZ_DATA_ERROR = -3,
356 MZ_MEM_ERROR = -4,
357 MZ_BUF_ERROR = -5,
358 MZ_VERSION_ERROR = -6,
359 MZ_PARAM_ERROR = -10000
360};
361
362/* Window bits */
363#define MZ_DEFAULT_WINDOW_BITS 15
364
365struct mz_internal_state;
366
367/* Compression/decompression stream struct. */
368typedef struct mz_stream_s {
369 const unsigned char *next_in; /* pointer to next byte to read */
370 unsigned int avail_in; /* number of bytes available at next_in */
371 mz_ulong total_in; /* total number of bytes consumed so far */
372
373 unsigned char *next_out; /* pointer to next byte to write */
374 unsigned int avail_out; /* number of bytes that can be written to next_out */
375 mz_ulong total_out; /* total number of bytes produced so far */
376
377 char *msg; /* error msg (unused) */
378 struct mz_internal_state
379 *state; /* internal state, allocated by zalloc/zfree */
380
381 mz_alloc_func
382 zalloc; /* optional heap allocation function (defaults to malloc) */
383 mz_free_func zfree; /* optional heap free function (defaults to free) */
384 void *opaque; /* heap alloc function user pointer */
385
386 int data_type; /* data_type (unused) */
387 mz_ulong adler; /* adler32 of the source or uncompressed data */
388 mz_ulong reserved; /* not used */
389} mz_stream;
390
391typedef mz_stream *mz_streamp;
392
393/* Returns the version string of miniz.c. */
394MINIZ_EXPORT const char *mz_version(void);
395
396#ifndef MINIZ_NO_DEFLATE_APIS
397
398/* mz_deflateInit() initializes a compressor with default options: */
399/* Parameters: */
400/* pStream must point to an initialized mz_stream struct. */
401/* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */
402/* level 1 enables a specially optimized compression function that's been
403 * optimized purely for performance, not ratio. */
404/* (This special func. is currently only enabled when
405 * MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */
406/* Return values: */
407/* MZ_OK on success. */
408/* MZ_STREAM_ERROR if the stream is bogus. */
409/* MZ_PARAM_ERROR if the input parameters are bogus. */
410/* MZ_MEM_ERROR on out of memory. */
411MINIZ_EXPORT int mz_deflateInit(mz_streamp pStream, int level);
412
413/* mz_deflateInit2() is like mz_deflate(), except with more control: */
414/* Additional parameters: */
415/* method must be MZ_DEFLATED */
416/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with
417 * zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no
418 * header or footer) */
419/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */
420MINIZ_EXPORT int mz_deflateInit2(mz_streamp pStream, int level, int method,
421 int window_bits, int mem_level, int strategy);
422
423/* Quickly resets a compressor without having to reallocate anything. Same as
424 * calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */
425MINIZ_EXPORT int mz_deflateReset(mz_streamp pStream);
426
427/* mz_deflate() compresses the input to output, consuming as much of the input
428 * and producing as much output as possible. */
429/* Parameters: */
430/* pStream is the stream to read from and write to. You must initialize/update
431 * the next_in, avail_in, next_out, and avail_out members. */
432/* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or
433 * MZ_FINISH. */
434/* Return values: */
435/* MZ_OK on success (when flushing, or if more input is needed but not
436 * available, and/or there's more output to be written but the output buffer is
437 * full). */
438/* MZ_STREAM_END if all input has been consumed and all output bytes have been
439 * written. Don't call mz_deflate() on the stream anymore. */
440/* MZ_STREAM_ERROR if the stream is bogus. */
441/* MZ_PARAM_ERROR if one of the parameters is invalid. */
442/* MZ_BUF_ERROR if no forward progress is possible because the input and/or
443 * output buffers are empty. (Fill up the input buffer or free up some output
444 * space and try again.) */
445MINIZ_EXPORT int mz_deflate(mz_streamp pStream, int flush);
446
447/* mz_deflateEnd() deinitializes a compressor: */
448/* Return values: */
449/* MZ_OK on success. */
450/* MZ_STREAM_ERROR if the stream is bogus. */
451MINIZ_EXPORT int mz_deflateEnd(mz_streamp pStream);
452
453/* mz_deflateBound() returns a (very) conservative upper bound on the amount of
454 * data that could be generated by deflate(), assuming flush is set to only
455 * MZ_NO_FLUSH or MZ_FINISH. */
456MINIZ_EXPORT mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
457
458/* Single-call compression functions mz_compress() and mz_compress2(): */
459/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on
460 * failure. */
461MINIZ_EXPORT int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
462 const unsigned char *pSource, mz_ulong source_len);
463MINIZ_EXPORT int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
464 const unsigned char *pSource, mz_ulong source_len,
465 int level);
466
467/* mz_compressBound() returns a (very) conservative upper bound on the amount of
468 * data that could be generated by calling mz_compress(). */
469MINIZ_EXPORT mz_ulong mz_compressBound(mz_ulong source_len);
470
471#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/
472
473#ifndef MINIZ_NO_INFLATE_APIS
474
475/* Initializes a decompressor. */
476MINIZ_EXPORT int mz_inflateInit(mz_streamp pStream);
477
478/* mz_inflateInit2() is like mz_inflateInit() with an additional option that
479 * controls the window size and whether or not the stream has been wrapped with
480 * a zlib header/footer: */
481/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or
482 * -MZ_DEFAULT_WINDOW_BITS (raw deflate). */
483MINIZ_EXPORT int mz_inflateInit2(mz_streamp pStream, int window_bits);
484
485/* Quickly resets a compressor without having to reallocate anything. Same as
486 * calling mz_inflateEnd() followed by mz_inflateInit()/mz_inflateInit2(). */
487MINIZ_EXPORT int mz_inflateReset(mz_streamp pStream);
488
489/* Decompresses the input stream to the output, consuming only as much of the
490 * input as needed, and writing as much to the output as possible. */
491/* Parameters: */
492/* pStream is the stream to read from and write to. You must initialize/update
493 * the next_in, avail_in, next_out, and avail_out members. */
494/* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */
495/* On the first call, if flush is MZ_FINISH it's assumed the input and output
496 * buffers are both sized large enough to decompress the entire stream in a
497 * single call (this is slightly faster). */
498/* MZ_FINISH implies that there are no more source bytes available beside
499 * what's already in the input buffer, and that the output buffer is large
500 * enough to hold the rest of the decompressed data. */
501/* Return values: */
502/* MZ_OK on success. Either more input is needed but not available, and/or
503 * there's more output to be written but the output buffer is full. */
504/* MZ_STREAM_END if all needed input has been consumed and all output bytes
505 * have been written. For zlib streams, the adler-32 of the decompressed data
506 * has also been verified. */
507/* MZ_STREAM_ERROR if the stream is bogus. */
508/* MZ_DATA_ERROR if the deflate stream is invalid. */
509/* MZ_PARAM_ERROR if one of the parameters is invalid. */
510/* MZ_BUF_ERROR if no forward progress is possible because the input buffer is
511 * empty but the inflater needs more input to continue, or if the output buffer
512 * is not large enough. Call mz_inflate() again */
513/* with more input data, or with more room in the output buffer (except when
514 * using single call decompression, described above). */
515MINIZ_EXPORT int mz_inflate(mz_streamp pStream, int flush);
516
517/* Deinitializes a decompressor. */
518MINIZ_EXPORT int mz_inflateEnd(mz_streamp pStream);
519
520/* Single-call decompression. */
521/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on
522 * failure. */
523MINIZ_EXPORT int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
524 const unsigned char *pSource,
525 mz_ulong source_len);
526MINIZ_EXPORT int mz_uncompress2(unsigned char *pDest, mz_ulong *pDest_len,
527 const unsigned char *pSource,
528 mz_ulong *pSource_len);
529#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/
530
531/* Returns a string description of the specified error code, or NULL if the
532 * error code is invalid. */
533MINIZ_EXPORT const char *mz_error(int err);
534
535/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used
536 * as a drop-in replacement for the subset of zlib that miniz.c supports. */
537/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you
538 * use zlib in the same project. */
539#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
540typedef unsigned char Byte;
541typedef unsigned int uInt;
542typedef mz_ulong uLong;
543typedef Byte Bytef;
544typedef uInt uIntf;
545typedef char charf;
546typedef int intf;
547typedef void *voidpf;
548typedef uLong uLongf;
549typedef void *voidp;
550typedef void *const voidpc;
551#define Z_NULL 0
552#define Z_NO_FLUSH MZ_NO_FLUSH
553#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
554#define Z_SYNC_FLUSH MZ_SYNC_FLUSH
555#define Z_FULL_FLUSH MZ_FULL_FLUSH
556#define Z_FINISH MZ_FINISH
557#define Z_BLOCK MZ_BLOCK
558#define Z_OK MZ_OK
559#define Z_STREAM_END MZ_STREAM_END
560#define Z_NEED_DICT MZ_NEED_DICT
561#define Z_ERRNO MZ_ERRNO
562#define Z_STREAM_ERROR MZ_STREAM_ERROR
563#define Z_DATA_ERROR MZ_DATA_ERROR
564#define Z_MEM_ERROR MZ_MEM_ERROR
565#define Z_BUF_ERROR MZ_BUF_ERROR
566#define Z_VERSION_ERROR MZ_VERSION_ERROR
567#define Z_PARAM_ERROR MZ_PARAM_ERROR
568#define Z_NO_COMPRESSION MZ_NO_COMPRESSION
569#define Z_BEST_SPEED MZ_BEST_SPEED
570#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
571#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
572#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
573#define Z_FILTERED MZ_FILTERED
574#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
575#define Z_RLE MZ_RLE
576#define Z_FIXED MZ_FIXED
577#define Z_DEFLATED MZ_DEFLATED
578#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
579#define alloc_func mz_alloc_func
580#define free_func mz_free_func
581#define internal_state mz_internal_state
582#define z_stream mz_stream
583
584#ifndef MINIZ_NO_DEFLATE_APIS
585#define deflateInit mz_deflateInit
586#define deflateInit2 mz_deflateInit2
587#define deflateReset mz_deflateReset
588#define deflate mz_deflate
589#define deflateEnd mz_deflateEnd
590#define deflateBound mz_deflateBound
591#define compress mz_compress
592#define compress2 mz_compress2
593#define compressBound mz_compressBound
594#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/
595
596#ifndef MINIZ_NO_INFLATE_APIS
597#define inflateInit mz_inflateInit
598#define inflateInit2 mz_inflateInit2
599#define inflateReset mz_inflateReset
600#define inflate mz_inflate
601#define inflateEnd mz_inflateEnd
602#define uncompress mz_uncompress
603#define uncompress2 mz_uncompress2
604#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/
605
606#define crc32 mz_crc32
607#define adler32 mz_adler32
608#define MAX_WBITS 15
609#define MAX_MEM_LEVEL 9
610#define zError mz_error
611#define ZLIB_VERSION MZ_VERSION
612#define ZLIB_VERNUM MZ_VERNUM
613#define ZLIB_VER_MAJOR MZ_VER_MAJOR
614#define ZLIB_VER_MINOR MZ_VER_MINOR
615#define ZLIB_VER_REVISION MZ_VER_REVISION
616#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
617#define zlibVersion mz_version
618#define zlib_version mz_version()
619#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */
620
621#endif /* MINIZ_NO_ZLIB_APIS */
622
623#ifdef __cplusplus
624}
625#endif
626
627#pragma once
628#include <assert.h>
629#include <stdint.h>
630#include <stdlib.h>
631#include <string.h>
632
633/* ------------------- Types and macros */
634typedef unsigned char mz_uint8;
635typedef signed short mz_int16;
636typedef unsigned short mz_uint16;
637typedef unsigned int mz_uint32;
638typedef unsigned int mz_uint;
639typedef int64_t mz_int64;
640typedef uint64_t mz_uint64;
641typedef int mz_bool;
642
643#define MZ_FALSE (0)
644#define MZ_TRUE (1)
645
646/* Works around MSVC's spammy "warning C4127: conditional expression is
647 * constant" message. */
648#ifdef _MSC_VER
649#define MZ_MACRO_END while (0, 0)
650#else
651#define MZ_MACRO_END while (0)
652#endif
653
654#ifdef MINIZ_NO_STDIO
655#define MZ_FILE void *
656#else
657#include <stdio.h>
658#define MZ_FILE FILE
659#endif /* #ifdef MINIZ_NO_STDIO */
660
661#ifdef MINIZ_NO_TIME
662typedef struct mz_dummy_time_t_tag {
663 mz_uint32 m_dummy1;
664 mz_uint32 m_dummy2;
665} mz_dummy_time_t;
666#define MZ_TIME_T mz_dummy_time_t
667#else
668#define MZ_TIME_T time_t
669#endif
670
671#define MZ_ASSERT(x) assert(x)
672
673#ifdef MINIZ_NO_MALLOC
674#define MZ_MALLOC(x) NULL
675#define MZ_FREE(x) (void)x, ((void)0)
676#define MZ_REALLOC(p, x) NULL
677#else
678#define MZ_MALLOC(x) malloc(x)
679#define MZ_FREE(x) free(x)
680#define MZ_REALLOC(p, x) realloc(p, x)
681#endif
682
683#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b))
684#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b))
685#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
686#define MZ_CLEAR_ARR(obj) memset((obj), 0, sizeof(obj))
687#define MZ_CLEAR_PTR(obj) memset((obj), 0, sizeof(*obj))
688
689#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
690#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
691#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
692#else
693#define MZ_READ_LE16(p) \
694 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
695 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
696#define MZ_READ_LE32(p) \
697 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
698 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \
699 ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \
700 ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
701#endif
702
703#define MZ_READ_LE64(p) \
704 (((mz_uint64)MZ_READ_LE32(p)) | \
705 (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) \
706 << 32U))
707
708#ifdef _MSC_VER
709#define MZ_FORCEINLINE __forceinline
710#elif defined(__GNUC__)
711#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__))
712#else
713#define MZ_FORCEINLINE inline
714#endif
715
716#ifdef __cplusplus
717extern "C" {
718#endif
719
720extern MINIZ_EXPORT void *miniz_def_alloc_func(void *opaque, size_t items,
721 size_t size);
722extern MINIZ_EXPORT void miniz_def_free_func(void *opaque, void *address);
723extern MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque, void *address,
724 size_t items, size_t size);
725
726#define MZ_UINT16_MAX (0xFFFFU)
727#define MZ_UINT32_MAX (0xFFFFFFFFU)
728
729#ifdef __cplusplus
730}
731#endif
732#pragma once
733
734#ifndef MINIZ_NO_DEFLATE_APIS
735
736#ifdef __cplusplus
737extern "C" {
738#endif
739/* ------------------- Low-level Compression API Definitions */
740
741/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly
742 * slower, and raw/dynamic blocks will be output more frequently). */
743#ifndef TDEFL_LESS_MEMORY
744#define TDEFL_LESS_MEMORY 0
745#endif
746
747/* tdefl_init() compression flags logically OR'd together (low 12 bits contain
748 * the max. number of probes per dictionary search): */
749/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes
750 * per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap
751 * compression), 4095=Huffman+LZ (slowest/best compression). */
752enum {
753 TDEFL_HUFFMAN_ONLY = 0,
754 TDEFL_DEFAULT_MAX_PROBES = 128,
755 TDEFL_MAX_PROBES_MASK = 0xFFF
756};
757
758/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before
759 * the deflate data, and the Adler-32 of the source data at the end. Otherwise,
760 * you'll get raw deflate data. */
761/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even
762 * when not writing zlib headers). */
763/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more
764 * efficient lazy parsing. */
765/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's
766 * initialization time to the minimum, but the output may vary from run to run
767 * given the same input (depending on the contents of memory). */
768/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1)
769 */
770/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */
771/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */
772/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */
773/* The low 12 bits are reserved to control the max # of hash probes per
774 * dictionary lookup (see TDEFL_MAX_PROBES_MASK). */
775enum {
776 TDEFL_WRITE_ZLIB_HEADER = 0x01000,
777 TDEFL_COMPUTE_ADLER32 = 0x02000,
778 TDEFL_GREEDY_PARSING_FLAG = 0x04000,
779 TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
780 TDEFL_RLE_MATCHES = 0x10000,
781 TDEFL_FILTER_MATCHES = 0x20000,
782 TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
783 TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
784};
785
786/* High level compression functions: */
787/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block
788 * allocated via malloc(). */
789/* On entry: */
790/* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */
791/* flags: The max match finder probes (default is 128) logically OR'd against
792 * the above flags. Higher probes are slower but improve compression. */
793/* On return: */
794/* Function returns a pointer to the compressed data, or NULL on failure. */
795/* *pOut_len will be set to the compressed data's size, which could be larger
796 * than src_buf_len on uncompressible data. */
797/* The caller must free() the returned block when it's no longer needed. */
798MINIZ_EXPORT void *tdefl_compress_mem_to_heap(const void *pSrc_buf,
799 size_t src_buf_len,
800 size_t *pOut_len, int flags);
801
802/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in
803 * memory. */
804/* Returns 0 on failure. */
805MINIZ_EXPORT size_t tdefl_compress_mem_to_mem(void *pOut_buf,
806 size_t out_buf_len,
807 const void *pSrc_buf,
808 size_t src_buf_len, int flags);
809
810/* Compresses an image to a compressed PNG file in memory. */
811/* On entry: */
812/* pImage, w, h, and num_chans describe the image to compress. num_chans may be
813 * 1, 2, 3, or 4. */
814/* The image pitch in bytes per scanline will be w*num_chans. The leftmost
815 * pixel on the top scanline is stored first in memory. */
816/* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED,
817 * MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */
818/* If flip is true, the image will be flipped on the Y axis (useful for OpenGL
819 * apps). */
820/* On return: */
821/* Function returns a pointer to the compressed data, or NULL on failure. */
822/* *pLen_out will be set to the size of the PNG image file. */
823/* The caller must mz_free() the returned heap block (which will typically be
824 * larger than *pLen_out) when it's no longer needed. */
825MINIZ_EXPORT void *
826tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h,
827 int num_chans, size_t *pLen_out,
828 mz_uint level, mz_bool flip);
829MINIZ_EXPORT void *tdefl_write_image_to_png_file_in_memory(const void *pImage,
830 int w, int h,
831 int num_chans,
832 size_t *pLen_out);
833
834/* Output stream interface. The compressor uses this interface to write
835 * compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */
836typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len,
837 void *pUser);
838
839/* tdefl_compress_mem_to_output() compresses a block to an output stream. The
840 * above helpers use this function internally. */
841MINIZ_EXPORT mz_bool tdefl_compress_mem_to_output(
842 const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func,
843 void *pPut_buf_user, int flags);
844
845enum {
846 TDEFL_MAX_HUFF_TABLES = 3,
847 TDEFL_MAX_HUFF_SYMBOLS_0 = 288,
848 TDEFL_MAX_HUFF_SYMBOLS_1 = 32,
849 TDEFL_MAX_HUFF_SYMBOLS_2 = 19,
850 TDEFL_LZ_DICT_SIZE = 32768,
851 TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1,
852 TDEFL_MIN_MATCH_LEN = 3,
853 TDEFL_MAX_MATCH_LEN = 258
854};
855
856/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed
857 * output block (using static/fixed Huffman codes). */
858#if TDEFL_LESS_MEMORY
859enum {
860 TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024,
861 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
862 TDEFL_MAX_HUFF_SYMBOLS = 288,
863 TDEFL_LZ_HASH_BITS = 12,
864 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
865 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
866 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
867};
868#else
869enum {
870 TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024,
871 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
872 TDEFL_MAX_HUFF_SYMBOLS = 288,
873 TDEFL_LZ_HASH_BITS = 15,
874 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
875 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
876 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
877};
878#endif
879
880/* The low-level tdefl functions below may be used directly if the above helper
881 * functions aren't flexible enough. The low-level functions don't make any heap
882 * allocations, unlike the above helper functions. */
883typedef enum {
884 TDEFL_STATUS_BAD_PARAM = -2,
885 TDEFL_STATUS_PUT_BUF_FAILED = -1,
886 TDEFL_STATUS_OKAY = 0,
887 TDEFL_STATUS_DONE = 1
888} tdefl_status;
889
890/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */
891typedef enum {
892 TDEFL_NO_FLUSH = 0,
893 TDEFL_SYNC_FLUSH = 2,
894 TDEFL_FULL_FLUSH = 3,
895 TDEFL_FINISH = 4
896} tdefl_flush;
897
898/* tdefl's compression state structure. */
899typedef struct {
900 tdefl_put_buf_func_ptr m_pPut_buf_func;
901 void *m_pPut_buf_user;
902 mz_uint m_flags, m_max_probes[2];
903 int m_greedy_parsing;
904 mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
905 mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
906 mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in,
907 m_bit_buffer;
908 mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit,
909 m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index,
910 m_wants_to_finish;
911 tdefl_status m_prev_return_status;
912 const void *m_pIn_buf;
913 void *m_pOut_buf;
914 size_t *m_pIn_buf_size, *m_pOut_buf_size;
915 tdefl_flush m_flush;
916 const mz_uint8 *m_pSrc;
917 size_t m_src_buf_left, m_out_buf_ofs;
918 mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
919 mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
920 mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
921 mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
922 mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
923 mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
924 mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
925 mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
927
928/* Initializes the compressor. */
929/* There is no corresponding deinit() function because the tdefl API's do not
930 * dynamically allocate memory. */
931/* pBut_buf_func: If NULL, output data will be supplied to the specified
932 * callback. In this case, the user should call the tdefl_compress_buffer() API
933 * for compression. */
934/* If pBut_buf_func is NULL the user should always call the tdefl_compress()
935 * API. */
936/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER,
937 * etc.) */
938MINIZ_EXPORT tdefl_status tdefl_init(tdefl_compressor *d,
939 tdefl_put_buf_func_ptr pPut_buf_func,
940 void *pPut_buf_user, int flags);
941
942/* Compresses a block of data, consuming as much of the specified input buffer
943 * as possible, and writing as much compressed data to the specified output
944 * buffer as possible. */
945MINIZ_EXPORT tdefl_status tdefl_compress(tdefl_compressor *d,
946 const void *pIn_buf,
947 size_t *pIn_buf_size, void *pOut_buf,
948 size_t *pOut_buf_size,
949 tdefl_flush flush);
950
951/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a
952 * non-NULL tdefl_put_buf_func_ptr. */
953/* tdefl_compress_buffer() always consumes the entire input buffer. */
954MINIZ_EXPORT tdefl_status tdefl_compress_buffer(tdefl_compressor *d,
955 const void *pIn_buf,
956 size_t in_buf_size,
957 tdefl_flush flush);
958
959MINIZ_EXPORT tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
960MINIZ_EXPORT mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
961
962/* Create tdefl_compress() flags given zlib-style compression parameters. */
963/* level may range from [0,10] (where 10 is absolute max compression, but may be
964 * much slower on some files) */
965/* window_bits may be -15 (raw deflate) or 15 (zlib) */
966/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY,
967 * MZ_RLE, or MZ_FIXED */
968MINIZ_EXPORT mz_uint tdefl_create_comp_flags_from_zip_params(int level,
969 int window_bits,
970 int strategy);
971
972#ifndef MINIZ_NO_MALLOC
973/* Allocate the tdefl_compressor structure in C so that */
974/* non-C language bindings to tdefl_ API don't need to worry about */
975/* structure size and allocation mechanism. */
976MINIZ_EXPORT tdefl_compressor *tdefl_compressor_alloc(void);
977MINIZ_EXPORT void tdefl_compressor_free(tdefl_compressor *pComp);
978#endif
979
980#ifdef __cplusplus
981}
982#endif
983
984#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/
985#pragma once
986
987/* ------------------- Low-level Decompression API Definitions */
988
989#ifndef MINIZ_NO_INFLATE_APIS
990
991#ifdef __cplusplus
992extern "C" {
993#endif
994/* Decompression flags used by tinfl_decompress(). */
995/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and
996 * ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the
997 * input is a raw deflate stream. */
998/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available
999 * beyond the end of the supplied input buffer. If clear, the input buffer
1000 * contains all remaining input. */
1001/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large
1002 * enough to hold the entire decompressed stream. If clear, the output buffer is
1003 * at least the size of the dictionary (typically 32KB). */
1004/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the
1005 * decompressed bytes. */
1006enum {
1007 TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
1008 TINFL_FLAG_HAS_MORE_INPUT = 2,
1009 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
1010 TINFL_FLAG_COMPUTE_ADLER32 = 8
1011};
1012
1013/* High level decompression functions: */
1014/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block
1015 * allocated via malloc(). */
1016/* On entry: */
1017/* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data
1018 * to decompress. */
1019/* On return: */
1020/* Function returns a pointer to the decompressed data, or NULL on failure. */
1021/* *pOut_len will be set to the decompressed data's size, which could be larger
1022 * than src_buf_len on uncompressible data. */
1023/* The caller must call mz_free() on the returned block when it's no longer
1024 * needed. */
1025MINIZ_EXPORT void *tinfl_decompress_mem_to_heap(const void *pSrc_buf,
1026 size_t src_buf_len,
1027 size_t *pOut_len, int flags);
1028
1029/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block
1030 * in memory. */
1031/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes
1032 * written on success. */
1033#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
1034MINIZ_EXPORT size_t tinfl_decompress_mem_to_mem(void *pOut_buf,
1035 size_t out_buf_len,
1036 const void *pSrc_buf,
1037 size_t src_buf_len, int flags);
1038
1039/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an
1040 * internal 32KB buffer, and a user provided callback function will be called to
1041 * flush the buffer. */
1042/* Returns 1 on success or 0 on failure. */
1043typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);
1044MINIZ_EXPORT int
1045tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
1046 tinfl_put_buf_func_ptr pPut_buf_func,
1047 void *pPut_buf_user, int flags);
1048
1050typedef struct tinfl_decompressor_tag tinfl_decompressor;
1051
1052#ifndef MINIZ_NO_MALLOC
1053/* Allocate the tinfl_decompressor structure in C so that */
1054/* non-C language bindings to tinfl_ API don't need to worry about */
1055/* structure size and allocation mechanism. */
1056MINIZ_EXPORT tinfl_decompressor *tinfl_decompressor_alloc(void);
1057MINIZ_EXPORT void tinfl_decompressor_free(tinfl_decompressor *pDecomp);
1058#endif
1059
1060/* Max size of LZ dictionary. */
1061#define TINFL_LZ_DICT_SIZE 32768
1062
1063/* Return status. */
1064typedef enum {
1065 /* This flags indicates the inflator needs 1 or more input bytes to make
1066 forward progress, but the caller is indicating that no more are available.
1067 The compressed data */
1068 /* is probably corrupted. If you call the inflator again with more bytes it'll
1069 try to continue processing the input but this is a BAD sign (either the
1070 data is corrupted or you called it incorrectly). */
1071 /* If you call it again with no input you'll just get
1072 TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */
1073 TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4,
1074
1075 /* This flag indicates that one or more of the input parameters was obviously
1076 bogus. (You can try calling it again, but if you get this error the calling
1077 code is wrong.) */
1078 TINFL_STATUS_BAD_PARAM = -3,
1079
1080 /* This flags indicate the inflator is finished but the adler32 check of the
1081 uncompressed data didn't match. If you call it again it'll return
1082 TINFL_STATUS_DONE. */
1083 TINFL_STATUS_ADLER32_MISMATCH = -2,
1084
1085 /* This flags indicate the inflator has somehow failed (bad code, corrupted
1086 input, etc.). If you call it again without resetting via tinfl_init() it
1087 it'll just keep on returning the same status failure code. */
1088 TINFL_STATUS_FAILED = -1,
1089
1090 /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */
1091
1092 /* This flag indicates the inflator has returned every byte of uncompressed
1093 data that it can, has consumed every byte that it needed, has successfully
1094 reached the end of the deflate stream, and */
1095 /* if zlib headers and adler32 checking enabled that it has successfully
1096 checked the uncompressed data's adler32. If you call it again you'll just
1097 get TINFL_STATUS_DONE over and over again. */
1098 TINFL_STATUS_DONE = 0,
1099
1100 /* This flag indicates the inflator MUST have more input data (even 1 byte)
1101 before it can make any more forward progress, or you need to clear the
1102 TINFL_FLAG_HAS_MORE_INPUT */
1103 /* flag on the next call if you don't have any more source data. If the source
1104 data was somehow corrupted it's also possible (but unlikely) for the
1105 inflator to keep on demanding input to */
1106 /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */
1107 TINFL_STATUS_NEEDS_MORE_INPUT = 1,
1108
1109 /* This flag indicates the inflator definitely has 1 or more bytes of
1110 uncompressed data available, but it cannot write this data into the output
1111 buffer. */
1112 /* Note if the source compressed data was corrupted it's possible for the
1113 inflator to return a lot of uncompressed data to the caller. I've been
1114 assuming you know how much uncompressed data to expect */
1115 /* (either exact or worst case) and will stop calling the inflator and fail
1116 after receiving too much. In pure streaming scenarios where you have no
1117 idea how many bytes to expect this may not be possible */
1118 /* so I may need to add some code to address this. */
1119 TINFL_STATUS_HAS_MORE_OUTPUT = 2
1120} tinfl_status;
1121
1122/* Initializes the decompressor to its initial state. */
1123#define tinfl_init(r) \
1124 do { \
1125 (r)->m_state = 0; \
1126 } \
1127 MZ_MACRO_END
1128#define tinfl_get_adler32(r) (r)->m_check_adler32
1129
1130/* Main low-level decompressor coroutine function. This is the only function
1131 * actually needed for decompression. All the other functions are just
1132 * high-level helpers for improved usability. */
1133/* This is a universal API, i.e. it can be used as a building block to build any
1134 * desired higher level decompression API. In the limit case, it can be called
1135 * once per every byte input or output. */
1136MINIZ_EXPORT tinfl_status tinfl_decompress(
1137 tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size,
1138 mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
1139 const mz_uint32 decomp_flags);
1140
1141/* Internal/private bits follow. */
1142enum {
1143 TINFL_MAX_HUFF_TABLES = 3,
1144 TINFL_MAX_HUFF_SYMBOLS_0 = 288,
1145 TINFL_MAX_HUFF_SYMBOLS_1 = 32,
1146 TINFL_MAX_HUFF_SYMBOLS_2 = 19,
1147 TINFL_FAST_LOOKUP_BITS = 10,
1148 TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
1149};
1150
1151#if MINIZ_HAS_64BIT_REGISTERS
1152#define TINFL_USE_64BIT_BITBUF 1
1153#else
1154#define TINFL_USE_64BIT_BITBUF 0
1155#endif
1156
1157#if TINFL_USE_64BIT_BITBUF
1158typedef mz_uint64 tinfl_bit_buf_t;
1159#define TINFL_BITBUF_SIZE (64)
1160#else
1161typedef mz_uint32 tinfl_bit_buf_t;
1162#define TINFL_BITBUF_SIZE (32)
1163#endif
1164
1166 mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type,
1167 m_check_adler32, m_dist, m_counter, m_num_extra,
1168 m_table_sizes[TINFL_MAX_HUFF_TABLES];
1169 tinfl_bit_buf_t m_bit_buf;
1170 size_t m_dist_from_out_buf_start;
1171 mz_int16 m_look_up[TINFL_MAX_HUFF_TABLES][TINFL_FAST_LOOKUP_SIZE];
1172 mz_int16 m_tree_0[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
1173 mz_int16 m_tree_1[TINFL_MAX_HUFF_SYMBOLS_1 * 2];
1174 mz_int16 m_tree_2[TINFL_MAX_HUFF_SYMBOLS_2 * 2];
1175 mz_uint8 m_code_size_0[TINFL_MAX_HUFF_SYMBOLS_0];
1176 mz_uint8 m_code_size_1[TINFL_MAX_HUFF_SYMBOLS_1];
1177 mz_uint8 m_code_size_2[TINFL_MAX_HUFF_SYMBOLS_2];
1178 mz_uint8 m_raw_header[4],
1179 m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
1180};
1181
1182#ifdef __cplusplus
1183}
1184#endif
1185
1186#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/
1187
1188#pragma once
1189
1190/* ------------------- ZIP archive reading/writing */
1191
1192#ifndef MINIZ_NO_ARCHIVE_APIS
1193
1194#ifdef __cplusplus
1195extern "C" {
1196#endif
1197
1198enum {
1199 /* Note: These enums can be reduced as needed to save memory or stack space -
1200 they are pretty conservative. */
1201 MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,
1202 MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512,
1203 MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512
1204};
1205
1206typedef struct {
1207 /* Central directory file index. */
1208 mz_uint32 m_file_index;
1209
1210 /* Byte offset of this entry in the archive's central directory. Note we
1211 * currently only support up to UINT_MAX or less bytes in the central dir. */
1212 mz_uint64 m_central_dir_ofs;
1213
1214 /* These fields are copied directly from the zip's central dir. */
1215 mz_uint16 m_version_made_by;
1216 mz_uint16 m_version_needed;
1217 mz_uint16 m_bit_flag;
1218 mz_uint16 m_method;
1219
1220 /* CRC-32 of uncompressed data. */
1221 mz_uint32 m_crc32;
1222
1223 /* File's compressed size. */
1224 mz_uint64 m_comp_size;
1225
1226 /* File's uncompressed size. Note, I've seen some old archives where directory
1227 * entries had 512 bytes for their uncompressed sizes, but when you try to
1228 * unpack them you actually get 0 bytes. */
1229 mz_uint64 m_uncomp_size;
1230
1231 /* Zip internal and external file attributes. */
1232 mz_uint16 m_internal_attr;
1233 mz_uint32 m_external_attr;
1234
1235 /* Entry's local header file offset in bytes. */
1236 mz_uint64 m_local_header_ofs;
1237
1238 /* Size of comment in bytes. */
1239 mz_uint32 m_comment_size;
1240
1241 /* MZ_TRUE if the entry appears to be a directory. */
1242 mz_bool m_is_directory;
1243
1244 /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip
1245 * doesn't support) */
1246 mz_bool m_is_encrypted;
1247
1248 /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a
1249 * compression method we support. */
1250 mz_bool m_is_supported;
1251
1252 /* Filename. If string ends in '/' it's a subdirectory entry. */
1253 /* Guaranteed to be zero terminated, may be truncated to fit. */
1254 char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
1255
1256 /* Comment field. */
1257 /* Guaranteed to be zero terminated, may be truncated to fit. */
1258 char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
1259
1260#ifdef MINIZ_NO_TIME
1261 MZ_TIME_T m_padding;
1262#else
1263 MZ_TIME_T m_time;
1264#endif
1266
1267typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
1268 void *pBuf, size_t n);
1269typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
1270 const void *pBuf, size_t n);
1271typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);
1272
1274typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
1275
1276typedef enum {
1277 MZ_ZIP_MODE_INVALID = 0,
1278 MZ_ZIP_MODE_READING = 1,
1279 MZ_ZIP_MODE_WRITING = 2,
1280 MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
1281} mz_zip_mode;
1282
1283typedef enum {
1284 MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
1285 MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
1286 MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
1287 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800,
1288 MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG =
1289 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each
1290 file as its validated to ensure the func finds the file in the
1291 central dir (intended for testing) */
1292 MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY =
1293 0x2000, /* validate the local headers, but don't decompress the entire
1294 file and check the crc32 */
1295 MZ_ZIP_FLAG_WRITE_ZIP64 =
1296 0x4000, /* always use the zip64 file format, instead of the original zip
1297 file format with automatic switch to zip64. Use as flags
1298 parameter with mz_zip_writer_init*_v2 */
1299 MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000,
1300 MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000,
1301 /*After adding a compressed file, seek back
1302 to local file header and set the correct sizes*/
1303 MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE = 0x20000
1304} mz_zip_flags;
1305
1306typedef enum {
1307 MZ_ZIP_TYPE_INVALID = 0,
1308 MZ_ZIP_TYPE_USER,
1309 MZ_ZIP_TYPE_MEMORY,
1310 MZ_ZIP_TYPE_HEAP,
1311 MZ_ZIP_TYPE_FILE,
1312 MZ_ZIP_TYPE_CFILE,
1313 MZ_ZIP_TOTAL_TYPES
1314} mz_zip_type;
1315
1316/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or
1317 * modify this enum. */
1318typedef enum {
1319 MZ_ZIP_NO_ERROR = 0,
1320 MZ_ZIP_UNDEFINED_ERROR,
1321 MZ_ZIP_TOO_MANY_FILES,
1322 MZ_ZIP_FILE_TOO_LARGE,
1323 MZ_ZIP_UNSUPPORTED_METHOD,
1324 MZ_ZIP_UNSUPPORTED_ENCRYPTION,
1325 MZ_ZIP_UNSUPPORTED_FEATURE,
1326 MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,
1327 MZ_ZIP_NOT_AN_ARCHIVE,
1328 MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,
1329 MZ_ZIP_UNSUPPORTED_MULTIDISK,
1330 MZ_ZIP_DECOMPRESSION_FAILED,
1331 MZ_ZIP_COMPRESSION_FAILED,
1332 MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,
1333 MZ_ZIP_CRC_CHECK_FAILED,
1334 MZ_ZIP_UNSUPPORTED_CDIR_SIZE,
1335 MZ_ZIP_ALLOC_FAILED,
1336 MZ_ZIP_FILE_OPEN_FAILED,
1337 MZ_ZIP_FILE_CREATE_FAILED,
1338 MZ_ZIP_FILE_WRITE_FAILED,
1339 MZ_ZIP_FILE_READ_FAILED,
1340 MZ_ZIP_FILE_CLOSE_FAILED,
1341 MZ_ZIP_FILE_SEEK_FAILED,
1342 MZ_ZIP_FILE_STAT_FAILED,
1343 MZ_ZIP_INVALID_PARAMETER,
1344 MZ_ZIP_INVALID_FILENAME,
1345 MZ_ZIP_BUF_TOO_SMALL,
1346 MZ_ZIP_INTERNAL_ERROR,
1347 MZ_ZIP_FILE_NOT_FOUND,
1348 MZ_ZIP_ARCHIVE_TOO_LARGE,
1349 MZ_ZIP_VALIDATION_FAILED,
1350 MZ_ZIP_WRITE_CALLBACK_FAILED,
1351 MZ_ZIP_TOTAL_ERRORS
1352} mz_zip_error;
1353
1354typedef struct {
1355 mz_uint64 m_archive_size;
1356 mz_uint64 m_central_directory_file_ofs;
1357
1358 /* We only support up to UINT32_MAX files in zip64 mode. */
1359 mz_uint32 m_total_files;
1360 mz_zip_mode m_zip_mode;
1361 mz_zip_type m_zip_type;
1362 mz_zip_error m_last_error;
1363
1364 mz_uint64 m_file_offset_alignment;
1365
1366 mz_alloc_func m_pAlloc;
1367 mz_free_func m_pFree;
1368 mz_realloc_func m_pRealloc;
1369 void *m_pAlloc_opaque;
1370
1371 mz_file_read_func m_pRead;
1372 mz_file_write_func m_pWrite;
1373 mz_file_needs_keepalive m_pNeeds_keepalive;
1374 void *m_pIO_opaque;
1375
1376 mz_zip_internal_state *m_pState;
1377
1379
1380typedef struct {
1381 mz_zip_archive *pZip;
1382 mz_uint flags;
1383
1384 int status;
1385
1386 mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining,
1387 out_buf_ofs, cur_file_ofs;
1388 mz_zip_archive_file_stat file_stat;
1389 void *pRead_buf;
1390 void *pWrite_buf;
1391
1392 size_t out_blk_remain;
1393
1394 tinfl_decompressor inflator;
1395
1396#ifdef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
1397 mz_uint padding;
1398#else
1399 mz_uint file_crc32;
1400#endif
1401
1403
1404/* -------- ZIP reading */
1405
1406/* Inits a ZIP archive reader. */
1407/* These functions read and validate the archive's central directory. */
1408MINIZ_EXPORT mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
1409 mz_uint flags);
1410
1411MINIZ_EXPORT mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip,
1412 const void *pMem, size_t size,
1413 mz_uint flags);
1414
1415#ifndef MINIZ_NO_STDIO
1416/* Read a archive from a disk file. */
1417/* file_start_ofs is the file offset where the archive actually begins, or 0. */
1418/* actual_archive_size is the true total size of the archive, which may be
1419 * smaller than the file's actual size on disk. If zero the entire file is
1420 * treated as the archive. */
1421MINIZ_EXPORT mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip,
1422 const char *pFilename,
1423 mz_uint32 flags);
1424MINIZ_EXPORT mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip,
1425 const char *pFilename,
1426 mz_uint flags,
1427 mz_uint64 file_start_ofs,
1428 mz_uint64 archive_size);
1429
1430/* Read an archive from an already opened FILE, beginning at the current file
1431 * position. */
1432/* The archive is assumed to be archive_size bytes long. If archive_size is 0,
1433 * then the entire rest of the file is assumed to contain the archive. */
1434/* The FILE will NOT be closed when mz_zip_reader_end() is called. */
1435MINIZ_EXPORT mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip,
1436 MZ_FILE *pFile,
1437 mz_uint64 archive_size,
1438 mz_uint flags);
1439#endif
1440
1441/* Ends archive reading, freeing all allocations, and closing the input archive
1442 * file if mz_zip_reader_init_file() was used. */
1443MINIZ_EXPORT mz_bool mz_zip_reader_end(mz_zip_archive *pZip);
1444
1445/* -------- ZIP reading or writing */
1446
1447/* Clears a mz_zip_archive struct to all zeros. */
1448/* Important: This must be done before passing the struct to any mz_zip
1449 * functions. */
1450MINIZ_EXPORT void mz_zip_zero_struct(mz_zip_archive *pZip);
1451
1452MINIZ_EXPORT mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip);
1453MINIZ_EXPORT mz_zip_type mz_zip_get_type(mz_zip_archive *pZip);
1454
1455/* Returns the total number of files in the archive. */
1456MINIZ_EXPORT mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
1457
1458MINIZ_EXPORT mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip);
1459MINIZ_EXPORT mz_uint64
1460mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip);
1461MINIZ_EXPORT MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip);
1462
1463/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf.
1464 */
1465MINIZ_EXPORT size_t mz_zip_read_archive_data(mz_zip_archive *pZip,
1466 mz_uint64 file_ofs, void *pBuf,
1467 size_t n);
1468
1469/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct.
1470 * These functions retrieve/manipulate this field. */
1471/* Note that the m_last_error functionality is not thread safe. */
1472MINIZ_EXPORT mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip,
1473 mz_zip_error err_num);
1474MINIZ_EXPORT mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip);
1475MINIZ_EXPORT mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip);
1476MINIZ_EXPORT mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip);
1477MINIZ_EXPORT const char *mz_zip_get_error_string(mz_zip_error mz_err);
1478
1479/* MZ_TRUE if the archive file entry is a directory entry. */
1480MINIZ_EXPORT mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
1481 mz_uint file_index);
1482
1483/* MZ_TRUE if the file is encrypted/strong encrypted. */
1484MINIZ_EXPORT mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
1485 mz_uint file_index);
1486
1487/* MZ_TRUE if the compression method is supported, and the file is not
1488 * encrypted, and the file is not a compressed patch file. */
1489MINIZ_EXPORT mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip,
1490 mz_uint file_index);
1491
1492/* Retrieves the filename of an archive file entry. */
1493/* Returns the number of bytes written to pFilename, or if filename_buf_size is
1494 * 0 this function returns the number of bytes needed to fully store the
1495 * filename. */
1496MINIZ_EXPORT mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip,
1497 mz_uint file_index,
1498 char *pFilename,
1499 mz_uint filename_buf_size);
1500
1501/* Attempts to locates a file in the archive's central directory. */
1502/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */
1503/* Returns -1 if the file cannot be found. */
1504MINIZ_EXPORT int mz_zip_reader_locate_file(mz_zip_archive *pZip,
1505 const char *pName,
1506 const char *pComment, mz_uint flags);
1507MINIZ_EXPORT mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip,
1508 const char *pName,
1509 const char *pComment,
1510 mz_uint flags,
1511 mz_uint32 *file_index);
1512
1513/* Returns detailed information about an archive file entry. */
1514MINIZ_EXPORT mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip,
1515 mz_uint file_index,
1517
1518/* MZ_TRUE if the file is in zip64 format. */
1519/* A file is considered zip64 if it contained a zip64 end of central directory
1520 * marker, or if it contained any zip64 extended file information fields in the
1521 * central directory. */
1522MINIZ_EXPORT mz_bool mz_zip_is_zip64(mz_zip_archive *pZip);
1523
1524/* Returns the total central directory size in bytes. */
1525/* The current max supported size is <= MZ_UINT32_MAX. */
1526MINIZ_EXPORT size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip);
1527
1528/* Extracts a archive file to a memory buffer using no memory allocation. */
1529/* There must be at least enough room on the stack to store the inflator's state
1530 * (~34KB or so). */
1531MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_mem_no_alloc(
1532 mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size,
1533 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
1534MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
1535 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
1536 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
1537
1538/* Extracts a archive file to a memory buffer. */
1539MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip,
1540 mz_uint file_index,
1541 void *pBuf, size_t buf_size,
1542 mz_uint flags);
1543MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
1544 const char *pFilename,
1545 void *pBuf,
1546 size_t buf_size,
1547 mz_uint flags);
1548
1549/* Extracts a archive file to a dynamically allocated heap buffer. */
1550/* The memory will be allocated via the mz_zip_archive's alloc/realloc
1551 * functions. */
1552/* Returns NULL and sets the last error on failure. */
1553MINIZ_EXPORT void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip,
1554 mz_uint file_index,
1555 size_t *pSize, mz_uint flags);
1556MINIZ_EXPORT void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
1557 const char *pFilename,
1558 size_t *pSize,
1559 mz_uint flags);
1560
1561/* Extracts a archive file using a callback function to output the file's data.
1562 */
1563MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_callback(
1564 mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback,
1565 void *pOpaque, mz_uint flags);
1566MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_callback(
1567 mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback,
1568 void *pOpaque, mz_uint flags);
1569
1570/* Extract a file iteratively */
1572mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index,
1573 mz_uint flags);
1575mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename,
1576 mz_uint flags);
1577MINIZ_EXPORT size_t mz_zip_reader_extract_iter_read(
1578 mz_zip_reader_extract_iter_state *pState, void *pvBuf, size_t buf_size);
1579MINIZ_EXPORT mz_bool
1580mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state *pState);
1581
1582#ifndef MINIZ_NO_STDIO
1583/* Extracts a archive file to a disk file and sets its last accessed and
1584 * modified times. */
1585/* This function only extracts files, not archive directory records. */
1586MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip,
1587 mz_uint file_index,
1588 const char *pDst_filename,
1589 mz_uint flags);
1590MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_file(
1591 mz_zip_archive *pZip, const char *pArchive_filename,
1592 const char *pDst_filename, mz_uint flags);
1593
1594/* Extracts a archive file starting at the current position in the destination
1595 * FILE stream. */
1596MINIZ_EXPORT mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip,
1597 mz_uint file_index,
1598 MZ_FILE *File,
1599 mz_uint flags);
1600MINIZ_EXPORT mz_bool mz_zip_reader_extract_file_to_cfile(
1601 mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile,
1602 mz_uint flags);
1603#endif
1604
1605#if 0
1606/* TODO */
1607 typedef void *mz_zip_streaming_extract_state_ptr;
1608 mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);
1609 mz_uint64 mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
1610 mz_uint64 mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
1611 mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, mz_uint64 new_ofs);
1612 size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size);
1613 mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
1614#endif
1615
1616/* This function compares the archive's local headers, the optional local zip64
1617 * extended information block, and the optional descriptor following the
1618 * compressed data vs. the data in the central directory. */
1619/* It also validates that each file can be successfully uncompressed unless the
1620 * MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */
1621MINIZ_EXPORT mz_bool mz_zip_validate_file(mz_zip_archive *pZip,
1622 mz_uint file_index, mz_uint flags);
1623
1624/* Validates an entire archive by calling mz_zip_validate_file() on each file.
1625 */
1626MINIZ_EXPORT mz_bool mz_zip_validate_archive(mz_zip_archive *pZip,
1627 mz_uint flags);
1628
1629/* Misc utils/helpers, valid for ZIP reading or writing */
1630MINIZ_EXPORT mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size,
1631 mz_uint flags,
1632 mz_zip_error *pErr);
1633#ifndef MINIZ_NO_STDIO
1634MINIZ_EXPORT mz_bool mz_zip_validate_file_archive(const char *pFilename,
1635 mz_uint flags,
1636 mz_zip_error *pErr);
1637#endif
1638
1639/* Universal end function - calls either mz_zip_reader_end() or
1640 * mz_zip_writer_end(). */
1641MINIZ_EXPORT mz_bool mz_zip_end(mz_zip_archive *pZip);
1642
1643/* -------- ZIP writing */
1644
1645#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
1646
1647/* Inits a ZIP archive writer. */
1648/*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init
1649 * or mz_zip_writer_init_v2*/
1650/*The output is streamable, i.e. file_ofs in mz_file_write_func always increases
1651 * only by n*/
1652MINIZ_EXPORT mz_bool mz_zip_writer_init(mz_zip_archive *pZip,
1653 mz_uint64 existing_size);
1654MINIZ_EXPORT mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip,
1655 mz_uint64 existing_size,
1656 mz_uint flags);
1657
1658MINIZ_EXPORT mz_bool mz_zip_writer_init_heap(
1659 mz_zip_archive *pZip, size_t size_to_reserve_at_beginning,
1660 size_t initial_allocation_size);
1661MINIZ_EXPORT mz_bool mz_zip_writer_init_heap_v2(
1662 mz_zip_archive *pZip, size_t size_to_reserve_at_beginning,
1663 size_t initial_allocation_size, mz_uint flags);
1664
1665#ifndef MINIZ_NO_STDIO
1666MINIZ_EXPORT mz_bool
1667mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
1668 mz_uint64 size_to_reserve_at_beginning);
1669MINIZ_EXPORT mz_bool mz_zip_writer_init_file_v2(
1670 mz_zip_archive *pZip, const char *pFilename,
1671 mz_uint64 size_to_reserve_at_beginning, mz_uint flags);
1672MINIZ_EXPORT mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip,
1673 MZ_FILE *pFile, mz_uint flags);
1674#endif
1675
1676/* Converts a ZIP archive reader object into a writer object, to allow efficient
1677 * in-place file appends to occur on an existing archive. */
1678/* For archives opened using mz_zip_reader_init_file, pFilename must be the
1679 * archive's filename so it can be reopened for writing. If the file can't be
1680 * reopened, mz_zip_reader_end() will be called. */
1681/* For archives opened using mz_zip_reader_init_mem, the memory block must be
1682 * growable using the realloc callback (which defaults to realloc unless you've
1683 * overridden it). */
1684/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's
1685 * user provided m_pWrite function cannot be NULL. */
1686/* Note: In-place archive modification is not recommended unless you know what
1687 * you're doing, because if execution stops or something goes wrong before */
1688/* the archive is finalized the file's central directory will be hosed. */
1689MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
1690 const char *pFilename);
1691MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip,
1692 const char *pFilename,
1693 mz_uint flags);
1694
1695/* Adds the contents of a memory buffer to an archive. These functions record
1696 * the current local time into the archive. */
1697/* To add a directory entry, call this method with an archive name ending in a
1698 * forwardslash with an empty buffer. */
1699/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1700 * MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1701 * just set to MZ_DEFAULT_COMPRESSION. */
1702MINIZ_EXPORT mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip,
1703 const char *pArchive_name,
1704 const void *pBuf, size_t buf_size,
1705 mz_uint level_and_flags);
1706
1707/* Like mz_zip_writer_add_mem(), except you can specify a file comment field,
1708 * and optionally supply the function with already compressed data. */
1709/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA
1710 * flag is specified. */
1711MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex(
1712 mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf,
1713 size_t buf_size, const void *pComment, mz_uint16 comment_size,
1714 mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32);
1715
1716MINIZ_EXPORT mz_bool mz_zip_writer_add_mem_ex_v2(
1717 mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf,
1718 size_t buf_size, const void *pComment, mz_uint16 comment_size,
1719 mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32,
1720 MZ_TIME_T *last_modified, const char *user_extra_data_local,
1721 mz_uint user_extra_data_local_len, const char *user_extra_data_central,
1722 mz_uint user_extra_data_central_len);
1723
1724/* Adds the contents of a file to an archive. This function also records the
1725 * disk file's modified time into the archive. */
1726/* File data is supplied via a read callback function. User
1727 * mz_zip_writer_add_(c)file to add a file directly.*/
1728MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback(
1729 mz_zip_archive *pZip, const char *pArchive_name,
1730 mz_file_read_func read_callback, void *callback_opaque, mz_uint64 max_size,
1731 const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size,
1732 mz_uint level_and_flags, mz_uint32 ext_attributes,
1733 const char *user_extra_data_local, mz_uint user_extra_data_local_len,
1734 const char *user_extra_data_central, mz_uint user_extra_data_central_len);
1735
1736#ifndef MINIZ_NO_STDIO
1737/* Adds the contents of a disk file to an archive. This function also records
1738 * the disk file's modified time into the archive. */
1739/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1740 * MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1741 * just set to MZ_DEFAULT_COMPRESSION. */
1742MINIZ_EXPORT mz_bool mz_zip_writer_add_file(
1743 mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename,
1744 const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
1745 mz_uint32 ext_attributes);
1746
1747/* Like mz_zip_writer_add_file(), except the file data is read from the
1748 * specified FILE stream. */
1749MINIZ_EXPORT mz_bool mz_zip_writer_add_cfile(
1750 mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file,
1751 mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment,
1752 mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes,
1753 const char *user_extra_data_local, mz_uint user_extra_data_local_len,
1754 const char *user_extra_data_central, mz_uint user_extra_data_central_len);
1755#endif
1756
1757/* Adds a file to an archive by fully cloning the data from another archive. */
1758/* This function fully clones the source file's compressed data (no
1759 * recompression), along with its full filename, extra data (it may add or
1760 * modify the zip64 local header extra data field), and the optional descriptor
1761 * following the compressed data. */
1762MINIZ_EXPORT mz_bool mz_zip_writer_add_from_zip_reader(
1763 mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index);
1764
1765/* Finalizes the archive by writing the central directory records followed by
1766 * the end of central directory record. */
1767/* After an archive is finalized, the only valid call on the mz_zip_archive
1768 * struct is mz_zip_writer_end(). */
1769/* An archive must be manually finalized by calling this function for it to be
1770 * valid. */
1771MINIZ_EXPORT mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);
1772
1773/* Finalizes a heap archive, returning a pointer to the heap block and its size.
1774 */
1775/* The heap block will be allocated using the mz_zip_archive's alloc/realloc
1776 * callbacks. */
1777MINIZ_EXPORT mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip,
1778 void **ppBuf,
1779 size_t *pSize);
1780
1781/* Ends archive writing, freeing all allocations, and closing the output file if
1782 * mz_zip_writer_init_file() was used. */
1783/* Note for the archive to be valid, it *must* have been finalized before ending
1784 * (this function will not do it for you). */
1785MINIZ_EXPORT mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
1786
1787/* -------- Misc. high-level helper functions: */
1788
1789/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically)
1790 * appends a memory blob to a ZIP archive. */
1791/* Note this is NOT a fully safe operation. If it crashes or dies in some way
1792 * your archive can be left in a screwed up state (without a central directory).
1793 */
1794/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
1795 * MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
1796 * just set to MZ_DEFAULT_COMPRESSION. */
1797/* TODO: Perhaps add an option to leave the existing central dir in place in
1798 * case the add dies? We could then truncate the file (so the old central dir
1799 * would be at the end) if something goes wrong. */
1800MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place(
1801 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
1802 size_t buf_size, const void *pComment, mz_uint16 comment_size,
1803 mz_uint level_and_flags);
1804MINIZ_EXPORT mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(
1805 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
1806 size_t buf_size, const void *pComment, mz_uint16 comment_size,
1807 mz_uint level_and_flags, mz_zip_error *pErr);
1808
1809#ifndef MINIZ_NO_STDIO
1810/* Reads a single file from an archive into a heap block. */
1811/* If pComment is not NULL, only the file with the specified comment will be
1812 * extracted. */
1813/* Returns NULL on failure. */
1814MINIZ_EXPORT void *
1815mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
1816 const char *pArchive_name, size_t *pSize,
1817 mz_uint flags);
1818MINIZ_EXPORT void *mz_zip_extract_archive_file_to_heap_v2(
1819 const char *pZip_filename, const char *pArchive_name, const char *pComment,
1820 size_t *pSize, mz_uint flags, mz_zip_error *pErr);
1821#endif
1822
1823#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */
1824
1825#ifdef __cplusplus
1826}
1827#endif
1828
1829#endif /* MINIZ_NO_ARCHIVE_APIS */
1830
1831#ifndef MINIZ_HEADER_FILE_ONLY
1832/**************************************************************************
1833 *
1834 * Copyright 2013-2014 RAD Game Tools and Valve Software
1835 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
1836 * All Rights Reserved.
1837 *
1838 * Permission is hereby granted, free of charge, to any person obtaining a copy
1839 * of this software and associated documentation files (the "Software"), to deal
1840 * in the Software without restriction, including without limitation the rights
1841 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1842 * copies of the Software, and to permit persons to whom the Software is
1843 * furnished to do so, subject to the following conditions:
1844 *
1845 * The above copyright notice and this permission notice shall be included in
1846 * all copies or substantial portions of the Software.
1847 *
1848 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1849 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1850 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1851 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1852 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1853 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1854 * THE SOFTWARE.
1855 *
1856 **************************************************************************/
1857
1858typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];
1859typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];
1860typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
1861
1862#ifdef __cplusplus
1863extern "C" {
1864#endif
1865
1866/* ------------------- zlib-style API's */
1867
1868mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) {
1869 mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16);
1870 size_t block_len = buf_len % 5552;
1871 if (!ptr)
1872 return MZ_ADLER32_INIT;
1873 while (buf_len) {
1874 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
1875 s1 += ptr[0], s2 += s1;
1876 s1 += ptr[1], s2 += s1;
1877 s1 += ptr[2], s2 += s1;
1878 s1 += ptr[3], s2 += s1;
1879 s1 += ptr[4], s2 += s1;
1880 s1 += ptr[5], s2 += s1;
1881 s1 += ptr[6], s2 += s1;
1882 s1 += ptr[7], s2 += s1;
1883 }
1884 for (; i < block_len; ++i)
1885 s1 += *ptr++, s2 += s1;
1886 s1 %= 65521U, s2 %= 65521U;
1887 buf_len -= block_len;
1888 block_len = 5552;
1889 }
1890 return (s2 << 16) + s1;
1891}
1892
1893/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C
1894 * implementation that balances processor cache usage against speed":
1895 * http://www.geocities.com/malbrain/ */
1896#if 0
1897 mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
1898 {
1899 static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
1900 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
1901 mz_uint32 crcu32 = (mz_uint32)crc;
1902 if (!ptr)
1903 return MZ_CRC32_INIT;
1904 crcu32 = ~crcu32;
1905 while (buf_len--)
1906 {
1907 mz_uint8 b = *ptr++;
1908 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];
1909 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];
1910 }
1911 return ~crcu32;
1912 }
1913#elif defined(USE_EXTERNAL_MZCRC)
1914/* If USE_EXTERNAL_CRC is defined, an external module will export the
1915 * mz_crc32() symbol for us to use, e.g. an SSE-accelerated version.
1916 * Depending on the impl, it may be necessary to ~ the input/output crc values.
1917 */
1918mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len);
1919#else
1920/* Faster, but larger CPU cache footprint.
1921 */
1922mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) {
1923 static const mz_uint32 s_crc_table[256] = {
1924 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
1925 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1926 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
1927 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1928 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
1929 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1930 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
1931 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1932 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
1933 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1934 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
1935 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1936 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
1937 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1938 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
1939 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1940 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
1941 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1942 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
1943 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1944 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
1945 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1946 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
1947 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1948 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
1949 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1950 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
1951 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1952 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
1953 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1954 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
1955 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1956 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
1957 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1958 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
1959 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1960 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
1961 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1962 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
1963 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1964 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
1965 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1966 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
1967
1968 mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF;
1969 const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr;
1970
1971 while (buf_len >= 4) {
1972 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];
1973 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF];
1974 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF];
1975 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF];
1976 pByte_buf += 4;
1977 buf_len -= 4;
1978 }
1979
1980 while (buf_len) {
1981 crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];
1982 ++pByte_buf;
1983 --buf_len;
1984 }
1985
1986 return ~crc32;
1987}
1988#endif
1989
1990void mz_free(void *p) { MZ_FREE(p); }
1991
1992MINIZ_EXPORT void *miniz_def_alloc_func(void *opaque, size_t items,
1993 size_t size) {
1994 (void)opaque, (void)items, (void)size;
1995 return MZ_MALLOC(items * size);
1996}
1997MINIZ_EXPORT void miniz_def_free_func(void *opaque, void *address) {
1998 (void)opaque, (void)address;
1999 MZ_FREE(address);
2000}
2001MINIZ_EXPORT void *miniz_def_realloc_func(void *opaque, void *address,
2002 size_t items, size_t size) {
2003 (void)opaque, (void)address, (void)items, (void)size;
2004 return MZ_REALLOC(address, items * size);
2005}
2006
2007const char *mz_version(void) { return MZ_VERSION; }
2008
2009#ifndef MINIZ_NO_ZLIB_APIS
2010
2011#ifndef MINIZ_NO_DEFLATE_APIS
2012
2013int mz_deflateInit(mz_streamp pStream, int level) {
2014 return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9,
2015 MZ_DEFAULT_STRATEGY);
2016}
2017
2018int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
2019 int mem_level, int strategy) {
2020 tdefl_compressor *pComp;
2021 mz_uint comp_flags =
2022 TDEFL_COMPUTE_ADLER32 |
2023 tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
2024
2025 if (!pStream)
2026 return MZ_STREAM_ERROR;
2027 if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) ||
2028 ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
2029 (-window_bits != MZ_DEFAULT_WINDOW_BITS)))
2030 return MZ_PARAM_ERROR;
2031
2032 pStream->data_type = 0;
2033 pStream->adler = MZ_ADLER32_INIT;
2034 pStream->msg = NULL;
2035 pStream->reserved = 0;
2036 pStream->total_in = 0;
2037 pStream->total_out = 0;
2038 if (!pStream->zalloc)
2039 pStream->zalloc = miniz_def_alloc_func;
2040 if (!pStream->zfree)
2041 pStream->zfree = miniz_def_free_func;
2042
2043 pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1,
2044 sizeof(tdefl_compressor));
2045 if (!pComp)
2046 return MZ_MEM_ERROR;
2047
2048 pStream->state = (struct mz_internal_state *)pComp;
2049
2050 if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) {
2051 mz_deflateEnd(pStream);
2052 return MZ_PARAM_ERROR;
2053 }
2054
2055 return MZ_OK;
2056}
2057
2058int mz_deflateReset(mz_streamp pStream) {
2059 if ((!pStream) || (!pStream->state) || (!pStream->zalloc) ||
2060 (!pStream->zfree))
2061 return MZ_STREAM_ERROR;
2062 pStream->total_in = pStream->total_out = 0;
2063 tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL,
2064 ((tdefl_compressor *)pStream->state)->m_flags);
2065 return MZ_OK;
2066}
2067
2068int mz_deflate(mz_streamp pStream, int flush) {
2069 size_t in_bytes, out_bytes;
2070 mz_ulong orig_total_in, orig_total_out;
2071 int mz_status = MZ_OK;
2072
2073 if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) ||
2074 (!pStream->next_out))
2075 return MZ_STREAM_ERROR;
2076 if (!pStream->avail_out)
2077 return MZ_BUF_ERROR;
2078
2079 if (flush == MZ_PARTIAL_FLUSH)
2080 flush = MZ_SYNC_FLUSH;
2081
2082 if (((tdefl_compressor *)pStream->state)->m_prev_return_status ==
2083 TDEFL_STATUS_DONE)
2084 return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
2085
2086 orig_total_in = pStream->total_in;
2087 orig_total_out = pStream->total_out;
2088 for (;;) {
2089 tdefl_status defl_status;
2090 in_bytes = pStream->avail_in;
2091 out_bytes = pStream->avail_out;
2092
2093 defl_status = tdefl_compress((tdefl_compressor *)pStream->state,
2094 pStream->next_in, &in_bytes, pStream->next_out,
2095 &out_bytes, (tdefl_flush)flush);
2096 pStream->next_in += (mz_uint)in_bytes;
2097 pStream->avail_in -= (mz_uint)in_bytes;
2098 pStream->total_in += (mz_uint)in_bytes;
2099 pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state);
2100
2101 pStream->next_out += (mz_uint)out_bytes;
2102 pStream->avail_out -= (mz_uint)out_bytes;
2103 pStream->total_out += (mz_uint)out_bytes;
2104
2105 if (defl_status < 0) {
2106 mz_status = MZ_STREAM_ERROR;
2107 break;
2108 } else if (defl_status == TDEFL_STATUS_DONE) {
2109 mz_status = MZ_STREAM_END;
2110 break;
2111 } else if (!pStream->avail_out)
2112 break;
2113 else if ((!pStream->avail_in) && (flush != MZ_FINISH)) {
2114 if ((flush) || (pStream->total_in != orig_total_in) ||
2115 (pStream->total_out != orig_total_out))
2116 break;
2117 return MZ_BUF_ERROR; /* Can't make forward progress without some input.
2118 */
2119 }
2120 }
2121 return mz_status;
2122}
2123
2124int mz_deflateEnd(mz_streamp pStream) {
2125 if (!pStream)
2126 return MZ_STREAM_ERROR;
2127 if (pStream->state) {
2128 pStream->zfree(pStream->opaque, pStream->state);
2129 pStream->state = NULL;
2130 }
2131 return MZ_OK;
2132}
2133
2134mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) {
2135 (void)pStream;
2136 /* This is really over conservative. (And lame, but it's actually pretty
2137 * tricky to compute a true upper bound given the way tdefl's blocking works.)
2138 */
2139 return MZ_MAX(128 + (source_len * 110) / 100,
2140 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
2141}
2142
2143int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
2144 const unsigned char *pSource, mz_ulong source_len, int level) {
2145 int status;
2146 mz_stream stream;
2147 memset(&stream, 0, sizeof(stream));
2148
2149#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__WATCOMC__)
2150 /* In case mz_ulong is 64-bits (argh I hate longs). */
2151#else
2152 if ((mz_uint64)(source_len | *pDest_len) > 0xFFFFFFFFU)
2153 return MZ_PARAM_ERROR;
2154#endif
2155 stream.next_in = pSource;
2156 stream.avail_in = (mz_uint32)source_len;
2157 stream.next_out = pDest;
2158 stream.avail_out = (mz_uint32)*pDest_len;
2159
2160 status = mz_deflateInit(&stream, level);
2161 if (status != MZ_OK)
2162 return status;
2163
2164 status = mz_deflate(&stream, MZ_FINISH);
2165 if (status != MZ_STREAM_END) {
2166 mz_deflateEnd(&stream);
2167 return (status == MZ_OK) ? MZ_BUF_ERROR : status;
2168 }
2169
2170 *pDest_len = stream.total_out;
2171 return mz_deflateEnd(&stream);
2172}
2173
2174int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
2175 const unsigned char *pSource, mz_ulong source_len) {
2176 return mz_compress2(pDest, pDest_len, pSource, source_len,
2177 MZ_DEFAULT_COMPRESSION);
2178}
2179
2180mz_ulong mz_compressBound(mz_ulong source_len) {
2181 return mz_deflateBound(NULL, source_len);
2182}
2183
2184#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/
2185
2186#ifndef MINIZ_NO_INFLATE_APIS
2187
2188typedef struct {
2189 tinfl_decompressor m_decomp;
2190 mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed;
2191 int m_window_bits;
2192 mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
2193 tinfl_status m_last_status;
2195
2196int mz_inflateInit2(mz_streamp pStream, int window_bits) {
2197 inflate_state *pDecomp;
2198 if (!pStream)
2199 return MZ_STREAM_ERROR;
2200 if ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
2201 (-window_bits != MZ_DEFAULT_WINDOW_BITS))
2202 return MZ_PARAM_ERROR;
2203
2204 pStream->data_type = 0;
2205 pStream->adler = 0;
2206 pStream->msg = NULL;
2207 pStream->total_in = 0;
2208 pStream->total_out = 0;
2209 pStream->reserved = 0;
2210 if (!pStream->zalloc)
2211 pStream->zalloc = miniz_def_alloc_func;
2212 if (!pStream->zfree)
2213 pStream->zfree = miniz_def_free_func;
2214
2215 pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1,
2216 sizeof(inflate_state));
2217 if (!pDecomp)
2218 return MZ_MEM_ERROR;
2219
2220 pStream->state = (struct mz_internal_state *)pDecomp;
2221
2222 tinfl_init(&pDecomp->m_decomp);
2223 pDecomp->m_dict_ofs = 0;
2224 pDecomp->m_dict_avail = 0;
2225 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
2226 pDecomp->m_first_call = 1;
2227 pDecomp->m_has_flushed = 0;
2228 pDecomp->m_window_bits = window_bits;
2229
2230 return MZ_OK;
2231}
2232
2233int mz_inflateInit(mz_streamp pStream) {
2234 return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
2235}
2236
2237int mz_inflateReset(mz_streamp pStream) {
2238 inflate_state *pDecomp;
2239 if (!pStream)
2240 return MZ_STREAM_ERROR;
2241
2242 pStream->data_type = 0;
2243 pStream->adler = 0;
2244 pStream->msg = NULL;
2245 pStream->total_in = 0;
2246 pStream->total_out = 0;
2247 pStream->reserved = 0;
2248
2249 pDecomp = (inflate_state *)pStream->state;
2250
2251 tinfl_init(&pDecomp->m_decomp);
2252 pDecomp->m_dict_ofs = 0;
2253 pDecomp->m_dict_avail = 0;
2254 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
2255 pDecomp->m_first_call = 1;
2256 pDecomp->m_has_flushed = 0;
2257 /* pDecomp->m_window_bits = window_bits */;
2258
2259 return MZ_OK;
2260}
2261
2262int mz_inflate(mz_streamp pStream, int flush) {
2263 inflate_state *pState;
2264 mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
2265 size_t in_bytes, out_bytes, orig_avail_in;
2266 tinfl_status status;
2267
2268 if ((!pStream) || (!pStream->state))
2269 return MZ_STREAM_ERROR;
2270 if (flush == MZ_PARTIAL_FLUSH)
2271 flush = MZ_SYNC_FLUSH;
2272 if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH))
2273 return MZ_STREAM_ERROR;
2274
2275 pState = (inflate_state *)pStream->state;
2276 if (pState->m_window_bits > 0)
2277 decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
2278 orig_avail_in = pStream->avail_in;
2279
2280 first_call = pState->m_first_call;
2281 pState->m_first_call = 0;
2282 if (pState->m_last_status < 0)
2283 return MZ_DATA_ERROR;
2284
2285 if (pState->m_has_flushed && (flush != MZ_FINISH))
2286 return MZ_STREAM_ERROR;
2287 pState->m_has_flushed |= (flush == MZ_FINISH);
2288
2289 if ((flush == MZ_FINISH) && (first_call)) {
2290 /* MZ_FINISH on the first call implies that the input and output buffers are
2291 * large enough to hold the entire compressed/decompressed file. */
2292 decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
2293 in_bytes = pStream->avail_in;
2294 out_bytes = pStream->avail_out;
2295 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes,
2296 pStream->next_out, pStream->next_out, &out_bytes,
2297 decomp_flags);
2298 pState->m_last_status = status;
2299 pStream->next_in += (mz_uint)in_bytes;
2300 pStream->avail_in -= (mz_uint)in_bytes;
2301 pStream->total_in += (mz_uint)in_bytes;
2302 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
2303 pStream->next_out += (mz_uint)out_bytes;
2304 pStream->avail_out -= (mz_uint)out_bytes;
2305 pStream->total_out += (mz_uint)out_bytes;
2306
2307 if (status < 0)
2308 return MZ_DATA_ERROR;
2309 else if (status != TINFL_STATUS_DONE) {
2310 pState->m_last_status = TINFL_STATUS_FAILED;
2311 return MZ_BUF_ERROR;
2312 }
2313 return MZ_STREAM_END;
2314 }
2315 /* flush != MZ_FINISH then we must assume there's more input. */
2316 if (flush != MZ_FINISH)
2317 decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
2318
2319 if (pState->m_dict_avail) {
2320 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
2321 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
2322 pStream->next_out += n;
2323 pStream->avail_out -= n;
2324 pStream->total_out += n;
2325 pState->m_dict_avail -= n;
2326 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
2327 return ((pState->m_last_status == TINFL_STATUS_DONE) &&
2328 (!pState->m_dict_avail))
2329 ? MZ_STREAM_END
2330 : MZ_OK;
2331 }
2332
2333 for (;;) {
2334 in_bytes = pStream->avail_in;
2335 out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
2336
2337 status = tinfl_decompress(
2338 &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict,
2339 pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
2340 pState->m_last_status = status;
2341
2342 pStream->next_in += (mz_uint)in_bytes;
2343 pStream->avail_in -= (mz_uint)in_bytes;
2344 pStream->total_in += (mz_uint)in_bytes;
2345 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
2346
2347 pState->m_dict_avail = (mz_uint)out_bytes;
2348
2349 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
2350 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
2351 pStream->next_out += n;
2352 pStream->avail_out -= n;
2353 pStream->total_out += n;
2354 pState->m_dict_avail -= n;
2355 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
2356
2357 if (status < 0)
2358 return MZ_DATA_ERROR; /* Stream is corrupted (there could be some
2359 uncompressed data left in the output dictionary -
2360 oh well). */
2361 else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
2362 return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress
2363 without supplying more input or by setting flush
2364 to MZ_FINISH. */
2365 else if (flush == MZ_FINISH) {
2366 /* The output buffer MUST be large to hold the remaining uncompressed data
2367 * when flush==MZ_FINISH. */
2368 if (status == TINFL_STATUS_DONE)
2369 return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
2370 /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's
2371 * at least 1 more byte on the way. If there's no more room left in the
2372 * output buffer then something is wrong. */
2373 else if (!pStream->avail_out)
2374 return MZ_BUF_ERROR;
2375 } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) ||
2376 (!pStream->avail_out) || (pState->m_dict_avail))
2377 break;
2378 }
2379
2380 return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail))
2381 ? MZ_STREAM_END
2382 : MZ_OK;
2383}
2384
2385int mz_inflateEnd(mz_streamp pStream) {
2386 if (!pStream)
2387 return MZ_STREAM_ERROR;
2388 if (pStream->state) {
2389 pStream->zfree(pStream->opaque, pStream->state);
2390 pStream->state = NULL;
2391 }
2392 return MZ_OK;
2393}
2394int mz_uncompress2(unsigned char *pDest, mz_ulong *pDest_len,
2395 const unsigned char *pSource, mz_ulong *pSource_len) {
2396 mz_stream stream;
2397 int status;
2398 memset(&stream, 0, sizeof(stream));
2399
2400#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__WATCOMC__)
2401 /* In case mz_ulong is 64-bits (argh I hate longs). */
2402#else
2403 if ((mz_uint64)(*pSource_len | *pDest_len) > 0xFFFFFFFFU)
2404 return MZ_PARAM_ERROR;
2405#endif
2406 stream.next_in = pSource;
2407 stream.avail_in = (mz_uint32)*pSource_len;
2408 stream.next_out = pDest;
2409 stream.avail_out = (mz_uint32)*pDest_len;
2410
2411 status = mz_inflateInit(&stream);
2412 if (status != MZ_OK)
2413 return status;
2414
2415 status = mz_inflate(&stream, MZ_FINISH);
2416 *pSource_len = *pSource_len - stream.avail_in;
2417 if (status != MZ_STREAM_END) {
2418 mz_inflateEnd(&stream);
2419 return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR
2420 : status;
2421 }
2422 *pDest_len = stream.total_out;
2423
2424 return mz_inflateEnd(&stream);
2425}
2426
2427int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
2428 const unsigned char *pSource, mz_ulong source_len) {
2429 return mz_uncompress2(pDest, pDest_len, pSource, &source_len);
2430}
2431
2432#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/
2433
2434const char *mz_error(int err) {
2435 static struct {
2436 int m_err;
2437 const char *m_pDesc;
2438 } s_error_descs[] = {{MZ_OK, ""},
2439 {MZ_STREAM_END, "stream end"},
2440 {MZ_NEED_DICT, "need dictionary"},
2441 {MZ_ERRNO, "file error"},
2442 {MZ_STREAM_ERROR, "stream error"},
2443 {MZ_DATA_ERROR, "data error"},
2444 {MZ_MEM_ERROR, "out of memory"},
2445 {MZ_BUF_ERROR, "buf error"},
2446 {MZ_VERSION_ERROR, "version error"},
2447 {MZ_PARAM_ERROR, "parameter error"}};
2448 mz_uint i;
2449 for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i)
2450 if (s_error_descs[i].m_err == err)
2451 return s_error_descs[i].m_pDesc;
2452 return NULL;
2453}
2454
2455#endif /*MINIZ_NO_ZLIB_APIS */
2456
2457#ifdef __cplusplus
2458}
2459#endif
2460
2461/*
2462 This is free and unencumbered software released into the public domain.
2463
2464 Anyone is free to copy, modify, publish, use, compile, sell, or
2465 distribute this software, either in source code form or as a compiled
2466 binary, for any purpose, commercial or non-commercial, and by any
2467 means.
2468
2469 In jurisdictions that recognize copyright laws, the author or authors
2470 of this software dedicate any and all copyright interest in the
2471 software to the public domain. We make this dedication for the benefit
2472 of the public at large and to the detriment of our heirs and
2473 successors. We intend this dedication to be an overt act of
2474 relinquishment in perpetuity of all present and future rights to this
2475 software under copyright law.
2476
2477 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2478 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2479 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2480 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2481 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2482 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2483 OTHER DEALINGS IN THE SOFTWARE.
2484
2485 For more information, please refer to <http://unlicense.org/>
2486*/
2487/**************************************************************************
2488 *
2489 * Copyright 2013-2014 RAD Game Tools and Valve Software
2490 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
2491 * All Rights Reserved.
2492 *
2493 * Permission is hereby granted, free of charge, to any person obtaining a copy
2494 * of this software and associated documentation files (the "Software"), to deal
2495 * in the Software without restriction, including without limitation the rights
2496 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2497 * copies of the Software, and to permit persons to whom the Software is
2498 * furnished to do so, subject to the following conditions:
2499 *
2500 * The above copyright notice and this permission notice shall be included in
2501 * all copies or substantial portions of the Software.
2502 *
2503 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2504 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2505 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2506 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2507 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2508 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2509 * THE SOFTWARE.
2510 *
2511 **************************************************************************/
2512
2513#ifndef MINIZ_NO_DEFLATE_APIS
2514
2515#ifdef __cplusplus
2516extern "C" {
2517#endif
2518
2519/* ------------------- Low-level Compression (independent from all decompression
2520 * API's) */
2521
2522/* Purposely making these tables static for faster init and thread safety. */
2523static const mz_uint16 s_tdefl_len_sym[256] = {
2524 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268,
2525 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272,
2526 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274,
2527 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276,
2528 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
2529 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
2530 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279,
2531 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280,
2532 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281,
2533 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
2534 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282,
2535 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
2536 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283,
2537 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
2538 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284,
2539 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
2540 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
2541 285};
2542
2543static const mz_uint8 s_tdefl_len_extra[256] = {
2544 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
2545 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2546 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
2547 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
2548 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
2549 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2550 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2551 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2552 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2553 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2554 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0};
2555
2556static const mz_uint8 s_tdefl_small_dist_sym[512] = {
2557 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
2558 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
2559 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
2560 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
2561 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
2562 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
2563 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14,
2564 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
2565 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
2566 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
2567 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
2568 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
2569 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
2570 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2571 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2572 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2573 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2574 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2575 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2576 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2577 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2578 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2579 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2580 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2581 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2582 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2583 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17};
2584
2585static const mz_uint8 s_tdefl_small_dist_extra[512] = {
2586 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,
2587 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,
2588 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2589 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2590 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2591 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2592 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2593 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2594 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2595 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2596 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,
2597 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2598 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2599 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2600 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2601 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2602 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2603 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2604 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2605 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2606 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
2607
2608static const mz_uint8 s_tdefl_large_dist_sym[128] = {
2609 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24,
2610 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26,
2611 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27,
2612 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
2613 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
2614 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
2615 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29};
2616
2617static const mz_uint8 s_tdefl_large_dist_extra[128] = {
2618 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11,
2619 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12,
2620 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
2621 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
2622 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
2623 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
2624 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
2625
2626/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted
2627 * values. */
2628typedef struct {
2629 mz_uint16 m_key, m_sym_index;
2631static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms,
2632 tdefl_sym_freq *pSyms0,
2633 tdefl_sym_freq *pSyms1) {
2634 mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2];
2635 tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1;
2636 MZ_CLEAR_ARR(hist);
2637 for (i = 0; i < num_syms; i++) {
2638 mz_uint freq = pSyms0[i].m_key;
2639 hist[freq & 0xFF]++;
2640 hist[256 + ((freq >> 8) & 0xFF)]++;
2641 }
2642 while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256]))
2643 total_passes--;
2644 for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) {
2645 const mz_uint32 *pHist = &hist[pass << 8];
2646 mz_uint offsets[256], cur_ofs = 0;
2647 for (i = 0; i < 256; i++) {
2648 offsets[i] = cur_ofs;
2649 cur_ofs += pHist[i];
2650 }
2651 for (i = 0; i < num_syms; i++)
2652 pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] =
2653 pCur_syms[i];
2654 {
2655 tdefl_sym_freq *t = pCur_syms;
2656 pCur_syms = pNew_syms;
2657 pNew_syms = t;
2658 }
2659 }
2660 return pCur_syms;
2661}
2662
2663/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat,
2664 * alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */
2665static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) {
2666 int root, leaf, next, avbl, used, dpth;
2667 if (n == 0)
2668 return;
2669 else if (n == 1) {
2670 A[0].m_key = 1;
2671 return;
2672 }
2673 A[0].m_key += A[1].m_key;
2674 root = 0;
2675 leaf = 2;
2676 for (next = 1; next < n - 1; next++) {
2677 if (leaf >= n || A[root].m_key < A[leaf].m_key) {
2678 A[next].m_key = A[root].m_key;
2679 A[root++].m_key = (mz_uint16)next;
2680 } else
2681 A[next].m_key = A[leaf++].m_key;
2682 if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) {
2683 A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key);
2684 A[root++].m_key = (mz_uint16)next;
2685 } else
2686 A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
2687 }
2688 A[n - 2].m_key = 0;
2689 for (next = n - 3; next >= 0; next--)
2690 A[next].m_key = A[A[next].m_key].m_key + 1;
2691 avbl = 1;
2692 used = dpth = 0;
2693 root = n - 2;
2694 next = n - 1;
2695 while (avbl > 0) {
2696 while (root >= 0 && (int)A[root].m_key == dpth) {
2697 used++;
2698 root--;
2699 }
2700 while (avbl > used) {
2701 A[next--].m_key = (mz_uint16)(dpth);
2702 avbl--;
2703 }
2704 avbl = 2 * used;
2705 dpth++;
2706 used = 0;
2707 }
2708}
2709
2710/* Limits canonical Huffman code table's max code size. */
2711enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
2712static void tdefl_huffman_enforce_max_code_size(int *pNum_codes,
2713 int code_list_len,
2714 int max_code_size) {
2715 int i;
2716 mz_uint32 total = 0;
2717 if (code_list_len <= 1)
2718 return;
2719 for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++)
2720 pNum_codes[max_code_size] += pNum_codes[i];
2721 for (i = max_code_size; i > 0; i--)
2722 total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
2723 while (total != (1UL << max_code_size)) {
2724 pNum_codes[max_code_size]--;
2725 for (i = max_code_size - 1; i > 0; i--)
2726 if (pNum_codes[i]) {
2727 pNum_codes[i]--;
2728 pNum_codes[i + 1] += 2;
2729 break;
2730 }
2731 total--;
2732 }
2733}
2734
2735static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num,
2736 int table_len, int code_size_limit,
2737 int static_table) {
2738 int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE];
2739 mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1];
2740 MZ_CLEAR_ARR(num_codes);
2741 if (static_table) {
2742 for (i = 0; i < table_len; i++)
2743 num_codes[d->m_huff_code_sizes[table_num][i]]++;
2744 } else {
2745 tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS],
2746 *pSyms;
2747 int num_used_syms = 0;
2748 const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
2749 for (i = 0; i < table_len; i++)
2750 if (pSym_count[i]) {
2751 syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i];
2752 syms0[num_used_syms++].m_sym_index = (mz_uint16)i;
2753 }
2754
2755 pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1);
2756 tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
2757
2758 for (i = 0; i < num_used_syms; i++)
2759 num_codes[pSyms[i].m_key]++;
2760
2761 tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms,
2762 code_size_limit);
2763
2764 MZ_CLEAR_ARR(d->m_huff_code_sizes[table_num]);
2765 MZ_CLEAR_ARR(d->m_huff_codes[table_num]);
2766 for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
2767 for (l = num_codes[i]; l > 0; l--)
2768 d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
2769 }
2770
2771 next_code[1] = 0;
2772 for (j = 0, i = 2; i <= code_size_limit; i++)
2773 next_code[i] = j = ((j + num_codes[i - 1]) << 1);
2774
2775 for (i = 0; i < table_len; i++) {
2776 mz_uint rev_code = 0, code, code_size;
2777 if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0)
2778 continue;
2779 code = next_code[code_size]++;
2780 for (l = code_size; l > 0; l--, code >>= 1)
2781 rev_code = (rev_code << 1) | (code & 1);
2782 d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
2783 }
2784}
2785
2786#define TDEFL_PUT_BITS(b, l) \
2787 do { \
2788 mz_uint bits = b; \
2789 mz_uint len = l; \
2790 MZ_ASSERT(bits <= ((1U << len) - 1U)); \
2791 d->m_bit_buffer |= (bits << d->m_bits_in); \
2792 d->m_bits_in += len; \
2793 while (d->m_bits_in >= 8) { \
2794 if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
2795 *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
2796 d->m_bit_buffer >>= 8; \
2797 d->m_bits_in -= 8; \
2798 } \
2799 } \
2800 MZ_MACRO_END
2801
2802#define TDEFL_RLE_PREV_CODE_SIZE() \
2803 { \
2804 if (rle_repeat_count) { \
2805 if (rle_repeat_count < 3) { \
2806 d->m_huff_count[2][prev_code_size] = \
2807 (mz_uint16)(d->m_huff_count[2][prev_code_size] + \
2808 rle_repeat_count); \
2809 while (rle_repeat_count--) \
2810 packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
2811 } else { \
2812 d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \
2813 packed_code_sizes[num_packed_code_sizes++] = 16; \
2814 packed_code_sizes[num_packed_code_sizes++] = \
2815 (mz_uint8)(rle_repeat_count - 3); \
2816 } \
2817 rle_repeat_count = 0; \
2818 } \
2819 }
2820
2821#define TDEFL_RLE_ZERO_CODE_SIZE() \
2822 { \
2823 if (rle_z_count) { \
2824 if (rle_z_count < 3) { \
2825 d->m_huff_count[2][0] = \
2826 (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \
2827 while (rle_z_count--) \
2828 packed_code_sizes[num_packed_code_sizes++] = 0; \
2829 } else if (rle_z_count <= 10) { \
2830 d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \
2831 packed_code_sizes[num_packed_code_sizes++] = 17; \
2832 packed_code_sizes[num_packed_code_sizes++] = \
2833 (mz_uint8)(rle_z_count - 3); \
2834 } else { \
2835 d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \
2836 packed_code_sizes[num_packed_code_sizes++] = 18; \
2837 packed_code_sizes[num_packed_code_sizes++] = \
2838 (mz_uint8)(rle_z_count - 11); \
2839 } \
2840 rle_z_count = 0; \
2841 } \
2842 }
2843
2844static const mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = {
2845 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
2846
2847static void tdefl_start_dynamic_block(tdefl_compressor *d) {
2848 int num_lit_codes, num_dist_codes, num_bit_lengths;
2849 mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count,
2850 rle_repeat_count, packed_code_sizes_index;
2851 mz_uint8
2852 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
2853 packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
2854 prev_code_size = 0xFF;
2855
2856 d->m_huff_count[0][256] = 1;
2857
2858 tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
2859 tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
2860
2861 for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--)
2862 if (d->m_huff_code_sizes[0][num_lit_codes - 1])
2863 break;
2864 for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--)
2865 if (d->m_huff_code_sizes[1][num_dist_codes - 1])
2866 break;
2867
2868 memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
2869 memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0],
2870 num_dist_codes);
2871 total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
2872 num_packed_code_sizes = 0;
2873 rle_z_count = 0;
2874 rle_repeat_count = 0;
2875
2876 memset(&d->m_huff_count[2][0], 0,
2877 sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
2878 for (i = 0; i < total_code_sizes_to_pack; i++) {
2879 mz_uint8 code_size = code_sizes_to_pack[i];
2880 if (!code_size) {
2881 TDEFL_RLE_PREV_CODE_SIZE();
2882 if (++rle_z_count == 138) {
2883 TDEFL_RLE_ZERO_CODE_SIZE();
2884 }
2885 } else {
2886 TDEFL_RLE_ZERO_CODE_SIZE();
2887 if (code_size != prev_code_size) {
2888 TDEFL_RLE_PREV_CODE_SIZE();
2889 d->m_huff_count[2][code_size] =
2890 (mz_uint16)(d->m_huff_count[2][code_size] + 1);
2891 packed_code_sizes[num_packed_code_sizes++] = code_size;
2892 } else if (++rle_repeat_count == 6) {
2893 TDEFL_RLE_PREV_CODE_SIZE();
2894 }
2895 }
2896 prev_code_size = code_size;
2897 }
2898 if (rle_repeat_count) {
2899 TDEFL_RLE_PREV_CODE_SIZE();
2900 } else {
2901 TDEFL_RLE_ZERO_CODE_SIZE();
2902 }
2903
2904 tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
2905
2906 TDEFL_PUT_BITS(2, 2);
2907
2908 TDEFL_PUT_BITS(num_lit_codes - 257, 5);
2909 TDEFL_PUT_BITS(num_dist_codes - 1, 5);
2910
2911 for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--)
2912 if (d->m_huff_code_sizes
2913 [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]])
2914 break;
2915 num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1));
2916 TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
2917 for (i = 0; (int)i < num_bit_lengths; i++)
2918 TDEFL_PUT_BITS(
2919 d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
2920
2921 for (packed_code_sizes_index = 0;
2922 packed_code_sizes_index < num_packed_code_sizes;) {
2923 mz_uint code = packed_code_sizes[packed_code_sizes_index++];
2924 MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
2925 TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
2926 if (code >= 16)
2927 TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++],
2928 "\02\03\07"[code - 16]);
2929 }
2930}
2931
2932static void tdefl_start_static_block(tdefl_compressor *d) {
2933 mz_uint i;
2934 mz_uint8 *p = &d->m_huff_code_sizes[0][0];
2935
2936 for (i = 0; i <= 143; ++i)
2937 *p++ = 8;
2938 for (; i <= 255; ++i)
2939 *p++ = 9;
2940 for (; i <= 279; ++i)
2941 *p++ = 7;
2942 for (; i <= 287; ++i)
2943 *p++ = 8;
2944
2945 memset(d->m_huff_code_sizes[1], 5, 32);
2946
2947 tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
2948 tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
2949
2950 TDEFL_PUT_BITS(1, 2);
2951}
2952
2953static const mz_uint mz_bitmasks[17] = {
2954 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
2955 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF};
2956
2957#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \
2958 MINIZ_HAS_64BIT_REGISTERS
2959static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
2960 mz_uint flags;
2961 mz_uint8 *pLZ_codes;
2962 mz_uint8 *pOutput_buf = d->m_pOutput_buf;
2963 mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
2964 mz_uint64 bit_buffer = d->m_bit_buffer;
2965 mz_uint bits_in = d->m_bits_in;
2966
2967#define TDEFL_PUT_BITS_FAST(b, l) \
2968 { \
2969 bit_buffer |= (((mz_uint64)(b)) << bits_in); \
2970 bits_in += (l); \
2971 }
2972
2973 flags = 1;
2974 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end;
2975 flags >>= 1) {
2976 if (flags == 1)
2977 flags = *pLZ_codes++ | 0x100;
2978
2979 if (flags & 1) {
2980 mz_uint s0, s1, n0, n1, sym, num_extra_bits;
2981 mz_uint match_len = pLZ_codes[0];
2982 mz_uint match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));
2983 pLZ_codes += 3;
2984
2985 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
2986 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
2987 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
2988 TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
2989 s_tdefl_len_extra[match_len]);
2990
2991 /* This sequence coaxes MSVC into using cmov's vs. jmp's. */
2992 s0 = s_tdefl_small_dist_sym[match_dist & 511];
2993 n0 = s_tdefl_small_dist_extra[match_dist & 511];
2994 s1 = s_tdefl_large_dist_sym[match_dist >> 8];
2995 n1 = s_tdefl_large_dist_extra[match_dist >> 8];
2996 sym = (match_dist < 512) ? s0 : s1;
2997 num_extra_bits = (match_dist < 512) ? n0 : n1;
2998
2999 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
3000 TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym],
3001 d->m_huff_code_sizes[1][sym]);
3002 TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits],
3003 num_extra_bits);
3004 } else {
3005 mz_uint lit = *pLZ_codes++;
3006 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3007 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3008 d->m_huff_code_sizes[0][lit]);
3009
3010 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
3011 flags >>= 1;
3012 lit = *pLZ_codes++;
3013 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3014 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3015 d->m_huff_code_sizes[0][lit]);
3016
3017 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
3018 flags >>= 1;
3019 lit = *pLZ_codes++;
3020 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3021 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3022 d->m_huff_code_sizes[0][lit]);
3023 }
3024 }
3025 }
3026
3027 if (pOutput_buf >= d->m_pOutput_buf_end)
3028 return MZ_FALSE;
3029
3030 memcpy(pOutput_buf, &bit_buffer, sizeof(mz_uint64));
3031 pOutput_buf += (bits_in >> 3);
3032 bit_buffer >>= (bits_in & ~7);
3033 bits_in &= 7;
3034 }
3035
3036#undef TDEFL_PUT_BITS_FAST
3037
3038 d->m_pOutput_buf = pOutput_buf;
3039 d->m_bits_in = 0;
3040 d->m_bit_buffer = 0;
3041
3042 while (bits_in) {
3043 mz_uint32 n = MZ_MIN(bits_in, 16);
3044 TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
3045 bit_buffer >>= n;
3046 bits_in -= n;
3047 }
3048
3049 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
3050
3051 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
3052}
3053#else
3054static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
3055 mz_uint flags;
3056 mz_uint8 *pLZ_codes;
3057
3058 flags = 1;
3059 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf;
3060 flags >>= 1) {
3061 if (flags == 1)
3062 flags = *pLZ_codes++ | 0x100;
3063 if (flags & 1) {
3064 mz_uint sym, num_extra_bits;
3065 mz_uint match_len = pLZ_codes[0],
3066 match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));
3067 pLZ_codes += 3;
3068
3069 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3070 TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
3071 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3072 TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
3073 s_tdefl_len_extra[match_len]);
3074
3075 if (match_dist < 512) {
3076 sym = s_tdefl_small_dist_sym[match_dist];
3077 num_extra_bits = s_tdefl_small_dist_extra[match_dist];
3078 } else {
3079 sym = s_tdefl_large_dist_sym[match_dist >> 8];
3080 num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
3081 }
3082 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
3083 TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
3084 TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
3085 } else {
3086 mz_uint lit = *pLZ_codes++;
3087 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3088 TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
3089 }
3090 }
3091
3092 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
3093
3094 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
3095}
3096#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \
3097 MINIZ_HAS_64BIT_REGISTERS */
3098
3099static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) {
3100 if (static_block)
3101 tdefl_start_static_block(d);
3102 else
3103 tdefl_start_dynamic_block(d);
3104 return tdefl_compress_lz_codes(d);
3105}
3106
3107static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32,
3108 128, 256, 512, 768, 1500};
3109
3110static int tdefl_flush_block(tdefl_compressor *d, int flush) {
3111 mz_uint saved_bit_buf, saved_bits_in;
3112 mz_uint8 *pSaved_output_buf;
3113 mz_bool comp_block_succeeded = MZ_FALSE;
3114 int n, use_raw_block =
3115 ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
3116 (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
3117 mz_uint8 *pOutput_buf_start =
3118 ((d->m_pPut_buf_func == NULL) &&
3119 ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE))
3120 ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs)
3121 : d->m_output_buf;
3122
3123 d->m_pOutput_buf = pOutput_buf_start;
3124 d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
3125
3126 MZ_ASSERT(!d->m_output_flush_remaining);
3127 d->m_output_flush_ofs = 0;
3128 d->m_output_flush_remaining = 0;
3129
3130 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
3131 d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
3132
3133 if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) {
3134 const mz_uint8 cmf = 0x78;
3135 mz_uint8 flg, flevel = 3;
3136 mz_uint header, i, mz_un = sizeof(s_tdefl_num_probes) / sizeof(mz_uint);
3137
3138 /* Determine compression level by reversing the process in
3139 * tdefl_create_comp_flags_from_zip_params() */
3140 for (i = 0; i < mz_un; i++)
3141 if (s_tdefl_num_probes[i] == (d->m_flags & 0xFFF))
3142 break;
3143
3144 if (i < 2)
3145 flevel = 0;
3146 else if (i < 6)
3147 flevel = 1;
3148 else if (i == 6)
3149 flevel = 2;
3150
3151 header = cmf << 8 | (flevel << 6);
3152 header += 31 - (header % 31);
3153 flg = header & 0xFF;
3154
3155 TDEFL_PUT_BITS(cmf, 8);
3156 TDEFL_PUT_BITS(flg, 8);
3157 }
3158
3159 TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
3160
3161 pSaved_output_buf = d->m_pOutput_buf;
3162 saved_bit_buf = d->m_bit_buffer;
3163 saved_bits_in = d->m_bits_in;
3164
3165 if (!use_raw_block)
3166 comp_block_succeeded =
3167 tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
3168 (d->m_total_lz_bytes < 48));
3169
3170 /* If the block gets expanded, forget the current contents of the output
3171 * buffer and send a raw block instead. */
3172 if (((use_raw_block) ||
3173 ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >=
3174 d->m_total_lz_bytes))) &&
3175 ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) {
3176 mz_uint i;
3177 d->m_pOutput_buf = pSaved_output_buf;
3178 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
3179 TDEFL_PUT_BITS(0, 2);
3180 if (d->m_bits_in) {
3181 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3182 }
3183 for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) {
3184 TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
3185 }
3186 for (i = 0; i < d->m_total_lz_bytes; ++i) {
3187 TDEFL_PUT_BITS(
3188 d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK],
3189 8);
3190 }
3191 }
3192 /* Check for the extremely unlikely (if not impossible) case of the compressed
3193 block not fitting into the output buffer when using dynamic codes. */
3194 else if (!comp_block_succeeded) {
3195 d->m_pOutput_buf = pSaved_output_buf;
3196 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
3197 tdefl_compress_block(d, MZ_TRUE);
3198 }
3199
3200 if (flush) {
3201 if (flush == TDEFL_FINISH) {
3202 if (d->m_bits_in) {
3203 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3204 }
3205 if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) {
3206 mz_uint i, a = d->m_adler32;
3207 for (i = 0; i < 4; i++) {
3208 TDEFL_PUT_BITS((a >> 24) & 0xFF, 8);
3209 a <<= 8;
3210 }
3211 }
3212 } else {
3213 mz_uint i, z = 0;
3214 TDEFL_PUT_BITS(0, 3);
3215 if (d->m_bits_in) {
3216 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3217 }
3218 for (i = 2; i; --i, z ^= 0xFFFF) {
3219 TDEFL_PUT_BITS(z & 0xFFFF, 16);
3220 }
3221 }
3222 }
3223
3224 MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
3225
3226 memset(&d->m_huff_count[0][0], 0,
3227 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
3228 memset(&d->m_huff_count[1][0], 0,
3229 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
3230
3231 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
3232 d->m_pLZ_flags = d->m_lz_code_buf;
3233 d->m_num_flags_left = 8;
3234 d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes;
3235 d->m_total_lz_bytes = 0;
3236 d->m_block_index++;
3237
3238 if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) {
3239 if (d->m_pPut_buf_func) {
3240 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
3241 if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
3242 return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
3243 } else if (pOutput_buf_start == d->m_output_buf) {
3244 int bytes_to_copy = (int)MZ_MIN(
3245 (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
3246 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf,
3247 bytes_to_copy);
3248 d->m_out_buf_ofs += bytes_to_copy;
3249 if ((n -= bytes_to_copy) != 0) {
3250 d->m_output_flush_ofs = bytes_to_copy;
3251 d->m_output_flush_remaining = n;
3252 }
3253 } else {
3254 d->m_out_buf_ofs += n;
3255 }
3256 }
3257
3258 return d->m_output_flush_remaining;
3259}
3260
3261#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
3262#ifdef MINIZ_UNALIGNED_USE_MEMCPY
3263static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8 *p) {
3264 mz_uint16 ret;
3265 memcpy(&ret, p, sizeof(mz_uint16));
3266 return ret;
3267}
3268static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16 *p) {
3269 mz_uint16 ret;
3270 memcpy(&ret, p, sizeof(mz_uint16));
3271 return ret;
3272}
3273#else
3274#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p)
3275#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p)
3276#endif
3277static MZ_FORCEINLINE void
3278tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
3279 mz_uint max_match_len, mz_uint *pMatch_dist,
3280 mz_uint *pMatch_len) {
3281 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
3282 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
3283 probe_len;
3284 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
3285 const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q;
3286 mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]),
3287 s01 = TDEFL_READ_UNALIGNED_WORD2(s);
3288 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
3289 if (max_match_len <= match_len)
3290 return;
3291 for (;;) {
3292 for (;;) {
3293 if (--num_probes_left == 0)
3294 return;
3295#define TDEFL_PROBE \
3296 next_probe_pos = d->m_next[probe_pos]; \
3297 if ((!next_probe_pos) || \
3298 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
3299 return; \
3300 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
3301 if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \
3302 break;
3303 TDEFL_PROBE;
3304 TDEFL_PROBE;
3305 TDEFL_PROBE;
3306 }
3307 if (!dist)
3308 break;
3309 q = (const mz_uint16 *)(d->m_dict + probe_pos);
3310 if (TDEFL_READ_UNALIGNED_WORD2(q) != s01)
3311 continue;
3312 p = s;
3313 probe_len = 32;
3314 do {
3315 } while (
3316 (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&
3317 (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&
3318 (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&
3319 (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&
3320 (--probe_len > 0));
3321 if (!probe_len) {
3322 *pMatch_dist = dist;
3323 *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN);
3324 break;
3325 } else if ((probe_len = ((mz_uint)(p - s) * 2) +
3326 (mz_uint)(*(const mz_uint8 *)p ==
3327 *(const mz_uint8 *)q)) > match_len) {
3328 *pMatch_dist = dist;
3329 if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) ==
3330 max_match_len)
3331 break;
3332 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
3333 }
3334 }
3335}
3336#else
3337static MZ_FORCEINLINE void
3338tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
3339 mz_uint max_match_len, mz_uint *pMatch_dist,
3340 mz_uint *pMatch_len) {
3341 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
3342 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
3343 probe_len;
3344 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
3345 const mz_uint8 *s = d->m_dict + pos, *p, *q;
3346 mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
3347 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
3348 if (max_match_len <= match_len)
3349 return;
3350 for (;;) {
3351 for (;;) {
3352 if (--num_probes_left == 0)
3353 return;
3354#define TDEFL_PROBE \
3355 next_probe_pos = d->m_next[probe_pos]; \
3356 if ((!next_probe_pos) || \
3357 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
3358 return; \
3359 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
3360 if ((d->m_dict[probe_pos + match_len] == c0) && \
3361 (d->m_dict[probe_pos + match_len - 1] == c1)) \
3362 break;
3363 TDEFL_PROBE;
3364 TDEFL_PROBE;
3365 TDEFL_PROBE;
3366 }
3367 if (!dist)
3368 break;
3369 p = s;
3370 q = d->m_dict + probe_pos;
3371 for (probe_len = 0; probe_len < max_match_len; probe_len++)
3372 if (*p++ != *q++)
3373 break;
3374 if (probe_len > match_len) {
3375 *pMatch_dist = dist;
3376 if ((*pMatch_len = match_len = probe_len) == max_match_len)
3377 return;
3378 c0 = d->m_dict[pos + match_len];
3379 c1 = d->m_dict[pos + match_len - 1];
3380 }
3381 }
3382}
3383#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */
3384
3385#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
3386#ifdef MINIZ_UNALIGNED_USE_MEMCPY
3387static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8 *p) {
3388 mz_uint32 ret;
3389 memcpy(&ret, p, sizeof(mz_uint32));
3390 return ret;
3391}
3392#else
3393#define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p)
3394#endif
3395static mz_bool tdefl_compress_fast(tdefl_compressor *d) {
3396 /* Faster, minimally featured LZRW1-style match+parse loop with better
3397 * register utilization. Intended for applications where raw throughput is
3398 * valued more highly than ratio. */
3399 mz_uint lookahead_pos = d->m_lookahead_pos,
3400 lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size,
3401 total_lz_bytes = d->m_total_lz_bytes,
3402 num_flags_left = d->m_num_flags_left;
3403 mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
3404 mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
3405
3406 while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) {
3407 const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
3408 mz_uint dst_pos =
3409 (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
3410 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
3411 d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
3412 d->m_src_buf_left -= num_bytes_to_process;
3413 lookahead_size += num_bytes_to_process;
3414
3415 while (num_bytes_to_process) {
3416 mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
3417 memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
3418 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
3419 memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc,
3420 MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
3421 d->m_pSrc += n;
3422 dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
3423 num_bytes_to_process -= n;
3424 }
3425
3426 dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
3427 if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE))
3428 break;
3429
3430 while (lookahead_size >= 4) {
3431 mz_uint cur_match_dist, cur_match_len = 1;
3432 mz_uint8 *pCur_dict = d->m_dict + cur_pos;
3433 mz_uint first_trigram = TDEFL_READ_UNALIGNED_WORD32(pCur_dict) & 0xFFFFFF;
3434 mz_uint hash =
3435 (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) &
3436 TDEFL_LEVEL1_HASH_SIZE_MASK;
3437 mz_uint probe_pos = d->m_hash[hash];
3438 d->m_hash[hash] = (mz_uint16)lookahead_pos;
3439
3440 if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <=
3441 dict_size) &&
3442 ((TDEFL_READ_UNALIGNED_WORD32(
3443 d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) &
3444 0xFFFFFF) == first_trigram)) {
3445 const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
3446 const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
3447 mz_uint32 probe_len = 32;
3448 do {
3449 } while ((TDEFL_READ_UNALIGNED_WORD2(++p) ==
3450 TDEFL_READ_UNALIGNED_WORD2(++q)) &&
3451 (TDEFL_READ_UNALIGNED_WORD2(++p) ==
3452 TDEFL_READ_UNALIGNED_WORD2(++q)) &&
3453 (TDEFL_READ_UNALIGNED_WORD2(++p) ==
3454 TDEFL_READ_UNALIGNED_WORD2(++q)) &&
3455 (TDEFL_READ_UNALIGNED_WORD2(++p) ==
3456 TDEFL_READ_UNALIGNED_WORD2(++q)) &&
3457 (--probe_len > 0));
3458 cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) +
3459 (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
3460 if (!probe_len)
3461 cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
3462
3463 if ((cur_match_len < TDEFL_MIN_MATCH_LEN) ||
3464 ((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
3465 (cur_match_dist >= 8U * 1024U))) {
3466 cur_match_len = 1;
3467 *pLZ_code_buf++ = (mz_uint8)first_trigram;
3468 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3469 d->m_huff_count[0][(mz_uint8)first_trigram]++;
3470 } else {
3471 mz_uint32 s0, s1;
3472 cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
3473
3474 MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) &&
3475 (cur_match_dist >= 1) &&
3476 (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
3477
3478 cur_match_dist--;
3479
3480 pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
3481#ifdef MINIZ_UNALIGNED_USE_MEMCPY
3482 memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist));
3483#else
3484 *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
3485#endif
3486 pLZ_code_buf += 3;
3487 *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
3488
3489 s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
3490 s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
3491 d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
3492
3493 d->m_huff_count[0][s_tdefl_len_sym[cur_match_len -
3494 TDEFL_MIN_MATCH_LEN]]++;
3495 }
3496 } else {
3497 *pLZ_code_buf++ = (mz_uint8)first_trigram;
3498 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3499 d->m_huff_count[0][(mz_uint8)first_trigram]++;
3500 }
3501
3502 if (--num_flags_left == 0) {
3503 num_flags_left = 8;
3504 pLZ_flags = pLZ_code_buf++;
3505 }
3506
3507 total_lz_bytes += cur_match_len;
3508 lookahead_pos += cur_match_len;
3509 dict_size =
3510 MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE);
3511 cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
3512 MZ_ASSERT(lookahead_size >= cur_match_len);
3513 lookahead_size -= cur_match_len;
3514
3515 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
3516 int n;
3517 d->m_lookahead_pos = lookahead_pos;
3518 d->m_lookahead_size = lookahead_size;
3519 d->m_dict_size = dict_size;
3520 d->m_total_lz_bytes = total_lz_bytes;
3521 d->m_pLZ_code_buf = pLZ_code_buf;
3522 d->m_pLZ_flags = pLZ_flags;
3523 d->m_num_flags_left = num_flags_left;
3524 if ((n = tdefl_flush_block(d, 0)) != 0)
3525 return (n < 0) ? MZ_FALSE : MZ_TRUE;
3526 total_lz_bytes = d->m_total_lz_bytes;
3527 pLZ_code_buf = d->m_pLZ_code_buf;
3528 pLZ_flags = d->m_pLZ_flags;
3529 num_flags_left = d->m_num_flags_left;
3530 }
3531 }
3532
3533 while (lookahead_size) {
3534 mz_uint8 lit = d->m_dict[cur_pos];
3535
3536 total_lz_bytes++;
3537 *pLZ_code_buf++ = lit;
3538 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3539 if (--num_flags_left == 0) {
3540 num_flags_left = 8;
3541 pLZ_flags = pLZ_code_buf++;
3542 }
3543
3544 d->m_huff_count[0][lit]++;
3545
3546 lookahead_pos++;
3547 dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE);
3548 cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
3549 lookahead_size--;
3550
3551 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
3552 int n;
3553 d->m_lookahead_pos = lookahead_pos;
3554 d->m_lookahead_size = lookahead_size;
3555 d->m_dict_size = dict_size;
3556 d->m_total_lz_bytes = total_lz_bytes;
3557 d->m_pLZ_code_buf = pLZ_code_buf;
3558 d->m_pLZ_flags = pLZ_flags;
3559 d->m_num_flags_left = num_flags_left;
3560 if ((n = tdefl_flush_block(d, 0)) != 0)
3561 return (n < 0) ? MZ_FALSE : MZ_TRUE;
3562 total_lz_bytes = d->m_total_lz_bytes;
3563 pLZ_code_buf = d->m_pLZ_code_buf;
3564 pLZ_flags = d->m_pLZ_flags;
3565 num_flags_left = d->m_num_flags_left;
3566 }
3567 }
3568 }
3569
3570 d->m_lookahead_pos = lookahead_pos;
3571 d->m_lookahead_size = lookahead_size;
3572 d->m_dict_size = dict_size;
3573 d->m_total_lz_bytes = total_lz_bytes;
3574 d->m_pLZ_code_buf = pLZ_code_buf;
3575 d->m_pLZ_flags = pLZ_flags;
3576 d->m_num_flags_left = num_flags_left;
3577 return MZ_TRUE;
3578}
3579#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */
3580
3581static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d,
3582 mz_uint8 lit) {
3583 d->m_total_lz_bytes++;
3584 *d->m_pLZ_code_buf++ = lit;
3585 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1);
3586 if (--d->m_num_flags_left == 0) {
3587 d->m_num_flags_left = 8;
3588 d->m_pLZ_flags = d->m_pLZ_code_buf++;
3589 }
3590 d->m_huff_count[0][lit]++;
3591}
3592
3593static MZ_FORCEINLINE void
3594tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) {
3595 mz_uint32 s0, s1;
3596
3597 MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) &&
3598 (match_dist <= TDEFL_LZ_DICT_SIZE));
3599
3600 d->m_total_lz_bytes += match_len;
3601
3602 d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
3603
3604 match_dist -= 1;
3605 d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
3606 d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8);
3607 d->m_pLZ_code_buf += 3;
3608
3609 *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80);
3610 if (--d->m_num_flags_left == 0) {
3611 d->m_num_flags_left = 8;
3612 d->m_pLZ_flags = d->m_pLZ_code_buf++;
3613 }
3614
3615 s0 = s_tdefl_small_dist_sym[match_dist & 511];
3616 s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
3617 d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
3618 d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
3619}
3620
3621static mz_bool tdefl_compress_normal(tdefl_compressor *d) {
3622 const mz_uint8 *pSrc = d->m_pSrc;
3623 size_t src_buf_left = d->m_src_buf_left;
3624 tdefl_flush flush = d->m_flush;
3625
3626 while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) {
3627 mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
3628 /* Update dictionary and hash chains. Keeps the lookahead size equal to
3629 * TDEFL_MAX_MATCH_LEN. */
3630 if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) {
3631 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
3632 TDEFL_LZ_DICT_SIZE_MASK,
3633 ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;
3634 mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
3635 << TDEFL_LZ_HASH_SHIFT) ^
3636 d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];
3637 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
3638 src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
3639 const mz_uint8 *pSrc_end = pSrc ? pSrc + num_bytes_to_process : NULL;
3640 src_buf_left -= num_bytes_to_process;
3641 d->m_lookahead_size += num_bytes_to_process;
3642 while (pSrc != pSrc_end) {
3643 mz_uint8 c = *pSrc++;
3644 d->m_dict[dst_pos] = c;
3645 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
3646 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
3647 hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
3648 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
3649 d->m_hash[hash] = (mz_uint16)(ins_pos);
3650 dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
3651 ins_pos++;
3652 }
3653 } else {
3654 while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) {
3655 mz_uint8 c = *pSrc++;
3656 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
3657 TDEFL_LZ_DICT_SIZE_MASK;
3658 src_buf_left--;
3659 d->m_dict[dst_pos] = c;
3660 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
3661 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
3662 if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) {
3663 mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
3664 mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
3665 << (TDEFL_LZ_HASH_SHIFT * 2)) ^
3666 (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]
3667 << TDEFL_LZ_HASH_SHIFT) ^
3668 c) &
3669 (TDEFL_LZ_HASH_SIZE - 1);
3670 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
3671 d->m_hash[hash] = (mz_uint16)(ins_pos);
3672 }
3673 }
3674 }
3675 d->m_dict_size =
3676 MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
3677 if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
3678 break;
3679
3680 /* Simple lazy/greedy parsing state machine. */
3681 len_to_move = 1;
3682 cur_match_dist = 0;
3683 cur_match_len =
3684 d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1);
3685 cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
3686 if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) {
3687 if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) {
3688 mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
3689 cur_match_len = 0;
3690 while (cur_match_len < d->m_lookahead_size) {
3691 if (d->m_dict[cur_pos + cur_match_len] != c)
3692 break;
3693 cur_match_len++;
3694 }
3695 if (cur_match_len < TDEFL_MIN_MATCH_LEN)
3696 cur_match_len = 0;
3697 else
3698 cur_match_dist = 1;
3699 }
3700 } else {
3701 tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size,
3702 d->m_lookahead_size, &cur_match_dist, &cur_match_len);
3703 }
3704 if (((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
3705 (cur_match_dist >= 8U * 1024U)) ||
3706 (cur_pos == cur_match_dist) ||
3707 ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) {
3708 cur_match_dist = cur_match_len = 0;
3709 }
3710 if (d->m_saved_match_len) {
3711 if (cur_match_len > d->m_saved_match_len) {
3712 tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
3713 if (cur_match_len >= 128) {
3714 tdefl_record_match(d, cur_match_len, cur_match_dist);
3715 d->m_saved_match_len = 0;
3716 len_to_move = cur_match_len;
3717 } else {
3718 d->m_saved_lit = d->m_dict[cur_pos];
3719 d->m_saved_match_dist = cur_match_dist;
3720 d->m_saved_match_len = cur_match_len;
3721 }
3722 } else {
3723 tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
3724 len_to_move = d->m_saved_match_len - 1;
3725 d->m_saved_match_len = 0;
3726 }
3727 } else if (!cur_match_dist)
3728 tdefl_record_literal(d,
3729 d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
3730 else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) ||
3731 (cur_match_len >= 128)) {
3732 tdefl_record_match(d, cur_match_len, cur_match_dist);
3733 len_to_move = cur_match_len;
3734 } else {
3735 d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)];
3736 d->m_saved_match_dist = cur_match_dist;
3737 d->m_saved_match_len = cur_match_len;
3738 }
3739 /* Move the lookahead forward by len_to_move bytes. */
3740 d->m_lookahead_pos += len_to_move;
3741 MZ_ASSERT(d->m_lookahead_size >= len_to_move);
3742 d->m_lookahead_size -= len_to_move;
3743 d->m_dict_size =
3744 MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE);
3745 /* Check if it's time to flush the current LZ codes to the internal output
3746 * buffer. */
3747 if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
3748 ((d->m_total_lz_bytes > 31 * 1024) &&
3749 (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >=
3750 d->m_total_lz_bytes) ||
3751 (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) {
3752 int n;
3753 d->m_pSrc = pSrc;
3754 d->m_src_buf_left = src_buf_left;
3755 if ((n = tdefl_flush_block(d, 0)) != 0)
3756 return (n < 0) ? MZ_FALSE : MZ_TRUE;
3757 }
3758 }
3759
3760 d->m_pSrc = pSrc;
3761 d->m_src_buf_left = src_buf_left;
3762 return MZ_TRUE;
3763}
3764
3765static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) {
3766 if (d->m_pIn_buf_size) {
3767 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
3768 }
3769
3770 if (d->m_pOut_buf_size) {
3771 size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs,
3772 d->m_output_flush_remaining);
3773 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs,
3774 d->m_output_buf + d->m_output_flush_ofs, n);
3775 d->m_output_flush_ofs += (mz_uint)n;
3776 d->m_output_flush_remaining -= (mz_uint)n;
3777 d->m_out_buf_ofs += n;
3778
3779 *d->m_pOut_buf_size = d->m_out_buf_ofs;
3780 }
3781
3782 return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE
3783 : TDEFL_STATUS_OKAY;
3784}
3785
3786tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf,
3787 size_t *pIn_buf_size, void *pOut_buf,
3788 size_t *pOut_buf_size, tdefl_flush flush) {
3789 if (!d) {
3790 if (pIn_buf_size)
3791 *pIn_buf_size = 0;
3792 if (pOut_buf_size)
3793 *pOut_buf_size = 0;
3794 return TDEFL_STATUS_BAD_PARAM;
3795 }
3796
3797 d->m_pIn_buf = pIn_buf;
3798 d->m_pIn_buf_size = pIn_buf_size;
3799 d->m_pOut_buf = pOut_buf;
3800 d->m_pOut_buf_size = pOut_buf_size;
3801 d->m_pSrc = (const mz_uint8 *)(pIn_buf);
3802 d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
3803 d->m_out_buf_ofs = 0;
3804 d->m_flush = flush;
3805
3806 if (((d->m_pPut_buf_func != NULL) ==
3807 ((pOut_buf != NULL) || (pOut_buf_size != NULL))) ||
3808 (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
3809 (d->m_wants_to_finish && (flush != TDEFL_FINISH)) ||
3810 (pIn_buf_size && *pIn_buf_size && !pIn_buf) ||
3811 (pOut_buf_size && *pOut_buf_size && !pOut_buf)) {
3812 if (pIn_buf_size)
3813 *pIn_buf_size = 0;
3814 if (pOut_buf_size)
3815 *pOut_buf_size = 0;
3816 return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
3817 }
3818 d->m_wants_to_finish |= (flush == TDEFL_FINISH);
3819
3820 if ((d->m_output_flush_remaining) || (d->m_finished))
3821 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
3822
3823#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
3824 if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
3825 ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
3826 ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS |
3827 TDEFL_RLE_MATCHES)) == 0)) {
3828 if (!tdefl_compress_fast(d))
3829 return d->m_prev_return_status;
3830 } else
3831#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */
3832 {
3833 if (!tdefl_compress_normal(d))
3834 return d->m_prev_return_status;
3835 }
3836
3837 if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) &&
3838 (pIn_buf))
3839 d->m_adler32 =
3840 (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf,
3841 d->m_pSrc - (const mz_uint8 *)pIn_buf);
3842
3843 if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) &&
3844 (!d->m_output_flush_remaining)) {
3845 if (tdefl_flush_block(d, flush) < 0)
3846 return d->m_prev_return_status;
3847 d->m_finished = (flush == TDEFL_FINISH);
3848 if (flush == TDEFL_FULL_FLUSH) {
3849 MZ_CLEAR_ARR(d->m_hash);
3850 MZ_CLEAR_ARR(d->m_next);
3851 d->m_dict_size = 0;
3852 }
3853 }
3854
3855 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
3856}
3857
3858tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf,
3859 size_t in_buf_size, tdefl_flush flush) {
3860 MZ_ASSERT(d->m_pPut_buf_func);
3861 return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
3862}
3863
3864tdefl_status tdefl_init(tdefl_compressor *d,
3865 tdefl_put_buf_func_ptr pPut_buf_func,
3866 void *pPut_buf_user, int flags) {
3867 d->m_pPut_buf_func = pPut_buf_func;
3868 d->m_pPut_buf_user = pPut_buf_user;
3869 d->m_flags = (mz_uint)(flags);
3870 d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3;
3871 d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
3872 d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
3873 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG))
3874 MZ_CLEAR_ARR(d->m_hash);
3875 d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size =
3876 d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;
3877 d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished =
3878 d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;
3879 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
3880 d->m_pLZ_flags = d->m_lz_code_buf;
3881 *d->m_pLZ_flags = 0;
3882 d->m_num_flags_left = 8;
3883 d->m_pOutput_buf = d->m_output_buf;
3884 d->m_pOutput_buf_end = d->m_output_buf;
3885 d->m_prev_return_status = TDEFL_STATUS_OKAY;
3886 d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0;
3887 d->m_adler32 = 1;
3888 d->m_pIn_buf = NULL;
3889 d->m_pOut_buf = NULL;
3890 d->m_pIn_buf_size = NULL;
3891 d->m_pOut_buf_size = NULL;
3892 d->m_flush = TDEFL_NO_FLUSH;
3893 d->m_pSrc = NULL;
3894 d->m_src_buf_left = 0;
3895 d->m_out_buf_ofs = 0;
3896 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG))
3897 MZ_CLEAR_ARR(d->m_dict);
3898 memset(&d->m_huff_count[0][0], 0,
3899 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
3900 memset(&d->m_huff_count[1][0], 0,
3901 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
3902 return TDEFL_STATUS_OKAY;
3903}
3904
3905tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) {
3906 return d->m_prev_return_status;
3907}
3908
3909mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; }
3910
3911mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len,
3912 tdefl_put_buf_func_ptr pPut_buf_func,
3913 void *pPut_buf_user, int flags) {
3914 tdefl_compressor *pComp;
3915 mz_bool succeeded;
3916 if (((buf_len) && (!pBuf)) || (!pPut_buf_func))
3917 return MZ_FALSE;
3918 pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
3919 if (!pComp)
3920 return MZ_FALSE;
3921 succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) ==
3922 TDEFL_STATUS_OKAY);
3923 succeeded =
3924 succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) ==
3925 TDEFL_STATUS_DONE);
3926 MZ_FREE(pComp);
3927 return succeeded;
3928}
3929
3930typedef struct {
3931 size_t m_size, m_capacity;
3932 mz_uint8 *m_pBuf;
3933 mz_bool m_expandable;
3935
3936static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len,
3937 void *pUser) {
3939 size_t new_size = p->m_size + len;
3940 if (new_size > p->m_capacity) {
3941 size_t new_capacity = p->m_capacity;
3942 mz_uint8 *pNew_buf;
3943 if (!p->m_expandable)
3944 return MZ_FALSE;
3945 do {
3946 new_capacity = MZ_MAX(128U, new_capacity << 1U);
3947 } while (new_size > new_capacity);
3948 pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity);
3949 if (!pNew_buf)
3950 return MZ_FALSE;
3951 p->m_pBuf = pNew_buf;
3952 p->m_capacity = new_capacity;
3953 }
3954 memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len);
3955 p->m_size = new_size;
3956 return MZ_TRUE;
3957}
3958
3959void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
3960 size_t *pOut_len, int flags) {
3961 tdefl_output_buffer out_buf;
3962 MZ_CLEAR_OBJ(out_buf);
3963 if (!pOut_len)
3964 return MZ_FALSE;
3965 else
3966 *pOut_len = 0;
3967 out_buf.m_expandable = MZ_TRUE;
3968 if (!tdefl_compress_mem_to_output(
3969 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
3970 return NULL;
3971 *pOut_len = out_buf.m_size;
3972 return out_buf.m_pBuf;
3973}
3974
3975size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
3976 const void *pSrc_buf, size_t src_buf_len,
3977 int flags) {
3978 tdefl_output_buffer out_buf;
3979 MZ_CLEAR_OBJ(out_buf);
3980 if (!pOut_buf)
3981 return 0;
3982 out_buf.m_pBuf = (mz_uint8 *)pOut_buf;
3983 out_buf.m_capacity = out_buf_len;
3984 if (!tdefl_compress_mem_to_output(
3985 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
3986 return 0;
3987 return out_buf.m_size;
3988}
3989
3990/* level may actually range from [0,10] (10 is a "hidden" max level, where we
3991 * want a bit more compression and it's fine if throughput to fall off a cliff
3992 * on some files). */
3993mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
3994 int strategy) {
3995 mz_uint comp_flags =
3996 s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] |
3997 ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
3998 if (window_bits > 0)
3999 comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
4000
4001 if (!level)
4002 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
4003 else if (strategy == MZ_FILTERED)
4004 comp_flags |= TDEFL_FILTER_MATCHES;
4005 else if (strategy == MZ_HUFFMAN_ONLY)
4006 comp_flags &= ~TDEFL_MAX_PROBES_MASK;
4007 else if (strategy == MZ_FIXED)
4008 comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
4009 else if (strategy == MZ_RLE)
4010 comp_flags |= TDEFL_RLE_MATCHES;
4011
4012 return comp_flags;
4013}
4014
4015#ifdef _MSC_VER
4016#pragma warning(push)
4017#pragma warning(disable : 4204) /* nonstandard extension used : non-constant \
4018 aggregate initializer (also supported by \
4019 GNU C and C99, so no big deal) */
4020#endif
4021
4022/* Simple PNG writer function by Alex Evans, 2011. Released into the public
4023 domain: https://gist.github.com/908299, more context at
4024 http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
4025 This is actually a modification of Alex's original code so PNG files generated
4026 by this function pass pngcheck. */
4027void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w,
4028 int h, int num_chans,
4029 size_t *pLen_out,
4030 mz_uint level, mz_bool flip) {
4031 /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was
4032 * defined. */
4033 static const mz_uint s_tdefl_png_num_probes[11] = {
4034 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500};
4035 tdefl_compressor *pComp =
4036 (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
4037 tdefl_output_buffer out_buf;
4038 int i, bpl = w * num_chans, y, z;
4039 mz_uint32 c;
4040 *pLen_out = 0;
4041 if (!pComp)
4042 return NULL;
4043 MZ_CLEAR_OBJ(out_buf);
4044 out_buf.m_expandable = MZ_TRUE;
4045 out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h);
4046 if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) {
4047 MZ_FREE(pComp);
4048 return NULL;
4049 }
4050 /* write dummy header */
4051 for (z = 41; z; --z)
4052 tdefl_output_buffer_putter(&z, 1, &out_buf);
4053 /* compress image data */
4054 tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf,
4055 s_tdefl_png_num_probes[MZ_MIN(10, level)] |
4056 TDEFL_WRITE_ZLIB_HEADER);
4057 for (y = 0; y < h; ++y) {
4058 tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH);
4059 tdefl_compress_buffer(pComp,
4060 (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl,
4061 bpl, TDEFL_NO_FLUSH);
4062 }
4063 if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) !=
4064 TDEFL_STATUS_DONE) {
4065 MZ_FREE(pComp);
4066 MZ_FREE(out_buf.m_pBuf);
4067 return NULL;
4068 }
4069 /* write real header */
4070 *pLen_out = out_buf.m_size - 41;
4071 {
4072 static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06};
4073 mz_uint8 pnghdr[41] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00,
4074 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00,
4075 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
4076 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4077 0x00, 0x49, 0x44, 0x41, 0x54};
4078 pnghdr[18] = (mz_uint8)(w >> 8);
4079 pnghdr[19] = (mz_uint8)w;
4080 pnghdr[22] = (mz_uint8)(h >> 8);
4081 pnghdr[23] = (mz_uint8)h;
4082 pnghdr[25] = chans[num_chans];
4083 pnghdr[33] = (mz_uint8)(*pLen_out >> 24);
4084 pnghdr[34] = (mz_uint8)(*pLen_out >> 16);
4085 pnghdr[35] = (mz_uint8)(*pLen_out >> 8);
4086 pnghdr[36] = (mz_uint8)*pLen_out;
4087 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17);
4088 for (i = 0; i < 4; ++i, c <<= 8)
4089 ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24);
4090 memcpy(out_buf.m_pBuf, pnghdr, 41);
4091 }
4092 /* write footer (IDAT CRC-32, followed by IEND chunk) */
4093 if (!tdefl_output_buffer_putter(
4094 "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) {
4095 *pLen_out = 0;
4096 MZ_FREE(pComp);
4097 MZ_FREE(out_buf.m_pBuf);
4098 return NULL;
4099 }
4100 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4,
4101 *pLen_out + 4);
4102 for (i = 0; i < 4; ++i, c <<= 8)
4103 (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24);
4104 /* compute final size of file, grab compressed data buffer and return */
4105 *pLen_out += 57;
4106 MZ_FREE(pComp);
4107 return out_buf.m_pBuf;
4108}
4109void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
4110 int num_chans, size_t *pLen_out) {
4111 /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we
4112 * can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's
4113 * where #defined out) */
4114 return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans,
4115 pLen_out, 6, MZ_FALSE);
4116}
4117
4118#ifndef MINIZ_NO_MALLOC
4119/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that
4120 */
4121/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */
4122/* structure size and allocation mechanism. */
4123tdefl_compressor *tdefl_compressor_alloc(void) {
4124 return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
4125}
4126
4127void tdefl_compressor_free(tdefl_compressor *pComp) { MZ_FREE(pComp); }
4128#endif
4129
4130#ifdef _MSC_VER
4131#pragma warning(pop)
4132#endif
4133
4134#ifdef __cplusplus
4135}
4136#endif
4137
4138#endif /*#ifndef MINIZ_NO_DEFLATE_APIS*/
4139/**************************************************************************
4140 *
4141 * Copyright 2013-2014 RAD Game Tools and Valve Software
4142 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
4143 * All Rights Reserved.
4144 *
4145 * Permission is hereby granted, free of charge, to any person obtaining a copy
4146 * of this software and associated documentation files (the "Software"), to deal
4147 * in the Software without restriction, including without limitation the rights
4148 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4149 * copies of the Software, and to permit persons to whom the Software is
4150 * furnished to do so, subject to the following conditions:
4151 *
4152 * The above copyright notice and this permission notice shall be included in
4153 * all copies or substantial portions of the Software.
4154 *
4155 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4156 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4157 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4158 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4159 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4160 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4161 * THE SOFTWARE.
4162 *
4163 **************************************************************************/
4164
4165#ifndef MINIZ_NO_INFLATE_APIS
4166
4167#ifdef __cplusplus
4168extern "C" {
4169#endif
4170
4171/* ------------------- Low-level Decompression (completely independent from all
4172 * compression API's) */
4173
4174#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
4175#define TINFL_MEMSET(p, c, l) memset(p, c, l)
4176
4177#define TINFL_CR_BEGIN \
4178 switch (r->m_state) { \
4179 case 0:
4180#define TINFL_CR_RETURN(state_index, result) \
4181 do { \
4182 status = result; \
4183 r->m_state = state_index; \
4184 goto common_exit; \
4185 case state_index:; \
4186 } \
4187 MZ_MACRO_END
4188#define TINFL_CR_RETURN_FOREVER(state_index, result) \
4189 do { \
4190 for (;;) { \
4191 TINFL_CR_RETURN(state_index, result); \
4192 } \
4193 } \
4194 MZ_MACRO_END
4195#define TINFL_CR_FINISH }
4196
4197#define TINFL_GET_BYTE(state_index, c) \
4198 do { \
4199 while (pIn_buf_cur >= pIn_buf_end) { \
4200 TINFL_CR_RETURN(state_index, \
4201 (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) \
4202 ? TINFL_STATUS_NEEDS_MORE_INPUT \
4203 : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \
4204 } \
4205 c = *pIn_buf_cur++; \
4206 } \
4207 MZ_MACRO_END
4208
4209#define TINFL_NEED_BITS(state_index, n) \
4210 do { \
4211 mz_uint c; \
4212 TINFL_GET_BYTE(state_index, c); \
4213 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
4214 num_bits += 8; \
4215 } while (num_bits < (mz_uint)(n))
4216#define TINFL_SKIP_BITS(state_index, n) \
4217 do { \
4218 if (num_bits < (mz_uint)(n)) { \
4219 TINFL_NEED_BITS(state_index, n); \
4220 } \
4221 bit_buf >>= (n); \
4222 num_bits -= (n); \
4223 } \
4224 MZ_MACRO_END
4225#define TINFL_GET_BITS(state_index, b, n) \
4226 do { \
4227 if (num_bits < (mz_uint)(n)) { \
4228 TINFL_NEED_BITS(state_index, n); \
4229 } \
4230 b = bit_buf & ((1 << (n)) - 1); \
4231 bit_buf >>= (n); \
4232 num_bits -= (n); \
4233 } \
4234 MZ_MACRO_END
4235
4236/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes
4237 * remaining in the input buffer falls below 2. */
4238/* It reads just enough bytes from the input stream that are needed to decode
4239 * the next Huffman code (and absolutely no more). It works by trying to fully
4240 * decode a */
4241/* Huffman code by using whatever bits are currently present in the bit buffer.
4242 * If this fails, it reads another byte, and tries again until it succeeds or
4243 * until the */
4244/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */
4245#define TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree) \
4246 do { \
4247 temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
4248 if (temp >= 0) { \
4249 code_len = temp >> 9; \
4250 if ((code_len) && (num_bits >= code_len)) \
4251 break; \
4252 } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
4253 code_len = TINFL_FAST_LOOKUP_BITS; \
4254 do { \
4255 temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \
4256 } while ((temp < 0) && (num_bits >= (code_len + 1))); \
4257 if (temp >= 0) \
4258 break; \
4259 } \
4260 TINFL_GET_BYTE(state_index, c); \
4261 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
4262 num_bits += 8; \
4263 } while (num_bits < 15);
4264
4265/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex
4266 * than you would initially expect because the zlib API expects the decompressor
4267 * to never read */
4268/* beyond the final byte of the deflate stream. (In other words, when this macro
4269 * wants to read another byte from the input, it REALLY needs another byte in
4270 * order to fully */
4271/* decode the next Huffman code.) Handling this properly is particularly
4272 * important on raw deflate (non-zlib) streams, which aren't followed by a byte
4273 * aligned adler-32. */
4274/* The slow path is only executed at the very end of the input buffer. */
4275/* v1.16: The original macro handled the case at the very end of the passed-in
4276 * input buffer, but we also need to handle the case where the user passes in
4277 * 1+zillion bytes */
4278/* following the deflate data and our non-conservative read-ahead path won't
4279 * kick in here on this code. This is much trickier. */
4280#define TINFL_HUFF_DECODE(state_index, sym, pLookUp, pTree) \
4281 do { \
4282 int temp; \
4283 mz_uint code_len, c; \
4284 if (num_bits < 15) { \
4285 if ((pIn_buf_end - pIn_buf_cur) < 2) { \
4286 TINFL_HUFF_BITBUF_FILL(state_index, pLookUp, pTree); \
4287 } else { \
4288 bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \
4289 (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \
4290 pIn_buf_cur += 2; \
4291 num_bits += 16; \
4292 } \
4293 } \
4294 if ((temp = pLookUp[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
4295 code_len = temp >> 9, temp &= 511; \
4296 else { \
4297 code_len = TINFL_FAST_LOOKUP_BITS; \
4298 do { \
4299 temp = pTree[~temp + ((bit_buf >> code_len++) & 1)]; \
4300 } while (temp < 0); \
4301 } \
4302 sym = temp; \
4303 bit_buf >>= code_len; \
4304 num_bits -= code_len; \
4305 } \
4306 MZ_MACRO_END
4307
4308static void tinfl_clear_tree(tinfl_decompressor *r) {
4309 if (r->m_type == 0)
4310 MZ_CLEAR_ARR(r->m_tree_0);
4311 else if (r->m_type == 1)
4312 MZ_CLEAR_ARR(r->m_tree_1);
4313 else
4314 MZ_CLEAR_ARR(r->m_tree_2);
4315}
4316
4317tinfl_status tinfl_decompress(tinfl_decompressor *r,
4318 const mz_uint8 *pIn_buf_next,
4319 size_t *pIn_buf_size, mz_uint8 *pOut_buf_start,
4320 mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
4321 const mz_uint32 decomp_flags) {
4322 static const mz_uint16 s_length_base[31] = {
4323 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
4324 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
4325 static const mz_uint8 s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
4326 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
4327 4, 4, 5, 5, 5, 5, 0, 0, 0};
4328 static const mz_uint16 s_dist_base[32] = {
4329 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33,
4330 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
4331 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0};
4332 static const mz_uint8 s_dist_extra[32] = {
4333 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6,
4334 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
4335 static const mz_uint8 s_length_dezigzag[19] = {
4336 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
4337 static const mz_uint16 s_min_table_sizes[3] = {257, 1, 4};
4338
4339 mz_int16 *pTrees[3];
4340 mz_uint8 *pCode_sizes[3];
4341
4342 tinfl_status status = TINFL_STATUS_FAILED;
4343 mz_uint32 num_bits, dist, counter, num_extra;
4344 tinfl_bit_buf_t bit_buf;
4345 const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end =
4346 pIn_buf_next + *pIn_buf_size;
4347 mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end =
4348 pOut_buf_next ? pOut_buf_next +
4349 *pOut_buf_size
4350 : NULL;
4351 size_t out_buf_size_mask =
4352 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)
4353 ? (size_t)-1
4354 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1,
4355 dist_from_out_buf_start;
4356
4357 /* Ensure the output buffer's size is a power of 2, unless the output buffer
4358 * is large enough to hold the entire output file (in which case it doesn't
4359 * matter). */
4360 if (((out_buf_size_mask + 1) & out_buf_size_mask) ||
4361 (pOut_buf_next < pOut_buf_start)) {
4362 *pIn_buf_size = *pOut_buf_size = 0;
4363 return TINFL_STATUS_BAD_PARAM;
4364 }
4365
4366 pTrees[0] = r->m_tree_0;
4367 pTrees[1] = r->m_tree_1;
4368 pTrees[2] = r->m_tree_2;
4369 pCode_sizes[0] = r->m_code_size_0;
4370 pCode_sizes[1] = r->m_code_size_1;
4371 pCode_sizes[2] = r->m_code_size_2;
4372
4373 num_bits = r->m_num_bits;
4374 bit_buf = r->m_bit_buf;
4375 dist = r->m_dist;
4376 counter = r->m_counter;
4377 num_extra = r->m_num_extra;
4378 dist_from_out_buf_start = r->m_dist_from_out_buf_start;
4379 TINFL_CR_BEGIN
4380
4381 bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0;
4382 r->m_z_adler32 = r->m_check_adler32 = 1;
4383 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
4384 TINFL_GET_BYTE(1, r->m_zhdr0);
4385 TINFL_GET_BYTE(2, r->m_zhdr1);
4386 counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) ||
4387 (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
4388 if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
4389 counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) ||
4390 ((out_buf_size_mask + 1) <
4391 (size_t)((size_t)1 << (8U + (r->m_zhdr0 >> 4)))));
4392 if (counter) {
4393 TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED);
4394 }
4395 }
4396
4397 do {
4398 TINFL_GET_BITS(3, r->m_final, 3);
4399 r->m_type = r->m_final >> 1;
4400 if (r->m_type == 0) {
4401 TINFL_SKIP_BITS(5, num_bits & 7);
4402 for (counter = 0; counter < 4; ++counter) {
4403 if (num_bits)
4404 TINFL_GET_BITS(6, r->m_raw_header[counter], 8);
4405 else
4406 TINFL_GET_BYTE(7, r->m_raw_header[counter]);
4407 }
4408 if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) !=
4409 (mz_uint)(0xFFFF ^
4410 (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) {
4411 TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED);
4412 }
4413 while ((counter) && (num_bits)) {
4414 TINFL_GET_BITS(51, dist, 8);
4415 while (pOut_buf_cur >= pOut_buf_end) {
4416 TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT);
4417 }
4418 *pOut_buf_cur++ = (mz_uint8)dist;
4419 counter--;
4420 }
4421 while (counter) {
4422 size_t n;
4423 while (pOut_buf_cur >= pOut_buf_end) {
4424 TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT);
4425 }
4426 while (pIn_buf_cur >= pIn_buf_end) {
4427 TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
4428 ? TINFL_STATUS_NEEDS_MORE_INPUT
4429 : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS);
4430 }
4431 n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur),
4432 (size_t)(pIn_buf_end - pIn_buf_cur)),
4433 counter);
4434 TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n);
4435 pIn_buf_cur += n;
4436 pOut_buf_cur += n;
4437 counter -= (mz_uint)n;
4438 }
4439 } else if (r->m_type == 3) {
4440 TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
4441 } else {
4442 if (r->m_type == 1) {
4443 mz_uint8 *p = r->m_code_size_0;
4444 mz_uint i;
4445 r->m_table_sizes[0] = 288;
4446 r->m_table_sizes[1] = 32;
4447 TINFL_MEMSET(r->m_code_size_1, 5, 32);
4448 for (i = 0; i <= 143; ++i)
4449 *p++ = 8;
4450 for (; i <= 255; ++i)
4451 *p++ = 9;
4452 for (; i <= 279; ++i)
4453 *p++ = 7;
4454 for (; i <= 287; ++i)
4455 *p++ = 8;
4456 } else {
4457 for (counter = 0; counter < 3; counter++) {
4458 TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]);
4459 r->m_table_sizes[counter] += s_min_table_sizes[counter];
4460 }
4461 MZ_CLEAR_ARR(r->m_code_size_2);
4462 for (counter = 0; counter < r->m_table_sizes[2]; counter++) {
4463 mz_uint s;
4464 TINFL_GET_BITS(14, s, 3);
4465 r->m_code_size_2[s_length_dezigzag[counter]] = (mz_uint8)s;
4466 }
4467 r->m_table_sizes[2] = 19;
4468 }
4469 for (; (int)r->m_type >= 0; r->m_type--) {
4470 int tree_next, tree_cur;
4471 mz_int16 *pLookUp;
4472 mz_int16 *pTree;
4473 mz_uint8 *pCode_size;
4474 mz_uint i, j, used_syms, total, sym_index, next_code[17],
4475 total_syms[16];
4476 pLookUp = r->m_look_up[r->m_type];
4477 pTree = pTrees[r->m_type];
4478 pCode_size = pCode_sizes[r->m_type];
4479 MZ_CLEAR_ARR(total_syms);
4480 TINFL_MEMSET(pLookUp, 0, sizeof(r->m_look_up[0]));
4481 tinfl_clear_tree(r);
4482 for (i = 0; i < r->m_table_sizes[r->m_type]; ++i)
4483 total_syms[pCode_size[i]]++;
4484 used_syms = 0, total = 0;
4485 next_code[0] = next_code[1] = 0;
4486 for (i = 1; i <= 15; ++i) {
4487 used_syms += total_syms[i];
4488 next_code[i + 1] = (total = ((total + total_syms[i]) << 1));
4489 }
4490 if ((65536 != total) && (used_syms > 1)) {
4491 TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
4492 }
4493 for (tree_next = -1, sym_index = 0;
4494 sym_index < r->m_table_sizes[r->m_type]; ++sym_index) {
4495 mz_uint rev_code = 0, l, cur_code, code_size = pCode_size[sym_index];
4496 if (!code_size)
4497 continue;
4498 cur_code = next_code[code_size]++;
4499 for (l = code_size; l > 0; l--, cur_code >>= 1)
4500 rev_code = (rev_code << 1) | (cur_code & 1);
4501 if (code_size <= TINFL_FAST_LOOKUP_BITS) {
4502 mz_int16 k = (mz_int16)((code_size << 9) | sym_index);
4503 while (rev_code < TINFL_FAST_LOOKUP_SIZE) {
4504 pLookUp[rev_code] = k;
4505 rev_code += (1 << code_size);
4506 }
4507 continue;
4508 }
4509 if (0 ==
4510 (tree_cur = pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) {
4511 pLookUp[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] =
4512 (mz_int16)tree_next;
4513 tree_cur = tree_next;
4514 tree_next -= 2;
4515 }
4516 rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
4517 for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) {
4518 tree_cur -= ((rev_code >>= 1) & 1);
4519 if (!pTree[-tree_cur - 1]) {
4520 pTree[-tree_cur - 1] = (mz_int16)tree_next;
4521 tree_cur = tree_next;
4522 tree_next -= 2;
4523 } else
4524 tree_cur = pTree[-tree_cur - 1];
4525 }
4526 tree_cur -= ((rev_code >>= 1) & 1);
4527 pTree[-tree_cur - 1] = (mz_int16)sym_index;
4528 }
4529 if (r->m_type == 2) {
4530 for (counter = 0;
4531 counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) {
4532 mz_uint s;
4533 TINFL_HUFF_DECODE(16, dist, r->m_look_up[2], r->m_tree_2);
4534 if (dist < 16) {
4535 r->m_len_codes[counter++] = (mz_uint8)dist;
4536 continue;
4537 }
4538 if ((dist == 16) && (!counter)) {
4539 TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
4540 }
4541 num_extra = "\02\03\07"[dist - 16];
4542 TINFL_GET_BITS(18, s, num_extra);
4543 s += "\03\03\013"[dist - 16];
4544 TINFL_MEMSET(r->m_len_codes + counter,
4545 (dist == 16) ? r->m_len_codes[counter - 1] : 0, s);
4546 counter += s;
4547 }
4548 if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) {
4549 TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
4550 }
4551 TINFL_MEMCPY(r->m_code_size_0, r->m_len_codes, r->m_table_sizes[0]);
4552 TINFL_MEMCPY(r->m_code_size_1, r->m_len_codes + r->m_table_sizes[0],
4553 r->m_table_sizes[1]);
4554 }
4555 }
4556 for (;;) {
4557 mz_uint8 *pSrc;
4558 for (;;) {
4559 if (((pIn_buf_end - pIn_buf_cur) < 4) ||
4560 ((pOut_buf_end - pOut_buf_cur) < 2)) {
4561 TINFL_HUFF_DECODE(23, counter, r->m_look_up[0], r->m_tree_0);
4562 if (counter >= 256)
4563 break;
4564 while (pOut_buf_cur >= pOut_buf_end) {
4565 TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT);
4566 }
4567 *pOut_buf_cur++ = (mz_uint8)counter;
4568 } else {
4569 int sym2;
4570 mz_uint code_len;
4571#if TINFL_USE_64BIT_BITBUF
4572 if (num_bits < 30) {
4573 bit_buf |=
4574 (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits);
4575 pIn_buf_cur += 4;
4576 num_bits += 32;
4577 }
4578#else
4579 if (num_bits < 15) {
4580 bit_buf |=
4581 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
4582 pIn_buf_cur += 2;
4583 num_bits += 16;
4584 }
4585#endif
4586 if ((sym2 =
4587 r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
4588 0)
4589 code_len = sym2 >> 9;
4590 else {
4591 code_len = TINFL_FAST_LOOKUP_BITS;
4592 do {
4593 sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)];
4594 } while (sym2 < 0);
4595 }
4596 counter = sym2;
4597 bit_buf >>= code_len;
4598 num_bits -= code_len;
4599 if (counter & 256)
4600 break;
4601
4602#if !TINFL_USE_64BIT_BITBUF
4603 if (num_bits < 15) {
4604 bit_buf |=
4605 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
4606 pIn_buf_cur += 2;
4607 num_bits += 16;
4608 }
4609#endif
4610 if ((sym2 =
4611 r->m_look_up[0][bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
4612 0)
4613 code_len = sym2 >> 9;
4614 else {
4615 code_len = TINFL_FAST_LOOKUP_BITS;
4616 do {
4617 sym2 = r->m_tree_0[~sym2 + ((bit_buf >> code_len++) & 1)];
4618 } while (sym2 < 0);
4619 }
4620 bit_buf >>= code_len;
4621 num_bits -= code_len;
4622
4623 pOut_buf_cur[0] = (mz_uint8)counter;
4624 if (sym2 & 256) {
4625 pOut_buf_cur++;
4626 counter = sym2;
4627 break;
4628 }
4629 pOut_buf_cur[1] = (mz_uint8)sym2;
4630 pOut_buf_cur += 2;
4631 }
4632 }
4633 if ((counter &= 511) == 256)
4634 break;
4635
4636 num_extra = s_length_extra[counter - 257];
4637 counter = s_length_base[counter - 257];
4638 if (num_extra) {
4639 mz_uint extra_bits;
4640 TINFL_GET_BITS(25, extra_bits, num_extra);
4641 counter += extra_bits;
4642 }
4643
4644 TINFL_HUFF_DECODE(26, dist, r->m_look_up[1], r->m_tree_1);
4645 num_extra = s_dist_extra[dist];
4646 dist = s_dist_base[dist];
4647 if (num_extra) {
4648 mz_uint extra_bits;
4649 TINFL_GET_BITS(27, extra_bits, num_extra);
4650 dist += extra_bits;
4651 }
4652
4653 dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
4654 if ((dist == 0 || dist > dist_from_out_buf_start ||
4655 dist_from_out_buf_start == 0) &&
4656 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) {
4657 TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
4658 }
4659
4660 pSrc = pOut_buf_start +
4661 ((dist_from_out_buf_start - dist) & out_buf_size_mask);
4662
4663 if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) {
4664 while (counter--) {
4665 while (pOut_buf_cur >= pOut_buf_end) {
4666 TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT);
4667 }
4668 *pOut_buf_cur++ =
4669 pOut_buf_start[(dist_from_out_buf_start++ - dist) &
4670 out_buf_size_mask];
4671 }
4672 continue;
4673 }
4674#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
4675 else if ((counter >= 9) && (counter <= dist)) {
4676 const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
4677 do {
4678#ifdef MINIZ_UNALIGNED_USE_MEMCPY
4679 memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32) * 2);
4680#else
4681 ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
4682 ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
4683#endif
4684 pOut_buf_cur += 8;
4685 } while ((pSrc += 8) < pSrc_end);
4686 if ((counter &= 7) < 3) {
4687 if (counter) {
4688 pOut_buf_cur[0] = pSrc[0];
4689 if (counter > 1)
4690 pOut_buf_cur[1] = pSrc[1];
4691 pOut_buf_cur += counter;
4692 }
4693 continue;
4694 }
4695 }
4696#endif
4697 while (counter > 2) {
4698 pOut_buf_cur[0] = pSrc[0];
4699 pOut_buf_cur[1] = pSrc[1];
4700 pOut_buf_cur[2] = pSrc[2];
4701 pOut_buf_cur += 3;
4702 pSrc += 3;
4703 counter -= 3;
4704 }
4705 if (counter > 0) {
4706 pOut_buf_cur[0] = pSrc[0];
4707 if (counter > 1)
4708 pOut_buf_cur[1] = pSrc[1];
4709 pOut_buf_cur += counter;
4710 }
4711 }
4712 }
4713 } while (!(r->m_final & 1));
4714
4715 /* Ensure byte alignment and put back any bytes from the bitbuf if we've
4716 * looked ahead too far on gzip, or other Deflate streams followed by
4717 * arbitrary data. */
4718 /* I'm being super conservative here. A number of simplifications can be made
4719 * to the byte alignment part, and the Adler32 check shouldn't ever need to
4720 * worry about reading from the bitbuf now. */
4721 TINFL_SKIP_BITS(32, num_bits & 7);
4722 while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) {
4723 --pIn_buf_cur;
4724 num_bits -= 8;
4725 }
4726 bit_buf &= ~(~(tinfl_bit_buf_t)0 << num_bits);
4727 MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end
4728 of non-deflate/zlib streams with following data (such
4729 as gzip streams). */
4730
4731 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
4732 for (counter = 0; counter < 4; ++counter) {
4733 mz_uint s;
4734 if (num_bits)
4735 TINFL_GET_BITS(41, s, 8);
4736 else
4737 TINFL_GET_BYTE(42, s);
4738 r->m_z_adler32 = (r->m_z_adler32 << 8) | s;
4739 }
4740 }
4741 TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
4742
4743 TINFL_CR_FINISH
4744
4745common_exit:
4746 /* As long as we aren't telling the caller that we NEED more input to make
4747 * forward progress: */
4748 /* Put back any bytes from the bitbuf in case we've looked ahead too far on
4749 * gzip, or other Deflate streams followed by arbitrary data. */
4750 /* We need to be very careful here to NOT push back any bytes we definitely
4751 * know we need to make forward progress, though, or we'll lock the caller up
4752 * into an inf loop. */
4753 if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) &&
4754 (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) {
4755 while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) {
4756 --pIn_buf_cur;
4757 num_bits -= 8;
4758 }
4759 }
4760 r->m_num_bits = num_bits;
4761 r->m_bit_buf = bit_buf & ~(~(tinfl_bit_buf_t)0 << num_bits);
4762 r->m_dist = dist;
4763 r->m_counter = counter;
4764 r->m_num_extra = num_extra;
4765 r->m_dist_from_out_buf_start = dist_from_out_buf_start;
4766 *pIn_buf_size = pIn_buf_cur - pIn_buf_next;
4767 *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
4768 if ((decomp_flags &
4769 (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) &&
4770 (status >= 0)) {
4771 const mz_uint8 *ptr = pOut_buf_next;
4772 size_t buf_len = *pOut_buf_size;
4773 mz_uint32 i, s1 = r->m_check_adler32 & 0xffff,
4774 s2 = r->m_check_adler32 >> 16;
4775 size_t block_len = buf_len % 5552;
4776 while (buf_len) {
4777 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
4778 s1 += ptr[0], s2 += s1;
4779 s1 += ptr[1], s2 += s1;
4780 s1 += ptr[2], s2 += s1;
4781 s1 += ptr[3], s2 += s1;
4782 s1 += ptr[4], s2 += s1;
4783 s1 += ptr[5], s2 += s1;
4784 s1 += ptr[6], s2 += s1;
4785 s1 += ptr[7], s2 += s1;
4786 }
4787 for (; i < block_len; ++i)
4788 s1 += *ptr++, s2 += s1;
4789 s1 %= 65521U, s2 %= 65521U;
4790 buf_len -= block_len;
4791 block_len = 5552;
4792 }
4793 r->m_check_adler32 = (s2 << 16) + s1;
4794 if ((status == TINFL_STATUS_DONE) &&
4795 (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) &&
4796 (r->m_check_adler32 != r->m_z_adler32))
4797 status = TINFL_STATUS_ADLER32_MISMATCH;
4798 }
4799 return status;
4800}
4801
4802/* Higher level helper functions. */
4803void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
4804 size_t *pOut_len, int flags) {
4805 tinfl_decompressor decomp;
4806 void *pBuf = NULL, *pNew_buf;
4807 size_t src_buf_ofs = 0, out_buf_capacity = 0;
4808 *pOut_len = 0;
4809 tinfl_init(&decomp);
4810 for (;;) {
4811 size_t src_buf_size = src_buf_len - src_buf_ofs,
4812 dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
4813 tinfl_status status = tinfl_decompress(
4814 &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
4815 (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
4816 &dst_buf_size,
4817 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
4818 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
4819 if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
4820 MZ_FREE(pBuf);
4821 *pOut_len = 0;
4822 return NULL;
4823 }
4824 src_buf_ofs += src_buf_size;
4825 *pOut_len += dst_buf_size;
4826 if (status == TINFL_STATUS_DONE)
4827 break;
4828 new_out_buf_capacity = out_buf_capacity * 2;
4829 if (new_out_buf_capacity < 128)
4830 new_out_buf_capacity = 128;
4831 pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
4832 if (!pNew_buf) {
4833 MZ_FREE(pBuf);
4834 *pOut_len = 0;
4835 return NULL;
4836 }
4837 pBuf = pNew_buf;
4838 out_buf_capacity = new_out_buf_capacity;
4839 }
4840 return pBuf;
4841}
4842
4843size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
4844 const void *pSrc_buf, size_t src_buf_len,
4845 int flags) {
4846 tinfl_decompressor decomp;
4847 tinfl_status status;
4848 tinfl_init(&decomp);
4849 status =
4850 tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len,
4851 (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len,
4852 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
4853 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
4854 return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED
4855 : out_buf_len;
4856}
4857
4858int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
4859 tinfl_put_buf_func_ptr pPut_buf_func,
4860 void *pPut_buf_user, int flags) {
4861 int result = 0;
4862 tinfl_decompressor decomp;
4863 mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE);
4864 size_t in_buf_ofs = 0, dict_ofs = 0;
4865 if (!pDict)
4866 return TINFL_STATUS_FAILED;
4867 memset(pDict, 0, TINFL_LZ_DICT_SIZE);
4868 tinfl_init(&decomp);
4869 for (;;) {
4870 size_t in_buf_size = *pIn_buf_size - in_buf_ofs,
4871 dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
4872 tinfl_status status =
4873 tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs,
4874 &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
4875 (flags & ~(TINFL_FLAG_HAS_MORE_INPUT |
4876 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
4877 in_buf_ofs += in_buf_size;
4878 if ((dst_buf_size) &&
4879 (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
4880 break;
4881 if (status != TINFL_STATUS_HAS_MORE_OUTPUT) {
4882 result = (status == TINFL_STATUS_DONE);
4883 break;
4884 }
4885 dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
4886 }
4887 MZ_FREE(pDict);
4888 *pIn_buf_size = in_buf_ofs;
4889 return result;
4890}
4891
4892#ifndef MINIZ_NO_MALLOC
4893tinfl_decompressor *tinfl_decompressor_alloc(void) {
4894 tinfl_decompressor *pDecomp =
4895 (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor));
4896 if (pDecomp)
4897 tinfl_init(pDecomp);
4898 return pDecomp;
4899}
4900
4901void tinfl_decompressor_free(tinfl_decompressor *pDecomp) { MZ_FREE(pDecomp); }
4902#endif
4903
4904#ifdef __cplusplus
4905}
4906#endif
4907
4908#endif /*#ifndef MINIZ_NO_INFLATE_APIS*/
4909/**************************************************************************
4910 *
4911 * Copyright 2013-2014 RAD Game Tools and Valve Software
4912 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
4913 * Copyright 2016 Martin Raiber
4914 * All Rights Reserved.
4915 *
4916 * Permission is hereby granted, free of charge, to any person obtaining a copy
4917 * of this software and associated documentation files (the "Software"), to deal
4918 * in the Software without restriction, including without limitation the rights
4919 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
4920 * copies of the Software, and to permit persons to whom the Software is
4921 * furnished to do so, subject to the following conditions:
4922 *
4923 * The above copyright notice and this permission notice shall be included in
4924 * all copies or substantial portions of the Software.
4925 *
4926 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4927 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
4928 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
4929 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
4930 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
4931 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
4932 * THE SOFTWARE.
4933 *
4934 **************************************************************************/
4935
4936#ifndef MINIZ_NO_ARCHIVE_APIS
4937
4938#ifdef __cplusplus
4939extern "C" {
4940#endif
4941
4942/* ------------------- .ZIP archive reading */
4943
4944#ifdef MINIZ_NO_STDIO
4945#define MZ_FILE void *
4946#else
4947#include <sys/stat.h>
4948
4949#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__)
4950
4951#ifndef WIN32_LEAN_AND_MEAN
4952#define WIN32_LEAN_AND_MEAN
4953#endif
4954#ifndef __cplusplus
4955#define MICROSOFT_WINDOWS_WINBASE_H_DEFINE_INTERLOCKED_CPLUSPLUS_OVERLOADS 0
4956#endif
4957#ifndef NOMINMAX
4958#define NOMINMAX
4959#endif
4960#include <windows.h>
4961
4962static WCHAR *mz_utf8z_to_widechar(const char *str) {
4963 int reqChars = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
4964 WCHAR *wStr = (WCHAR *)malloc(reqChars * sizeof(WCHAR));
4965 MultiByteToWideChar(CP_UTF8, 0, str, -1, wStr, reqChars);
4966 return wStr;
4967}
4968
4969static FILE *mz_fopen(const char *pFilename, const char *pMode) {
4970 WCHAR *wFilename = mz_utf8z_to_widechar(pFilename);
4971 WCHAR *wMode = mz_utf8z_to_widechar(pMode);
4972 FILE *pFile = NULL;
4973#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN
4974 pFile = _wfopen(wFilename, wMode);
4975#else
4976 errno_t err = _wfopen_s(&pFile, wFilename, wMode);
4977#endif
4978 free(wFilename);
4979 free(wMode);
4980#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN
4981 return pFile;
4982#else
4983 return err ? NULL : pFile;
4984#endif
4985}
4986
4987static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) {
4988 WCHAR *wPath = mz_utf8z_to_widechar(pPath);
4989 WCHAR *wMode = mz_utf8z_to_widechar(pMode);
4990 FILE *pFile = NULL;
4991#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN
4992 pFile = _wfreopen(wPath, wMode, pStream);
4993#else
4994 errno_t err = _wfreopen_s(&pFile, wPath, wMode, pStream);
4995#endif
4996 free(wPath);
4997 free(wMode);
4998#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN
4999 return pFile;
5000#else
5001 return err ? NULL : pFile;
5002#endif
5003}
5004
5005#if defined(__MINGW32__)
5006static int mz_stat(const char *path, struct _stat *buffer) {
5007 WCHAR *wPath = mz_utf8z_to_widechar(path);
5008 int res = _wstat(wPath, buffer);
5009 free(wPath);
5010 return res;
5011}
5012#else
5013static int mz_stat64(const char *path, struct __stat64 *buffer) {
5014 WCHAR *wPath = mz_utf8z_to_widechar(path);
5015 int res = _wstat64(wPath, buffer);
5016 free(wPath);
5017 return res;
5018}
5019#endif
5020
5021static int mz_mkdir(const char *pDirname) {
5022 WCHAR *wDirname = mz_utf8z_to_widechar(pDirname);
5023 int res = _wmkdir(wDirname);
5024 free(wDirname);
5025 return res;
5026}
5027
5028#ifndef MINIZ_NO_TIME
5029#include <sys/utime.h>
5030#endif
5031#define MZ_FOPEN mz_fopen
5032#define MZ_FCLOSE fclose
5033#define MZ_FREAD fread
5034#define MZ_FWRITE fwrite
5035#define MZ_FTELL64 _ftelli64
5036#define MZ_FSEEK64 _fseeki64
5037#if defined(__MINGW32__)
5038#define MZ_FILE_STAT_STRUCT _stat
5039#define MZ_FILE_STAT mz_stat
5040#else
5041#define MZ_FILE_STAT_STRUCT _stat64
5042#define MZ_FILE_STAT mz_stat64
5043#endif
5044#define MZ_FFLUSH fflush
5045#define MZ_FREOPEN mz_freopen
5046#define MZ_DELETE_FILE remove
5047#define MZ_MKDIR(d) mz_mkdir(d)
5048
5049#elif defined(__MINGW32__) || defined(__WATCOMC__)
5050#ifndef MINIZ_NO_TIME
5051#include <sys/utime.h>
5052#endif
5053#define MZ_FOPEN(f, m) fopen(f, m)
5054#define MZ_FCLOSE fclose
5055#define MZ_FREAD fread
5056#define MZ_FWRITE fwrite
5057#define MZ_FTELL64 _ftelli64
5058#define MZ_FSEEK64 _fseeki64
5059#define MZ_FILE_STAT_STRUCT stat
5060#define MZ_FILE_STAT stat
5061#define MZ_FFLUSH fflush
5062#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
5063#define MZ_DELETE_FILE remove
5064#define MZ_MKDIR(d) _mkdir(d)
5065
5066#elif defined(__TINYC__)
5067#ifndef MINIZ_NO_TIME
5068#include <sys/utime.h>
5069#endif
5070#define MZ_FOPEN(f, m) fopen(f, m)
5071#define MZ_FCLOSE fclose
5072#define MZ_FREAD fread
5073#define MZ_FWRITE fwrite
5074#define MZ_FTELL64 ftell
5075#define MZ_FSEEK64 fseek
5076#define MZ_FILE_STAT_STRUCT stat
5077#define MZ_FILE_STAT stat
5078#define MZ_FFLUSH fflush
5079#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
5080#define MZ_DELETE_FILE remove
5081#if defined(_WIN32) || defined(_WIN64)
5082#define MZ_MKDIR(d) _mkdir(d)
5083#else
5084#define MZ_MKDIR(d) mkdir(d, 0755)
5085#endif
5086
5087#elif defined(__USE_LARGEFILE64) /* gcc, clang */
5088#ifndef MINIZ_NO_TIME
5089#include <utime.h>
5090#endif
5091#define MZ_FOPEN(f, m) fopen64(f, m)
5092#define MZ_FCLOSE fclose
5093#define MZ_FREAD fread
5094#define MZ_FWRITE fwrite
5095#define MZ_FTELL64 ftello64
5096#define MZ_FSEEK64 fseeko64
5097#define MZ_FILE_STAT_STRUCT stat64
5098#define MZ_FILE_STAT stat64
5099#define MZ_FFLUSH fflush
5100#define MZ_FREOPEN(p, m, s) freopen64(p, m, s)
5101#define MZ_DELETE_FILE remove
5102#define MZ_MKDIR(d) mkdir(d, 0755)
5103
5104#elif defined(__APPLE__) || defined(__FreeBSD__) || \
5105 (defined(__linux__) && defined(__x86_64__))
5106#ifndef MINIZ_NO_TIME
5107#include <utime.h>
5108#endif
5109#define MZ_FOPEN(f, m) fopen(f, m)
5110#define MZ_FCLOSE fclose
5111#define MZ_FREAD fread
5112#define MZ_FWRITE fwrite
5113#define MZ_FTELL64 ftello
5114#define MZ_FSEEK64 fseeko
5115#define MZ_FILE_STAT_STRUCT stat
5116#define MZ_FILE_STAT stat
5117#define MZ_FFLUSH fflush
5118#define MZ_FREOPEN(p, m, s) freopen(p, m, s)
5119#define MZ_DELETE_FILE remove
5120#define MZ_MKDIR(d) mkdir(d, 0755)
5121
5122#else
5123#pragma message( \
5124 "Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.")
5125#ifndef MINIZ_NO_TIME
5126#include <utime.h>
5127#endif
5128#define MZ_FOPEN(f, m) fopen(f, m)
5129#define MZ_FCLOSE fclose
5130#define MZ_FREAD fread
5131#define MZ_FWRITE fwrite
5132#ifdef __STRICT_ANSI__
5133#define MZ_FTELL64 ftell
5134#define MZ_FSEEK64 fseek
5135#else
5136#define MZ_FTELL64 ftello
5137#define MZ_FSEEK64 fseeko
5138#endif
5139#define MZ_FILE_STAT_STRUCT stat
5140#define MZ_FILE_STAT stat
5141#define MZ_FFLUSH fflush
5142#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
5143#define MZ_DELETE_FILE remove
5144#define MZ_MKDIR(d) mkdir(d, 0755)
5145#endif /* #ifdef _MSC_VER */
5146#endif /* #ifdef MINIZ_NO_STDIO */
5147
5148#ifndef CHMOD
5149// Upon successful completion, a value of 0 is returned.
5150// Otherwise, a value of -1 is returned and errno is set to indicate the error.
5151// int chmod(const char *path, mode_t mode);
5152#define CHMOD(f, m) chmod(f, m)
5153#endif
5154
5155#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
5156
5157/* Various ZIP archive enums. To completely avoid cross platform compiler
5158 * alignment and platform endian issues, miniz.c doesn't use structs for any of
5159 * this stuff. */
5160enum {
5161 /* ZIP archive identifiers and record sizes */
5162 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50,
5163 MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50,
5164 MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
5165 MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
5166 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
5167 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
5168
5169 /* ZIP64 archive identifier and record sizes */
5170 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,
5171 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,
5172 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,
5173 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,
5174 MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,
5175 MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,
5176 MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,
5177 MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,
5178
5179 /* Central directory header record offsets */
5180 MZ_ZIP_CDH_SIG_OFS = 0,
5181 MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
5182 MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6,
5183 MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
5184 MZ_ZIP_CDH_METHOD_OFS = 10,
5185 MZ_ZIP_CDH_FILE_TIME_OFS = 12,
5186 MZ_ZIP_CDH_FILE_DATE_OFS = 14,
5187 MZ_ZIP_CDH_CRC32_OFS = 16,
5188 MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20,
5189 MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24,
5190 MZ_ZIP_CDH_FILENAME_LEN_OFS = 28,
5191 MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
5192 MZ_ZIP_CDH_COMMENT_LEN_OFS = 32,
5193 MZ_ZIP_CDH_DISK_START_OFS = 34,
5194 MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36,
5195 MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38,
5196 MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
5197
5198 /* Local directory header offsets */
5199 MZ_ZIP_LDH_SIG_OFS = 0,
5200 MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4,
5201 MZ_ZIP_LDH_BIT_FLAG_OFS = 6,
5202 MZ_ZIP_LDH_METHOD_OFS = 8,
5203 MZ_ZIP_LDH_FILE_TIME_OFS = 10,
5204 MZ_ZIP_LDH_FILE_DATE_OFS = 12,
5205 MZ_ZIP_LDH_CRC32_OFS = 14,
5206 MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18,
5207 MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
5208 MZ_ZIP_LDH_FILENAME_LEN_OFS = 26,
5209 MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
5210 MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3,
5211
5212 /* End of central directory offsets */
5213 MZ_ZIP_ECDH_SIG_OFS = 0,
5214 MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4,
5215 MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6,
5216 MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
5217 MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10,
5218 MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
5219 MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
5220 MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
5221
5222 /* ZIP64 End of central directory locator offsets */
5223 MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */
5224 MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */
5225 MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */
5226 MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */
5227
5228 /* ZIP64 End of central directory header offsets */
5229 MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */
5230 MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */
5231 MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */
5232 MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */
5233 MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */
5234 MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */
5235 MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */
5236 MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */
5237 MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */
5238 MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */
5239 MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,
5240 MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,
5241 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,
5242 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,
5243 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,
5244 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,
5245 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11
5246};
5247
5248typedef struct {
5249 void *m_p;
5250 size_t m_size, m_capacity;
5251 mz_uint m_element_size;
5252} mz_zip_array;
5253
5255 mz_zip_array m_central_dir;
5256 mz_zip_array m_central_dir_offsets;
5257 mz_zip_array m_sorted_central_dir_offsets;
5258
5259 /* The flags passed in when the archive is initially opened. */
5260 mz_uint32 m_init_flags;
5261
5262 /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc.
5263 */
5264 mz_bool m_zip64;
5265
5266 /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64
5267 * will also be slammed to true too, even if we didn't find a zip64 end of
5268 * central dir header, etc.) */
5269 mz_bool m_zip64_has_extended_info_fields;
5270
5271 /* These fields are used by the file, FILE, memory, and memory/heap read/write
5272 * helpers. */
5273 MZ_FILE *m_pFile;
5274 mz_uint64 m_file_archive_start_ofs;
5275
5276 void *m_pMem;
5277 size_t m_mem_size;
5278 size_t m_mem_capacity;
5279};
5280
5281#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \
5282 (array_ptr)->m_element_size = element_size
5283
5284#if defined(DEBUG) || defined(_DEBUG)
5285static MZ_FORCEINLINE mz_uint
5286mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) {
5287 MZ_ASSERT(index < pArray->m_size);
5288 return index;
5289}
5290#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \
5291 ((element_type *)((array_ptr) \
5292 ->m_p))[mz_zip_array_range_check(array_ptr, index)]
5293#else
5294#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \
5295 ((element_type *)((array_ptr)->m_p))[index]
5296#endif
5297
5298static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray,
5299 mz_uint32 element_size) {
5300 memset(pArray, 0, sizeof(mz_zip_array));
5301 pArray->m_element_size = element_size;
5302}
5303
5304static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip,
5305 mz_zip_array *pArray) {
5306 pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
5307 memset(pArray, 0, sizeof(mz_zip_array));
5308}
5309
5310static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip,
5311 mz_zip_array *pArray,
5312 size_t min_new_capacity,
5313 mz_uint growing) {
5314 void *pNew_p;
5315 size_t new_capacity = min_new_capacity;
5316 MZ_ASSERT(pArray->m_element_size);
5317 if (pArray->m_capacity >= min_new_capacity)
5318 return MZ_TRUE;
5319 if (growing) {
5320 new_capacity = MZ_MAX(1, pArray->m_capacity);
5321 while (new_capacity < min_new_capacity)
5322 new_capacity *= 2;
5323 }
5324 if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p,
5325 pArray->m_element_size, new_capacity)))
5326 return MZ_FALSE;
5327 pArray->m_p = pNew_p;
5328 pArray->m_capacity = new_capacity;
5329 return MZ_TRUE;
5330}
5331
5332static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip,
5333 mz_zip_array *pArray,
5334 size_t new_capacity,
5335 mz_uint growing) {
5336 if (new_capacity > pArray->m_capacity) {
5337 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))
5338 return MZ_FALSE;
5339 }
5340 return MZ_TRUE;
5341}
5342
5343static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip,
5344 mz_zip_array *pArray,
5345 size_t new_size,
5346 mz_uint growing) {
5347 if (new_size > pArray->m_capacity) {
5348 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))
5349 return MZ_FALSE;
5350 }
5351 pArray->m_size = new_size;
5352 return MZ_TRUE;
5353}
5354
5355static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip,
5356 mz_zip_array *pArray,
5357 size_t n) {
5358 return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
5359}
5360
5361static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip,
5362 mz_zip_array *pArray,
5363 const void *pElements,
5364 size_t n) {
5365 size_t orig_size = pArray->m_size;
5366 if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE))
5367 return MZ_FALSE;
5368 if (n > 0)
5369 memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size,
5370 pElements, n * pArray->m_element_size);
5371 return MZ_TRUE;
5372}
5373
5374#ifndef MINIZ_NO_TIME
5375static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) {
5376 struct tm tm;
5377 memset(&tm, 0, sizeof(tm));
5378 tm.tm_isdst = -1;
5379 tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900;
5380 tm.tm_mon = ((dos_date >> 5) & 15) - 1;
5381 tm.tm_mday = dos_date & 31;
5382 tm.tm_hour = (dos_time >> 11) & 31;
5383 tm.tm_min = (dos_time >> 5) & 63;
5384 tm.tm_sec = (dos_time << 1) & 62;
5385 return mktime(&tm);
5386}
5387
5388#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
5389static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time,
5390 mz_uint16 *pDOS_date) {
5391#ifdef _MSC_VER
5392 struct tm tm_struct;
5393 struct tm *tm = &tm_struct;
5394 errno_t err = localtime_s(tm, &time);
5395 if (err) {
5396 *pDOS_date = 0;
5397 *pDOS_time = 0;
5398 return;
5399 }
5400#else
5401 struct tm *tm = localtime(&time);
5402#endif /* #ifdef _MSC_VER */
5403
5404 *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) +
5405 ((tm->tm_sec) >> 1));
5406 *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) +
5407 ((tm->tm_mon + 1) << 5) + tm->tm_mday);
5408}
5409#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */
5410
5411#ifndef MINIZ_NO_STDIO
5412#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
5413static mz_bool mz_zip_get_file_modified_time(const char *pFilename,
5414 MZ_TIME_T *pTime) {
5415 struct MZ_FILE_STAT_STRUCT file_stat;
5416
5417 /* On Linux with x86 glibc, this call will fail on large files (I think >=
5418 * 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */
5419 if (MZ_FILE_STAT(pFilename, &file_stat) != 0)
5420 return MZ_FALSE;
5421
5422 *pTime = file_stat.st_mtime;
5423
5424 return MZ_TRUE;
5425}
5426#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/
5427
5428static mz_bool mz_zip_set_file_times(const char *pFilename,
5429 MZ_TIME_T access_time,
5430 MZ_TIME_T modified_time) {
5431 struct utimbuf t;
5432
5433 memset(&t, 0, sizeof(t));
5434 t.actime = access_time;
5435 t.modtime = modified_time;
5436
5437 return !utime(pFilename, &t);
5438}
5439#endif /* #ifndef MINIZ_NO_STDIO */
5440#endif /* #ifndef MINIZ_NO_TIME */
5441
5442static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip,
5443 mz_zip_error err_num) {
5444 if (pZip)
5445 pZip->m_last_error = err_num;
5446 return MZ_FALSE;
5447}
5448
5449static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
5450 mz_uint flags) {
5451 (void)flags;
5452 if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
5453 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
5454
5455 if (!pZip->m_pAlloc)
5456 pZip->m_pAlloc = miniz_def_alloc_func;
5457 if (!pZip->m_pFree)
5458 pZip->m_pFree = miniz_def_free_func;
5459 if (!pZip->m_pRealloc)
5460 pZip->m_pRealloc = miniz_def_realloc_func;
5461
5462 pZip->m_archive_size = 0;
5463 pZip->m_central_directory_file_ofs = 0;
5464 pZip->m_total_files = 0;
5465 pZip->m_last_error = MZ_ZIP_NO_ERROR;
5466
5467 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
5468 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
5469 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
5470
5471 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
5472 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
5473 sizeof(mz_uint8));
5474 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
5475 sizeof(mz_uint32));
5476 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
5477 sizeof(mz_uint32));
5478 pZip->m_pState->m_init_flags = flags;
5479 pZip->m_pState->m_zip64 = MZ_FALSE;
5480 pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE;
5481
5482 pZip->m_zip_mode = MZ_ZIP_MODE_READING;
5483
5484 return MZ_TRUE;
5485}
5486
5487static MZ_FORCEINLINE mz_bool
5488mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array,
5489 const mz_zip_array *pCentral_dir_offsets,
5490 mz_uint l_index, mz_uint r_index) {
5491 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
5492 pCentral_dir_array, mz_uint8,
5493 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
5494 l_index)),
5495 *pE;
5496 const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(
5497 pCentral_dir_array, mz_uint8,
5498 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
5499 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS),
5500 r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5501 mz_uint8 l = 0, r = 0;
5502 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5503 pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5504 pE = pL + MZ_MIN(l_len, r_len);
5505 while (pL < pE) {
5506 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
5507 break;
5508 pL++;
5509 pR++;
5510 }
5511 return (pL == pE) ? (l_len < r_len) : (l < r);
5512}
5513
5514#define MZ_SWAP_UINT32(a, b) \
5515 do { \
5516 mz_uint32 t = a; \
5517 a = b; \
5518 b = t; \
5519 } \
5520 MZ_MACRO_END
5521
5522/* Heap sort of lowercased filenames, used to help accelerate plain central
5523 * directory searches by mz_zip_reader_locate_file(). (Could also use qsort(),
5524 * but it could allocate memory.) */
5525static void
5526mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) {
5527 mz_zip_internal_state *pState = pZip->m_pState;
5528 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
5529 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
5530 mz_uint32 *pIndices;
5531 mz_uint32 start, end;
5532 const mz_uint32 size = pZip->m_total_files;
5533
5534 if (size <= 1U)
5535 return;
5536
5537 pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets,
5538 mz_uint32, 0);
5539
5540 start = (size - 2U) >> 1U;
5541 for (;;) {
5542 mz_uint64 child, root = start;
5543 for (;;) {
5544 if ((child = (root << 1U) + 1U) >= size)
5545 break;
5546 child += (((child + 1U) < size) &&
5547 (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
5548 pIndices[child],
5549 pIndices[child + 1U])));
5550 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
5551 pIndices[root], pIndices[child]))
5552 break;
5553 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
5554 root = child;
5555 }
5556 if (!start)
5557 break;
5558 start--;
5559 }
5560
5561 end = size - 1;
5562 while (end > 0) {
5563 mz_uint64 child, root = 0;
5564 MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
5565 for (;;) {
5566 if ((child = (root << 1U) + 1U) >= end)
5567 break;
5568 child +=
5569 (((child + 1U) < end) &&
5570 mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
5571 pIndices[child], pIndices[child + 1U]));
5572 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
5573 pIndices[root], pIndices[child]))
5574 break;
5575 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
5576 root = child;
5577 }
5578 end--;
5579 }
5580}
5581
5582static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip,
5583 mz_uint32 record_sig,
5584 mz_uint32 record_size,
5585 mz_int64 *pOfs) {
5586 mz_int64 cur_file_ofs;
5587 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
5588 mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
5589
5590 /* Basic sanity checks - reject files which are too small */
5591 if (pZip->m_archive_size < record_size)
5592 return MZ_FALSE;
5593
5594 /* Find the record by scanning the file from the end towards the beginning. */
5595 cur_file_ofs =
5596 MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
5597 for (;;) {
5598 int i,
5599 n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
5600
5601 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
5602 return MZ_FALSE;
5603
5604 for (i = n - 4; i >= 0; --i) {
5605 mz_uint s = MZ_READ_LE32(pBuf + i);
5606 if (s == record_sig) {
5607 if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)
5608 break;
5609 }
5610 }
5611
5612 if (i >= 0) {
5613 cur_file_ofs += i;
5614 break;
5615 }
5616
5617 /* Give up if we've searched the entire file, or we've gone back "too far"
5618 * (~64kb) */
5619 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
5620 ((mz_uint64)(MZ_UINT16_MAX) + record_size)))
5621 return MZ_FALSE;
5622
5623 cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
5624 }
5625
5626 *pOfs = cur_file_ofs;
5627 return MZ_TRUE;
5628}
5629
5630static mz_bool mz_zip_reader_eocd64_valid(mz_zip_archive *pZip, uint64_t offset,
5631 uint8_t *buf) {
5632 if (pZip->m_pRead(pZip->m_pIO_opaque, offset, buf,
5633 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ==
5634 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) {
5635 if (MZ_READ_LE32(buf + MZ_ZIP64_ECDH_SIG_OFS) ==
5636 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) {
5637 return MZ_TRUE;
5638 }
5639 }
5640
5641 return MZ_FALSE;
5642}
5643
5644static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
5645 mz_uint flags) {
5646 mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0,
5647 cdir_disk_index = 0;
5648 mz_uint64 cdir_ofs = 0, eocd_ofs = 0, archive_ofs = 0;
5649 mz_int64 cur_file_ofs = 0;
5650 const mz_uint8 *p;
5651
5652 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
5653 mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
5654 mz_bool sort_central_dir =
5655 ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
5656 mz_uint32 zip64_end_of_central_dir_locator_u32
5657 [(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) /
5658 sizeof(mz_uint32)];
5659 mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;
5660
5661 mz_uint32 zip64_end_of_central_dir_header_u32
5662 [(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5663 sizeof(mz_uint32)];
5664 mz_uint8 *pZip64_end_of_central_dir =
5665 (mz_uint8 *)zip64_end_of_central_dir_header_u32;
5666
5667 mz_uint64 zip64_end_of_central_dir_ofs = 0;
5668
5669 /* Basic sanity checks - reject files which are too small, and check the first
5670 * 4 bytes of the file to make sure a local header is there. */
5671 if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
5672 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
5673
5674 if (!mz_zip_reader_locate_header_sig(
5675 pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG,
5676 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))
5677 return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);
5678
5679 eocd_ofs = cur_file_ofs;
5680 /* Read and verify the end of central directory record. */
5681 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
5682 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
5683 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
5684 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
5685
5686 if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
5687 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
5688 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
5689
5690 if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE +
5691 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) {
5692 if (pZip->m_pRead(pZip->m_pIO_opaque,
5693 cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE,
5694 pZip64_locator,
5695 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ==
5696 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) {
5697 if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) ==
5698 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) {
5699 pZip->m_pState->m_zip64 = MZ_TRUE;
5700 }
5701 }
5702 }
5703
5704 if (pZip->m_pState->m_zip64) {
5705 /* Try locating the EOCD64 right before the EOCD64 locator. This works even
5706 * when the effective start of the zip header is not yet known. */
5707 if (cur_file_ofs < MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE +
5708 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)
5709 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
5710
5711 zip64_end_of_central_dir_ofs = cur_file_ofs -
5712 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE -
5713 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE;
5714
5715 if (!mz_zip_reader_eocd64_valid(pZip, zip64_end_of_central_dir_ofs,
5716 pZip64_end_of_central_dir)) {
5717 /* That failed, try reading where the locator tells us to. */
5718 zip64_end_of_central_dir_ofs = MZ_READ_LE64(
5719 pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);
5720
5721 if (zip64_end_of_central_dir_ofs >
5722 (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
5723 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
5724
5725 if (!mz_zip_reader_eocd64_valid(pZip, zip64_end_of_central_dir_ofs,
5726 pZip64_end_of_central_dir))
5727 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
5728 }
5729 }
5730
5731 pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);
5732 cdir_entries_on_this_disk =
5733 MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
5734 num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
5735 cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
5736 cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);
5737 cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
5738
5739 if (pZip->m_pState->m_zip64) {
5740 mz_uint32 zip64_total_num_of_disks =
5741 MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);
5742 mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(
5743 pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);
5744 mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(
5745 pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
5746 mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(
5747 pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);
5748 mz_uint64 zip64_size_of_central_directory =
5749 MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);
5750
5751 if (zip64_size_of_end_of_central_dir_record <
5752 (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))
5753 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5754
5755 if (zip64_total_num_of_disks != 1U)
5756 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
5757
5758 /* Check for miniz's practical limits */
5759 if (zip64_cdir_total_entries > MZ_UINT32_MAX)
5760 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
5761
5762 pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;
5763
5764 if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)
5765 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
5766
5767 cdir_entries_on_this_disk =
5768 (mz_uint32)zip64_cdir_total_entries_on_this_disk;
5769
5770 /* Check for miniz's current practical limits (sorry, this should be enough
5771 * for millions of files) */
5772 if (zip64_size_of_central_directory > MZ_UINT32_MAX)
5773 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
5774
5775 cdir_size = (mz_uint32)zip64_size_of_central_directory;
5776
5777 num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir +
5778 MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);
5779
5780 cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir +
5781 MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);
5782
5783 cdir_ofs =
5784 MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);
5785 }
5786
5787 if (pZip->m_total_files != cdir_entries_on_this_disk)
5788 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
5789
5790 if (((num_this_disk | cdir_disk_index) != 0) &&
5791 ((num_this_disk != 1) || (cdir_disk_index != 1)))
5792 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
5793
5794 if (cdir_size <
5795 (mz_uint64)pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
5796 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5797
5798 if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
5799 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5800
5801 if (eocd_ofs < cdir_ofs + cdir_size)
5802 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5803
5804 /* The end of central dir follows the central dir, unless the zip file has
5805 * some trailing data (e.g. it is appended to an executable file). */
5806 archive_ofs = eocd_ofs - (cdir_ofs + cdir_size);
5807 if (pZip->m_pState->m_zip64) {
5808 if (archive_ofs < MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE +
5809 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE)
5810 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5811
5812 archive_ofs -= MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE +
5813 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE;
5814 }
5815
5816 /* Update the archive start position, but only if not specified. */
5817 if ((pZip->m_zip_type == MZ_ZIP_TYPE_FILE ||
5818 pZip->m_zip_type == MZ_ZIP_TYPE_CFILE) &&
5819 pZip->m_pState->m_file_archive_start_ofs == 0) {
5820 pZip->m_pState->m_file_archive_start_ofs = archive_ofs;
5821 pZip->m_archive_size -= archive_ofs;
5822 }
5823
5824 pZip->m_central_directory_file_ofs = cdir_ofs;
5825
5826 if (pZip->m_total_files) {
5827 mz_uint i, n;
5828 /* Read the entire central directory into a heap block, and allocate another
5829 * heap block to hold the unsorted central dir file record offsets, and
5830 * possibly another to hold the sorted indices. */
5831 if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
5832 MZ_FALSE)) ||
5833 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
5834 pZip->m_total_files, MZ_FALSE)))
5835 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
5836
5837 if (sort_central_dir) {
5838 if (!mz_zip_array_resize(pZip,
5839 &pZip->m_pState->m_sorted_central_dir_offsets,
5840 pZip->m_total_files, MZ_FALSE))
5841 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
5842 }
5843
5844 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
5845 pZip->m_pState->m_central_dir.m_p,
5846 cdir_size) != cdir_size)
5847 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
5848
5849 /* Now create an index into the central directory file records, do some
5850 * basic sanity checking on each record */
5851 p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
5852 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
5853 mz_uint total_header_size, disk_index, bit_flags, filename_size,
5854 ext_data_size;
5855 mz_uint64 comp_size, decomp_size, local_header_ofs;
5856
5857 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
5858 (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
5859 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5860
5861 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5862 i) =
5863 (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
5864
5865 if (sort_central_dir)
5866 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
5867 mz_uint32, i) = i;
5868
5869 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5870 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5871 local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
5872 filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5873 ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
5874
5875 if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&
5876 (ext_data_size) &&
5877 (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) ==
5878 MZ_UINT32_MAX)) {
5879 /* Attempt to find zip64 extended information field in the entry's extra
5880 * data */
5881 mz_uint32 extra_size_remaining = ext_data_size;
5882
5883 if (extra_size_remaining) {
5884 const mz_uint8 *pExtra_data;
5885 void *buf = NULL;
5886
5887 if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size >
5888 n) {
5889 buf = MZ_MALLOC(ext_data_size);
5890 if (buf == NULL)
5891 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
5892
5893 if (pZip->m_pRead(pZip->m_pIO_opaque,
5894 cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
5895 filename_size,
5896 buf, ext_data_size) != ext_data_size) {
5897 MZ_FREE(buf);
5898 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
5899 }
5900
5901 pExtra_data = (mz_uint8 *)buf;
5902 } else {
5903 pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
5904 }
5905
5906 do {
5907 mz_uint32 field_id;
5908 mz_uint32 field_data_size;
5909
5910 if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
5911 MZ_FREE(buf);
5912 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5913 }
5914
5915 field_id = MZ_READ_LE16(pExtra_data);
5916 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
5917
5918 if ((field_data_size + sizeof(mz_uint16) * 2) >
5919 extra_size_remaining) {
5920 MZ_FREE(buf);
5921 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5922 }
5923
5924 if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
5925 /* Ok, the archive didn't have any zip64 headers but it uses a
5926 * zip64 extended information field so mark it as zip64 anyway
5927 * (this can occur with infozip's zip util when it reads
5928 * compresses files from stdin). */
5929 pZip->m_pState->m_zip64 = MZ_TRUE;
5930 pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;
5931 break;
5932 }
5933
5934 pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
5935 extra_size_remaining =
5936 extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
5937 } while (extra_size_remaining);
5938
5939 MZ_FREE(buf);
5940 }
5941 }
5942
5943 /* I've seen archives that aren't marked as zip64 that uses zip64 ext
5944 * data, argh */
5945 if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) {
5946 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
5947 (decomp_size != comp_size)) ||
5948 (decomp_size && !comp_size))
5949 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5950 }
5951
5952 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
5953 if ((disk_index == MZ_UINT16_MAX) ||
5954 ((disk_index != num_this_disk) && (disk_index != 1)))
5955 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
5956
5957 if (comp_size != MZ_UINT32_MAX) {
5958 if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
5959 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
5960 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5961 }
5962
5963 bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
5964 if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)
5965 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
5966
5967 if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
5968 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
5969 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
5970 MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
5971 n)
5972 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
5973
5974 n -= total_header_size;
5975 p += total_header_size;
5976 }
5977 }
5978
5979 if (sort_central_dir)
5980 mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
5981
5982 return MZ_TRUE;
5983}
5984
5985void mz_zip_zero_struct(mz_zip_archive *pZip) {
5986 if (pZip)
5987 MZ_CLEAR_PTR(pZip);
5988}
5989
5990static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip,
5991 mz_bool set_last_error) {
5992 mz_bool status = MZ_TRUE;
5993
5994 if (!pZip)
5995 return MZ_FALSE;
5996
5997 if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
5998 (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) {
5999 if (set_last_error)
6000 pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER;
6001
6002 return MZ_FALSE;
6003 }
6004
6005 if (pZip->m_pState) {
6006 mz_zip_internal_state *pState = pZip->m_pState;
6007 pZip->m_pState = NULL;
6008
6009 mz_zip_array_clear(pZip, &pState->m_central_dir);
6010 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
6011 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
6012
6013#ifndef MINIZ_NO_STDIO
6014 if (pState->m_pFile) {
6015 if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) {
6016 if (MZ_FCLOSE(pState->m_pFile) == EOF) {
6017 if (set_last_error)
6018 pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED;
6019 status = MZ_FALSE;
6020 }
6021 }
6022 pState->m_pFile = NULL;
6023 }
6024#endif /* #ifndef MINIZ_NO_STDIO */
6025
6026 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
6027 }
6028 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
6029
6030 return status;
6031}
6032
6033mz_bool mz_zip_reader_end(mz_zip_archive *pZip) {
6034 return mz_zip_reader_end_internal(pZip, MZ_TRUE);
6035}
6036mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
6037 mz_uint flags) {
6038 if ((!pZip) || (!pZip->m_pRead))
6039 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6040
6041 if (!mz_zip_reader_init_internal(pZip, flags))
6042 return MZ_FALSE;
6043
6044 pZip->m_zip_type = MZ_ZIP_TYPE_USER;
6045 pZip->m_archive_size = size;
6046
6047 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
6048 mz_zip_reader_end_internal(pZip, MZ_FALSE);
6049 return MZ_FALSE;
6050 }
6051
6052 return MZ_TRUE;
6053}
6054
6055static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs,
6056 void *pBuf, size_t n) {
6057 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
6058 size_t s = (file_ofs >= pZip->m_archive_size)
6059 ? 0
6060 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
6061 memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
6062 return s;
6063}
6064
6065mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem,
6066 size_t size, mz_uint flags) {
6067 if (!pMem)
6068 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6069
6070 if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
6071 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
6072
6073 if (!mz_zip_reader_init_internal(pZip, flags))
6074 return MZ_FALSE;
6075
6076 pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY;
6077 pZip->m_archive_size = size;
6078 pZip->m_pRead = mz_zip_mem_read_func;
6079 pZip->m_pIO_opaque = pZip;
6080 pZip->m_pNeeds_keepalive = NULL;
6081
6082#ifdef __cplusplus
6083 pZip->m_pState->m_pMem = const_cast<void *>(pMem);
6084#else
6085 pZip->m_pState->m_pMem = (void *)pMem;
6086#endif
6087
6088 pZip->m_pState->m_mem_size = size;
6089
6090 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
6091 mz_zip_reader_end_internal(pZip, MZ_FALSE);
6092 return MZ_FALSE;
6093 }
6094
6095 return MZ_TRUE;
6096}
6097
6098#ifndef MINIZ_NO_STDIO
6099static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs,
6100 void *pBuf, size_t n) {
6101 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
6102 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
6103
6104 file_ofs += pZip->m_pState->m_file_archive_start_ofs;
6105
6106 if (((mz_int64)file_ofs < 0) ||
6107 (((cur_ofs != (mz_int64)file_ofs)) &&
6108 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
6109 return 0;
6110
6111 return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
6112}
6113
6114mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename,
6115 mz_uint32 flags) {
6116 return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0);
6117}
6118
6119mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename,
6120 mz_uint flags, mz_uint64 file_start_ofs,
6121 mz_uint64 archive_size) {
6122 mz_uint64 file_size;
6123 MZ_FILE *pFile;
6124
6125 if ((!pZip) || (!pFilename) ||
6126 ((archive_size) &&
6127 (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
6128 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6129
6130 pFile = MZ_FOPEN(pFilename, "rb");
6131 if (!pFile)
6132 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
6133
6134 file_size = archive_size;
6135 if (!file_size) {
6136 if (MZ_FSEEK64(pFile, 0, SEEK_END)) {
6137 MZ_FCLOSE(pFile);
6138 return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
6139 }
6140
6141 file_size = MZ_FTELL64(pFile);
6142 }
6143
6144 /* TODO: Better sanity check archive_size and the # of actual remaining bytes
6145 */
6146
6147 if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) {
6148 MZ_FCLOSE(pFile);
6149 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
6150 }
6151
6152 if (!mz_zip_reader_init_internal(pZip, flags)) {
6153 MZ_FCLOSE(pFile);
6154 return MZ_FALSE;
6155 }
6156
6157 pZip->m_zip_type = MZ_ZIP_TYPE_FILE;
6158 pZip->m_pRead = mz_zip_file_read_func;
6159 pZip->m_pIO_opaque = pZip;
6160 pZip->m_pState->m_pFile = pFile;
6161 pZip->m_archive_size = file_size;
6162 pZip->m_pState->m_file_archive_start_ofs = file_start_ofs;
6163
6164 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
6165 mz_zip_reader_end_internal(pZip, MZ_FALSE);
6166 return MZ_FALSE;
6167 }
6168
6169 return MZ_TRUE;
6170}
6171
6172mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile,
6173 mz_uint64 archive_size, mz_uint flags) {
6174 mz_uint64 cur_file_ofs;
6175
6176 if ((!pZip) || (!pFile))
6177 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
6178
6179 cur_file_ofs = MZ_FTELL64(pFile);
6180
6181 if (!archive_size) {
6182 if (MZ_FSEEK64(pFile, 0, SEEK_END))
6183 return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
6184
6185 archive_size = MZ_FTELL64(pFile) - cur_file_ofs;
6186
6187 if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
6188 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
6189 }
6190
6191 if (!mz_zip_reader_init_internal(pZip, flags))
6192 return MZ_FALSE;
6193
6194 pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;
6195 pZip->m_pRead = mz_zip_file_read_func;
6196
6197 pZip->m_pIO_opaque = pZip;
6198 pZip->m_pState->m_pFile = pFile;
6199 pZip->m_archive_size = archive_size;
6200 pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs;
6201
6202 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
6203 mz_zip_reader_end_internal(pZip, MZ_FALSE);
6204 return MZ_FALSE;
6205 }
6206
6207 return MZ_TRUE;
6208}
6209
6210#endif /* #ifndef MINIZ_NO_STDIO */
6211
6212static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip,
6213 mz_uint file_index) {
6214 if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files))
6215 return NULL;
6216 return &MZ_ZIP_ARRAY_ELEMENT(
6217 &pZip->m_pState->m_central_dir, mz_uint8,
6218 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
6219 file_index));
6220}
6221
6222mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
6223 mz_uint file_index) {
6224 mz_uint m_bit_flag;
6225 const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
6226 if (!p) {
6227 mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6228 return MZ_FALSE;
6229 }
6230
6231 m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
6232 return (m_bit_flag &
6233 (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED |
6234 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0;
6235}
6236
6237mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip,
6238 mz_uint file_index) {
6239 mz_uint bit_flag;
6240 mz_uint method;
6241
6242 const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
6243 if (!p) {
6244 mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6245 return MZ_FALSE;
6246 }
6247
6248 method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
6249 bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
6250
6251 if ((method != 0) && (method != MZ_DEFLATED)) {
6252 mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
6253 return MZ_FALSE;
6254 }
6255
6256 if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED |
6257 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) {
6258 mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
6259 return MZ_FALSE;
6260 }
6261
6262 if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) {
6263 mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
6264 return MZ_FALSE;
6265 }
6266
6267 return MZ_TRUE;
6268}
6269
6270mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
6271 mz_uint file_index) {
6272 mz_uint filename_len, attribute_mapping_id, external_attr;
6273 const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
6274 if (!p) {
6275 mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6276 return MZ_FALSE;
6277 }
6278
6279 filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
6280 if (filename_len) {
6281 if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
6282 return MZ_TRUE;
6283 }
6284
6285 /* Bugfix: This code was also checking if the internal attribute was non-zero,
6286 * which wasn't correct. */
6287 /* Most/all zip writers (hopefully) set DOS file/directory attributes in the
6288 * low 16-bits, so check for the DOS directory flag and ignore the source OS
6289 * ID in the created by field. */
6290 /* FIXME: Remove this check? Is it necessary - we already check the filename.
6291 */
6292 attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8;
6293 (void)attribute_mapping_id;
6294
6295 external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
6296 if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) {
6297 return MZ_TRUE;
6298 }
6299
6300 return MZ_FALSE;
6301}
6302
6303static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip,
6304 mz_uint file_index,
6305 const mz_uint8 *pCentral_dir_header,
6307 mz_bool *pFound_zip64_extra_data) {
6308 mz_uint n;
6309 const mz_uint8 *p = pCentral_dir_header;
6310
6311 if (pFound_zip64_extra_data)
6312 *pFound_zip64_extra_data = MZ_FALSE;
6313
6314 if ((!p) || (!pStat))
6315 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6316
6317 /* Extract fields from the central directory record. */
6318 pStat->m_file_index = file_index;
6319 pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(
6320 &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
6321 pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
6322 pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
6323 pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
6324 pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
6325#ifndef MINIZ_NO_TIME
6326 pStat->m_time =
6327 mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS),
6328 MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));
6329#endif
6330 pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
6331 pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
6332 pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
6333 pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
6334 pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
6335 pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
6336
6337 /* Copy as much of the filename and comment as possible. */
6338 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
6339 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
6340 memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
6341 pStat->m_filename[n] = '\0';
6342
6343 n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
6344 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
6345 pStat->m_comment_size = n;
6346 memcpy(pStat->m_comment,
6347 p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6348 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
6349 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
6350 n);
6351 pStat->m_comment[n] = '\0';
6352
6353 /* Set some flags for convienance */
6354 pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index);
6355 pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index);
6356 pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index);
6357
6358 /* See if we need to read any zip64 extended information fields. */
6359 /* Confusingly, these zip64 fields can be present even on non-zip64 archives
6360 * (Debian zip on a huge files from stdin piped to stdout creates them). */
6361 if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size),
6362 pStat->m_local_header_ofs) == MZ_UINT32_MAX) {
6363 /* Attempt to find zip64 extended information field in the entry's extra
6364 * data */
6365 mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
6366
6367 if (extra_size_remaining) {
6368 const mz_uint8 *pExtra_data =
6369 p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6370 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
6371
6372 do {
6373 mz_uint32 field_id;
6374 mz_uint32 field_data_size;
6375
6376 if (extra_size_remaining < (sizeof(mz_uint16) * 2))
6377 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
6378
6379 field_id = MZ_READ_LE16(pExtra_data);
6380 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
6381
6382 if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)
6383 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
6384
6385 if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
6386 const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2;
6387 mz_uint32 field_data_remaining = field_data_size;
6388
6389 if (pFound_zip64_extra_data)
6390 *pFound_zip64_extra_data = MZ_TRUE;
6391
6392 if (pStat->m_uncomp_size == MZ_UINT32_MAX) {
6393 if (field_data_remaining < sizeof(mz_uint64))
6394 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
6395
6396 pStat->m_uncomp_size = MZ_READ_LE64(pField_data);
6397 pField_data += sizeof(mz_uint64);
6398 field_data_remaining -= sizeof(mz_uint64);
6399 }
6400
6401 if (pStat->m_comp_size == MZ_UINT32_MAX) {
6402 if (field_data_remaining < sizeof(mz_uint64))
6403 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
6404
6405 pStat->m_comp_size = MZ_READ_LE64(pField_data);
6406 pField_data += sizeof(mz_uint64);
6407 field_data_remaining -= sizeof(mz_uint64);
6408 }
6409
6410 if (pStat->m_local_header_ofs == MZ_UINT32_MAX) {
6411 if (field_data_remaining < sizeof(mz_uint64))
6412 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
6413
6414 pStat->m_local_header_ofs = MZ_READ_LE64(pField_data);
6415 pField_data += sizeof(mz_uint64);
6416 field_data_remaining -= sizeof(mz_uint64);
6417 }
6418
6419 break;
6420 }
6421
6422 pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
6423 extra_size_remaining =
6424 extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
6425 } while (extra_size_remaining);
6426 }
6427 }
6428
6429 return MZ_TRUE;
6430}
6431
6432static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA,
6433 const char *pB, mz_uint len,
6434 mz_uint flags) {
6435 mz_uint i;
6436 if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE)
6437 return 0 == memcmp(pA, pB, len);
6438 for (i = 0; i < len; ++i)
6439 if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i]))
6440 return MZ_FALSE;
6441 return MZ_TRUE;
6442}
6443
6444static MZ_FORCEINLINE int
6445mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array,
6446 const mz_zip_array *pCentral_dir_offsets,
6447 mz_uint l_index, const char *pR, mz_uint r_len) {
6448 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
6449 pCentral_dir_array, mz_uint8,
6450 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
6451 l_index)),
6452 *pE;
6453 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
6454 mz_uint8 l = 0, r = 0;
6455 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
6456 pE = pL + MZ_MIN(l_len, r_len);
6457 while (pL < pE) {
6458 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
6459 break;
6460 pL++;
6461 pR++;
6462 }
6463 return (pL == pE) ? (int)(l_len - r_len) : (l - r);
6464}
6465
6466static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip,
6467 const char *pFilename,
6468 mz_uint32 *pIndex) {
6469 mz_zip_internal_state *pState = pZip->m_pState;
6470 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
6471 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
6472 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
6473 &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
6474 const mz_uint32 size = pZip->m_total_files;
6475 const mz_uint filename_len = (mz_uint)strlen(pFilename);
6476
6477 if (pIndex)
6478 *pIndex = 0;
6479
6480 if (size) {
6481 /* yes I could use uint32_t's, but then we would have to add some special
6482 * case checks in the loop, argh, and */
6483 /* honestly the major expense here on 32-bit CPU's will still be the
6484 * filename compare */
6485 mz_int64 l = 0, h = (mz_int64)size - 1;
6486
6487 while (l <= h) {
6488 mz_int64 m = l + ((h - l) >> 1);
6489 mz_uint32 file_index = pIndices[(mz_uint32)m];
6490
6491 int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets,
6492 file_index, pFilename, filename_len);
6493 if (!comp) {
6494 if (pIndex)
6495 *pIndex = file_index;
6496 return MZ_TRUE;
6497 } else if (comp < 0)
6498 l = m + 1;
6499 else
6500 h = m - 1;
6501 }
6502 }
6503
6504 return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);
6505}
6506
6507int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
6508 const char *pComment, mz_uint flags) {
6509 mz_uint32 index;
6510 if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index))
6511 return -1;
6512 else
6513 return (int)index;
6514}
6515
6516mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName,
6517 const char *pComment, mz_uint flags,
6518 mz_uint32 *pIndex) {
6519 mz_uint file_index;
6520 size_t name_len, comment_len;
6521
6522 if (pIndex)
6523 *pIndex = 0;
6524
6525 if ((!pZip) || (!pZip->m_pState) || (!pName))
6526 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6527
6528 /* See if we can use a binary search */
6529 if (((pZip->m_pState->m_init_flags &
6530 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) &&
6531 (pZip->m_zip_mode == MZ_ZIP_MODE_READING) &&
6532 ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) &&
6533 (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) {
6534 return mz_zip_locate_file_binary_search(pZip, pName, pIndex);
6535 }
6536
6537 /* Locate the entry by scanning the entire central directory */
6538 name_len = strlen(pName);
6539 if (name_len > MZ_UINT16_MAX)
6540 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6541
6542 comment_len = pComment ? strlen(pComment) : 0;
6543 if (comment_len > MZ_UINT16_MAX)
6544 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6545
6546 for (file_index = 0; file_index < pZip->m_total_files; file_index++) {
6547 const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(
6548 &pZip->m_pState->m_central_dir, mz_uint8,
6549 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
6550 file_index));
6551 mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
6552 const char *pFilename =
6553 (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
6554 if (filename_len < name_len)
6555 continue;
6556 if (comment_len) {
6557 mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS),
6558 file_comment_len =
6559 MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);
6560 const char *pFile_comment = pFilename + filename_len + file_extra_len;
6561 if ((file_comment_len != comment_len) ||
6562 (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len,
6563 flags)))
6564 continue;
6565 }
6566 if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) {
6567 int ofs = filename_len - 1;
6568 do {
6569 if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') ||
6570 (pFilename[ofs] == ':'))
6571 break;
6572 } while (--ofs >= 0);
6573 ofs++;
6574 pFilename += ofs;
6575 filename_len -= ofs;
6576 }
6577 if ((filename_len == name_len) &&
6578 (mz_zip_string_equal(pName, pFilename, filename_len, flags))) {
6579 if (pIndex)
6580 *pIndex = file_index;
6581 return MZ_TRUE;
6582 }
6583 }
6584
6585 return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);
6586}
6587
6588static mz_bool mz_zip_reader_extract_to_mem_no_alloc1(
6589 mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size,
6590 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size,
6591 const mz_zip_archive_file_stat *st) {
6592 int status = TINFL_STATUS_DONE;
6593 mz_uint64 needed_size, cur_file_ofs, comp_remaining,
6594 out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
6595 mz_zip_archive_file_stat file_stat;
6596 void *pRead_buf;
6597 mz_uint32
6598 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
6599 sizeof(mz_uint32)];
6600 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
6601 tinfl_decompressor inflator;
6602
6603 if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) ||
6604 ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead))
6605 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6606
6607 if (st) {
6608 file_stat = *st;
6609 } else if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
6610 return MZ_FALSE;
6611
6612 /* A directory or zero length file */
6613 if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))
6614 return MZ_TRUE;
6615
6616 /* Encryption and patch files are not supported. */
6617 if (file_stat.m_bit_flag &
6618 (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED |
6619 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION |
6620 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))
6621 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
6622
6623 /* This function only supports decompressing stored and deflate. */
6624 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
6625 (file_stat.m_method != MZ_DEFLATED))
6626 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
6627
6628 /* Ensure supplied output buffer is large enough. */
6629 needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size
6630 : file_stat.m_uncomp_size;
6631 if (buf_size < needed_size)
6632 return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL);
6633
6634 /* Read and parse the local directory entry. */
6635 cur_file_ofs = file_stat.m_local_header_ofs;
6636 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
6637 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
6638 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
6639 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
6640
6641 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
6642 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
6643
6644 cur_file_ofs += (mz_uint64)(MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +
6645 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
6646 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
6647 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
6648 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
6649
6650 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
6651 /* The file is stored or the caller has requested the compressed data. */
6652 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
6653 (size_t)needed_size) != needed_size)
6654 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
6655
6656#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
6657 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) {
6658 if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
6659 (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)
6660 return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);
6661 }
6662#endif
6663
6664 return MZ_TRUE;
6665 }
6666
6667 /* Decompress the file either directly from memory or from a file input
6668 * buffer. */
6669 tinfl_init(&inflator);
6670
6671 if (pZip->m_pState->m_pMem) {
6672 /* Read directly from the archive in memory. */
6673 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
6674 read_buf_size = read_buf_avail = file_stat.m_comp_size;
6675 comp_remaining = 0;
6676 } else if (pUser_read_buf) {
6677 /* Use a user provided read buffer. */
6678 if (!user_read_buf_size)
6679 return MZ_FALSE;
6680 pRead_buf = (mz_uint8 *)pUser_read_buf;
6681 read_buf_size = user_read_buf_size;
6682 read_buf_avail = 0;
6683 comp_remaining = file_stat.m_comp_size;
6684 } else {
6685 /* Temporarily allocate a read buffer. */
6686 read_buf_size =
6687 MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
6688 if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
6689 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
6690
6691 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
6692 (size_t)read_buf_size)))
6693 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6694
6695 read_buf_avail = 0;
6696 comp_remaining = file_stat.m_comp_size;
6697 }
6698
6699 do {
6700 /* The size_t cast here should be OK because we've verified that the output
6701 * buffer is >= file_stat.m_uncomp_size above */
6702 size_t in_buf_size,
6703 out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
6704 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
6705 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
6706 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
6707 (size_t)read_buf_avail) != read_buf_avail) {
6708 status = TINFL_STATUS_FAILED;
6709 mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
6710 break;
6711 }
6712 cur_file_ofs += read_buf_avail;
6713 comp_remaining -= read_buf_avail;
6714 read_buf_ofs = 0;
6715 }
6716 in_buf_size = (size_t)read_buf_avail;
6717 status = tinfl_decompress(
6718 &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
6719 (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size,
6720 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF |
6721 (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));
6722 read_buf_avail -= in_buf_size;
6723 read_buf_ofs += in_buf_size;
6724 out_buf_ofs += out_buf_size;
6725 } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
6726
6727 if (status == TINFL_STATUS_DONE) {
6728 /* Make sure the entire file was decompressed, and check its CRC. */
6729 if (out_buf_ofs != file_stat.m_uncomp_size) {
6730 mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);
6731 status = TINFL_STATUS_FAILED;
6732 }
6733#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
6734 else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
6735 (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) {
6736 mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);
6737 status = TINFL_STATUS_FAILED;
6738 }
6739#endif
6740 }
6741
6742 if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
6743 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6744
6745 return status == TINFL_STATUS_DONE;
6746}
6747
6748mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
6749 mz_uint file_index, void *pBuf,
6750 size_t buf_size, mz_uint flags,
6751 void *pUser_read_buf,
6752 size_t user_read_buf_size) {
6753 return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf,
6754 buf_size, flags, pUser_read_buf,
6755 user_read_buf_size, NULL);
6756}
6757
6758mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
6759 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
6760 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) {
6761 mz_uint32 file_index;
6762 if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
6763 return MZ_FALSE;
6764 return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf,
6765 buf_size, flags, pUser_read_buf,
6766 user_read_buf_size, NULL);
6767}
6768
6769mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index,
6770 void *pBuf, size_t buf_size,
6771 mz_uint flags) {
6772 return mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf,
6773 buf_size, flags, NULL, 0, NULL);
6774}
6775
6776mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
6777 const char *pFilename, void *pBuf,
6778 size_t buf_size, mz_uint flags) {
6779 return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf,
6780 buf_size, flags, NULL, 0);
6781}
6782
6783void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index,
6784 size_t *pSize, mz_uint flags) {
6785 mz_zip_archive_file_stat file_stat;
6786 mz_uint64 alloc_size;
6787 void *pBuf;
6788
6789 if (pSize)
6790 *pSize = 0;
6791
6792 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
6793 return NULL;
6794
6795 alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size
6796 : file_stat.m_uncomp_size;
6797 if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) {
6798 mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
6799 return NULL;
6800 }
6801
6802 if (NULL ==
6803 (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) {
6804 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6805 return NULL;
6806 }
6807
6808 if (!mz_zip_reader_extract_to_mem_no_alloc1(pZip, file_index, pBuf,
6809 (size_t)alloc_size, flags, NULL,
6810 0, &file_stat)) {
6811 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6812 return NULL;
6813 }
6814
6815 if (pSize)
6816 *pSize = (size_t)alloc_size;
6817 return pBuf;
6818}
6819
6820void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
6821 const char *pFilename, size_t *pSize,
6822 mz_uint flags) {
6823 mz_uint32 file_index;
6824 if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags,
6825 &file_index)) {
6826 if (pSize)
6827 *pSize = 0;
6828 return MZ_FALSE;
6829 }
6830 return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
6831}
6832
6833mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
6834 mz_uint file_index,
6835 mz_file_write_func pCallback,
6836 void *pOpaque, mz_uint flags) {
6837 int status = TINFL_STATUS_DONE;
6838#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
6839 mz_uint file_crc32 = MZ_CRC32_INIT;
6840#endif
6841 mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining,
6842 out_buf_ofs = 0, cur_file_ofs;
6843 mz_zip_archive_file_stat file_stat;
6844 void *pRead_buf = NULL;
6845 void *pWrite_buf = NULL;
6846 mz_uint32
6847 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
6848 sizeof(mz_uint32)];
6849 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
6850
6851 if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead))
6852 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
6853
6854 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
6855 return MZ_FALSE;
6856
6857 /* A directory or zero length file */
6858 if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))
6859 return MZ_TRUE;
6860
6861 /* Encryption and patch files are not supported. */
6862 if (file_stat.m_bit_flag &
6863 (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED |
6864 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION |
6865 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))
6866 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
6867
6868 /* This function only supports decompressing stored and deflate. */
6869 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
6870 (file_stat.m_method != MZ_DEFLATED))
6871 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
6872
6873 /* Read and do some minimal validation of the local directory entry (this
6874 * doesn't crack the zip64 stuff, which we already have from the central dir)
6875 */
6876 cur_file_ofs = file_stat.m_local_header_ofs;
6877 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
6878 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
6879 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
6880 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
6881
6882 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
6883 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
6884
6885 cur_file_ofs += (mz_uint64)(MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +
6886 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
6887 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
6888 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
6889 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
6890
6891 /* Decompress the file either directly from memory or from a file input
6892 * buffer. */
6893 if (pZip->m_pState->m_pMem) {
6894 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
6895 read_buf_size = read_buf_avail = file_stat.m_comp_size;
6896 comp_remaining = 0;
6897 } else {
6898 read_buf_size =
6899 MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
6900 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
6901 (size_t)read_buf_size)))
6902 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6903
6904 read_buf_avail = 0;
6905 comp_remaining = file_stat.m_comp_size;
6906 }
6907
6908 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
6909 /* The file is stored or the caller has requested the compressed data. */
6910 if (pZip->m_pState->m_pMem) {
6911 if (((sizeof(size_t) == sizeof(mz_uint32))) &&
6912 (file_stat.m_comp_size > MZ_UINT32_MAX))
6913 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
6914
6915 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
6916 (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) {
6917 mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
6918 status = TINFL_STATUS_FAILED;
6919 } else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
6920#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
6921 file_crc32 =
6922 (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf,
6923 (size_t)file_stat.m_comp_size);
6924#endif
6925 }
6926
6927 cur_file_ofs += file_stat.m_comp_size;
6928 out_buf_ofs += file_stat.m_comp_size;
6929 comp_remaining = 0;
6930 } else {
6931 while (comp_remaining) {
6932 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
6933 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
6934 (size_t)read_buf_avail) != read_buf_avail) {
6935 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
6936 status = TINFL_STATUS_FAILED;
6937 break;
6938 }
6939
6940#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
6941 if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
6942 file_crc32 = (mz_uint32)mz_crc32(
6943 file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
6944 }
6945#endif
6946
6947 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
6948 (size_t)read_buf_avail) != read_buf_avail) {
6949 mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
6950 status = TINFL_STATUS_FAILED;
6951 break;
6952 }
6953
6954 cur_file_ofs += read_buf_avail;
6955 out_buf_ofs += read_buf_avail;
6956 comp_remaining -= read_buf_avail;
6957 }
6958 }
6959 } else {
6960 tinfl_decompressor inflator;
6961 tinfl_init(&inflator);
6962
6963 if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
6964 TINFL_LZ_DICT_SIZE))) {
6965 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
6966 status = TINFL_STATUS_FAILED;
6967 } else {
6968 do {
6969 mz_uint8 *pWrite_buf_cur =
6970 (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
6971 size_t in_buf_size,
6972 out_buf_size =
6973 TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
6974 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
6975 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
6976 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
6977 (size_t)read_buf_avail) != read_buf_avail) {
6978 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
6979 status = TINFL_STATUS_FAILED;
6980 break;
6981 }
6982 cur_file_ofs += read_buf_avail;
6983 comp_remaining -= read_buf_avail;
6984 read_buf_ofs = 0;
6985 }
6986
6987 in_buf_size = (size_t)read_buf_avail;
6988 status = tinfl_decompress(
6989 &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
6990 (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size,
6991 comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
6992 read_buf_avail -= in_buf_size;
6993 read_buf_ofs += in_buf_size;
6994
6995 if (out_buf_size) {
6996 if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) !=
6997 out_buf_size) {
6998 mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
6999 status = TINFL_STATUS_FAILED;
7000 break;
7001 }
7002
7003#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
7004 file_crc32 =
7005 (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
7006#endif
7007 if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) {
7008 mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
7009 status = TINFL_STATUS_FAILED;
7010 break;
7011 }
7012 }
7013 } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) ||
7014 (status == TINFL_STATUS_HAS_MORE_OUTPUT));
7015 }
7016 }
7017
7018 if ((status == TINFL_STATUS_DONE) &&
7019 (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) {
7020 /* Make sure the entire file was decompressed, and check its CRC. */
7021 if (out_buf_ofs != file_stat.m_uncomp_size) {
7022 mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);
7023 status = TINFL_STATUS_FAILED;
7024 }
7025#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
7026 else if (file_crc32 != file_stat.m_crc32) {
7027 mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
7028 status = TINFL_STATUS_FAILED;
7029 }
7030#endif
7031 }
7032
7033 if (!pZip->m_pState->m_pMem)
7034 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
7035
7036 if (pWrite_buf)
7037 pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
7038
7039 return status == TINFL_STATUS_DONE;
7040}
7041
7042mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
7043 const char *pFilename,
7044 mz_file_write_func pCallback,
7045 void *pOpaque, mz_uint flags) {
7046 mz_uint32 file_index;
7047 if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
7048 return MZ_FALSE;
7049
7050 return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque,
7051 flags);
7052}
7053
7055mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index,
7056 mz_uint flags) {
7058 mz_uint32
7059 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
7060 sizeof(mz_uint32)];
7061 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
7062
7063 /* Argument sanity check */
7064 if ((!pZip) || (!pZip->m_pState))
7065 return NULL;
7066
7067 /* Allocate an iterator status structure */
7068 pState = (mz_zip_reader_extract_iter_state *)pZip->m_pAlloc(
7069 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state));
7070 if (!pState) {
7071 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7072 return NULL;
7073 }
7074
7075 /* Fetch file details */
7076 if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) {
7077 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
7078 return NULL;
7079 }
7080
7081 /* Encryption and patch files are not supported. */
7082 if (pState->file_stat.m_bit_flag &
7083 (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED |
7084 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION |
7085 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) {
7086 mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
7087 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
7088 return NULL;
7089 }
7090
7091 /* This function only supports decompressing stored and deflate. */
7092 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) &&
7093 (pState->file_stat.m_method != 0) &&
7094 (pState->file_stat.m_method != MZ_DEFLATED)) {
7095 mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
7096 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
7097 return NULL;
7098 }
7099
7100 /* Init state - save args */
7101 pState->pZip = pZip;
7102 pState->flags = flags;
7103
7104 /* Init state - reset variables to defaults */
7105 pState->status = TINFL_STATUS_DONE;
7106#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
7107 pState->file_crc32 = MZ_CRC32_INIT;
7108#endif
7109 pState->read_buf_ofs = 0;
7110 pState->out_buf_ofs = 0;
7111 pState->pRead_buf = NULL;
7112 pState->pWrite_buf = NULL;
7113 pState->out_blk_remain = 0;
7114
7115 /* Read and parse the local directory entry. */
7116 pState->cur_file_ofs = pState->file_stat.m_local_header_ofs;
7117 if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header,
7118 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
7119 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) {
7120 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7121 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
7122 return NULL;
7123 }
7124
7125 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) {
7126 mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7127 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
7128 return NULL;
7129 }
7130
7131 pState->cur_file_ofs +=
7132 (mz_uint64)(MZ_ZIP_LOCAL_DIR_HEADER_SIZE) +
7133 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
7134 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
7135 if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) >
7136 pZip->m_archive_size) {
7137 mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7138 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
7139 return NULL;
7140 }
7141
7142 /* Decompress the file either directly from memory or from a file input
7143 * buffer. */
7144 if (pZip->m_pState->m_pMem) {
7145 pState->pRead_buf =
7146 (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs;
7147 pState->read_buf_size = pState->read_buf_avail =
7148 pState->file_stat.m_comp_size;
7149 pState->comp_remaining = pState->file_stat.m_comp_size;
7150 } else {
7151 if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ||
7152 (!pState->file_stat.m_method))) {
7153 /* Decompression required, therefore intermediate read buffer required */
7154 pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size,
7155 (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
7156 if (NULL ==
7157 (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
7158 (size_t)pState->read_buf_size))) {
7159 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7160 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
7161 return NULL;
7162 }
7163 } else {
7164 /* Decompression not required - we will be reading directly into user
7165 * buffer, no temp buf required */
7166 pState->read_buf_size = 0;
7167 }
7168 pState->read_buf_avail = 0;
7169 pState->comp_remaining = pState->file_stat.m_comp_size;
7170 }
7171
7172 if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ||
7173 (!pState->file_stat.m_method))) {
7174 /* Decompression required, init decompressor */
7175 tinfl_init(&pState->inflator);
7176
7177 /* Allocate write buffer */
7178 if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
7179 TINFL_LZ_DICT_SIZE))) {
7180 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7181 if (pState->pRead_buf)
7182 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf);
7183 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
7184 return NULL;
7185 }
7186 }
7187
7188 return pState;
7189}
7190
7192mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename,
7193 mz_uint flags) {
7194 mz_uint32 file_index;
7195
7196 /* Locate file index by name */
7197 if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
7198 return NULL;
7199
7200 /* Construct iterator */
7201 return mz_zip_reader_extract_iter_new(pZip, file_index, flags);
7202}
7203
7204size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state *pState,
7205 void *pvBuf, size_t buf_size) {
7206 size_t copied_to_caller = 0;
7207
7208 /* Argument sanity check */
7209 if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf))
7210 return 0;
7211
7212 if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ||
7213 (!pState->file_stat.m_method)) {
7214 /* The file is stored or the caller has requested the compressed data, calc
7215 * amount to return. */
7216 copied_to_caller = (size_t)MZ_MIN(buf_size, pState->comp_remaining);
7217
7218 /* Zip is in memory....or requires reading from a file? */
7219 if (pState->pZip->m_pState->m_pMem) {
7220 /* Copy data to caller's buffer */
7221 memcpy(pvBuf, pState->pRead_buf, copied_to_caller);
7222 pState->pRead_buf = ((mz_uint8 *)pState->pRead_buf) + copied_to_caller;
7223 } else {
7224 /* Read directly into caller's buffer */
7225 if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque,
7226 pState->cur_file_ofs, pvBuf,
7227 copied_to_caller) != copied_to_caller) {
7228 /* Failed to read all that was asked for, flag failure and alert user */
7229 mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED);
7230 pState->status = TINFL_STATUS_FAILED;
7231 copied_to_caller = 0;
7232 }
7233 }
7234
7235#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
7236 /* Compute CRC if not returning compressed data only */
7237 if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
7238 pState->file_crc32 = (mz_uint32)mz_crc32(
7239 pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller);
7240#endif
7241
7242 /* Advance offsets, dec counters */
7243 pState->cur_file_ofs += copied_to_caller;
7244 pState->out_buf_ofs += copied_to_caller;
7245 pState->comp_remaining -= copied_to_caller;
7246 } else {
7247 do {
7248 /* Calc ptr to write buffer - given current output pos and block size */
7249 mz_uint8 *pWrite_buf_cur =
7250 (mz_uint8 *)pState->pWrite_buf +
7251 (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
7252
7253 /* Calc max output size - given current output pos and block size */
7254 size_t in_buf_size,
7255 out_buf_size = TINFL_LZ_DICT_SIZE -
7256 (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
7257
7258 if (!pState->out_blk_remain) {
7259 /* Read more data from file if none available (and reading from file) */
7260 if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) {
7261 /* Calc read size */
7262 pState->read_buf_avail =
7263 MZ_MIN(pState->read_buf_size, pState->comp_remaining);
7264 if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque,
7265 pState->cur_file_ofs, pState->pRead_buf,
7266 (size_t)pState->read_buf_avail) !=
7267 pState->read_buf_avail) {
7268 mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED);
7269 pState->status = TINFL_STATUS_FAILED;
7270 break;
7271 }
7272
7273 /* Advance offsets, dec counters */
7274 pState->cur_file_ofs += pState->read_buf_avail;
7275 pState->comp_remaining -= pState->read_buf_avail;
7276 pState->read_buf_ofs = 0;
7277 }
7278
7279 /* Perform decompression */
7280 in_buf_size = (size_t)pState->read_buf_avail;
7281 pState->status = tinfl_decompress(
7282 &pState->inflator,
7283 (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs,
7284 &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur,
7285 &out_buf_size,
7286 pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
7287 pState->read_buf_avail -= in_buf_size;
7288 pState->read_buf_ofs += in_buf_size;
7289
7290 /* Update current output block size remaining */
7291 pState->out_blk_remain = out_buf_size;
7292 }
7293
7294 if (pState->out_blk_remain) {
7295 /* Calc amount to return. */
7296 size_t to_copy =
7297 MZ_MIN((buf_size - copied_to_caller), pState->out_blk_remain);
7298
7299 /* Copy data to caller's buffer */
7300 memcpy((mz_uint8 *)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy);
7301
7302#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
7303 /* Perform CRC */
7304 pState->file_crc32 =
7305 (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy);
7306#endif
7307
7308 /* Decrement data consumed from block */
7309 pState->out_blk_remain -= to_copy;
7310
7311 /* Inc output offset, while performing sanity check */
7312 if ((pState->out_buf_ofs += to_copy) >
7313 pState->file_stat.m_uncomp_size) {
7314 mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED);
7315 pState->status = TINFL_STATUS_FAILED;
7316 break;
7317 }
7318
7319 /* Increment counter of data copied to caller */
7320 copied_to_caller += to_copy;
7321 }
7322 } while ((copied_to_caller < buf_size) &&
7323 ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) ||
7324 (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)));
7325 }
7326
7327 /* Return how many bytes were copied into user buffer */
7328 return copied_to_caller;
7329}
7330
7331mz_bool
7332mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state *pState) {
7333 int status;
7334
7335 /* Argument sanity check */
7336 if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState))
7337 return MZ_FALSE;
7338
7339 /* Was decompression completed and requested? */
7340 if ((pState->status == TINFL_STATUS_DONE) &&
7341 (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) {
7342 /* Make sure the entire file was decompressed, and check its CRC. */
7343 if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) {
7344 mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);
7345 pState->status = TINFL_STATUS_FAILED;
7346 }
7347#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
7348 else if (pState->file_crc32 != pState->file_stat.m_crc32) {
7349 mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED);
7350 pState->status = TINFL_STATUS_FAILED;
7351 }
7352#endif
7353 }
7354
7355 /* Free buffers */
7356 if (!pState->pZip->m_pState->m_pMem)
7357 pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf);
7358 if (pState->pWrite_buf)
7359 pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf);
7360
7361 /* Save status */
7362 status = pState->status;
7363
7364 /* Free context */
7365 pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState);
7366
7367 return status == TINFL_STATUS_DONE;
7368}
7369
7370#ifndef MINIZ_NO_STDIO
7371static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs,
7372 const void *pBuf, size_t n) {
7373 (void)ofs;
7374
7375 return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque);
7376}
7377
7378mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index,
7379 const char *pDst_filename,
7380 mz_uint flags) {
7381 mz_bool status;
7382 mz_zip_archive_file_stat file_stat;
7383 MZ_FILE *pFile;
7384
7385 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
7386 return MZ_FALSE;
7387
7388 if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))
7389 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
7390
7391 pFile = MZ_FOPEN(pDst_filename, "wb");
7392 if (!pFile)
7393 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
7394
7395 status = mz_zip_reader_extract_to_callback(
7396 pZip, file_index, mz_zip_file_write_callback, pFile, flags);
7397
7398 if (MZ_FCLOSE(pFile) == EOF) {
7399 if (status)
7400 mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
7401
7402 status = MZ_FALSE;
7403 }
7404
7405#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)
7406 if (status)
7407 mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
7408#endif
7409
7410 return status;
7411}
7412
7413mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
7414 const char *pArchive_filename,
7415 const char *pDst_filename,
7416 mz_uint flags) {
7417 mz_uint32 file_index;
7418 if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags,
7419 &file_index))
7420 return MZ_FALSE;
7421
7422 return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
7423}
7424
7425mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index,
7426 MZ_FILE *pFile, mz_uint flags) {
7427 mz_zip_archive_file_stat file_stat;
7428
7429 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
7430 return MZ_FALSE;
7431
7432 if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))
7433 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
7434
7435 return mz_zip_reader_extract_to_callback(
7436 pZip, file_index, mz_zip_file_write_callback, pFile, flags);
7437}
7438
7439mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip,
7440 const char *pArchive_filename,
7441 MZ_FILE *pFile, mz_uint flags) {
7442 mz_uint32 file_index;
7443 if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags,
7444 &file_index))
7445 return MZ_FALSE;
7446
7447 return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags);
7448}
7449#endif /* #ifndef MINIZ_NO_STDIO */
7450
7451static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs,
7452 const void *pBuf, size_t n) {
7453 mz_uint32 *p = (mz_uint32 *)pOpaque;
7454 (void)file_ofs;
7455 *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n);
7456 return n;
7457}
7458
7459mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index,
7460 mz_uint flags) {
7461 mz_zip_archive_file_stat file_stat;
7462 mz_zip_internal_state *pState;
7463 const mz_uint8 *pCentral_dir_header;
7464 mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE;
7465 mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;
7466 mz_uint32
7467 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
7468 sizeof(mz_uint32)];
7469 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
7470 mz_uint64 local_header_ofs = 0;
7471 mz_uint32 local_header_filename_len, local_header_extra_len,
7472 local_header_crc32;
7473 mz_uint64 local_header_comp_size, local_header_uncomp_size;
7474 mz_uint32 uncomp_crc32 = MZ_CRC32_INIT;
7475 mz_bool has_data_descriptor;
7476 mz_uint32 local_header_bit_flags;
7477
7478 mz_zip_array file_data_array;
7479 mz_zip_array_init(&file_data_array, 1);
7480
7481 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
7482 (!pZip->m_pRead))
7483 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7484
7485 if (file_index > pZip->m_total_files)
7486 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7487
7488 pState = pZip->m_pState;
7489
7490 pCentral_dir_header = mz_zip_get_cdh(pZip, file_index);
7491
7492 if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header,
7493 &file_stat, &found_zip64_ext_data_in_cdir))
7494 return MZ_FALSE;
7495
7496 /* A directory or zero length file */
7497 if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size))
7498 return MZ_TRUE;
7499
7500 /* Encryption and patch files are not supported. */
7501 if (file_stat.m_is_encrypted)
7502 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
7503
7504 /* This function only supports stored and deflate. */
7505 if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
7506 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
7507
7508 if (!file_stat.m_is_supported)
7509 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
7510
7511 /* Read and parse the local directory entry. */
7512 local_header_ofs = file_stat.m_local_header_ofs;
7513 if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header,
7514 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
7515 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
7516 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7517
7518 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
7519 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7520
7521 local_header_filename_len =
7522 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);
7523 local_header_extra_len =
7524 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
7525 local_header_comp_size =
7526 MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);
7527 local_header_uncomp_size =
7528 MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);
7529 local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS);
7530 local_header_bit_flags =
7531 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
7532 has_data_descriptor = (local_header_bit_flags & 8) != 0;
7533
7534 if (local_header_filename_len != strlen(file_stat.m_filename))
7535 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7536
7537 if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
7538 local_header_filename_len + local_header_extra_len +
7539 file_stat.m_comp_size) > pZip->m_archive_size)
7540 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7541
7542 if (!mz_zip_array_resize(
7543 pZip, &file_data_array,
7544 MZ_MAX(local_header_filename_len, local_header_extra_len),
7545 MZ_FALSE)) {
7546 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7547 goto handle_failure;
7548 }
7549
7550 if (local_header_filename_len) {
7551 if (pZip->m_pRead(pZip->m_pIO_opaque,
7552 local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE,
7553 file_data_array.m_p,
7554 local_header_filename_len) != local_header_filename_len) {
7555 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7556 goto handle_failure;
7557 }
7558
7559 /* I've seen 1 archive that had the same pathname, but used backslashes in
7560 * the local dir and forward slashes in the central dir. Do we care about
7561 * this? For now, this case will fail validation. */
7562 if (memcmp(file_stat.m_filename, file_data_array.m_p,
7563 local_header_filename_len) != 0) {
7564 mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
7565 goto handle_failure;
7566 }
7567 }
7568
7569 if ((local_header_extra_len) &&
7570 ((local_header_comp_size == MZ_UINT32_MAX) ||
7571 (local_header_uncomp_size == MZ_UINT32_MAX))) {
7572 mz_uint32 extra_size_remaining = local_header_extra_len;
7573 const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p;
7574
7575 if (pZip->m_pRead(pZip->m_pIO_opaque,
7576 local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
7577 local_header_filename_len,
7578 file_data_array.m_p,
7579 local_header_extra_len) != local_header_extra_len) {
7580 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7581 goto handle_failure;
7582 }
7583
7584 do {
7585 mz_uint32 field_id, field_data_size, field_total_size;
7586
7587 if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
7588 mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7589 goto handle_failure;
7590 }
7591
7592 field_id = MZ_READ_LE16(pExtra_data);
7593 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
7594 field_total_size = field_data_size + sizeof(mz_uint16) * 2;
7595
7596 if (field_total_size > extra_size_remaining) {
7597 mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7598 goto handle_failure;
7599 }
7600
7601 if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
7602 const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);
7603
7604 if (field_data_size < sizeof(mz_uint64) * 2) {
7605 mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
7606 goto handle_failure;
7607 }
7608
7609 local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);
7610 local_header_comp_size =
7611 MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64));
7612
7613 found_zip64_ext_data_in_ldir = MZ_TRUE;
7614 break;
7615 }
7616
7617 pExtra_data += field_total_size;
7618 extra_size_remaining -= field_total_size;
7619 } while (extra_size_remaining);
7620 }
7621
7622 /* TODO: parse local header extra data when local_header_comp_size is
7623 * 0xFFFFFFFF! (big_descriptor.zip) */
7624 /* I've seen zips in the wild with the data descriptor bit set, but proper
7625 * local header values and bogus data descriptors */
7626 if ((has_data_descriptor) && (!local_header_comp_size) &&
7627 (!local_header_crc32)) {
7628 mz_uint8 descriptor_buf[32];
7629 mz_bool has_id;
7630 const mz_uint8 *pSrc;
7631 mz_uint32 file_crc32;
7632 mz_uint64 comp_size = 0, uncomp_size = 0;
7633
7634 mz_uint32 num_descriptor_uint32s =
7635 ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4;
7636
7637 if (pZip->m_pRead(pZip->m_pIO_opaque,
7638 local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
7639 local_header_filename_len + local_header_extra_len +
7640 file_stat.m_comp_size,
7641 descriptor_buf,
7642 sizeof(mz_uint32) * num_descriptor_uint32s) !=
7643 (sizeof(mz_uint32) * num_descriptor_uint32s)) {
7644 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
7645 goto handle_failure;
7646 }
7647
7648 has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID);
7649 pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf;
7650
7651 file_crc32 = MZ_READ_LE32(pSrc);
7652
7653 if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) {
7654 comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32));
7655 uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64));
7656 } else {
7657 comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32));
7658 uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32));
7659 }
7660
7661 if ((file_crc32 != file_stat.m_crc32) ||
7662 (comp_size != file_stat.m_comp_size) ||
7663 (uncomp_size != file_stat.m_uncomp_size)) {
7664 mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
7665 goto handle_failure;
7666 }
7667 } else {
7668 if ((local_header_crc32 != file_stat.m_crc32) ||
7669 (local_header_comp_size != file_stat.m_comp_size) ||
7670 (local_header_uncomp_size != file_stat.m_uncomp_size)) {
7671 mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
7672 goto handle_failure;
7673 }
7674 }
7675
7676 mz_zip_array_clear(pZip, &file_data_array);
7677
7678 if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) {
7679 if (!mz_zip_reader_extract_to_callback(
7680 pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0))
7681 return MZ_FALSE;
7682
7683 /* 1 more check to be sure, although the extract checks too. */
7684 if (uncomp_crc32 != file_stat.m_crc32) {
7685 mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
7686 return MZ_FALSE;
7687 }
7688 }
7689
7690 return MZ_TRUE;
7691
7692handle_failure:
7693 mz_zip_array_clear(pZip, &file_data_array);
7694 return MZ_FALSE;
7695}
7696
7697mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) {
7698 mz_zip_internal_state *pState;
7699 mz_uint32 i;
7700
7701 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
7702 (!pZip->m_pRead))
7703 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7704
7705 pState = pZip->m_pState;
7706
7707 /* Basic sanity checks */
7708 if (!pState->m_zip64) {
7709 if (pZip->m_total_files > MZ_UINT16_MAX)
7710 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
7711
7712 if (pZip->m_archive_size > MZ_UINT32_MAX)
7713 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
7714 } else {
7715 if (pState->m_central_dir.m_size >= MZ_UINT32_MAX)
7716 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
7717 }
7718
7719 for (i = 0; i < pZip->m_total_files; i++) {
7720 if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) {
7721 mz_uint32 found_index;
7723
7724 if (!mz_zip_reader_file_stat(pZip, i, &stat))
7725 return MZ_FALSE;
7726
7727 if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0,
7728 &found_index))
7729 return MZ_FALSE;
7730
7731 /* This check can fail if there are duplicate filenames in the archive
7732 * (which we don't check for when writing - that's up to the user) */
7733 if (found_index != i)
7734 return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
7735 }
7736
7737 if (!mz_zip_validate_file(pZip, i, flags))
7738 return MZ_FALSE;
7739 }
7740
7741 return MZ_TRUE;
7742}
7743
7744mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size,
7745 mz_uint flags, mz_zip_error *pErr) {
7746 mz_bool success = MZ_TRUE;
7747 mz_zip_archive zip;
7748 mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
7749
7750 if ((!pMem) || (!size)) {
7751 if (pErr)
7752 *pErr = MZ_ZIP_INVALID_PARAMETER;
7753 return MZ_FALSE;
7754 }
7755
7756 mz_zip_zero_struct(&zip);
7757
7758 if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) {
7759 if (pErr)
7760 *pErr = zip.m_last_error;
7761 return MZ_FALSE;
7762 }
7763
7764 if (!mz_zip_validate_archive(&zip, flags)) {
7765 actual_err = zip.m_last_error;
7766 success = MZ_FALSE;
7767 }
7768
7769 if (!mz_zip_reader_end_internal(&zip, success)) {
7770 if (!actual_err)
7771 actual_err = zip.m_last_error;
7772 success = MZ_FALSE;
7773 }
7774
7775 if (pErr)
7776 *pErr = actual_err;
7777
7778 return success;
7779}
7780
7781#ifndef MINIZ_NO_STDIO
7782mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags,
7783 mz_zip_error *pErr) {
7784 mz_bool success = MZ_TRUE;
7785 mz_zip_archive zip;
7786 mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
7787
7788 if (!pFilename) {
7789 if (pErr)
7790 *pErr = MZ_ZIP_INVALID_PARAMETER;
7791 return MZ_FALSE;
7792 }
7793
7794 mz_zip_zero_struct(&zip);
7795
7796 if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) {
7797 if (pErr)
7798 *pErr = zip.m_last_error;
7799 return MZ_FALSE;
7800 }
7801
7802 if (!mz_zip_validate_archive(&zip, flags)) {
7803 actual_err = zip.m_last_error;
7804 success = MZ_FALSE;
7805 }
7806
7807 if (!mz_zip_reader_end_internal(&zip, success)) {
7808 if (!actual_err)
7809 actual_err = zip.m_last_error;
7810 success = MZ_FALSE;
7811 }
7812
7813 if (pErr)
7814 *pErr = actual_err;
7815
7816 return success;
7817}
7818#endif /* #ifndef MINIZ_NO_STDIO */
7819
7820/* ------------------- .ZIP archive writing */
7821
7822#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
7823
7824static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) {
7825 p[0] = (mz_uint8)v;
7826 p[1] = (mz_uint8)(v >> 8);
7827}
7828static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) {
7829 p[0] = (mz_uint8)v;
7830 p[1] = (mz_uint8)(v >> 8);
7831 p[2] = (mz_uint8)(v >> 16);
7832 p[3] = (mz_uint8)(v >> 24);
7833}
7834static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) {
7835 mz_write_le32(p, (mz_uint32)v);
7836 mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32));
7837}
7838
7839#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
7840#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
7841#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v))
7842
7843static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs,
7844 const void *pBuf, size_t n) {
7845 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
7846 mz_zip_internal_state *pState = pZip->m_pState;
7847 mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
7848
7849 if (!n)
7850 return 0;
7851
7852 /* An allocation this big is likely to just fail on 32-bit systems, so don't
7853 * even go there. */
7854 if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) {
7855 mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
7856 return 0;
7857 }
7858
7859 if (new_size > pState->m_mem_capacity) {
7860 void *pNew_block;
7861 size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity);
7862
7863 while (new_capacity < new_size)
7864 new_capacity *= 2;
7865
7866 if (NULL == (pNew_block = pZip->m_pRealloc(
7867 pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) {
7868 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7869 return 0;
7870 }
7871
7872 pState->m_pMem = pNew_block;
7873 pState->m_mem_capacity = new_capacity;
7874 }
7875 memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
7876 pState->m_mem_size = (size_t)new_size;
7877 return n;
7878}
7879
7880static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip,
7881 mz_bool set_last_error) {
7882 mz_zip_internal_state *pState;
7883 mz_bool status = MZ_TRUE;
7884
7885 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
7886 ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) &&
7887 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) {
7888 if (set_last_error)
7889 mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7890 return MZ_FALSE;
7891 }
7892
7893 pState = pZip->m_pState;
7894 pZip->m_pState = NULL;
7895 mz_zip_array_clear(pZip, &pState->m_central_dir);
7896 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
7897 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
7898
7899#ifndef MINIZ_NO_STDIO
7900 if (pState->m_pFile) {
7901 if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) {
7902 if (MZ_FCLOSE(pState->m_pFile) == EOF) {
7903 if (set_last_error)
7904 mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
7905 status = MZ_FALSE;
7906 }
7907 }
7908
7909 pState->m_pFile = NULL;
7910 }
7911#endif /* #ifndef MINIZ_NO_STDIO */
7912
7913 if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) {
7914 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
7915 pState->m_pMem = NULL;
7916 }
7917
7918 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
7919 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
7920 return status;
7921}
7922
7923mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size,
7924 mz_uint flags) {
7925 mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0;
7926
7927 if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) ||
7928 (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
7929 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7930
7931 if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) {
7932 if (!pZip->m_pRead)
7933 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7934 }
7935
7936 if (pZip->m_file_offset_alignment) {
7937 /* Ensure user specified file offset alignment is a power of 2. */
7938 if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
7939 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
7940 }
7941
7942 if (!pZip->m_pAlloc)
7943 pZip->m_pAlloc = miniz_def_alloc_func;
7944 if (!pZip->m_pFree)
7945 pZip->m_pFree = miniz_def_free_func;
7946 if (!pZip->m_pRealloc)
7947 pZip->m_pRealloc = miniz_def_realloc_func;
7948
7949 pZip->m_archive_size = existing_size;
7950 pZip->m_central_directory_file_ofs = 0;
7951 pZip->m_total_files = 0;
7952
7953 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
7954 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
7955 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
7956
7957 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
7958
7959 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
7960 sizeof(mz_uint8));
7961 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
7962 sizeof(mz_uint32));
7963 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
7964 sizeof(mz_uint32));
7965
7966 pZip->m_pState->m_zip64 = zip64;
7967 pZip->m_pState->m_zip64_has_extended_info_fields = zip64;
7968
7969 pZip->m_zip_type = MZ_ZIP_TYPE_USER;
7970 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
7971
7972 return MZ_TRUE;
7973}
7974
7975mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) {
7976 return mz_zip_writer_init_v2(pZip, existing_size, 0);
7977}
7978
7979mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip,
7980 size_t size_to_reserve_at_beginning,
7981 size_t initial_allocation_size,
7982 mz_uint flags) {
7983 pZip->m_pWrite = mz_zip_heap_write_func;
7984 pZip->m_pNeeds_keepalive = NULL;
7985
7986 if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
7987 pZip->m_pRead = mz_zip_mem_read_func;
7988
7989 pZip->m_pIO_opaque = pZip;
7990
7991 if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))
7992 return MZ_FALSE;
7993
7994 pZip->m_zip_type = MZ_ZIP_TYPE_HEAP;
7995
7996 if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size,
7997 size_to_reserve_at_beginning))) {
7998 if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(
7999 pZip->m_pAlloc_opaque, 1, initial_allocation_size))) {
8000 mz_zip_writer_end_internal(pZip, MZ_FALSE);
8001 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
8002 }
8003 pZip->m_pState->m_mem_capacity = initial_allocation_size;
8004 }
8005
8006 return MZ_TRUE;
8007}
8008
8009mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
8010 size_t size_to_reserve_at_beginning,
8011 size_t initial_allocation_size) {
8012 return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning,
8013 initial_allocation_size, 0);
8014}
8015
8016#ifndef MINIZ_NO_STDIO
8017static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs,
8018 const void *pBuf, size_t n) {
8019 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
8020 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
8021
8022 file_ofs += pZip->m_pState->m_file_archive_start_ofs;
8023
8024 if (((mz_int64)file_ofs < 0) ||
8025 (((cur_ofs != (mz_int64)file_ofs)) &&
8026 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) {
8027 mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
8028 return 0;
8029 }
8030
8031 return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
8032}
8033
8034mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
8035 mz_uint64 size_to_reserve_at_beginning) {
8036 return mz_zip_writer_init_file_v2(pZip, pFilename,
8037 size_to_reserve_at_beginning, 0);
8038}
8039
8040mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename,
8041 mz_uint64 size_to_reserve_at_beginning,
8042 mz_uint flags) {
8043 MZ_FILE *pFile;
8044
8045 pZip->m_pWrite = mz_zip_file_write_func;
8046 pZip->m_pNeeds_keepalive = NULL;
8047
8048 if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
8049 pZip->m_pRead = mz_zip_file_read_func;
8050
8051 pZip->m_pIO_opaque = pZip;
8052
8053 if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))
8054 return MZ_FALSE;
8055
8056 if (NULL == (pFile = MZ_FOPEN(
8057 pFilename,
8058 (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) {
8059 mz_zip_writer_end(pZip);
8060 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
8061 }
8062
8063 pZip->m_pState->m_pFile = pFile;
8064 pZip->m_zip_type = MZ_ZIP_TYPE_FILE;
8065
8066 if (size_to_reserve_at_beginning) {
8067 mz_uint64 cur_ofs = 0;
8068 char buf[4096];
8069
8070 MZ_CLEAR_ARR(buf);
8071
8072 do {
8073 size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
8074 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) {
8075 mz_zip_writer_end(pZip);
8076 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8077 }
8078 cur_ofs += n;
8079 size_to_reserve_at_beginning -= n;
8080 } while (size_to_reserve_at_beginning);
8081 }
8082
8083 return MZ_TRUE;
8084}
8085
8086mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile,
8087 mz_uint flags) {
8088 pZip->m_pWrite = mz_zip_file_write_func;
8089 pZip->m_pNeeds_keepalive = NULL;
8090
8091 if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
8092 pZip->m_pRead = mz_zip_file_read_func;
8093
8094 pZip->m_pIO_opaque = pZip;
8095
8096 if (!mz_zip_writer_init_v2(pZip, 0, flags))
8097 return MZ_FALSE;
8098
8099 pZip->m_pState->m_pFile = pFile;
8100 pZip->m_pState->m_file_archive_start_ofs =
8101 MZ_FTELL64(pZip->m_pState->m_pFile);
8102 pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;
8103
8104 return MZ_TRUE;
8105}
8106#endif /* #ifndef MINIZ_NO_STDIO */
8107
8108mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip,
8109 const char *pFilename,
8110 mz_uint flags) {
8111 mz_zip_internal_state *pState;
8112
8113 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
8114 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8115
8116 if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) {
8117 /* We don't support converting a non-zip64 file to zip64 - this seems like
8118 * more trouble than it's worth. (What about the existing 32-bit data
8119 * descriptors that could follow the compressed data?) */
8120 if (!pZip->m_pState->m_zip64)
8121 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8122 }
8123
8124 /* No sense in trying to write to an archive that's already at the support max
8125 * size */
8126 if (pZip->m_pState->m_zip64) {
8127 if (pZip->m_total_files == MZ_UINT32_MAX)
8128 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
8129 } else {
8130 if (pZip->m_total_files == MZ_UINT16_MAX)
8131 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
8132
8133 if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
8134 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)
8135 return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
8136 }
8137
8138 pState = pZip->m_pState;
8139
8140 if (pState->m_pFile) {
8141#ifdef MINIZ_NO_STDIO
8142 (void)pFilename;
8143 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8144#else
8145 if (pZip->m_pIO_opaque != pZip)
8146 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8147
8148 if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) {
8149 if (!pFilename)
8150 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8151
8152 /* Archive is being read from stdio and was originally opened only for
8153 * reading. Try to reopen as writable. */
8154 if (NULL ==
8155 (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) {
8156 /* The mz_zip_archive is now in a bogus state because pState->m_pFile is
8157 * NULL, so just close it. */
8158 mz_zip_reader_end_internal(pZip, MZ_FALSE);
8159 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
8160 }
8161 }
8162
8163 pZip->m_pWrite = mz_zip_file_write_func;
8164 pZip->m_pNeeds_keepalive = NULL;
8165#endif /* #ifdef MINIZ_NO_STDIO */
8166 } else if (pState->m_pMem) {
8167 /* Archive lives in a memory block. Assume it's from the heap that we can
8168 * resize using the realloc callback. */
8169 if (pZip->m_pIO_opaque != pZip)
8170 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8171
8172 pState->m_mem_capacity = pState->m_mem_size;
8173 pZip->m_pWrite = mz_zip_heap_write_func;
8174 pZip->m_pNeeds_keepalive = NULL;
8175 }
8176 /* Archive is being read via a user provided read function - make sure the
8177 user has specified a write function too. */
8178 else if (!pZip->m_pWrite)
8179 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8180
8181 /* Start writing new files at the archive's current central directory
8182 * location. */
8183 /* TODO: We could add a flag that lets the user start writing immediately
8184 * AFTER the existing central dir - this would be safer. */
8185 pZip->m_archive_size = pZip->m_central_directory_file_ofs;
8186 pZip->m_central_directory_file_ofs = 0;
8187
8188 /* Clear the sorted central dir offsets, they aren't useful or maintained now.
8189 */
8190 /* Even though we're now in write mode, files can still be extracted and
8191 * verified, but file locates will be slow. */
8192 /* TODO: We could easily maintain the sorted central directory offsets. */
8193 mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets);
8194
8195 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
8196
8197 return MZ_TRUE;
8198}
8199
8200mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
8201 const char *pFilename) {
8202 return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0);
8203}
8204
8205/* TODO: pArchive_name is a terrible name here! */
8206mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name,
8207 const void *pBuf, size_t buf_size,
8208 mz_uint level_and_flags) {
8209 return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0,
8210 level_and_flags, 0, 0);
8211}
8212
8213typedef struct {
8214 mz_zip_archive *m_pZip;
8215 mz_uint64 m_cur_archive_file_ofs;
8216 mz_uint64 m_comp_size;
8218
8219static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len,
8220 void *pUser) {
8222 if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque,
8223 pState->m_cur_archive_file_ofs, pBuf,
8224 len) != len)
8225 return MZ_FALSE;
8226
8227 pState->m_cur_archive_file_ofs += len;
8228 pState->m_comp_size += len;
8229 return MZ_TRUE;
8230}
8231
8232#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE \
8233 (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2)
8234#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE \
8235 (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3)
8236static mz_uint32
8237mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size,
8238 mz_uint64 *pComp_size,
8239 mz_uint64 *pLocal_header_ofs) {
8240 mz_uint8 *pDst = pBuf;
8241 mz_uint32 field_size = 0;
8242
8243 MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);
8244 MZ_WRITE_LE16(pDst + 2, 0);
8245 pDst += sizeof(mz_uint16) * 2;
8246
8247 if (pUncomp_size) {
8248 MZ_WRITE_LE64(pDst, *pUncomp_size);
8249 pDst += sizeof(mz_uint64);
8250 field_size += sizeof(mz_uint64);
8251 }
8252
8253 if (pComp_size) {
8254 MZ_WRITE_LE64(pDst, *pComp_size);
8255 pDst += sizeof(mz_uint64);
8256 field_size += sizeof(mz_uint64);
8257 }
8258
8259 if (pLocal_header_ofs) {
8260 MZ_WRITE_LE64(pDst, *pLocal_header_ofs);
8261 pDst += sizeof(mz_uint64);
8262 field_size += sizeof(mz_uint64);
8263 }
8264
8265 MZ_WRITE_LE16(pBuf + 2, field_size);
8266
8267 return (mz_uint32)(pDst - pBuf);
8268}
8269
8270static mz_bool mz_zip_writer_create_local_dir_header(
8271 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
8272 mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
8273 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
8274 mz_uint16 dos_time, mz_uint16 dos_date) {
8275 (void)pZip;
8276 memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
8277 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
8278 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
8279 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
8280 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
8281 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
8282 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
8283 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
8284 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS,
8285 MZ_MIN(comp_size, MZ_UINT32_MAX));
8286 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS,
8287 MZ_MIN(uncomp_size, MZ_UINT32_MAX));
8288 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
8289 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
8290 return MZ_TRUE;
8291}
8292
8293static mz_bool mz_zip_writer_create_central_dir_header(
8294 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
8295 mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size,
8296 mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method,
8297 mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,
8298 mz_uint64 local_header_ofs, mz_uint32 ext_attributes) {
8299 (void)pZip;
8300 memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
8301 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
8302 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_MADE_BY_OFS, 0x031E);
8303 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
8304 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
8305 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
8306 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
8307 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
8308 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
8309 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS,
8310 MZ_MIN(comp_size, MZ_UINT32_MAX));
8311 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS,
8312 MZ_MIN(uncomp_size, MZ_UINT32_MAX));
8313 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
8314 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
8315 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
8316 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
8317 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS,
8318 MZ_MIN(local_header_ofs, MZ_UINT32_MAX));
8319 return MZ_TRUE;
8320}
8321
8322static mz_bool mz_zip_writer_add_to_central_dir(
8323 mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size,
8324 const void *pExtra, mz_uint16 extra_size, const void *pComment,
8325 mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
8326 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
8327 mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs,
8328 mz_uint32 ext_attributes, const char *user_extra_data,
8329 mz_uint user_extra_data_len) {
8330 mz_zip_internal_state *pState = pZip->m_pState;
8331 mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
8332 size_t orig_central_dir_size = pState->m_central_dir.m_size;
8333 mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
8334
8335 if (!pZip->m_pState->m_zip64) {
8336 if (local_header_ofs > 0xFFFFFFFF)
8337 return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
8338 }
8339
8340 /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
8341 if (((mz_uint64)pState->m_central_dir.m_size +
8342 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size +
8343 user_extra_data_len + comment_size) >= MZ_UINT32_MAX)
8344 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
8345
8346 if (!mz_zip_writer_create_central_dir_header(
8347 pZip, central_dir_header, filename_size,
8348 (mz_uint16)(extra_size + user_extra_data_len), comment_size,
8349 uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time,
8350 dos_date, local_header_ofs, ext_attributes))
8351 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
8352
8353 if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header,
8354 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
8355 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename,
8356 filename_size)) ||
8357 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra,
8358 extra_size)) ||
8359 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data,
8360 user_extra_data_len)) ||
8361 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment,
8362 comment_size)) ||
8363 (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets,
8364 &central_dir_ofs, 1))) {
8365 /* Try to resize the central directory array back into its original state.
8366 */
8367 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
8368 MZ_FALSE);
8369 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
8370 }
8371
8372 return MZ_TRUE;
8373}
8374
8375static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) {
8376 /* Basic ZIP archive filename validity checks: Valid filenames cannot start
8377 * with a forward slash, cannot contain a drive letter, and cannot use
8378 * DOS-style backward slashes. */
8379 if (*pArchive_name == '/')
8380 return MZ_FALSE;
8381
8382 /* Making sure the name does not contain drive letters or DOS style backward
8383 * slashes is the responsibility of the program using miniz*/
8384
8385 return MZ_TRUE;
8386}
8387
8388static mz_uint
8389mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) {
8390 mz_uint32 n;
8391 if (!pZip->m_file_offset_alignment)
8392 return 0;
8393 n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
8394 return (mz_uint)((pZip->m_file_offset_alignment - n) &
8395 (pZip->m_file_offset_alignment - 1));
8396}
8397
8398static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip,
8399 mz_uint64 cur_file_ofs, mz_uint32 n) {
8400 char buf[4096];
8401 memset(buf, 0, MZ_MIN(sizeof(buf), n));
8402 while (n) {
8403 mz_uint32 s = MZ_MIN(sizeof(buf), n);
8404 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
8405 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8406
8407 cur_file_ofs += s;
8408 n -= s;
8409 }
8410 return MZ_TRUE;
8411}
8412
8413mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
8414 const char *pArchive_name, const void *pBuf,
8415 size_t buf_size, const void *pComment,
8416 mz_uint16 comment_size,
8417 mz_uint level_and_flags, mz_uint64 uncomp_size,
8418 mz_uint32 uncomp_crc32) {
8419 return mz_zip_writer_add_mem_ex_v2(
8420 pZip, pArchive_name, pBuf, buf_size, pComment, comment_size,
8421 level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0);
8422}
8423
8424mz_bool mz_zip_writer_add_mem_ex_v2(
8425 mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf,
8426 size_t buf_size, const void *pComment, mz_uint16 comment_size,
8427 mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32,
8428 MZ_TIME_T *last_modified, const char *user_extra_data,
8429 mz_uint user_extra_data_len, const char *user_extra_data_central,
8430 mz_uint user_extra_data_central_len) {
8431 mz_uint16 method = 0, dos_time = 0, dos_date = 0;
8432 mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
8433 mz_uint64 local_dir_header_ofs = pZip->m_archive_size,
8434 cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
8435 size_t archive_name_size;
8436 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
8437 tdefl_compressor *pComp = NULL;
8438 mz_bool store_data_uncompressed;
8439 mz_zip_internal_state *pState;
8440 mz_uint8 *pExtra_data = NULL;
8441 mz_uint32 extra_size = 0;
8442 mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];
8443 mz_uint16 bit_flags = 0;
8444
8445 if ((int)level_and_flags < 0)
8446 level_and_flags = MZ_DEFAULT_LEVEL;
8447
8448 if (uncomp_size ||
8449 (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
8450 bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;
8451
8452 if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))
8453 bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;
8454
8455 level = level_and_flags & 0xF;
8456 store_data_uncompressed =
8457 ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
8458
8459 if ((!pZip) || (!pZip->m_pState) ||
8460 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) ||
8461 (!pArchive_name) || ((comment_size) && (!pComment)) ||
8462 (level > MZ_UBER_COMPRESSION))
8463 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8464
8465 pState = pZip->m_pState;
8466
8467 if (pState->m_zip64) {
8468 if (pZip->m_total_files == MZ_UINT32_MAX)
8469 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
8470 } else {
8471 if (pZip->m_total_files == MZ_UINT16_MAX) {
8472 pState->m_zip64 = MZ_TRUE;
8473 /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */
8474 }
8475 if (((mz_uint64)buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) {
8476 pState->m_zip64 = MZ_TRUE;
8477 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
8478 }
8479 }
8480
8481 if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
8482 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8483
8484 if (!mz_zip_writer_validate_archive_name(pArchive_name))
8485 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
8486
8487#ifndef MINIZ_NO_TIME
8488 if (last_modified != NULL) {
8489 mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date);
8490 } else {
8491 MZ_TIME_T cur_time;
8492 time(&cur_time);
8493 mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date);
8494 }
8495#else
8496 (void)last_modified;
8497#endif /* #ifndef MINIZ_NO_TIME */
8498
8499 if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
8500 uncomp_crc32 =
8501 (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
8502 uncomp_size = buf_size;
8503 if (uncomp_size <= 3) {
8504 level = 0;
8505 store_data_uncompressed = MZ_TRUE;
8506 }
8507 }
8508
8509 archive_name_size = strlen(pArchive_name);
8510 if (archive_name_size > MZ_UINT16_MAX)
8511 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
8512
8513 num_alignment_padding_bytes =
8514 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
8515
8516 /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
8517 if (((mz_uint64)pState->m_central_dir.m_size +
8518 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size +
8519 MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX)
8520 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
8521
8522 if (!pState->m_zip64) {
8523 /* Bail early if the archive would obviously become too large */
8524 if ((pZip->m_archive_size + num_alignment_padding_bytes +
8525 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size +
8526 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size +
8527 user_extra_data_len + pState->m_central_dir.m_size +
8528 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len +
8529 MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) {
8530 pState->m_zip64 = MZ_TRUE;
8531 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
8532 }
8533 }
8534
8535 if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) {
8536 /* Set DOS Subdirectory attribute bit. */
8537 ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG;
8538
8539 /* Subdirectories cannot contain data. */
8540 if ((buf_size) || (uncomp_size))
8541 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8542 }
8543
8544 /* Try to do any allocations before writing to the archive, so if an
8545 * allocation fails the file remains unmodified. (A good idea if we're doing
8546 * an in-place modification.) */
8547 if ((!mz_zip_array_ensure_room(
8548 pZip, &pState->m_central_dir,
8549 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size +
8550 (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) ||
8551 (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))
8552 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
8553
8554 if ((!store_data_uncompressed) && (buf_size)) {
8555 if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(
8556 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
8557 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
8558 }
8559
8560 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs,
8561 num_alignment_padding_bytes)) {
8562 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
8563 return MZ_FALSE;
8564 }
8565
8566 local_dir_header_ofs += num_alignment_padding_bytes;
8567 if (pZip->m_file_offset_alignment) {
8568 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
8569 0);
8570 }
8571 cur_archive_file_ofs += num_alignment_padding_bytes;
8572
8573 MZ_CLEAR_ARR(local_dir_header);
8574
8575 if (!store_data_uncompressed ||
8576 (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
8577 method = MZ_DEFLATED;
8578 }
8579
8580 if (pState->m_zip64) {
8581 if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) {
8582 pExtra_data = extra_data;
8583 extra_size = mz_zip_writer_create_zip64_extra_data(
8584 extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
8585 (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL,
8586 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs
8587 : NULL);
8588 }
8589
8590 if (!mz_zip_writer_create_local_dir_header(
8591 pZip, local_dir_header, (mz_uint16)archive_name_size,
8592 (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method,
8593 bit_flags, dos_time, dos_date))
8594 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
8595
8596 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs,
8597 local_dir_header,
8598 sizeof(local_dir_header)) != sizeof(local_dir_header))
8599 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8600
8601 cur_archive_file_ofs += sizeof(local_dir_header);
8602
8603 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
8604 archive_name_size) != archive_name_size) {
8605 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
8606 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8607 }
8608 cur_archive_file_ofs += archive_name_size;
8609
8610 if (pExtra_data != NULL) {
8611 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data,
8612 extra_size) != extra_size)
8613 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8614
8615 cur_archive_file_ofs += extra_size;
8616 }
8617 } else {
8618 if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))
8619 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
8620 if (!mz_zip_writer_create_local_dir_header(
8621 pZip, local_dir_header, (mz_uint16)archive_name_size,
8622 (mz_uint16)user_extra_data_len, 0, 0, 0, method, bit_flags,
8623 dos_time, dos_date))
8624 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
8625
8626 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs,
8627 local_dir_header,
8628 sizeof(local_dir_header)) != sizeof(local_dir_header))
8629 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8630
8631 cur_archive_file_ofs += sizeof(local_dir_header);
8632
8633 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
8634 archive_name_size) != archive_name_size) {
8635 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
8636 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8637 }
8638 cur_archive_file_ofs += archive_name_size;
8639 }
8640
8641 if (user_extra_data_len > 0) {
8642 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
8643 user_extra_data,
8644 user_extra_data_len) != user_extra_data_len)
8645 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8646
8647 cur_archive_file_ofs += user_extra_data_len;
8648 }
8649
8650 if (store_data_uncompressed) {
8651 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf,
8652 buf_size) != buf_size) {
8653 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
8654 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8655 }
8656
8657 cur_archive_file_ofs += buf_size;
8658 comp_size = buf_size;
8659 } else if (buf_size) {
8661
8662 state.m_pZip = pZip;
8663 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
8664 state.m_comp_size = 0;
8665
8666 if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
8667 tdefl_create_comp_flags_from_zip_params(
8668 level, -15, MZ_DEFAULT_STRATEGY)) !=
8669 TDEFL_STATUS_OKAY) ||
8670 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) !=
8671 TDEFL_STATUS_DONE)) {
8672 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
8673 return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);
8674 }
8675
8676 comp_size = state.m_comp_size;
8677 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
8678 }
8679
8680 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
8681 pComp = NULL;
8682
8683 if (uncomp_size) {
8684 mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];
8685 mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;
8686
8687 MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR);
8688
8689 MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);
8690 MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);
8691 if (pExtra_data == NULL) {
8692 if (comp_size > MZ_UINT32_MAX)
8693 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
8694
8695 MZ_WRITE_LE32(local_dir_footer + 8, comp_size);
8696 MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);
8697 } else {
8698 MZ_WRITE_LE64(local_dir_footer + 8, comp_size);
8699 MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);
8700 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;
8701 }
8702
8703 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
8704 local_dir_footer,
8705 local_dir_footer_size) != local_dir_footer_size)
8706 return MZ_FALSE;
8707
8708 cur_archive_file_ofs += local_dir_footer_size;
8709 }
8710
8711 if (pExtra_data != NULL) {
8712 extra_size = mz_zip_writer_create_zip64_extra_data(
8713 extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
8714 (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL,
8715 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
8716 }
8717
8718 if (!mz_zip_writer_add_to_central_dir(
8719 pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data,
8720 (mz_uint16)extra_size, pComment, comment_size, uncomp_size, comp_size,
8721 uncomp_crc32, method, bit_flags, dos_time, dos_date,
8722 local_dir_header_ofs, ext_attributes, user_extra_data_central,
8723 user_extra_data_central_len))
8724 return MZ_FALSE;
8725
8726 pZip->m_total_files++;
8727 pZip->m_archive_size = cur_archive_file_ofs;
8728
8729 return MZ_TRUE;
8730}
8731
8732mz_bool mz_zip_writer_add_read_buf_callback(
8733 mz_zip_archive *pZip, const char *pArchive_name,
8734 mz_file_read_func read_callback, void *callback_opaque, mz_uint64 max_size,
8735 const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size,
8736 mz_uint level_and_flags, mz_uint32 ext_attributes,
8737 const char *user_extra_data, mz_uint user_extra_data_len,
8738 const char *user_extra_data_central, mz_uint user_extra_data_central_len) {
8739 mz_uint16 gen_flags;
8740 mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
8741 mz_uint16 method = 0, dos_time = 0, dos_date = 0;
8742 mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size,
8743 uncomp_size = 0, comp_size = 0;
8744 size_t archive_name_size;
8745 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
8746 mz_uint8 *pExtra_data = NULL;
8747 mz_uint32 extra_size = 0;
8748 mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];
8749 mz_zip_internal_state *pState;
8750 mz_uint64 file_ofs = 0, cur_archive_header_file_ofs;
8751
8752 if ((int)level_and_flags < 0)
8753 level_and_flags = MZ_DEFAULT_LEVEL;
8754 level = level_and_flags & 0xF;
8755
8756 gen_flags = (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE)
8757 ? 0
8758 : MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;
8759
8760 if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))
8761 gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;
8762
8763 /* Sanity checks */
8764 if ((!pZip) || (!pZip->m_pState) ||
8765 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) ||
8766 ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
8767 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8768
8769 pState = pZip->m_pState;
8770
8771 if ((!pState->m_zip64) && (max_size > MZ_UINT32_MAX)) {
8772 /* Source file is too large for non-zip64 */
8773 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
8774 pState->m_zip64 = MZ_TRUE;
8775 }
8776
8777 /* We could support this, but why? */
8778 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
8779 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
8780
8781 if (!mz_zip_writer_validate_archive_name(pArchive_name))
8782 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
8783
8784 if (pState->m_zip64) {
8785 if (pZip->m_total_files == MZ_UINT32_MAX)
8786 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
8787 } else {
8788 if (pZip->m_total_files == MZ_UINT16_MAX) {
8789 pState->m_zip64 = MZ_TRUE;
8790 /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */
8791 }
8792 }
8793
8794 archive_name_size = strlen(pArchive_name);
8795 if (archive_name_size > MZ_UINT16_MAX)
8796 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
8797
8798 num_alignment_padding_bytes =
8799 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
8800
8801 /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
8802 if (((mz_uint64)pState->m_central_dir.m_size +
8803 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size +
8804 MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX)
8805 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
8806
8807 if (!pState->m_zip64) {
8808 /* Bail early if the archive would obviously become too large */
8809 if ((pZip->m_archive_size + num_alignment_padding_bytes +
8810 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size +
8811 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size +
8812 user_extra_data_len + pState->m_central_dir.m_size +
8813 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 +
8814 MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) >
8815 0xFFFFFFFF) {
8816 pState->m_zip64 = MZ_TRUE;
8817 /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
8818 }
8819 }
8820
8821#ifndef MINIZ_NO_TIME
8822 if (pFile_time) {
8823 mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date);
8824 }
8825#else
8826 (void)pFile_time;
8827#endif
8828
8829 if (max_size <= 3)
8830 level = 0;
8831
8832 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs,
8833 num_alignment_padding_bytes)) {
8834 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8835 }
8836
8837 cur_archive_file_ofs += num_alignment_padding_bytes;
8838 local_dir_header_ofs = cur_archive_file_ofs;
8839
8840 if (pZip->m_file_offset_alignment) {
8841 MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) ==
8842 0);
8843 }
8844
8845 if (max_size && level) {
8846 method = MZ_DEFLATED;
8847 }
8848
8849 MZ_CLEAR_ARR(local_dir_header);
8850 if (pState->m_zip64) {
8851 if (max_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) {
8852 pExtra_data = extra_data;
8853 if (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE)
8854 extra_size = mz_zip_writer_create_zip64_extra_data(
8855 extra_data, (max_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
8856 (max_size >= MZ_UINT32_MAX) ? &comp_size : NULL,
8857 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs
8858 : NULL);
8859 else
8860 extra_size = mz_zip_writer_create_zip64_extra_data(
8861 extra_data, NULL, NULL,
8862 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs
8863 : NULL);
8864 }
8865
8866 if (!mz_zip_writer_create_local_dir_header(
8867 pZip, local_dir_header, (mz_uint16)archive_name_size,
8868 (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method,
8869 gen_flags, dos_time, dos_date))
8870 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
8871
8872 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
8873 local_dir_header,
8874 sizeof(local_dir_header)) != sizeof(local_dir_header))
8875 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8876
8877 cur_archive_file_ofs += sizeof(local_dir_header);
8878
8879 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
8880 archive_name_size) != archive_name_size) {
8881 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8882 }
8883
8884 cur_archive_file_ofs += archive_name_size;
8885
8886 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data,
8887 extra_size) != extra_size)
8888 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8889
8890 cur_archive_file_ofs += extra_size;
8891 } else {
8892 if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))
8893 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
8894 if (!mz_zip_writer_create_local_dir_header(
8895 pZip, local_dir_header, (mz_uint16)archive_name_size,
8896 (mz_uint16)user_extra_data_len, 0, 0, 0, method, gen_flags,
8897 dos_time, dos_date))
8898 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
8899
8900 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
8901 local_dir_header,
8902 sizeof(local_dir_header)) != sizeof(local_dir_header))
8903 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8904
8905 cur_archive_file_ofs += sizeof(local_dir_header);
8906
8907 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
8908 archive_name_size) != archive_name_size) {
8909 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8910 }
8911
8912 cur_archive_file_ofs += archive_name_size;
8913 }
8914
8915 if (user_extra_data_len > 0) {
8916 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
8917 user_extra_data,
8918 user_extra_data_len) != user_extra_data_len)
8919 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8920
8921 cur_archive_file_ofs += user_extra_data_len;
8922 }
8923
8924 if (max_size) {
8925 void *pRead_buf =
8926 pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
8927 if (!pRead_buf) {
8928 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
8929 }
8930
8931 if (!level) {
8932 while (1) {
8933 size_t n = read_callback(callback_opaque, file_ofs, pRead_buf,
8934 MZ_ZIP_MAX_IO_BUF_SIZE);
8935 if (n == 0)
8936 break;
8937
8938 if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) {
8939 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
8940 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
8941 }
8942 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf,
8943 n) != n) {
8944 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
8945 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
8946 }
8947 file_ofs += n;
8948 uncomp_crc32 =
8949 (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
8950 cur_archive_file_ofs += n;
8951 }
8952 uncomp_size = file_ofs;
8953 comp_size = uncomp_size;
8954 } else {
8955 mz_bool result = MZ_FALSE;
8957 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(
8958 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
8959 if (!pComp) {
8960 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
8961 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
8962 }
8963
8964 state.m_pZip = pZip;
8965 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
8966 state.m_comp_size = 0;
8967
8968 if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
8969 tdefl_create_comp_flags_from_zip_params(
8970 level, -15, MZ_DEFAULT_STRATEGY)) !=
8971 TDEFL_STATUS_OKAY) {
8972 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
8973 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
8974 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
8975 }
8976
8977 for (;;) {
8978 tdefl_status status;
8979 tdefl_flush flush = TDEFL_NO_FLUSH;
8980
8981 size_t n = read_callback(callback_opaque, file_ofs, pRead_buf,
8982 MZ_ZIP_MAX_IO_BUF_SIZE);
8983 if ((n > MZ_ZIP_MAX_IO_BUF_SIZE) || (file_ofs + n > max_size)) {
8984 mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
8985 break;
8986 }
8987
8988 file_ofs += n;
8989 uncomp_crc32 =
8990 (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
8991
8992 if (pZip->m_pNeeds_keepalive != NULL &&
8993 pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque))
8994 flush = TDEFL_FULL_FLUSH;
8995
8996 if (n == 0)
8997 flush = TDEFL_FINISH;
8998
8999 status = tdefl_compress_buffer(pComp, pRead_buf, n, flush);
9000 if (status == TDEFL_STATUS_DONE) {
9001 result = MZ_TRUE;
9002 break;
9003 } else if (status != TDEFL_STATUS_OKAY) {
9004 mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);
9005 break;
9006 }
9007 }
9008
9009 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
9010
9011 if (!result) {
9012 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
9013 return MZ_FALSE;
9014 }
9015
9016 uncomp_size = file_ofs;
9017 comp_size = state.m_comp_size;
9018 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
9019 }
9020
9021 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
9022 }
9023
9024 if (!(level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE)) {
9025 mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];
9026 mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;
9027
9028 MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);
9029 MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);
9030 if (pExtra_data == NULL) {
9031 if (comp_size > MZ_UINT32_MAX)
9032 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
9033
9034 MZ_WRITE_LE32(local_dir_footer + 8, comp_size);
9035 MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);
9036 } else {
9037 MZ_WRITE_LE64(local_dir_footer + 8, comp_size);
9038 MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);
9039 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;
9040 }
9041
9042 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs,
9043 local_dir_footer,
9044 local_dir_footer_size) != local_dir_footer_size)
9045 return MZ_FALSE;
9046
9047 cur_archive_file_ofs += local_dir_footer_size;
9048 }
9049
9050 if (level_and_flags & MZ_ZIP_FLAG_WRITE_HEADER_SET_SIZE) {
9051 if (pExtra_data != NULL) {
9052 extra_size = mz_zip_writer_create_zip64_extra_data(
9053 extra_data, (max_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
9054 (max_size >= MZ_UINT32_MAX) ? &comp_size : NULL,
9055 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs
9056 : NULL);
9057 }
9058
9059 if (!mz_zip_writer_create_local_dir_header(
9060 pZip, local_dir_header, (mz_uint16)archive_name_size,
9061 (mz_uint16)(extra_size + user_extra_data_len),
9062 (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : uncomp_size,
9063 (max_size >= MZ_UINT32_MAX) ? MZ_UINT32_MAX : comp_size,
9064 uncomp_crc32, method, gen_flags, dos_time, dos_date))
9065 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
9066
9067 cur_archive_header_file_ofs = local_dir_header_ofs;
9068
9069 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs,
9070 local_dir_header,
9071 sizeof(local_dir_header)) != sizeof(local_dir_header))
9072 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
9073
9074 if (pExtra_data != NULL) {
9075 cur_archive_header_file_ofs += sizeof(local_dir_header);
9076
9077 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs,
9078 pArchive_name,
9079 archive_name_size) != archive_name_size) {
9080 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
9081 }
9082
9083 cur_archive_header_file_ofs += archive_name_size;
9084
9085 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_header_file_ofs,
9086 extra_data, extra_size) != extra_size)
9087 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
9088
9089 cur_archive_header_file_ofs += extra_size;
9090 }
9091 }
9092
9093 if (pExtra_data != NULL) {
9094 extra_size = mz_zip_writer_create_zip64_extra_data(
9095 extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
9096 (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL,
9097 (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
9098 }
9099
9100 if (!mz_zip_writer_add_to_central_dir(
9101 pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data,
9102 (mz_uint16)extra_size, pComment, comment_size, uncomp_size, comp_size,
9103 uncomp_crc32, method, gen_flags, dos_time, dos_date,
9104 local_dir_header_ofs, ext_attributes, user_extra_data_central,
9105 user_extra_data_central_len))
9106 return MZ_FALSE;
9107
9108 pZip->m_total_files++;
9109 pZip->m_archive_size = cur_archive_file_ofs;
9110
9111 return MZ_TRUE;
9112}
9113
9114#ifndef MINIZ_NO_STDIO
9115
9116static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs,
9117 void *pBuf, size_t n) {
9118 MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque;
9119 mz_int64 cur_ofs = MZ_FTELL64(pSrc_file);
9120
9121 if (((mz_int64)file_ofs < 0) ||
9122 (((cur_ofs != (mz_int64)file_ofs)) &&
9123 (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET))))
9124 return 0;
9125
9126 return MZ_FREAD(pBuf, 1, n, pSrc_file);
9127}
9128
9129mz_bool mz_zip_writer_add_cfile(
9130 mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file,
9131 mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment,
9132 mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes,
9133 const char *user_extra_data, mz_uint user_extra_data_len,
9134 const char *user_extra_data_central, mz_uint user_extra_data_central_len) {
9135 return mz_zip_writer_add_read_buf_callback(
9136 pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, max_size,
9137 pFile_time, pComment, comment_size, level_and_flags, ext_attributes,
9138 user_extra_data, user_extra_data_len, user_extra_data_central,
9139 user_extra_data_central_len);
9140}
9141
9142mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name,
9143 const char *pSrc_filename, const void *pComment,
9144 mz_uint16 comment_size, mz_uint level_and_flags,
9145 mz_uint32 ext_attributes) {
9146 MZ_FILE *pSrc_file = NULL;
9147 mz_uint64 uncomp_size = 0;
9148 MZ_TIME_T file_modified_time;
9149 MZ_TIME_T *pFile_time = NULL;
9150 mz_bool status;
9151
9152 memset(&file_modified_time, 0, sizeof(file_modified_time));
9153
9154#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)
9155 pFile_time = &file_modified_time;
9156 if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time))
9157 return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED);
9158#endif
9159
9160 pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
9161 if (!pSrc_file)
9162 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
9163
9164 MZ_FSEEK64(pSrc_file, 0, SEEK_END);
9165 uncomp_size = MZ_FTELL64(pSrc_file);
9166 MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
9167
9168 status = mz_zip_writer_add_cfile(
9169 pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment,
9170 comment_size, level_and_flags, ext_attributes, NULL, 0, NULL, 0);
9171
9172 MZ_FCLOSE(pSrc_file);
9173
9174 return status;
9175}
9176#endif /* #ifndef MINIZ_NO_STDIO */
9177
9178static mz_bool mz_zip_writer_update_zip64_extension_block(
9179 mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt,
9180 mz_uint32 ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size,
9181 mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) {
9182 /* + 64 should be enough for any new zip64 data */
9183 if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE))
9184 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9185
9186 mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE);
9187
9188 if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) {
9189 mz_uint8 new_ext_block[64];
9190 mz_uint8 *pDst = new_ext_block;
9191 mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);
9192 mz_write_le16(pDst + sizeof(mz_uint16), 0);
9193 pDst += sizeof(mz_uint16) * 2;
9194
9195 if (pUncomp_size) {
9196 mz_write_le64(pDst, *pUncomp_size);
9197 pDst += sizeof(mz_uint64);
9198 }
9199
9200 if (pComp_size) {
9201 mz_write_le64(pDst, *pComp_size);
9202 pDst += sizeof(mz_uint64);
9203 }
9204
9205 if (pLocal_header_ofs) {
9206 mz_write_le64(pDst, *pLocal_header_ofs);
9207 pDst += sizeof(mz_uint64);
9208 }
9209
9210 if (pDisk_start) {
9211 mz_write_le32(pDst, *pDisk_start);
9212 pDst += sizeof(mz_uint32);
9213 }
9214
9215 mz_write_le16(new_ext_block + sizeof(mz_uint16),
9216 (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2));
9217
9218 if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block,
9219 pDst - new_ext_block))
9220 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9221 }
9222
9223 if ((pExt) && (ext_len)) {
9224 mz_uint32 extra_size_remaining = ext_len;
9225 const mz_uint8 *pExtra_data = pExt;
9226
9227 do {
9228 mz_uint32 field_id, field_data_size, field_total_size;
9229
9230 if (extra_size_remaining < (sizeof(mz_uint16) * 2))
9231 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
9232
9233 field_id = MZ_READ_LE16(pExtra_data);
9234 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
9235 field_total_size = field_data_size + sizeof(mz_uint16) * 2;
9236
9237 if (field_total_size > extra_size_remaining)
9238 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
9239
9240 if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
9241 if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data,
9242 field_total_size))
9243 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9244 }
9245
9246 pExtra_data += field_total_size;
9247 extra_size_remaining -= field_total_size;
9248 } while (extra_size_remaining);
9249 }
9250
9251 return MZ_TRUE;
9252}
9253
9254/* TODO: This func is now pretty freakin complex due to zip64, split it up? */
9255mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
9256 mz_zip_archive *pSource_zip,
9257 mz_uint src_file_index) {
9258 mz_uint n, bit_flags, num_alignment_padding_bytes,
9259 src_central_dir_following_data_size;
9260 mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs;
9261 mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
9262 mz_uint32
9263 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
9264 sizeof(mz_uint32)];
9265 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
9266 mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
9267 size_t orig_central_dir_size;
9268 mz_zip_internal_state *pState;
9269 void *pBuf;
9270 const mz_uint8 *pSrc_central_header;
9271 mz_zip_archive_file_stat src_file_stat;
9272 mz_uint32 src_filename_len, src_comment_len, src_ext_len;
9273 mz_uint32 local_header_filename_size, local_header_extra_len;
9274 mz_uint64 local_header_comp_size, local_header_uncomp_size;
9275 mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;
9276
9277 /* Sanity checks */
9278 if ((!pZip) || (!pZip->m_pState) ||
9279 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead))
9280 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
9281
9282 pState = pZip->m_pState;
9283
9284 /* Don't support copying files from zip64 archives to non-zip64, even though
9285 * in some cases this is possible */
9286 if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64))
9287 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
9288
9289 /* Get pointer to the source central dir header and crack it */
9290 if (NULL ==
9291 (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index)))
9292 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
9293
9294 if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) !=
9295 MZ_ZIP_CENTRAL_DIR_HEADER_SIG)
9296 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
9297
9298 src_filename_len =
9299 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS);
9300 src_comment_len =
9301 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
9302 src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS);
9303 src_central_dir_following_data_size =
9304 src_filename_len + src_ext_len + src_comment_len;
9305
9306 /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32
9307 * fudge factor in case we need to add more extra data) */
9308 if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
9309 src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX)
9310 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
9311
9312 num_alignment_padding_bytes =
9313 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
9314
9315 if (!pState->m_zip64) {
9316 if (pZip->m_total_files == MZ_UINT16_MAX)
9317 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
9318 } else {
9319 /* TODO: Our zip64 support still has some 32-bit limits that may not be
9320 * worth fixing. */
9321 if (pZip->m_total_files == MZ_UINT32_MAX)
9322 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
9323 }
9324
9325 if (!mz_zip_file_stat_internal(pSource_zip, src_file_index,
9326 pSrc_central_header, &src_file_stat, NULL))
9327 return MZ_FALSE;
9328
9329 cur_src_file_ofs = src_file_stat.m_local_header_ofs;
9330 cur_dst_file_ofs = pZip->m_archive_size;
9331
9332 /* Read the source archive's local dir header */
9333 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs,
9334 pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
9335 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
9336 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
9337
9338 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
9339 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
9340
9341 cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
9342
9343 /* Compute the total size we need to copy (filename+extra data+compressed
9344 * data) */
9345 local_header_filename_size =
9346 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);
9347 local_header_extra_len =
9348 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
9349 local_header_comp_size =
9350 MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);
9351 local_header_uncomp_size =
9352 MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);
9353 src_archive_bytes_remaining = src_file_stat.m_comp_size +
9354 local_header_filename_size +
9355 local_header_extra_len;
9356
9357 /* Try to find a zip64 extended information field */
9358 if ((local_header_extra_len) &&
9359 ((local_header_comp_size == MZ_UINT32_MAX) ||
9360 (local_header_uncomp_size == MZ_UINT32_MAX))) {
9361 mz_zip_array file_data_array;
9362 const mz_uint8 *pExtra_data;
9363 mz_uint32 extra_size_remaining = local_header_extra_len;
9364
9365 mz_zip_array_init(&file_data_array, 1);
9366 if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len,
9367 MZ_FALSE)) {
9368 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9369 }
9370
9371 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque,
9372 src_file_stat.m_local_header_ofs +
9373 MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
9374 local_header_filename_size,
9375 file_data_array.m_p, local_header_extra_len) !=
9376 local_header_extra_len) {
9377 mz_zip_array_clear(pZip, &file_data_array);
9378 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
9379 }
9380
9381 pExtra_data = (const mz_uint8 *)file_data_array.m_p;
9382
9383 do {
9384 mz_uint32 field_id, field_data_size, field_total_size;
9385
9386 if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
9387 mz_zip_array_clear(pZip, &file_data_array);
9388 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
9389 }
9390
9391 field_id = MZ_READ_LE16(pExtra_data);
9392 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
9393 field_total_size = field_data_size + sizeof(mz_uint16) * 2;
9394
9395 if (field_total_size > extra_size_remaining) {
9396 mz_zip_array_clear(pZip, &file_data_array);
9397 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
9398 }
9399
9400 if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
9401 const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);
9402
9403 if (field_data_size < sizeof(mz_uint64) * 2) {
9404 mz_zip_array_clear(pZip, &file_data_array);
9405 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
9406 }
9407
9408 local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);
9409 local_header_comp_size = MZ_READ_LE64(
9410 pSrc_field_data +
9411 sizeof(mz_uint64)); /* may be 0 if there's a descriptor */
9412
9413 found_zip64_ext_data_in_ldir = MZ_TRUE;
9414 break;
9415 }
9416
9417 pExtra_data += field_total_size;
9418 extra_size_remaining -= field_total_size;
9419 } while (extra_size_remaining);
9420
9421 mz_zip_array_clear(pZip, &file_data_array);
9422 }
9423
9424 if (!pState->m_zip64) {
9425 /* Try to detect if the new archive will most likely wind up too big and
9426 * bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which
9427 * could be present, +64 is a fudge factor). */
9428 /* We also check when the archive is finalized so this doesn't need to be
9429 * perfect. */
9430 mz_uint64 approx_new_archive_size =
9431 cur_dst_file_ofs + num_alignment_padding_bytes +
9432 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining +
9433 (sizeof(mz_uint32) * 4) + pState->m_central_dir.m_size +
9434 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size +
9435 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64;
9436
9437 if (approx_new_archive_size >= MZ_UINT32_MAX)
9438 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
9439 }
9440
9441 /* Write dest archive padding */
9442 if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs,
9443 num_alignment_padding_bytes))
9444 return MZ_FALSE;
9445
9446 cur_dst_file_ofs += num_alignment_padding_bytes;
9447
9448 local_dir_header_ofs = cur_dst_file_ofs;
9449 if (pZip->m_file_offset_alignment) {
9450 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
9451 0);
9452 }
9453
9454 /* The original zip's local header+ext block doesn't change, even with zip64,
9455 * so we can just copy it over to the dest zip */
9456 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header,
9457 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
9458 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
9459 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
9460
9461 cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
9462
9463 /* Copy over the source archive bytes to the dest archive, also ensure we have
9464 * enough buf space to handle optional data descriptor */
9465 if (NULL == (pBuf = pZip->m_pAlloc(
9466 pZip->m_pAlloc_opaque, 1,
9467 (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE,
9468 src_archive_bytes_remaining)))))
9469 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9470
9471 while (src_archive_bytes_remaining) {
9472 n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE,
9473 src_archive_bytes_remaining);
9474 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
9475 n) != n) {
9476 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
9477 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
9478 }
9479 cur_src_file_ofs += n;
9480
9481 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
9482 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
9483 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
9484 }
9485 cur_dst_file_ofs += n;
9486
9487 src_archive_bytes_remaining -= n;
9488 }
9489
9490 /* Now deal with the optional data descriptor */
9491 bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
9492 if (bit_flags & 8) {
9493 /* Copy data descriptor */
9494 if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) {
9495 /* src is zip64, dest must be zip64 */
9496
9497 /* name uint32_t's */
9498 /* id 1 (optional in zip64?) */
9499 /* crc 1 */
9500 /* comp_size 2 */
9501 /* uncomp_size 2 */
9502 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs,
9503 pBuf, (sizeof(mz_uint32) * 6)) !=
9504 (sizeof(mz_uint32) * 6)) {
9505 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
9506 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
9507 }
9508
9509 n = sizeof(mz_uint32) *
9510 ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5);
9511 } else {
9512 /* src is NOT zip64 */
9513 mz_bool has_id;
9514
9515 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs,
9516 pBuf, sizeof(mz_uint32) * 4) !=
9517 sizeof(mz_uint32) * 4) {
9518 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
9519 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
9520 }
9521
9522 has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID);
9523
9524 if (pZip->m_pState->m_zip64) {
9525 /* dest is zip64, so upgrade the data descriptor */
9526 const mz_uint8 *pSrc_descriptor =
9527 (const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0);
9528 const mz_uint32 src_crc32 = MZ_READ_LE32(pSrc_descriptor);
9529 const mz_uint64 src_comp_size =
9530 MZ_READ_LE32(pSrc_descriptor + sizeof(mz_uint32));
9531 const mz_uint64 src_uncomp_size =
9532 MZ_READ_LE32(pSrc_descriptor + 2 * sizeof(mz_uint32));
9533
9534 mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID);
9535 mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32);
9536 mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size);
9537 mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4,
9538 src_uncomp_size);
9539
9540 n = sizeof(mz_uint32) * 6;
9541 } else {
9542 /* dest is NOT zip64, just copy it as-is */
9543 n = sizeof(mz_uint32) * (has_id ? 4 : 3);
9544 }
9545 }
9546
9547 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
9548 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
9549 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
9550 }
9551
9552 cur_src_file_ofs += n;
9553 cur_dst_file_ofs += n;
9554 }
9555 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
9556
9557 /* Finally, add the new central dir header */
9558 orig_central_dir_size = pState->m_central_dir.m_size;
9559
9560 memcpy(new_central_header, pSrc_central_header,
9561 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
9562
9563 if (pState->m_zip64) {
9564 /* This is the painful part: We need to write a new central dir header + ext
9565 * block with updated zip64 fields, and ensure the old fields (if any) are
9566 * not included. */
9567 const mz_uint8 *pSrc_ext =
9568 pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len;
9569 mz_zip_array new_ext_block;
9570
9571 mz_zip_array_init(&new_ext_block, sizeof(mz_uint8));
9572
9573 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS,
9574 MZ_UINT32_MAX);
9575 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS,
9576 MZ_UINT32_MAX);
9577 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS,
9578 MZ_UINT32_MAX);
9579
9580 if (!mz_zip_writer_update_zip64_extension_block(
9581 &new_ext_block, pZip, pSrc_ext, src_ext_len,
9582 &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size,
9583 &local_dir_header_ofs, NULL)) {
9584 mz_zip_array_clear(pZip, &new_ext_block);
9585 return MZ_FALSE;
9586 }
9587
9588 MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS,
9589 new_ext_block.m_size);
9590
9591 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir,
9592 new_central_header,
9593 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) {
9594 mz_zip_array_clear(pZip, &new_ext_block);
9595 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9596 }
9597
9598 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir,
9599 pSrc_central_header +
9600 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE,
9601 src_filename_len)) {
9602 mz_zip_array_clear(pZip, &new_ext_block);
9603 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
9604 MZ_FALSE);
9605 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9606 }
9607
9608 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p,
9609 new_ext_block.m_size)) {
9610 mz_zip_array_clear(pZip, &new_ext_block);
9611 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
9612 MZ_FALSE);
9613 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9614 }
9615
9616 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir,
9617 pSrc_central_header +
9618 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
9619 src_filename_len + src_ext_len,
9620 src_comment_len)) {
9621 mz_zip_array_clear(pZip, &new_ext_block);
9622 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
9623 MZ_FALSE);
9624 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9625 }
9626
9627 mz_zip_array_clear(pZip, &new_ext_block);
9628 } else {
9629 /* sanity checks */
9630 if (cur_dst_file_ofs > MZ_UINT32_MAX)
9631 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
9632
9633 if (local_dir_header_ofs >= MZ_UINT32_MAX)
9634 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
9635
9636 MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS,
9637 local_dir_header_ofs);
9638
9639 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir,
9640 new_central_header,
9641 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
9642 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9643
9644 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir,
9645 pSrc_central_header +
9646 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE,
9647 src_central_dir_following_data_size)) {
9648 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
9649 MZ_FALSE);
9650 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9651 }
9652 }
9653
9654 /* This shouldn't trigger unless we screwed up during the initial sanity
9655 * checks */
9656 if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) {
9657 /* TODO: Support central dirs >= 32-bits in size */
9658 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
9659 MZ_FALSE);
9660 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
9661 }
9662
9663 n = (mz_uint32)orig_central_dir_size;
9664 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) {
9665 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
9666 MZ_FALSE);
9667 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
9668 }
9669
9670 pZip->m_total_files++;
9671 pZip->m_archive_size = cur_dst_file_ofs;
9672
9673 return MZ_TRUE;
9674}
9675
9676mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) {
9677 mz_zip_internal_state *pState;
9678 mz_uint64 central_dir_ofs, central_dir_size;
9679 mz_uint8 hdr[256];
9680
9681 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
9682 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
9683
9684 pState = pZip->m_pState;
9685
9686 if (pState->m_zip64) {
9687 if ((mz_uint64)pState->m_central_dir.m_size >= MZ_UINT32_MAX)
9688 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
9689 } else {
9690 if ((pZip->m_total_files > MZ_UINT16_MAX) ||
9691 ((pZip->m_archive_size + pState->m_central_dir.m_size +
9692 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX))
9693 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
9694 }
9695
9696 central_dir_ofs = 0;
9697 central_dir_size = 0;
9698 if (pZip->m_total_files) {
9699 /* Write central directory */
9700 central_dir_ofs = pZip->m_archive_size;
9701 central_dir_size = pState->m_central_dir.m_size;
9702 pZip->m_central_directory_file_ofs = central_dir_ofs;
9703 if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs,
9704 pState->m_central_dir.m_p,
9705 (size_t)central_dir_size) != central_dir_size)
9706 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
9707
9708 pZip->m_archive_size += central_dir_size;
9709 }
9710
9711 if (pState->m_zip64) {
9712 /* Write zip64 end of central directory header */
9713 mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size;
9714
9715 MZ_CLEAR_ARR(hdr);
9716 MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS,
9717 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG);
9718 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS,
9719 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) -
9720 sizeof(mz_uint64));
9721 MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS,
9722 0x031E); /* TODO: always Unix */
9723 MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D);
9724 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS,
9725 pZip->m_total_files);
9726 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS,
9727 pZip->m_total_files);
9728 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size);
9729 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs);
9730 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr,
9731 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
9732 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)
9733 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
9734
9735 pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE;
9736
9737 /* Write zip64 end of central directory locator */
9738 MZ_CLEAR_ARR(hdr);
9739 MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS,
9740 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG);
9741 MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS,
9742 rel_ofs_to_zip64_ecdr);
9743 MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1);
9744 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr,
9745 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) !=
9746 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE)
9747 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
9748
9749 pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE;
9750 }
9751
9752 /* Write end of central directory record */
9753 MZ_CLEAR_ARR(hdr);
9754 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS,
9755 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
9756 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS,
9757 MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));
9758 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS,
9759 MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));
9760 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS,
9761 MZ_MIN(MZ_UINT32_MAX, central_dir_size));
9762 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS,
9763 MZ_MIN(MZ_UINT32_MAX, central_dir_ofs));
9764
9765 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr,
9766 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
9767 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
9768 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
9769
9770#ifndef MINIZ_NO_STDIO
9771 if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))
9772 return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
9773#endif /* #ifndef MINIZ_NO_STDIO */
9774
9775 pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE;
9776
9777 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
9778 return MZ_TRUE;
9779}
9780
9781mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf,
9782 size_t *pSize) {
9783 if ((!ppBuf) || (!pSize))
9784 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
9785
9786 *ppBuf = NULL;
9787 *pSize = 0;
9788
9789 if ((!pZip) || (!pZip->m_pState))
9790 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
9791
9792 if (pZip->m_pWrite != mz_zip_heap_write_func)
9793 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
9794
9795 if (!mz_zip_writer_finalize_archive(pZip))
9796 return MZ_FALSE;
9797
9798 *ppBuf = pZip->m_pState->m_pMem;
9799 *pSize = pZip->m_pState->m_mem_size;
9800 pZip->m_pState->m_pMem = NULL;
9801 pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
9802
9803 return MZ_TRUE;
9804}
9805
9806mz_bool mz_zip_writer_end(mz_zip_archive *pZip) {
9807 return mz_zip_writer_end_internal(pZip, MZ_TRUE);
9808}
9809
9810#ifndef MINIZ_NO_STDIO
9811mz_bool mz_zip_add_mem_to_archive_file_in_place(
9812 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
9813 size_t buf_size, const void *pComment, mz_uint16 comment_size,
9814 mz_uint level_and_flags) {
9815 return mz_zip_add_mem_to_archive_file_in_place_v2(
9816 pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size,
9817 level_and_flags, NULL);
9818}
9819
9820mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(
9821 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
9822 size_t buf_size, const void *pComment, mz_uint16 comment_size,
9823 mz_uint level_and_flags, mz_zip_error *pErr) {
9824 mz_bool status, created_new_archive = MZ_FALSE;
9825 mz_zip_archive zip_archive;
9826 struct MZ_FILE_STAT_STRUCT file_stat;
9827 mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
9828
9829 mz_zip_zero_struct(&zip_archive);
9830 if ((int)level_and_flags < 0)
9831 level_and_flags = MZ_DEFAULT_LEVEL;
9832
9833 if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) ||
9834 ((comment_size) && (!pComment)) ||
9835 ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) {
9836 if (pErr)
9837 *pErr = MZ_ZIP_INVALID_PARAMETER;
9838 return MZ_FALSE;
9839 }
9840
9841 if (!mz_zip_writer_validate_archive_name(pArchive_name)) {
9842 if (pErr)
9843 *pErr = MZ_ZIP_INVALID_FILENAME;
9844 return MZ_FALSE;
9845 }
9846
9847 /* Important: The regular non-64 bit version of stat() can fail here if the
9848 * file is very large, which could cause the archive to be overwritten. */
9849 /* So be sure to compile with _LARGEFILE64_SOURCE 1 */
9850 if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) {
9851 /* Create a new archive. */
9852 if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0,
9853 level_and_flags)) {
9854 if (pErr)
9855 *pErr = zip_archive.m_last_error;
9856 return MZ_FALSE;
9857 }
9858
9859 created_new_archive = MZ_TRUE;
9860 } else {
9861 /* Append to an existing archive. */
9862 if (!mz_zip_reader_init_file_v2(
9863 &zip_archive, pZip_filename,
9864 level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0,
9865 0)) {
9866 if (pErr)
9867 *pErr = zip_archive.m_last_error;
9868 return MZ_FALSE;
9869 }
9870
9871 if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename,
9872 level_and_flags)) {
9873 if (pErr)
9874 *pErr = zip_archive.m_last_error;
9875
9876 mz_zip_reader_end_internal(&zip_archive, MZ_FALSE);
9877
9878 return MZ_FALSE;
9879 }
9880 }
9881
9882 status =
9883 mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size,
9884 pComment, comment_size, level_and_flags, 0, 0);
9885 actual_err = zip_archive.m_last_error;
9886
9887 /* Always finalize, even if adding failed for some reason, so we have a valid
9888 * central directory. (This may not always succeed, but we can try.) */
9889 if (!mz_zip_writer_finalize_archive(&zip_archive)) {
9890 if (!actual_err)
9891 actual_err = zip_archive.m_last_error;
9892
9893 status = MZ_FALSE;
9894 }
9895
9896 if (!mz_zip_writer_end_internal(&zip_archive, status)) {
9897 if (!actual_err)
9898 actual_err = zip_archive.m_last_error;
9899
9900 status = MZ_FALSE;
9901 }
9902
9903 if ((!status) && (created_new_archive)) {
9904 /* It's a new archive and something went wrong, so just delete it. */
9905 int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
9906 (void)ignoredStatus;
9907 }
9908
9909 if (pErr)
9910 *pErr = actual_err;
9911
9912 return status;
9913}
9914
9915void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename,
9916 const char *pArchive_name,
9917 const char *pComment,
9918 size_t *pSize, mz_uint flags,
9919 mz_zip_error *pErr) {
9920 mz_uint32 file_index;
9921 mz_zip_archive zip_archive;
9922 void *p = NULL;
9923
9924 if (pSize)
9925 *pSize = 0;
9926
9927 if ((!pZip_filename) || (!pArchive_name)) {
9928 if (pErr)
9929 *pErr = MZ_ZIP_INVALID_PARAMETER;
9930
9931 return NULL;
9932 }
9933
9934 mz_zip_zero_struct(&zip_archive);
9935 if (!mz_zip_reader_init_file_v2(
9936 &zip_archive, pZip_filename,
9937 flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) {
9938 if (pErr)
9939 *pErr = zip_archive.m_last_error;
9940
9941 return NULL;
9942 }
9943
9944 if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags,
9945 &file_index)) {
9946 p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
9947 }
9948
9949 mz_zip_reader_end_internal(&zip_archive, p != NULL);
9950
9951 if (pErr)
9952 *pErr = zip_archive.m_last_error;
9953
9954 return p;
9955}
9956
9957void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
9958 const char *pArchive_name,
9959 size_t *pSize, mz_uint flags) {
9960 return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name,
9961 NULL, pSize, flags, NULL);
9962}
9963
9964#endif /* #ifndef MINIZ_NO_STDIO */
9965
9966#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */
9967
9968/* ------------------- Misc utils */
9969
9970mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) {
9971 return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID;
9972}
9973
9974mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) {
9975 return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID;
9976}
9977
9978mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) {
9979 mz_zip_error prev_err;
9980
9981 if (!pZip)
9982 return MZ_ZIP_INVALID_PARAMETER;
9983
9984 prev_err = pZip->m_last_error;
9985
9986 pZip->m_last_error = err_num;
9987 return prev_err;
9988}
9989
9990mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) {
9991 if (!pZip)
9992 return MZ_ZIP_INVALID_PARAMETER;
9993
9994 return pZip->m_last_error;
9995}
9996
9997mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) {
9998 return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR);
9999}
10000
10001mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) {
10002 mz_zip_error prev_err;
10003
10004 if (!pZip)
10005 return MZ_ZIP_INVALID_PARAMETER;
10006
10007 prev_err = pZip->m_last_error;
10008
10009 pZip->m_last_error = MZ_ZIP_NO_ERROR;
10010 return prev_err;
10011}
10012
10013const char *mz_zip_get_error_string(mz_zip_error mz_err) {
10014 switch (mz_err) {
10015 case MZ_ZIP_NO_ERROR:
10016 return "no error";
10017 case MZ_ZIP_UNDEFINED_ERROR:
10018 return "undefined error";
10019 case MZ_ZIP_TOO_MANY_FILES:
10020 return "too many files";
10021 case MZ_ZIP_FILE_TOO_LARGE:
10022 return "file too large";
10023 case MZ_ZIP_UNSUPPORTED_METHOD:
10024 return "unsupported method";
10025 case MZ_ZIP_UNSUPPORTED_ENCRYPTION:
10026 return "unsupported encryption";
10027 case MZ_ZIP_UNSUPPORTED_FEATURE:
10028 return "unsupported feature";
10029 case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:
10030 return "failed finding central directory";
10031 case MZ_ZIP_NOT_AN_ARCHIVE:
10032 return "not a ZIP archive";
10033 case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:
10034 return "invalid header or archive is corrupted";
10035 case MZ_ZIP_UNSUPPORTED_MULTIDISK:
10036 return "unsupported multidisk archive";
10037 case MZ_ZIP_DECOMPRESSION_FAILED:
10038 return "decompression failed or archive is corrupted";
10039 case MZ_ZIP_COMPRESSION_FAILED:
10040 return "compression failed";
10041 case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:
10042 return "unexpected decompressed size";
10043 case MZ_ZIP_CRC_CHECK_FAILED:
10044 return "CRC-32 check failed";
10045 case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:
10046 return "unsupported central directory size";
10047 case MZ_ZIP_ALLOC_FAILED:
10048 return "allocation failed";
10049 case MZ_ZIP_FILE_OPEN_FAILED:
10050 return "file open failed";
10051 case MZ_ZIP_FILE_CREATE_FAILED:
10052 return "file create failed";
10053 case MZ_ZIP_FILE_WRITE_FAILED:
10054 return "file write failed";
10055 case MZ_ZIP_FILE_READ_FAILED:
10056 return "file read failed";
10057 case MZ_ZIP_FILE_CLOSE_FAILED:
10058 return "file close failed";
10059 case MZ_ZIP_FILE_SEEK_FAILED:
10060 return "file seek failed";
10061 case MZ_ZIP_FILE_STAT_FAILED:
10062 return "file stat failed";
10063 case MZ_ZIP_INVALID_PARAMETER:
10064 return "invalid parameter";
10065 case MZ_ZIP_INVALID_FILENAME:
10066 return "invalid filename";
10067 case MZ_ZIP_BUF_TOO_SMALL:
10068 return "buffer too small";
10069 case MZ_ZIP_INTERNAL_ERROR:
10070 return "internal error";
10071 case MZ_ZIP_FILE_NOT_FOUND:
10072 return "file not found";
10073 case MZ_ZIP_ARCHIVE_TOO_LARGE:
10074 return "archive is too large";
10075 case MZ_ZIP_VALIDATION_FAILED:
10076 return "validation failed";
10077 case MZ_ZIP_WRITE_CALLBACK_FAILED:
10078 return "write callback failed";
10079 case MZ_ZIP_TOTAL_ERRORS:
10080 return "total errors";
10081 default:
10082 break;
10083 }
10084
10085 return "unknown error";
10086}
10087
10088/* Note: Just because the archive is not zip64 doesn't necessarily mean it
10089 * doesn't have Zip64 extended information extra field, argh. */
10090mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) {
10091 if ((!pZip) || (!pZip->m_pState))
10092 return MZ_FALSE;
10093
10094 return pZip->m_pState->m_zip64;
10095}
10096
10097size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) {
10098 if ((!pZip) || (!pZip->m_pState))
10099 return 0;
10100
10101 return pZip->m_pState->m_central_dir.m_size;
10102}
10103
10104mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) {
10105 return pZip ? pZip->m_total_files : 0;
10106}
10107
10108mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) {
10109 if (!pZip)
10110 return 0;
10111 return pZip->m_archive_size;
10112}
10113
10114mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) {
10115 if ((!pZip) || (!pZip->m_pState))
10116 return 0;
10117 return pZip->m_pState->m_file_archive_start_ofs;
10118}
10119
10120MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) {
10121 if ((!pZip) || (!pZip->m_pState))
10122 return 0;
10123 return pZip->m_pState->m_pFile;
10124}
10125
10126size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs,
10127 void *pBuf, size_t n) {
10128 if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead))
10129 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
10130
10131 return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n);
10132}
10133
10134mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index,
10135 char *pFilename, mz_uint filename_buf_size) {
10136 mz_uint n;
10137 const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
10138 if (!p) {
10139 if (filename_buf_size)
10140 pFilename[0] = '\0';
10141 mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
10142 return 0;
10143 }
10144 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
10145 if (filename_buf_size) {
10146 n = MZ_MIN(n, filename_buf_size - 1);
10147 memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
10148 pFilename[n] = '\0';
10149 }
10150 return n + 1;
10151}
10152
10153mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
10154 mz_zip_archive_file_stat *pStat) {
10155 return mz_zip_file_stat_internal(
10156 pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL);
10157}
10158
10159mz_bool mz_zip_end(mz_zip_archive *pZip) {
10160 if (!pZip)
10161 return MZ_FALSE;
10162
10163 if (pZip->m_zip_mode == MZ_ZIP_MODE_READING)
10164 return mz_zip_reader_end(pZip);
10165#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
10166 else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) ||
10167 (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))
10168 return mz_zip_writer_end(pZip);
10169#endif
10170
10171 return MZ_FALSE;
10172}
10173
10174#ifdef __cplusplus
10175}
10176#endif
10177
10178#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/
10179
10180#endif // MINIZ_HEADER_FILE_ONLY