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