authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-16 21:51:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-16 21:51:58-07:00
log4d7e77cb1701a45e174a015d4803e01e12179b06
tree677e5c5c67217e398501820dd26351e67d48df04
parent1ed569e0b23c4432cd00604dcae89a17edc852a9

remove standalone test "issue_9812"

This test has a few problems: * I don't want to vendor third party projects into the main compiler repository such as kuba-zip just for test cases. If we want to test third party projects, that should be a separate repository dedicated to that purpose. * Ideally tests would be isolated to test a particular thing, rather than have a lot of unrelated logic that is not what is primarily being tested. * Ideally tests will not be named after GitHub issues, but named after the thing that is being tested. And not testing for the absence of a bug, but for the existence of correct behavior. Aside from these issues, it's also failing in the LLVM 16 branch: ``` kuba-zip/zip.c:276:16: error: call to undeclared function 'fileno'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] kuba-zip/zip.c:277:14: error: call to undeclared function 'ftruncate'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] kuba-zip/zip.c:364:11: error: call to undeclared function 'symlink'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] ``` These are not interesting failures related to the thing actually being tested; this is busywork related to the fact that we vendor third party code. So, that is why I chose to delete this test case instead of repair it.

6 files changed, 0 insertions(+), 9000 deletions(-)

test/standalone.zig-4
...@@ -175,10 +175,6 @@ pub const build_cases = [_]BuildCase{...@@ -175,10 +175,6 @@ pub const build_cases = [_]BuildCase{
175 .build_root = "test/standalone/empty_env",175 .build_root = "test/standalone/empty_env",
176 .import = @import("standalone/empty_env/build.zig"),176 .import = @import("standalone/empty_env/build.zig"),
177 },177 },
178 .{
179 .build_root = "test/standalone/issue_9812",
180 .import = @import("standalone/issue_9812/build.zig"),
181 },
182 .{178 .{
183 .build_root = "test/standalone/issue_11595",179 .build_root = "test/standalone/issue_11595",
184 .import = @import("standalone/issue_11595/build.zig"),180 .import = @import("standalone/issue_11595/build.zig"),
test/standalone/issue_9812/build.zig deleted-21
...@@ -1,21 +0,0 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) !void {
4 const test_step = b.step("test", "Test it");
5 b.default_step = test_step;
6
7 const optimize: std.builtin.OptimizeMode = .Debug;
8
9 const zip_add = b.addTest(.{
10 .root_source_file = .{ .path = "main.zig" },
11 .optimize = optimize,
12 });
13 zip_add.addCSourceFile("vendor/kuba-zip/zip.c", &[_][]const u8{
14 "-std=c99",
15 "-fno-sanitize=undefined",
16 });
17 zip_add.addIncludePath("vendor/kuba-zip");
18 zip_add.linkLibC();
19
20 test_step.dependOn(&zip_add.step);
21}
test/standalone/issue_9812/main.zig deleted-45
...@@ -1,45 +0,0 @@
1const std = @import("std");
2const testing = std.testing;
3
4const c = @cImport({
5 @cInclude("zip.h");
6});
7
8const Error = error{
9 FailedToWriteEntry,
10 FileNotFound,
11 FailedToCreateEntry,
12 Overflow,
13 OutOfMemory,
14 InvalidCmdLine,
15};
16
17test {
18 const allocator = std.heap.c_allocator;
19
20 const args = try std.process.argsAlloc(allocator);
21 if (args.len != 4) {
22 return;
23 }
24
25 const zip_file = args[1];
26 const src_file_name = args[2];
27 const dst_file_name = args[3];
28
29 errdefer |e| switch (@as(Error, e)) {
30 error.FailedToWriteEntry => std.log.err("could not find {s}", .{src_file_name}),
31 error.FileNotFound => std.log.err("could not open {s}", .{zip_file}),
32 error.FailedToCreateEntry => std.log.err("could not create {s}", .{dst_file_name}),
33 else => {},
34 };
35
36 const zip = c.zip_open(zip_file, c.ZIP_DEFAULT_COMPRESSION_LEVEL, 'a') orelse return error.FileNotFound;
37 defer c.zip_close(zip);
38
39 if (c.zip_entry_open(zip, dst_file_name) < 0)
40 return error.FailedToCreateEntry;
41 defer _ = c.zip_entry_close(zip);
42
43 if (c.zip_entry_fwrite(zip, src_file_name) < 0)
44 return error.FailedToWriteEntry;
45}
test/standalone/issue_9812/vendor/kuba-zip/miniz.h deleted-6875
...@@ -1,6875 +0,0 @@
1/*
2 miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP
3 reading/writing/appending, PNG writing See "unlicense" statement at the end
4 of this file. Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13,
5 2013 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951:
6 http://www.ietf.org/rfc/rfc1951.txt
7
8 Most API's defined in miniz.c are optional. For example, to disable the
9 archive related functions just define MINIZ_NO_ARCHIVE_APIS, or to get rid of
10 all stdio usage define MINIZ_NO_STDIO (see the list below for more macros).
11
12 * Change History
13 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major
14 release with Zip64 support (almost there!):
15 - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug
16 (thanks kahmyong.moon@hp.com) which could cause locate files to not find
17 files. This bug would only have occured in earlier versions if you explicitly
18 used this flag, OR if you used mz_zip_extract_archive_file_to_heap() or
19 mz_zip_add_mem_to_archive_file_in_place() (which used this flag). If you
20 can't switch to v1.15 but want to fix this bug, just remove the uses of this
21 flag from both helper funcs (and of course don't use the flag).
22 - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when
23 pUser_read_buf is not NULL and compressed size is > uncompressed size
24 - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract
25 compressed data from directory entries, to account for weird zipfiles which
26 contain zero-size compressed data on dir entries. Hopefully this fix won't
27 cause any issues on weird zip archives, because it assumes the low 16-bits of
28 zip external attributes are DOS attributes (which I believe they always are
29 in practice).
30 - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the
31 internal attributes, just the filename and external attributes
32 - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed
33 - Added cmake support for Linux builds which builds all the examples,
34 tested with clang v3.3 and gcc v4.6.
35 - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti
36 - Merged MZ_FORCEINLINE fix from hdeanclark
37 - Fix <time.h> include before config #ifdef, thanks emil.brink
38 - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping
39 (super useful for OpenGL apps), and explicit control over the compression
40 level (so you can set it to 1 for real-time compression).
41 - Merged in some compiler fixes from paulharris's github repro.
42 - Retested this build under Windows (VS 2010, including static analysis),
43 tcc 0.9.26, gcc v4.6 and clang v3.3.
44 - Added example6.c, which dumps an image of the mandelbrot set to a PNG
45 file.
46 - Modified example2 to help test the
47 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more.
48 - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix
49 possible src file fclose() leak if alignment bytes+local header file write
50 faiiled
51 - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): Was pushing the
52 wrong central dir header offset, appears harmless in this release, but it
53 became a problem in the zip64 branch 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1
54 compiler fixes: added MZ_FORCEINLINE, #include <time.h> (thanks fermtect).
55 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix
56 mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit.
57 - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and
58 re-ran a randomized regression test on ~500k files.
59 - Eliminated a bunch of warnings when compiling with GCC 32-bit/64.
60 - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze
61 (static analysis) option and fixed all warnings (except for the silly "Use of
62 the comma-operator in a tested expression.." analysis warning, which I
63 purposely use to work around a MSVC compiler warning).
64 - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and
65 tested Linux executables. The codeblocks workspace is compatible with
66 Linux+Win32/x64.
67 - Added miniz_tester solution/project, which is a useful little app
68 derived from LZHAM's tester app that I use as part of the regression test.
69 - Ran miniz.c and tinfl.c through another series of regression testing on
70 ~500,000 files and archives.
71 - Modified example5.c so it purposely disables a bunch of high-level
72 functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the
73 MINIZ_NO_STDIO bug report.)
74 - Fix ftell() usage in examples so they exit with an error on files which
75 are too large (a limitation of the examples, not miniz itself). 4/12/12 v1.12
76 - More comments, added low-level example5.c, fixed a couple minor
77 level_and_flags issues in the archive API's. level_and_flags can now be set
78 to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson <bruced@valvesoftware.com>
79 for the feedback/bug report. 5/28/11 v1.11 - Added statement from
80 unlicense.org 5/27/11 v1.10 - Substantial compressor optimizations:
81 - Level 1 is now ~4x faster than before. The L1 compressor's throughput
82 now varies between 70-110MB/sec. on a
83 - Core i7 (actual throughput varies depending on the type of data, and x64
84 vs. x86).
85 - Improved baseline L2-L9 compression perf. Also, greatly improved
86 compression perf. issues on some file types.
87 - Refactored the compression code for better readability and
88 maintainability.
89 - Added level 10 compression level (L10 has slightly better ratio than
90 level 9, but could have a potentially large drop in throughput on some
91 files). 5/15/11 v1.09 - Initial stable release.
92
93 * Low-level Deflate/Inflate implementation notes:
94
95 Compression: Use the "tdefl" API's. The compressor supports raw, static,
96 and dynamic blocks, lazy or greedy parsing, match length filtering, RLE-only,
97 and Huffman-only streams. It performs and compresses approximately as well as
98 zlib.
99
100 Decompression: Use the "tinfl" API's. The entire decompressor is
101 implemented as a single function coroutine: see tinfl_decompress(). It
102 supports decompression into a 32KB (or larger power of 2) wrapping buffer, or
103 into a memory block large enough to hold the entire file.
104
105 The low-level tdefl/tinfl API's do not make any use of dynamic memory
106 allocation.
107
108 * zlib-style API notes:
109
110 miniz.c implements a fairly large subset of zlib. There's enough
111 functionality present for it to be a drop-in zlib replacement in many apps:
112 The z_stream struct, optional memory allocation callbacks
113 deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
114 inflateInit/inflateInit2/inflate/inflateEnd
115 compress, compress2, compressBound, uncompress
116 CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly
117 routines. Supports raw deflate streams or standard zlib streams with adler-32
118 checking.
119
120 Limitations:
121 The callback API's are not implemented yet. No support for gzip headers or
122 zlib static dictionaries. I've tried to closely emulate zlib's various
123 flavors of stream flushing and return status codes, but there are no
124 guarantees that miniz.c pulls this off perfectly.
125
126 * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function,
127 originally written by Alex Evans. Supports 1-4 bytes/pixel images.
128
129 * ZIP archive API notes:
130
131 The ZIP archive API's where designed with simplicity and efficiency in
132 mind, with just enough abstraction to get the job done with minimal fuss.
133 There are simple API's to retrieve file information, read files from existing
134 archives, create new archives, append new files to existing archives, or
135 clone archive data from one archive to another. It supports archives located
136 in memory or the heap, on disk (using stdio.h), or you can specify custom
137 file read/write callbacks.
138
139 - Archive reading: Just call this function to read a single file from a
140 disk archive:
141
142 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const
143 char *pArchive_name, size_t *pSize, mz_uint zip_flags);
144
145 For more complex cases, use the "mz_zip_reader" functions. Upon opening an
146 archive, the entire central directory is located and read as-is into memory,
147 and subsequent file access only occurs when reading individual files.
148
149 - Archives file scanning: The simple way is to use this function to scan a
150 loaded archive for a specific file:
151
152 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
153 const char *pComment, mz_uint flags);
154
155 The locate operation can optionally check file comments too, which (as one
156 example) can be used to identify multiple versions of the same file in an
157 archive. This function uses a simple linear search through the central
158 directory, so it's not very fast.
159
160 Alternately, you can iterate through all the files in an archive (using
161 mz_zip_reader_get_num_files()) and retrieve detailed info on each file by
162 calling mz_zip_reader_file_stat().
163
164 - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer
165 immediately writes compressed file data to disk and builds an exact image of
166 the central directory in memory. The central directory image is written all
167 at once at the end of the archive file when the archive is finalized.
168
169 The archive writer can optionally align each file's local header and file
170 data to any power of 2 alignment, which can be useful when the archive will
171 be read from optical media. Also, the writer supports placing arbitrary data
172 blobs at the very beginning of ZIP archives. Archives written using either
173 feature are still readable by any ZIP tool.
174
175 - Archive appending: The simple way to add a single file to an archive is
176 to call this function:
177
178 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename,
179 const char *pArchive_name, const void *pBuf, size_t buf_size, const void
180 *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
181
182 The archive will be created if it doesn't already exist, otherwise it'll be
183 appended to. Note the appending is done in-place and is not an atomic
184 operation, so if something goes wrong during the operation it's possible the
185 archive could be left without a central directory (although the local file
186 headers and file data will be fine, so the archive will be recoverable).
187
188 For more complex archive modification scenarios:
189 1. The safest way is to use a mz_zip_reader to read the existing archive,
190 cloning only those bits you want to preserve into a new archive using using
191 the mz_zip_writer_add_from_zip_reader() function (which compiles the
192 compressed file data as-is). When you're done, delete the old archive and
193 rename the newly written archive, and you're done. This is safe but requires
194 a bunch of temporary disk space or heap memory.
195
196 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using
197 mz_zip_writer_init_from_reader(), append new files as needed, then finalize
198 the archive which will write an updated central directory to the original
199 archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place()
200 does.) There's a possibility that the archive's central directory could be
201 lost with this method if anything goes wrong, though.
202
203 - ZIP archive support limitations:
204 No zip64 or spanning support. Extraction functions can only handle
205 unencrypted, stored or deflated files. Requires streams capable of seeking.
206
207 * This is a header file library, like stb_image.c. To get only a header file,
208 either cut and paste the below header, or create miniz.h, #define
209 MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it.
210
211 * Important: For best perf. be sure to customize the below macros for your
212 target platform: #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define
213 MINIZ_LITTLE_ENDIAN 1 #define MINIZ_HAS_64BIT_REGISTERS 1
214
215 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before
216 including miniz.c to ensure miniz uses the 64-bit variants: fopen64(),
217 stat64(), etc. Otherwise you won't be able to process large files (i.e.
218 32-bit stat() fails for me on files > 0x7FFFFFFF bytes).
219*/
220
221#ifndef MINIZ_HEADER_INCLUDED
222#define MINIZ_HEADER_INCLUDED
223
224#include <stdint.h>
225#include <stdlib.h>
226
227// Defines to completely disable specific portions of miniz.c:
228// If all macros here are defined the only functionality remaining will be
229// CRC-32, adler-32, tinfl, and tdefl.
230
231// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on
232// stdio for file I/O.
233//#define MINIZ_NO_STDIO
234
235// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able
236// to get the current time, or get/set file times, and the C run-time funcs that
237// get/set times won't be called. The current downside is the times written to
238// your archives will be from 1979.
239//#define MINIZ_NO_TIME
240
241// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's.
242//#define MINIZ_NO_ARCHIVE_APIS
243
244// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive
245// API's.
246//#define MINIZ_NO_ARCHIVE_WRITING_APIS
247
248// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression
249// API's.
250//#define MINIZ_NO_ZLIB_APIS
251
252// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent
253// conflicts against stock zlib.
254//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
255
256// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
257// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom
258// user alloc/free/realloc callbacks to the zlib and archive API's, and a few
259// stand-alone helper API's which don't provide custom user functions (such as
260// tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work.
261//#define MINIZ_NO_MALLOC
262
263#if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
264// TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc
265// on Linux
266#define MINIZ_NO_TIME
267#endif
268
269#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
270#include <time.h>
271#endif
272
273#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \
274 defined(__i386) || defined(__i486__) || defined(__i486) || \
275 defined(i386) || defined(__ia64__) || defined(__x86_64__)
276// MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
277#define MINIZ_X86_OR_X64_CPU 1
278#endif
279
280#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
281// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
282#define MINIZ_LITTLE_ENDIAN 1
283#endif
284
285/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */
286#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES)
287#if MINIZ_X86_OR_X64_CPU
288/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
289 * integer loads and stores from unaligned addresses. */
290#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
291#define MINIZ_UNALIGNED_USE_MEMCPY
292#else
293#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0
294#endif
295#endif
296
297#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \
298 defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \
299 defined(__x86_64__)
300// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are
301// reasonably fast (and don't involve compiler generated calls to helper
302// functions).
303#define MINIZ_HAS_64BIT_REGISTERS 1
304#endif
305
306#ifdef __APPLE__
307#define ftello64 ftello
308#define fseeko64 fseeko
309#define fopen64 fopen
310#define freopen64 freopen
311
312// Darwin OSX
313#define MZ_PLATFORM 19
314#endif
315
316#ifndef MZ_PLATFORM
317#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__)
318#define MZ_PLATFORM 0
319#else
320// UNIX
321#define MZ_PLATFORM 3
322#endif
323#endif
324
325#ifdef __cplusplus
326extern "C" {
327#endif
328
329// ------------------- zlib-style API Definitions.
330
331// For more compatibility with zlib, miniz.c uses unsigned long for some
332// parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits!
333typedef unsigned long mz_ulong;
334
335// mz_free() internally uses the MZ_FREE() macro (which by default calls free()
336// unless you've modified the MZ_MALLOC macro) to release a block allocated from
337// the heap.
338void mz_free(void *p);
339
340#define MZ_ADLER32_INIT (1)
341// mz_adler32() returns the initial adler-32 value to use when called with
342// ptr==NULL.
343mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);
344
345#define MZ_CRC32_INIT (0)
346// mz_crc32() returns the initial CRC-32 value to use when called with
347// ptr==NULL.
348mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);
349
350// Compression strategies.
351enum {
352 MZ_DEFAULT_STRATEGY = 0,
353 MZ_FILTERED = 1,
354 MZ_HUFFMAN_ONLY = 2,
355 MZ_RLE = 3,
356 MZ_FIXED = 4
357};
358
359/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or
360 * modify this enum. */
361typedef enum {
362 MZ_ZIP_NO_ERROR = 0,
363 MZ_ZIP_UNDEFINED_ERROR,
364 MZ_ZIP_TOO_MANY_FILES,
365 MZ_ZIP_FILE_TOO_LARGE,
366 MZ_ZIP_UNSUPPORTED_METHOD,
367 MZ_ZIP_UNSUPPORTED_ENCRYPTION,
368 MZ_ZIP_UNSUPPORTED_FEATURE,
369 MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,
370 MZ_ZIP_NOT_AN_ARCHIVE,
371 MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,
372 MZ_ZIP_UNSUPPORTED_MULTIDISK,
373 MZ_ZIP_DECOMPRESSION_FAILED,
374 MZ_ZIP_COMPRESSION_FAILED,
375 MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,
376 MZ_ZIP_CRC_CHECK_FAILED,
377 MZ_ZIP_UNSUPPORTED_CDIR_SIZE,
378 MZ_ZIP_ALLOC_FAILED,
379 MZ_ZIP_FILE_OPEN_FAILED,
380 MZ_ZIP_FILE_CREATE_FAILED,
381 MZ_ZIP_FILE_WRITE_FAILED,
382 MZ_ZIP_FILE_READ_FAILED,
383 MZ_ZIP_FILE_CLOSE_FAILED,
384 MZ_ZIP_FILE_SEEK_FAILED,
385 MZ_ZIP_FILE_STAT_FAILED,
386 MZ_ZIP_INVALID_PARAMETER,
387 MZ_ZIP_INVALID_FILENAME,
388 MZ_ZIP_BUF_TOO_SMALL,
389 MZ_ZIP_INTERNAL_ERROR,
390 MZ_ZIP_FILE_NOT_FOUND,
391 MZ_ZIP_ARCHIVE_TOO_LARGE,
392 MZ_ZIP_VALIDATION_FAILED,
393 MZ_ZIP_WRITE_CALLBACK_FAILED,
394 MZ_ZIP_TOTAL_ERRORS
395} mz_zip_error;
396
397// Method
398#define MZ_DEFLATED 8
399
400#ifndef MINIZ_NO_ZLIB_APIS
401
402// Heap allocation callbacks.
403// Note that mz_alloc_func parameter types purposely differ from zlib's:
404// items/size is size_t, not unsigned long.
405typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
406typedef void (*mz_free_func)(void *opaque, void *address);
407typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items,
408 size_t size);
409
410#define MZ_VERSION "9.1.15"
411#define MZ_VERNUM 0x91F0
412#define MZ_VER_MAJOR 9
413#define MZ_VER_MINOR 1
414#define MZ_VER_REVISION 15
415#define MZ_VER_SUBREVISION 0
416
417// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The
418// other values are for advanced use (refer to the zlib docs).
419enum {
420 MZ_NO_FLUSH = 0,
421 MZ_PARTIAL_FLUSH = 1,
422 MZ_SYNC_FLUSH = 2,
423 MZ_FULL_FLUSH = 3,
424 MZ_FINISH = 4,
425 MZ_BLOCK = 5
426};
427
428// Return status codes. MZ_PARAM_ERROR is non-standard.
429enum {
430 MZ_OK = 0,
431 MZ_STREAM_END = 1,
432 MZ_NEED_DICT = 2,
433 MZ_ERRNO = -1,
434 MZ_STREAM_ERROR = -2,
435 MZ_DATA_ERROR = -3,
436 MZ_MEM_ERROR = -4,
437 MZ_BUF_ERROR = -5,
438 MZ_VERSION_ERROR = -6,
439 MZ_PARAM_ERROR = -10000
440};
441
442// Compression levels: 0-9 are the standard zlib-style levels, 10 is best
443// possible compression (not zlib compatible, and may be very slow),
444// MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL.
445enum {
446 MZ_NO_COMPRESSION = 0,
447 MZ_BEST_SPEED = 1,
448 MZ_BEST_COMPRESSION = 9,
449 MZ_UBER_COMPRESSION = 10,
450 MZ_DEFAULT_LEVEL = 6,
451 MZ_DEFAULT_COMPRESSION = -1
452};
453
454// Window bits
455#define MZ_DEFAULT_WINDOW_BITS 15
456
457struct mz_internal_state;
458
459// Compression/decompression stream struct.
460typedef struct mz_stream_s {
461 const unsigned char *next_in; // pointer to next byte to read
462 unsigned int avail_in; // number of bytes available at next_in
463 mz_ulong total_in; // total number of bytes consumed so far
464
465 unsigned char *next_out; // pointer to next byte to write
466 unsigned int avail_out; // number of bytes that can be written to next_out
467 mz_ulong total_out; // total number of bytes produced so far
468
469 char *msg; // error msg (unused)
470 struct mz_internal_state *state; // internal state, allocated by zalloc/zfree
471
472 mz_alloc_func
473 zalloc; // optional heap allocation function (defaults to malloc)
474 mz_free_func zfree; // optional heap free function (defaults to free)
475 void *opaque; // heap alloc function user pointer
476
477 int data_type; // data_type (unused)
478 mz_ulong adler; // adler32 of the source or uncompressed data
479 mz_ulong reserved; // not used
480} mz_stream;
481
482typedef mz_stream *mz_streamp;
483
484// Returns the version string of miniz.c.
485const char *mz_version(void);
486
487// mz_deflateInit() initializes a compressor with default options:
488// Parameters:
489// pStream must point to an initialized mz_stream struct.
490// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION].
491// level 1 enables a specially optimized compression function that's been
492// optimized purely for performance, not ratio. (This special func. is
493// currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and
494// MINIZ_LITTLE_ENDIAN are defined.)
495// Return values:
496// MZ_OK on success.
497// MZ_STREAM_ERROR if the stream is bogus.
498// MZ_PARAM_ERROR if the input parameters are bogus.
499// MZ_MEM_ERROR on out of memory.
500int mz_deflateInit(mz_streamp pStream, int level);
501
502// mz_deflateInit2() is like mz_deflate(), except with more control:
503// Additional parameters:
504// method must be MZ_DEFLATED
505// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with
506// zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no
507// header or footer) mem_level must be between [1, 9] (it's checked but
508// ignored by miniz.c)
509int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
510 int mem_level, int strategy);
511
512// Quickly resets a compressor without having to reallocate anything. Same as
513// calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2().
514int mz_deflateReset(mz_streamp pStream);
515
516// mz_deflate() compresses the input to output, consuming as much of the input
517// and producing as much output as possible. Parameters:
518// pStream is the stream to read from and write to. You must initialize/update
519// the next_in, avail_in, next_out, and avail_out members. flush may be
520// MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH.
521// Return values:
522// MZ_OK on success (when flushing, or if more input is needed but not
523// available, and/or there's more output to be written but the output buffer
524// is full). MZ_STREAM_END if all input has been consumed and all output bytes
525// have been written. Don't call mz_deflate() on the stream anymore.
526// MZ_STREAM_ERROR if the stream is bogus.
527// MZ_PARAM_ERROR if one of the parameters is invalid.
528// MZ_BUF_ERROR if no forward progress is possible because the input and/or
529// output buffers are empty. (Fill up the input buffer or free up some output
530// space and try again.)
531int mz_deflate(mz_streamp pStream, int flush);
532
533// mz_deflateEnd() deinitializes a compressor:
534// Return values:
535// MZ_OK on success.
536// MZ_STREAM_ERROR if the stream is bogus.
537int mz_deflateEnd(mz_streamp pStream);
538
539// mz_deflateBound() returns a (very) conservative upper bound on the amount of
540// data that could be generated by deflate(), assuming flush is set to only
541// MZ_NO_FLUSH or MZ_FINISH.
542mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
543
544// Single-call compression functions mz_compress() and mz_compress2():
545// Returns MZ_OK on success, or one of the error codes from mz_deflate() on
546// failure.
547int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
548 const unsigned char *pSource, mz_ulong source_len);
549int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
550 const unsigned char *pSource, mz_ulong source_len, int level);
551
552// mz_compressBound() returns a (very) conservative upper bound on the amount of
553// data that could be generated by calling mz_compress().
554mz_ulong mz_compressBound(mz_ulong source_len);
555
556// Initializes a decompressor.
557int mz_inflateInit(mz_streamp pStream);
558
559// mz_inflateInit2() is like mz_inflateInit() with an additional option that
560// controls the window size and whether or not the stream has been wrapped with
561// a zlib header/footer: window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse
562// zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate).
563int mz_inflateInit2(mz_streamp pStream, int window_bits);
564
565// Decompresses the input stream to the output, consuming only as much of the
566// input as needed, and writing as much to the output as possible. Parameters:
567// pStream is the stream to read from and write to. You must initialize/update
568// the next_in, avail_in, next_out, and avail_out members. flush may be
569// MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. On the first call, if flush is
570// MZ_FINISH it's assumed the input and output buffers are both sized large
571// enough to decompress the entire stream in a single call (this is slightly
572// faster). MZ_FINISH implies that there are no more source bytes available
573// beside what's already in the input buffer, and that the output buffer is
574// large enough to hold the rest of the decompressed data.
575// Return values:
576// MZ_OK on success. Either more input is needed but not available, and/or
577// there's more output to be written but the output buffer is full.
578// MZ_STREAM_END if all needed input has been consumed and all output bytes
579// have been written. For zlib streams, the adler-32 of the decompressed data
580// has also been verified. MZ_STREAM_ERROR if the stream is bogus.
581// MZ_DATA_ERROR if the deflate stream is invalid.
582// MZ_PARAM_ERROR if one of the parameters is invalid.
583// MZ_BUF_ERROR if no forward progress is possible because the input buffer is
584// empty but the inflater needs more input to continue, or if the output
585// buffer is not large enough. Call mz_inflate() again with more input data,
586// or with more room in the output buffer (except when using single call
587// decompression, described above).
588int mz_inflate(mz_streamp pStream, int flush);
589
590// Deinitializes a decompressor.
591int mz_inflateEnd(mz_streamp pStream);
592
593// Single-call decompression.
594// Returns MZ_OK on success, or one of the error codes from mz_inflate() on
595// failure.
596int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
597 const unsigned char *pSource, mz_ulong source_len);
598
599// Returns a string description of the specified error code, or NULL if the
600// error code is invalid.
601const char *mz_error(int err);
602
603// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used
604// as a drop-in replacement for the subset of zlib that miniz.c supports. Define
605// MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib
606// in the same project.
607#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
608typedef unsigned char Byte;
609typedef unsigned int uInt;
610typedef mz_ulong uLong;
611typedef Byte Bytef;
612typedef uInt uIntf;
613typedef char charf;
614typedef int intf;
615typedef void *voidpf;
616typedef uLong uLongf;
617typedef void *voidp;
618typedef void *const voidpc;
619#define Z_NULL 0
620#define Z_NO_FLUSH MZ_NO_FLUSH
621#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
622#define Z_SYNC_FLUSH MZ_SYNC_FLUSH
623#define Z_FULL_FLUSH MZ_FULL_FLUSH
624#define Z_FINISH MZ_FINISH
625#define Z_BLOCK MZ_BLOCK
626#define Z_OK MZ_OK
627#define Z_STREAM_END MZ_STREAM_END
628#define Z_NEED_DICT MZ_NEED_DICT
629#define Z_ERRNO MZ_ERRNO
630#define Z_STREAM_ERROR MZ_STREAM_ERROR
631#define Z_DATA_ERROR MZ_DATA_ERROR
632#define Z_MEM_ERROR MZ_MEM_ERROR
633#define Z_BUF_ERROR MZ_BUF_ERROR
634#define Z_VERSION_ERROR MZ_VERSION_ERROR
635#define Z_PARAM_ERROR MZ_PARAM_ERROR
636#define Z_NO_COMPRESSION MZ_NO_COMPRESSION
637#define Z_BEST_SPEED MZ_BEST_SPEED
638#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
639#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
640#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
641#define Z_FILTERED MZ_FILTERED
642#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
643#define Z_RLE MZ_RLE
644#define Z_FIXED MZ_FIXED
645#define Z_DEFLATED MZ_DEFLATED
646#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
647#define alloc_func mz_alloc_func
648#define free_func mz_free_func
649#define internal_state mz_internal_state
650#define z_stream mz_stream
651#define deflateInit mz_deflateInit
652#define deflateInit2 mz_deflateInit2
653#define deflateReset mz_deflateReset
654#define deflate mz_deflate
655#define deflateEnd mz_deflateEnd
656#define deflateBound mz_deflateBound
657#define compress mz_compress
658#define compress2 mz_compress2
659#define compressBound mz_compressBound
660#define inflateInit mz_inflateInit
661#define inflateInit2 mz_inflateInit2
662#define inflate mz_inflate
663#define inflateEnd mz_inflateEnd
664#define uncompress mz_uncompress
665#define crc32 mz_crc32
666#define adler32 mz_adler32
667#define MAX_WBITS 15
668#define MAX_MEM_LEVEL 9
669#define zError mz_error
670#define ZLIB_VERSION MZ_VERSION
671#define ZLIB_VERNUM MZ_VERNUM
672#define ZLIB_VER_MAJOR MZ_VER_MAJOR
673#define ZLIB_VER_MINOR MZ_VER_MINOR
674#define ZLIB_VER_REVISION MZ_VER_REVISION
675#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
676#define zlibVersion mz_version
677#define zlib_version mz_version()
678#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
679
680#endif // MINIZ_NO_ZLIB_APIS
681
682// ------------------- Types and macros
683
684typedef unsigned char mz_uint8;
685typedef signed short mz_int16;
686typedef unsigned short mz_uint16;
687typedef unsigned int mz_uint32;
688typedef unsigned int mz_uint;
689typedef long long mz_int64;
690typedef unsigned long long mz_uint64;
691typedef int mz_bool;
692
693#define MZ_FALSE (0)
694#define MZ_TRUE (1)
695
696// An attempt to work around MSVC's spammy "warning C4127: conditional
697// expression is constant" message.
698#ifdef _MSC_VER
699#define MZ_MACRO_END while (0, 0)
700#else
701#define MZ_MACRO_END while (0)
702#endif
703
704// ------------------- ZIP archive reading/writing
705
706#ifndef MINIZ_NO_ARCHIVE_APIS
707
708enum {
709 MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,
710 MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
711 MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
712};
713
714typedef struct {
715 mz_uint32 m_file_index;
716 mz_uint32 m_central_dir_ofs;
717 mz_uint16 m_version_made_by;
718 mz_uint16 m_version_needed;
719 mz_uint16 m_bit_flag;
720 mz_uint16 m_method;
721#ifndef MINIZ_NO_TIME
722 time_t m_time;
723#endif
724 mz_uint32 m_crc32;
725 mz_uint64 m_comp_size;
726 mz_uint64 m_uncomp_size;
727 mz_uint16 m_internal_attr;
728 mz_uint32 m_external_attr;
729 mz_uint64 m_local_header_ofs;
730 mz_uint32 m_comment_size;
731 char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
732 char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
733} mz_zip_archive_file_stat;
734
735typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
736 void *pBuf, size_t n);
737typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
738 const void *pBuf, size_t n);
739typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);
740
741struct mz_zip_internal_state_tag;
742typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
743
744typedef enum {
745 MZ_ZIP_MODE_INVALID = 0,
746 MZ_ZIP_MODE_READING = 1,
747 MZ_ZIP_MODE_WRITING = 2,
748 MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
749} mz_zip_mode;
750
751typedef enum {
752 MZ_ZIP_TYPE_INVALID = 0,
753 MZ_ZIP_TYPE_USER,
754 MZ_ZIP_TYPE_MEMORY,
755 MZ_ZIP_TYPE_HEAP,
756 MZ_ZIP_TYPE_FILE,
757 MZ_ZIP_TYPE_CFILE,
758 MZ_ZIP_TOTAL_TYPES
759} mz_zip_type;
760
761typedef struct {
762 mz_uint64 m_archive_size;
763 mz_uint64 m_central_directory_file_ofs;
764
765 /* We only support up to UINT32_MAX files in zip64 mode. */
766 mz_uint32 m_total_files;
767 mz_zip_mode m_zip_mode;
768 mz_zip_type m_zip_type;
769 mz_zip_error m_last_error;
770
771 mz_uint64 m_file_offset_alignment;
772
773 mz_alloc_func m_pAlloc;
774 mz_free_func m_pFree;
775 mz_realloc_func m_pRealloc;
776 void *m_pAlloc_opaque;
777
778 mz_file_read_func m_pRead;
779 mz_file_write_func m_pWrite;
780 mz_file_needs_keepalive m_pNeeds_keepalive;
781 void *m_pIO_opaque;
782
783 mz_zip_internal_state *m_pState;
784
785} mz_zip_archive;
786
787typedef enum {
788 MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
789 MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
790 MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
791 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
792} mz_zip_flags;
793
794// ZIP archive reading
795
796// Inits a ZIP archive reader.
797// These functions read and validate the archive's central directory.
798mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
799 mz_uint32 flags);
800mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem,
801 size_t size, mz_uint32 flags);
802
803#ifndef MINIZ_NO_STDIO
804mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename,
805 mz_uint32 flags);
806#endif
807
808// Returns the total number of files in the archive.
809mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
810
811// Returns detailed information about an archive file entry.
812mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
813 mz_zip_archive_file_stat *pStat);
814
815// Determines if an archive file entry is a directory entry.
816mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
817 mz_uint file_index);
818mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
819 mz_uint file_index);
820
821// Retrieves the filename of an archive file entry.
822// Returns the number of bytes written to pFilename, or if filename_buf_size is
823// 0 this function returns the number of bytes needed to fully store the
824// filename.
825mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index,
826 char *pFilename, mz_uint filename_buf_size);
827
828// Attempts to locates a file in the archive's central directory.
829// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH
830// Returns -1 if the file cannot be found.
831int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
832 const char *pComment, mz_uint flags);
833
834// Extracts a archive file to a memory buffer using no memory allocation.
835mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
836 mz_uint file_index, void *pBuf,
837 size_t buf_size, mz_uint flags,
838 void *pUser_read_buf,
839 size_t user_read_buf_size);
840mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
841 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
842 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
843
844// Extracts a archive file to a memory buffer.
845mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index,
846 void *pBuf, size_t buf_size,
847 mz_uint flags);
848mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
849 const char *pFilename, void *pBuf,
850 size_t buf_size, mz_uint flags);
851
852// Extracts a archive file to a dynamically allocated heap buffer.
853void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index,
854 size_t *pSize, mz_uint flags);
855void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
856 const char *pFilename, size_t *pSize,
857 mz_uint flags);
858
859// Extracts a archive file using a callback function to output the file's data.
860mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
861 mz_uint file_index,
862 mz_file_write_func pCallback,
863 void *pOpaque, mz_uint flags);
864mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
865 const char *pFilename,
866 mz_file_write_func pCallback,
867 void *pOpaque, mz_uint flags);
868
869#ifndef MINIZ_NO_STDIO
870// Extracts a archive file to a disk file and sets its last accessed and
871// modified times. This function only extracts files, not archive directory
872// records.
873mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index,
874 const char *pDst_filename, mz_uint flags);
875mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
876 const char *pArchive_filename,
877 const char *pDst_filename,
878 mz_uint flags);
879#endif
880
881// Ends archive reading, freeing all allocations, and closing the input archive
882// file if mz_zip_reader_init_file() was used.
883mz_bool mz_zip_reader_end(mz_zip_archive *pZip);
884
885// ZIP archive writing
886
887#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
888
889// Inits a ZIP archive writer.
890mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);
891mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
892 size_t size_to_reserve_at_beginning,
893 size_t initial_allocation_size);
894
895#ifndef MINIZ_NO_STDIO
896mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
897 mz_uint64 size_to_reserve_at_beginning);
898#endif
899
900// Converts a ZIP archive reader object into a writer object, to allow efficient
901// in-place file appends to occur on an existing archive. For archives opened
902// using mz_zip_reader_init_file, pFilename must be the archive's filename so it
903// can be reopened for writing. If the file can't be reopened,
904// mz_zip_reader_end() will be called. For archives opened using
905// mz_zip_reader_init_mem, the memory block must be growable using the realloc
906// callback (which defaults to realloc unless you've overridden it). Finally,
907// for archives opened using mz_zip_reader_init, the mz_zip_archive's user
908// provided m_pWrite function cannot be NULL. Note: In-place archive
909// modification is not recommended unless you know what you're doing, because if
910// execution stops or something goes wrong before the archive is finalized the
911// file's central directory will be hosed.
912mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
913 const char *pFilename);
914
915// Adds the contents of a memory buffer to an archive. These functions record
916// the current local time into the archive. To add a directory entry, call this
917// method with an archive name ending in a forwardslash with empty buffer.
918// level_and_flags - compression level (0-10, see MZ_BEST_SPEED,
919// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or
920// just set to MZ_DEFAULT_COMPRESSION.
921mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name,
922 const void *pBuf, size_t buf_size,
923 mz_uint level_and_flags);
924mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
925 const char *pArchive_name, const void *pBuf,
926 size_t buf_size, const void *pComment,
927 mz_uint16 comment_size,
928 mz_uint level_and_flags, mz_uint64 uncomp_size,
929 mz_uint32 uncomp_crc32);
930
931#ifndef MINIZ_NO_STDIO
932// Adds the contents of a disk file to an archive. This function also records
933// the disk file's modified time into the archive. level_and_flags - compression
934// level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd
935// with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
936mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name,
937 const char *pSrc_filename, const void *pComment,
938 mz_uint16 comment_size, mz_uint level_and_flags,
939 mz_uint32 ext_attributes);
940#endif
941
942// Adds a file to an archive by fully cloning the data from another archive.
943// This function fully clones the source file's compressed data (no
944// recompression), along with its full filename, extra data, and comment fields.
945mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
946 mz_zip_archive *pSource_zip,
947 mz_uint file_index);
948
949// Finalizes the archive by writing the central directory records followed by
950// the end of central directory record. After an archive is finalized, the only
951// valid call on the mz_zip_archive struct is mz_zip_writer_end(). An archive
952// must be manually finalized by calling this function for it to be valid.
953mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);
954mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf,
955 size_t *pSize);
956
957// Ends archive writing, freeing all allocations, and closing the output file if
958// mz_zip_writer_init_file() was used. Note for the archive to be valid, it must
959// have been finalized before ending.
960mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
961
962// Misc. high-level helper functions:
963
964// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically)
965// appends a memory blob to a ZIP archive. level_and_flags - compression level
966// (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero
967// or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
968mz_bool mz_zip_add_mem_to_archive_file_in_place(
969 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
970 size_t buf_size, const void *pComment, mz_uint16 comment_size,
971 mz_uint level_and_flags);
972
973// Reads a single file from an archive into a heap block.
974// Returns NULL on failure.
975void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
976 const char *pArchive_name,
977 size_t *pSize, mz_uint zip_flags);
978
979#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
980
981#endif // #ifndef MINIZ_NO_ARCHIVE_APIS
982
983// ------------------- Low-level Decompression API Definitions
984
985// Decompression flags used by tinfl_decompress().
986// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and
987// ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the
988// input is a raw deflate stream. TINFL_FLAG_HAS_MORE_INPUT: If set, there are
989// more input bytes available beyond the end of the supplied input buffer. If
990// clear, the input buffer contains all remaining input.
991// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large
992// enough to hold the entire decompressed stream. If clear, the output buffer is
993// at least the size of the dictionary (typically 32KB).
994// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the
995// decompressed bytes.
996enum {
997 TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
998 TINFL_FLAG_HAS_MORE_INPUT = 2,
999 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
1000 TINFL_FLAG_COMPUTE_ADLER32 = 8
1001};
1002
1003// High level decompression functions:
1004// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block
1005// allocated via malloc(). On entry:
1006// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data
1007// to decompress.
1008// On return:
1009// Function returns a pointer to the decompressed data, or NULL on failure.
1010// *pOut_len will be set to the decompressed data's size, which could be larger
1011// than src_buf_len on uncompressible data. The caller must call mz_free() on
1012// the returned block when it's no longer needed.
1013void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
1014 size_t *pOut_len, int flags);
1015
1016// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block
1017// in memory. Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the
1018// number of bytes written on success.
1019#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
1020size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
1021 const void *pSrc_buf, size_t src_buf_len,
1022 int flags);
1023
1024// tinfl_decompress_mem_to_callback() decompresses a block in memory to an
1025// internal 32KB buffer, and a user provided callback function will be called to
1026// flush the buffer. Returns 1 on success or 0 on failure.
1027typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);
1028int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
1029 tinfl_put_buf_func_ptr pPut_buf_func,
1030 void *pPut_buf_user, int flags);
1031
1032struct tinfl_decompressor_tag;
1033typedef struct tinfl_decompressor_tag tinfl_decompressor;
1034
1035// Max size of LZ dictionary.
1036#define TINFL_LZ_DICT_SIZE 32768
1037
1038// Return status.
1039typedef enum {
1040 TINFL_STATUS_BAD_PARAM = -3,
1041 TINFL_STATUS_ADLER32_MISMATCH = -2,
1042 TINFL_STATUS_FAILED = -1,
1043 TINFL_STATUS_DONE = 0,
1044 TINFL_STATUS_NEEDS_MORE_INPUT = 1,
1045 TINFL_STATUS_HAS_MORE_OUTPUT = 2
1046} tinfl_status;
1047
1048// Initializes the decompressor to its initial state.
1049#define tinfl_init(r) \
1050 do { \
1051 (r)->m_state = 0; \
1052 } \
1053 MZ_MACRO_END
1054#define tinfl_get_adler32(r) (r)->m_check_adler32
1055
1056// Main low-level decompressor coroutine function. This is the only function
1057// actually needed for decompression. All the other functions are just
1058// high-level helpers for improved usability. This is a universal API, i.e. it
1059// can be used as a building block to build any desired higher level
1060// decompression API. In the limit case, it can be called once per every byte
1061// input or output.
1062tinfl_status tinfl_decompress(tinfl_decompressor *r,
1063 const mz_uint8 *pIn_buf_next,
1064 size_t *pIn_buf_size, mz_uint8 *pOut_buf_start,
1065 mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
1066 const mz_uint32 decomp_flags);
1067
1068// Internal/private bits follow.
1069enum {
1070 TINFL_MAX_HUFF_TABLES = 3,
1071 TINFL_MAX_HUFF_SYMBOLS_0 = 288,
1072 TINFL_MAX_HUFF_SYMBOLS_1 = 32,
1073 TINFL_MAX_HUFF_SYMBOLS_2 = 19,
1074 TINFL_FAST_LOOKUP_BITS = 10,
1075 TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
1076};
1077
1078typedef struct {
1079 mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
1080 mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE],
1081 m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
1082} tinfl_huff_table;
1083
1084#if MINIZ_HAS_64BIT_REGISTERS
1085#define TINFL_USE_64BIT_BITBUF 1
1086#endif
1087
1088#if TINFL_USE_64BIT_BITBUF
1089typedef mz_uint64 tinfl_bit_buf_t;
1090#define TINFL_BITBUF_SIZE (64)
1091#else
1092typedef mz_uint32 tinfl_bit_buf_t;
1093#define TINFL_BITBUF_SIZE (32)
1094#endif
1095
1096struct tinfl_decompressor_tag {
1097 mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type,
1098 m_check_adler32, m_dist, m_counter, m_num_extra,
1099 m_table_sizes[TINFL_MAX_HUFF_TABLES];
1100 tinfl_bit_buf_t m_bit_buf;
1101 size_t m_dist_from_out_buf_start;
1102 tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
1103 mz_uint8 m_raw_header[4],
1104 m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
1105};
1106
1107// ------------------- Low-level Compression API Definitions
1108
1109// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly
1110// slower, and raw/dynamic blocks will be output more frequently).
1111#define TDEFL_LESS_MEMORY 0
1112
1113// tdefl_init() compression flags logically OR'd together (low 12 bits contain
1114// the max. number of probes per dictionary search): TDEFL_DEFAULT_MAX_PROBES:
1115// The compressor defaults to 128 dictionary probes per dictionary search.
1116// 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ
1117// (slowest/best compression).
1118enum {
1119 TDEFL_HUFFMAN_ONLY = 0,
1120 TDEFL_DEFAULT_MAX_PROBES = 128,
1121 TDEFL_MAX_PROBES_MASK = 0xFFF
1122};
1123
1124// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before
1125// the deflate data, and the Adler-32 of the source data at the end. Otherwise,
1126// you'll get raw deflate data. TDEFL_COMPUTE_ADLER32: Always compute the
1127// adler-32 of the input data (even when not writing zlib headers).
1128// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more
1129// efficient lazy parsing. TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to
1130// decrease the compressor's initialization time to the minimum, but the output
1131// may vary from run to run given the same input (depending on the contents of
1132// memory). TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a
1133// distance of 1) TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled.
1134// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables.
1135// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks.
1136// The low 12 bits are reserved to control the max # of hash probes per
1137// dictionary lookup (see TDEFL_MAX_PROBES_MASK).
1138enum {
1139 TDEFL_WRITE_ZLIB_HEADER = 0x01000,
1140 TDEFL_COMPUTE_ADLER32 = 0x02000,
1141 TDEFL_GREEDY_PARSING_FLAG = 0x04000,
1142 TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
1143 TDEFL_RLE_MATCHES = 0x10000,
1144 TDEFL_FILTER_MATCHES = 0x20000,
1145 TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
1146 TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
1147};
1148
1149// High level compression functions:
1150// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block
1151// allocated via malloc(). On entry:
1152// pSrc_buf, src_buf_len: Pointer and size of source block to compress.
1153// flags: The max match finder probes (default is 128) logically OR'd against
1154// the above flags. Higher probes are slower but improve compression.
1155// On return:
1156// Function returns a pointer to the compressed data, or NULL on failure.
1157// *pOut_len will be set to the compressed data's size, which could be larger
1158// than src_buf_len on uncompressible data. The caller must free() the returned
1159// block when it's no longer needed.
1160void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
1161 size_t *pOut_len, int flags);
1162
1163// tdefl_compress_mem_to_mem() compresses a block in memory to another block in
1164// memory. Returns 0 on failure.
1165size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
1166 const void *pSrc_buf, size_t src_buf_len,
1167 int flags);
1168
1169// Compresses an image to a compressed PNG file in memory.
1170// On entry:
1171// pImage, w, h, and num_chans describe the image to compress. num_chans may be
1172// 1, 2, 3, or 4. The image pitch in bytes per scanline will be w*num_chans.
1173// The leftmost pixel on the top scanline is stored first in memory. level may
1174// range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED,
1175// MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL If flip is
1176// true, the image will be flipped on the Y axis (useful for OpenGL apps).
1177// On return:
1178// Function returns a pointer to the compressed data, or NULL on failure.
1179// *pLen_out will be set to the size of the PNG image file.
1180// The caller must mz_free() the returned heap block (which will typically be
1181// larger than *pLen_out) when it's no longer needed.
1182void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w,
1183 int h, int num_chans,
1184 size_t *pLen_out,
1185 mz_uint level, mz_bool flip);
1186void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
1187 int num_chans, size_t *pLen_out);
1188
1189// Output stream interface. The compressor uses this interface to write
1190// compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
1191typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len,
1192 void *pUser);
1193
1194// tdefl_compress_mem_to_output() compresses a block to an output stream. The
1195// above helpers use this function internally.
1196mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len,
1197 tdefl_put_buf_func_ptr pPut_buf_func,
1198 void *pPut_buf_user, int flags);
1199
1200enum {
1201 TDEFL_MAX_HUFF_TABLES = 3,
1202 TDEFL_MAX_HUFF_SYMBOLS_0 = 288,
1203 TDEFL_MAX_HUFF_SYMBOLS_1 = 32,
1204 TDEFL_MAX_HUFF_SYMBOLS_2 = 19,
1205 TDEFL_LZ_DICT_SIZE = 32768,
1206 TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1,
1207 TDEFL_MIN_MATCH_LEN = 3,
1208 TDEFL_MAX_MATCH_LEN = 258
1209};
1210
1211// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed
1212// output block (using static/fixed Huffman codes).
1213#if TDEFL_LESS_MEMORY
1214enum {
1215 TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024,
1216 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
1217 TDEFL_MAX_HUFF_SYMBOLS = 288,
1218 TDEFL_LZ_HASH_BITS = 12,
1219 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
1220 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
1221 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
1222};
1223#else
1224enum {
1225 TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024,
1226 TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
1227 TDEFL_MAX_HUFF_SYMBOLS = 288,
1228 TDEFL_LZ_HASH_BITS = 15,
1229 TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
1230 TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
1231 TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
1232};
1233#endif
1234
1235// The low-level tdefl functions below may be used directly if the above helper
1236// functions aren't flexible enough. The low-level functions don't make any heap
1237// allocations, unlike the above helper functions.
1238typedef enum {
1239 TDEFL_STATUS_BAD_PARAM = -2,
1240 TDEFL_STATUS_PUT_BUF_FAILED = -1,
1241 TDEFL_STATUS_OKAY = 0,
1242 TDEFL_STATUS_DONE = 1,
1243} tdefl_status;
1244
1245// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
1246typedef enum {
1247 TDEFL_NO_FLUSH = 0,
1248 TDEFL_SYNC_FLUSH = 2,
1249 TDEFL_FULL_FLUSH = 3,
1250 TDEFL_FINISH = 4
1251} tdefl_flush;
1252
1253// tdefl's compression state structure.
1254typedef struct {
1255 tdefl_put_buf_func_ptr m_pPut_buf_func;
1256 void *m_pPut_buf_user;
1257 mz_uint m_flags, m_max_probes[2];
1258 int m_greedy_parsing;
1259 mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
1260 mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
1261 mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in,
1262 m_bit_buffer;
1263 mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit,
1264 m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index,
1265 m_wants_to_finish;
1266 tdefl_status m_prev_return_status;
1267 const void *m_pIn_buf;
1268 void *m_pOut_buf;
1269 size_t *m_pIn_buf_size, *m_pOut_buf_size;
1270 tdefl_flush m_flush;
1271 const mz_uint8 *m_pSrc;
1272 size_t m_src_buf_left, m_out_buf_ofs;
1273 mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
1274 mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1275 mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1276 mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
1277 mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
1278 mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
1279 mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
1280 mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
1281} tdefl_compressor;
1282
1283// Initializes the compressor.
1284// There is no corresponding deinit() function because the tdefl API's do not
1285// dynamically allocate memory. pBut_buf_func: If NULL, output data will be
1286// supplied to the specified callback. In this case, the user should call the
1287// tdefl_compress_buffer() API for compression. If pBut_buf_func is NULL the
1288// user should always call the tdefl_compress() API. flags: See the above enums
1289// (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.)
1290tdefl_status tdefl_init(tdefl_compressor *d,
1291 tdefl_put_buf_func_ptr pPut_buf_func,
1292 void *pPut_buf_user, int flags);
1293
1294// Compresses a block of data, consuming as much of the specified input buffer
1295// as possible, and writing as much compressed data to the specified output
1296// buffer as possible.
1297tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf,
1298 size_t *pIn_buf_size, void *pOut_buf,
1299 size_t *pOut_buf_size, tdefl_flush flush);
1300
1301// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a
1302// non-NULL tdefl_put_buf_func_ptr. tdefl_compress_buffer() always consumes the
1303// entire input buffer.
1304tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf,
1305 size_t in_buf_size, tdefl_flush flush);
1306
1307tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
1308mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
1309
1310// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't
1311// defined, because it uses some of its macros.
1312#ifndef MINIZ_NO_ZLIB_APIS
1313// Create tdefl_compress() flags given zlib-style compression parameters.
1314// level may range from [0,10] (where 10 is absolute max compression, but may be
1315// much slower on some files) window_bits may be -15 (raw deflate) or 15 (zlib)
1316// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY,
1317// MZ_RLE, or MZ_FIXED
1318mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
1319 int strategy);
1320#endif // #ifndef MINIZ_NO_ZLIB_APIS
1321
1322#define MZ_UINT16_MAX (0xFFFFU)
1323#define MZ_UINT32_MAX (0xFFFFFFFFU)
1324
1325#ifdef __cplusplus
1326}
1327#endif
1328
1329#endif // MINIZ_HEADER_INCLUDED
1330
1331// ------------------- End of Header: Implementation follows. (If you only want
1332// the header, define MINIZ_HEADER_FILE_ONLY.)
1333
1334#ifndef MINIZ_HEADER_FILE_ONLY
1335
1336typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];
1337typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];
1338typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
1339
1340#include <assert.h>
1341#include <string.h>
1342
1343#define MZ_ASSERT(x) assert(x)
1344
1345#ifdef MINIZ_NO_MALLOC
1346#define MZ_MALLOC(x) NULL
1347#define MZ_FREE(x) (void)x, ((void)0)
1348#define MZ_REALLOC(p, x) NULL
1349#else
1350#define MZ_MALLOC(x) malloc(x)
1351#define MZ_FREE(x) free(x)
1352#define MZ_REALLOC(p, x) realloc(p, x)
1353#endif
1354
1355#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b))
1356#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b))
1357#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
1358
1359#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1360#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
1361#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
1362#else
1363#define MZ_READ_LE16(p) \
1364 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
1365 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
1366#define MZ_READ_LE32(p) \
1367 ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \
1368 ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \
1369 ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \
1370 ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
1371#endif
1372
1373#define MZ_READ_LE64(p) \
1374 (((mz_uint64)MZ_READ_LE32(p)) | \
1375 (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) \
1376 << 32U))
1377
1378#ifdef _MSC_VER
1379#define MZ_FORCEINLINE __forceinline
1380#elif defined(__GNUC__)
1381#define MZ_FORCEINLINE inline __attribute__((__always_inline__))
1382#else
1383#define MZ_FORCEINLINE inline
1384#endif
1385
1386#ifdef __cplusplus
1387extern "C" {
1388#endif
1389
1390// ------------------- zlib-style API's
1391
1392mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) {
1393 mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16);
1394 size_t block_len = buf_len % 5552;
1395 if (!ptr)
1396 return MZ_ADLER32_INIT;
1397 while (buf_len) {
1398 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
1399 s1 += ptr[0], s2 += s1;
1400 s1 += ptr[1], s2 += s1;
1401 s1 += ptr[2], s2 += s1;
1402 s1 += ptr[3], s2 += s1;
1403 s1 += ptr[4], s2 += s1;
1404 s1 += ptr[5], s2 += s1;
1405 s1 += ptr[6], s2 += s1;
1406 s1 += ptr[7], s2 += s1;
1407 }
1408 for (; i < block_len; ++i)
1409 s1 += *ptr++, s2 += s1;
1410 s1 %= 65521U, s2 %= 65521U;
1411 buf_len -= block_len;
1412 block_len = 5552;
1413 }
1414 return (s2 << 16) + s1;
1415}
1416
1417// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C
1418// implementation that balances processor cache usage against speed":
1419// http://www.geocities.com/malbrain/
1420mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) {
1421 static const mz_uint32 s_crc32[16] = {
1422 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4,
1423 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
1424 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c};
1425 mz_uint32 crcu32 = (mz_uint32)crc;
1426 if (!ptr)
1427 return MZ_CRC32_INIT;
1428 crcu32 = ~crcu32;
1429 while (buf_len--) {
1430 mz_uint8 b = *ptr++;
1431 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];
1432 crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];
1433 }
1434 return ~crcu32;
1435}
1436
1437void mz_free(void *p) { MZ_FREE(p); }
1438
1439#ifndef MINIZ_NO_ZLIB_APIS
1440
1441static void *def_alloc_func(void *opaque, size_t items, size_t size) {
1442 (void)opaque, (void)items, (void)size;
1443 return MZ_MALLOC(items * size);
1444}
1445static void def_free_func(void *opaque, void *address) {
1446 (void)opaque, (void)address;
1447 MZ_FREE(address);
1448}
1449static void *def_realloc_func(void *opaque, void *address, size_t items,
1450 size_t size) {
1451 (void)opaque, (void)address, (void)items, (void)size;
1452 return MZ_REALLOC(address, items * size);
1453}
1454
1455const char *mz_version(void) { return MZ_VERSION; }
1456
1457int mz_deflateInit(mz_streamp pStream, int level) {
1458 return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9,
1459 MZ_DEFAULT_STRATEGY);
1460}
1461
1462int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits,
1463 int mem_level, int strategy) {
1464 tdefl_compressor *pComp;
1465 mz_uint comp_flags =
1466 TDEFL_COMPUTE_ADLER32 |
1467 tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
1468
1469 if (!pStream)
1470 return MZ_STREAM_ERROR;
1471 if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) ||
1472 ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
1473 (-window_bits != MZ_DEFAULT_WINDOW_BITS)))
1474 return MZ_PARAM_ERROR;
1475
1476 pStream->data_type = 0;
1477 pStream->adler = MZ_ADLER32_INIT;
1478 pStream->msg = NULL;
1479 pStream->reserved = 0;
1480 pStream->total_in = 0;
1481 pStream->total_out = 0;
1482 if (!pStream->zalloc)
1483 pStream->zalloc = def_alloc_func;
1484 if (!pStream->zfree)
1485 pStream->zfree = def_free_func;
1486
1487 pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1,
1488 sizeof(tdefl_compressor));
1489 if (!pComp)
1490 return MZ_MEM_ERROR;
1491
1492 pStream->state = (struct mz_internal_state *)pComp;
1493
1494 if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) {
1495 mz_deflateEnd(pStream);
1496 return MZ_PARAM_ERROR;
1497 }
1498
1499 return MZ_OK;
1500}
1501
1502int mz_deflateReset(mz_streamp pStream) {
1503 if ((!pStream) || (!pStream->state) || (!pStream->zalloc) ||
1504 (!pStream->zfree))
1505 return MZ_STREAM_ERROR;
1506 pStream->total_in = pStream->total_out = 0;
1507 tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL,
1508 ((tdefl_compressor *)pStream->state)->m_flags);
1509 return MZ_OK;
1510}
1511
1512int mz_deflate(mz_streamp pStream, int flush) {
1513 size_t in_bytes, out_bytes;
1514 mz_ulong orig_total_in, orig_total_out;
1515 int mz_status = MZ_OK;
1516
1517 if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) ||
1518 (!pStream->next_out))
1519 return MZ_STREAM_ERROR;
1520 if (!pStream->avail_out)
1521 return MZ_BUF_ERROR;
1522
1523 if (flush == MZ_PARTIAL_FLUSH)
1524 flush = MZ_SYNC_FLUSH;
1525
1526 if (((tdefl_compressor *)pStream->state)->m_prev_return_status ==
1527 TDEFL_STATUS_DONE)
1528 return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
1529
1530 orig_total_in = pStream->total_in;
1531 orig_total_out = pStream->total_out;
1532 for (;;) {
1533 tdefl_status defl_status;
1534 in_bytes = pStream->avail_in;
1535 out_bytes = pStream->avail_out;
1536
1537 defl_status = tdefl_compress((tdefl_compressor *)pStream->state,
1538 pStream->next_in, &in_bytes, pStream->next_out,
1539 &out_bytes, (tdefl_flush)flush);
1540 pStream->next_in += (mz_uint)in_bytes;
1541 pStream->avail_in -= (mz_uint)in_bytes;
1542 pStream->total_in += (mz_uint)in_bytes;
1543 pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state);
1544
1545 pStream->next_out += (mz_uint)out_bytes;
1546 pStream->avail_out -= (mz_uint)out_bytes;
1547 pStream->total_out += (mz_uint)out_bytes;
1548
1549 if (defl_status < 0) {
1550 mz_status = MZ_STREAM_ERROR;
1551 break;
1552 } else if (defl_status == TDEFL_STATUS_DONE) {
1553 mz_status = MZ_STREAM_END;
1554 break;
1555 } else if (!pStream->avail_out)
1556 break;
1557 else if ((!pStream->avail_in) && (flush != MZ_FINISH)) {
1558 if ((flush) || (pStream->total_in != orig_total_in) ||
1559 (pStream->total_out != orig_total_out))
1560 break;
1561 return MZ_BUF_ERROR; // Can't make forward progress without some input.
1562 }
1563 }
1564 return mz_status;
1565}
1566
1567int mz_deflateEnd(mz_streamp pStream) {
1568 if (!pStream)
1569 return MZ_STREAM_ERROR;
1570 if (pStream->state) {
1571 pStream->zfree(pStream->opaque, pStream->state);
1572 pStream->state = NULL;
1573 }
1574 return MZ_OK;
1575}
1576
1577mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) {
1578 (void)pStream;
1579 // This is really over conservative. (And lame, but it's actually pretty
1580 // tricky to compute a true upper bound given the way tdefl's blocking works.)
1581 return MZ_MAX(128 + (source_len * 110) / 100,
1582 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
1583}
1584
1585int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len,
1586 const unsigned char *pSource, mz_ulong source_len, int level) {
1587 int status;
1588 mz_stream stream;
1589 memset(&stream, 0, sizeof(stream));
1590
1591 // In case mz_ulong is 64-bits (argh I hate longs).
1592 if ((source_len | *pDest_len) > 0xFFFFFFFFU)
1593 return MZ_PARAM_ERROR;
1594
1595 stream.next_in = pSource;
1596 stream.avail_in = (mz_uint32)source_len;
1597 stream.next_out = pDest;
1598 stream.avail_out = (mz_uint32)*pDest_len;
1599
1600 status = mz_deflateInit(&stream, level);
1601 if (status != MZ_OK)
1602 return status;
1603
1604 status = mz_deflate(&stream, MZ_FINISH);
1605 if (status != MZ_STREAM_END) {
1606 mz_deflateEnd(&stream);
1607 return (status == MZ_OK) ? MZ_BUF_ERROR : status;
1608 }
1609
1610 *pDest_len = stream.total_out;
1611 return mz_deflateEnd(&stream);
1612}
1613
1614int mz_compress(unsigned char *pDest, mz_ulong *pDest_len,
1615 const unsigned char *pSource, mz_ulong source_len) {
1616 return mz_compress2(pDest, pDest_len, pSource, source_len,
1617 MZ_DEFAULT_COMPRESSION);
1618}
1619
1620mz_ulong mz_compressBound(mz_ulong source_len) {
1621 return mz_deflateBound(NULL, source_len);
1622}
1623
1624typedef struct {
1625 tinfl_decompressor m_decomp;
1626 mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed;
1627 int m_window_bits;
1628 mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
1629 tinfl_status m_last_status;
1630} inflate_state;
1631
1632int mz_inflateInit2(mz_streamp pStream, int window_bits) {
1633 inflate_state *pDecomp;
1634 if (!pStream)
1635 return MZ_STREAM_ERROR;
1636 if ((window_bits != MZ_DEFAULT_WINDOW_BITS) &&
1637 (-window_bits != MZ_DEFAULT_WINDOW_BITS))
1638 return MZ_PARAM_ERROR;
1639
1640 pStream->data_type = 0;
1641 pStream->adler = 0;
1642 pStream->msg = NULL;
1643 pStream->total_in = 0;
1644 pStream->total_out = 0;
1645 pStream->reserved = 0;
1646 if (!pStream->zalloc)
1647 pStream->zalloc = def_alloc_func;
1648 if (!pStream->zfree)
1649 pStream->zfree = def_free_func;
1650
1651 pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1,
1652 sizeof(inflate_state));
1653 if (!pDecomp)
1654 return MZ_MEM_ERROR;
1655
1656 pStream->state = (struct mz_internal_state *)pDecomp;
1657
1658 tinfl_init(&pDecomp->m_decomp);
1659 pDecomp->m_dict_ofs = 0;
1660 pDecomp->m_dict_avail = 0;
1661 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
1662 pDecomp->m_first_call = 1;
1663 pDecomp->m_has_flushed = 0;
1664 pDecomp->m_window_bits = window_bits;
1665
1666 return MZ_OK;
1667}
1668
1669int mz_inflateInit(mz_streamp pStream) {
1670 return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
1671}
1672
1673int mz_inflate(mz_streamp pStream, int flush) {
1674 inflate_state *pState;
1675 mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
1676 size_t in_bytes, out_bytes, orig_avail_in;
1677 tinfl_status status;
1678
1679 if ((!pStream) || (!pStream->state))
1680 return MZ_STREAM_ERROR;
1681 if (flush == MZ_PARTIAL_FLUSH)
1682 flush = MZ_SYNC_FLUSH;
1683 if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH))
1684 return MZ_STREAM_ERROR;
1685
1686 pState = (inflate_state *)pStream->state;
1687 if (pState->m_window_bits > 0)
1688 decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
1689 orig_avail_in = pStream->avail_in;
1690
1691 first_call = pState->m_first_call;
1692 pState->m_first_call = 0;
1693 if (pState->m_last_status < 0)
1694 return MZ_DATA_ERROR;
1695
1696 if (pState->m_has_flushed && (flush != MZ_FINISH))
1697 return MZ_STREAM_ERROR;
1698 pState->m_has_flushed |= (flush == MZ_FINISH);
1699
1700 if ((flush == MZ_FINISH) && (first_call)) {
1701 // MZ_FINISH on the first call implies that the input and output buffers are
1702 // large enough to hold the entire compressed/decompressed file.
1703 decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
1704 in_bytes = pStream->avail_in;
1705 out_bytes = pStream->avail_out;
1706 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes,
1707 pStream->next_out, pStream->next_out, &out_bytes,
1708 decomp_flags);
1709 pState->m_last_status = status;
1710 pStream->next_in += (mz_uint)in_bytes;
1711 pStream->avail_in -= (mz_uint)in_bytes;
1712 pStream->total_in += (mz_uint)in_bytes;
1713 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
1714 pStream->next_out += (mz_uint)out_bytes;
1715 pStream->avail_out -= (mz_uint)out_bytes;
1716 pStream->total_out += (mz_uint)out_bytes;
1717
1718 if (status < 0)
1719 return MZ_DATA_ERROR;
1720 else if (status != TINFL_STATUS_DONE) {
1721 pState->m_last_status = TINFL_STATUS_FAILED;
1722 return MZ_BUF_ERROR;
1723 }
1724 return MZ_STREAM_END;
1725 }
1726 // flush != MZ_FINISH then we must assume there's more input.
1727 if (flush != MZ_FINISH)
1728 decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
1729
1730 if (pState->m_dict_avail) {
1731 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
1732 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
1733 pStream->next_out += n;
1734 pStream->avail_out -= n;
1735 pStream->total_out += n;
1736 pState->m_dict_avail -= n;
1737 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
1738 return ((pState->m_last_status == TINFL_STATUS_DONE) &&
1739 (!pState->m_dict_avail))
1740 ? MZ_STREAM_END
1741 : MZ_OK;
1742 }
1743
1744 for (;;) {
1745 in_bytes = pStream->avail_in;
1746 out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
1747
1748 status = tinfl_decompress(
1749 &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict,
1750 pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
1751 pState->m_last_status = status;
1752
1753 pStream->next_in += (mz_uint)in_bytes;
1754 pStream->avail_in -= (mz_uint)in_bytes;
1755 pStream->total_in += (mz_uint)in_bytes;
1756 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
1757
1758 pState->m_dict_avail = (mz_uint)out_bytes;
1759
1760 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
1761 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
1762 pStream->next_out += n;
1763 pStream->avail_out -= n;
1764 pStream->total_out += n;
1765 pState->m_dict_avail -= n;
1766 pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
1767
1768 if (status < 0)
1769 return MZ_DATA_ERROR; // Stream is corrupted (there could be some
1770 // uncompressed data left in the output dictionary -
1771 // oh well).
1772 else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
1773 return MZ_BUF_ERROR; // Signal caller that we can't make forward progress
1774 // without supplying more input or by setting flush
1775 // to MZ_FINISH.
1776 else if (flush == MZ_FINISH) {
1777 // The output buffer MUST be large to hold the remaining uncompressed data
1778 // when flush==MZ_FINISH.
1779 if (status == TINFL_STATUS_DONE)
1780 return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
1781 // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's
1782 // at least 1 more byte on the way. If there's no more room left in the
1783 // output buffer then something is wrong.
1784 else if (!pStream->avail_out)
1785 return MZ_BUF_ERROR;
1786 } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) ||
1787 (!pStream->avail_out) || (pState->m_dict_avail))
1788 break;
1789 }
1790
1791 return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail))
1792 ? MZ_STREAM_END
1793 : MZ_OK;
1794}
1795
1796int mz_inflateEnd(mz_streamp pStream) {
1797 if (!pStream)
1798 return MZ_STREAM_ERROR;
1799 if (pStream->state) {
1800 pStream->zfree(pStream->opaque, pStream->state);
1801 pStream->state = NULL;
1802 }
1803 return MZ_OK;
1804}
1805
1806int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len,
1807 const unsigned char *pSource, mz_ulong source_len) {
1808 mz_stream stream;
1809 int status;
1810 memset(&stream, 0, sizeof(stream));
1811
1812 // In case mz_ulong is 64-bits (argh I hate longs).
1813 if ((source_len | *pDest_len) > 0xFFFFFFFFU)
1814 return MZ_PARAM_ERROR;
1815
1816 stream.next_in = pSource;
1817 stream.avail_in = (mz_uint32)source_len;
1818 stream.next_out = pDest;
1819 stream.avail_out = (mz_uint32)*pDest_len;
1820
1821 status = mz_inflateInit(&stream);
1822 if (status != MZ_OK)
1823 return status;
1824
1825 status = mz_inflate(&stream, MZ_FINISH);
1826 if (status != MZ_STREAM_END) {
1827 mz_inflateEnd(&stream);
1828 return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR
1829 : status;
1830 }
1831 *pDest_len = stream.total_out;
1832
1833 return mz_inflateEnd(&stream);
1834}
1835
1836const char *mz_error(int err) {
1837 static struct {
1838 int m_err;
1839 const char *m_pDesc;
1840 } s_error_descs[] = {{MZ_OK, ""},
1841 {MZ_STREAM_END, "stream end"},
1842 {MZ_NEED_DICT, "need dictionary"},
1843 {MZ_ERRNO, "file error"},
1844 {MZ_STREAM_ERROR, "stream error"},
1845 {MZ_DATA_ERROR, "data error"},
1846 {MZ_MEM_ERROR, "out of memory"},
1847 {MZ_BUF_ERROR, "buf error"},
1848 {MZ_VERSION_ERROR, "version error"},
1849 {MZ_PARAM_ERROR, "parameter error"}};
1850 mz_uint i;
1851 for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i)
1852 if (s_error_descs[i].m_err == err)
1853 return s_error_descs[i].m_pDesc;
1854 return NULL;
1855}
1856
1857#endif // MINIZ_NO_ZLIB_APIS
1858
1859// ------------------- Low-level Decompression (completely independent from all
1860// compression API's)
1861
1862#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
1863#define TINFL_MEMSET(p, c, l) memset(p, c, l)
1864
1865#define TINFL_CR_BEGIN \
1866 switch (r->m_state) { \
1867 case 0:
1868#define TINFL_CR_RETURN(state_index, result) \
1869 do { \
1870 status = result; \
1871 r->m_state = state_index; \
1872 goto common_exit; \
1873 case state_index:; \
1874 } \
1875 MZ_MACRO_END
1876#define TINFL_CR_RETURN_FOREVER(state_index, result) \
1877 do { \
1878 for (;;) { \
1879 TINFL_CR_RETURN(state_index, result); \
1880 } \
1881 } \
1882 MZ_MACRO_END
1883#define TINFL_CR_FINISH }
1884
1885// TODO: If the caller has indicated that there's no more input, and we attempt
1886// to read beyond the input buf, then something is wrong with the input because
1887// the inflator never reads ahead more than it needs to. Currently
1888// TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
1889#define TINFL_GET_BYTE(state_index, c) \
1890 do { \
1891 if (pIn_buf_cur >= pIn_buf_end) { \
1892 for (;;) { \
1893 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
1894 TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
1895 if (pIn_buf_cur < pIn_buf_end) { \
1896 c = *pIn_buf_cur++; \
1897 break; \
1898 } \
1899 } else { \
1900 c = 0; \
1901 break; \
1902 } \
1903 } \
1904 } else \
1905 c = *pIn_buf_cur++; \
1906 } \
1907 MZ_MACRO_END
1908
1909#define TINFL_NEED_BITS(state_index, n) \
1910 do { \
1911 mz_uint c; \
1912 TINFL_GET_BYTE(state_index, c); \
1913 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
1914 num_bits += 8; \
1915 } while (num_bits < (mz_uint)(n))
1916#define TINFL_SKIP_BITS(state_index, n) \
1917 do { \
1918 if (num_bits < (mz_uint)(n)) { \
1919 TINFL_NEED_BITS(state_index, n); \
1920 } \
1921 bit_buf >>= (n); \
1922 num_bits -= (n); \
1923 } \
1924 MZ_MACRO_END
1925#define TINFL_GET_BITS(state_index, b, n) \
1926 do { \
1927 if (num_bits < (mz_uint)(n)) { \
1928 TINFL_NEED_BITS(state_index, n); \
1929 } \
1930 b = bit_buf & ((1 << (n)) - 1); \
1931 bit_buf >>= (n); \
1932 num_bits -= (n); \
1933 } \
1934 MZ_MACRO_END
1935
1936// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes
1937// remaining in the input buffer falls below 2. It reads just enough bytes from
1938// the input stream that are needed to decode the next Huffman code (and
1939// absolutely no more). It works by trying to fully decode a Huffman code by
1940// using whatever bits are currently present in the bit buffer. If this fails,
1941// it reads another byte, and tries again until it succeeds or until the bit
1942// buffer contains >=15 bits (deflate's max. Huffman code size).
1943#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
1944 do { \
1945 temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
1946 if (temp >= 0) { \
1947 code_len = temp >> 9; \
1948 if ((code_len) && (num_bits >= code_len)) \
1949 break; \
1950 } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
1951 code_len = TINFL_FAST_LOOKUP_BITS; \
1952 do { \
1953 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
1954 } while ((temp < 0) && (num_bits >= (code_len + 1))); \
1955 if (temp >= 0) \
1956 break; \
1957 } \
1958 TINFL_GET_BYTE(state_index, c); \
1959 bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
1960 num_bits += 8; \
1961 } while (num_bits < 15);
1962
1963// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex
1964// than you would initially expect because the zlib API expects the decompressor
1965// to never read beyond the final byte of the deflate stream. (In other words,
1966// when this macro wants to read another byte from the input, it REALLY needs
1967// another byte in order to fully decode the next Huffman code.) Handling this
1968// properly is particularly important on raw deflate (non-zlib) streams, which
1969// aren't followed by a byte aligned adler-32. The slow path is only executed at
1970// the very end of the input buffer.
1971#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \
1972 do { \
1973 int temp; \
1974 mz_uint code_len, c; \
1975 if (num_bits < 15) { \
1976 if ((pIn_buf_end - pIn_buf_cur) < 2) { \
1977 TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
1978 } else { \
1979 bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \
1980 (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \
1981 pIn_buf_cur += 2; \
1982 num_bits += 16; \
1983 } \
1984 } \
1985 if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= \
1986 0) \
1987 code_len = temp >> 9, temp &= 511; \
1988 else { \
1989 code_len = TINFL_FAST_LOOKUP_BITS; \
1990 do { \
1991 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
1992 } while (temp < 0); \
1993 } \
1994 sym = temp; \
1995 bit_buf >>= code_len; \
1996 num_bits -= code_len; \
1997 } \
1998 MZ_MACRO_END
1999
2000tinfl_status tinfl_decompress(tinfl_decompressor *r,
2001 const mz_uint8 *pIn_buf_next,
2002 size_t *pIn_buf_size, mz_uint8 *pOut_buf_start,
2003 mz_uint8 *pOut_buf_next, size_t *pOut_buf_size,
2004 const mz_uint32 decomp_flags) {
2005 static const int s_length_base[31] = {
2006 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
2007 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
2008 static const int s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
2009 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4,
2010 4, 4, 5, 5, 5, 5, 0, 0, 0};
2011 static const int s_dist_base[32] = {
2012 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33,
2013 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
2014 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0};
2015 static const int s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
2016 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
2017 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
2018 static const mz_uint8 s_length_dezigzag[19] = {
2019 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
2020 static const int s_min_table_sizes[3] = {257, 1, 4};
2021
2022 tinfl_status status = TINFL_STATUS_FAILED;
2023 mz_uint32 num_bits, dist, counter, num_extra;
2024 tinfl_bit_buf_t bit_buf;
2025 const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end =
2026 pIn_buf_next + *pIn_buf_size;
2027 mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end =
2028 pOut_buf_next + *pOut_buf_size;
2029 size_t out_buf_size_mask =
2030 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)
2031 ? (size_t)-1
2032 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1,
2033 dist_from_out_buf_start;
2034
2035 // Ensure the output buffer's size is a power of 2, unless the output buffer
2036 // is large enough to hold the entire output file (in which case it doesn't
2037 // matter).
2038 if (((out_buf_size_mask + 1) & out_buf_size_mask) ||
2039 (pOut_buf_next < pOut_buf_start)) {
2040 *pIn_buf_size = *pOut_buf_size = 0;
2041 return TINFL_STATUS_BAD_PARAM;
2042 }
2043
2044 num_bits = r->m_num_bits;
2045 bit_buf = r->m_bit_buf;
2046 dist = r->m_dist;
2047 counter = r->m_counter;
2048 num_extra = r->m_num_extra;
2049 dist_from_out_buf_start = r->m_dist_from_out_buf_start;
2050 TINFL_CR_BEGIN
2051
2052 bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0;
2053 r->m_z_adler32 = r->m_check_adler32 = 1;
2054 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
2055 TINFL_GET_BYTE(1, r->m_zhdr0);
2056 TINFL_GET_BYTE(2, r->m_zhdr1);
2057 counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) ||
2058 (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
2059 if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
2060 counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) ||
2061 ((out_buf_size_mask + 1) <
2062 (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
2063 if (counter) {
2064 TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED);
2065 }
2066 }
2067
2068 do {
2069 TINFL_GET_BITS(3, r->m_final, 3);
2070 r->m_type = r->m_final >> 1;
2071 if (r->m_type == 0) {
2072 TINFL_SKIP_BITS(5, num_bits & 7);
2073 for (counter = 0; counter < 4; ++counter) {
2074 if (num_bits)
2075 TINFL_GET_BITS(6, r->m_raw_header[counter], 8);
2076 else
2077 TINFL_GET_BYTE(7, r->m_raw_header[counter]);
2078 }
2079 if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) !=
2080 (mz_uint)(0xFFFF ^
2081 (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) {
2082 TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED);
2083 }
2084 while ((counter) && (num_bits)) {
2085 TINFL_GET_BITS(51, dist, 8);
2086 while (pOut_buf_cur >= pOut_buf_end) {
2087 TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT);
2088 }
2089 *pOut_buf_cur++ = (mz_uint8)dist;
2090 counter--;
2091 }
2092 while (counter) {
2093 size_t n;
2094 while (pOut_buf_cur >= pOut_buf_end) {
2095 TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT);
2096 }
2097 while (pIn_buf_cur >= pIn_buf_end) {
2098 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) {
2099 TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
2100 } else {
2101 TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
2102 }
2103 }
2104 n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur),
2105 (size_t)(pIn_buf_end - pIn_buf_cur)),
2106 counter);
2107 TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n);
2108 pIn_buf_cur += n;
2109 pOut_buf_cur += n;
2110 counter -= (mz_uint)n;
2111 }
2112 } else if (r->m_type == 3) {
2113 TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
2114 } else {
2115 if (r->m_type == 1) {
2116 mz_uint8 *p = r->m_tables[0].m_code_size;
2117 mz_uint i;
2118 r->m_table_sizes[0] = 288;
2119 r->m_table_sizes[1] = 32;
2120 TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
2121 for (i = 0; i <= 143; ++i)
2122 *p++ = 8;
2123 for (; i <= 255; ++i)
2124 *p++ = 9;
2125 for (; i <= 279; ++i)
2126 *p++ = 7;
2127 for (; i <= 287; ++i)
2128 *p++ = 8;
2129 } else {
2130 for (counter = 0; counter < 3; counter++) {
2131 TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]);
2132 r->m_table_sizes[counter] += s_min_table_sizes[counter];
2133 }
2134 MZ_CLEAR_OBJ(r->m_tables[2].m_code_size);
2135 for (counter = 0; counter < r->m_table_sizes[2]; counter++) {
2136 mz_uint s;
2137 TINFL_GET_BITS(14, s, 3);
2138 r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s;
2139 }
2140 r->m_table_sizes[2] = 19;
2141 }
2142 for (; (int)r->m_type >= 0; r->m_type--) {
2143 int tree_next, tree_cur;
2144 tinfl_huff_table *pTable;
2145 mz_uint i, j, used_syms, total, sym_index, next_code[17],
2146 total_syms[16];
2147 pTable = &r->m_tables[r->m_type];
2148 MZ_CLEAR_OBJ(total_syms);
2149 MZ_CLEAR_OBJ(pTable->m_look_up);
2150 MZ_CLEAR_OBJ(pTable->m_tree);
2151 for (i = 0; i < r->m_table_sizes[r->m_type]; ++i)
2152 total_syms[pTable->m_code_size[i]]++;
2153 used_syms = 0, total = 0;
2154 next_code[0] = next_code[1] = 0;
2155 for (i = 1; i <= 15; ++i) {
2156 used_syms += total_syms[i];
2157 next_code[i + 1] = (total = ((total + total_syms[i]) << 1));
2158 }
2159 if ((65536 != total) && (used_syms > 1)) {
2160 TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
2161 }
2162 for (tree_next = -1, sym_index = 0;
2163 sym_index < r->m_table_sizes[r->m_type]; ++sym_index) {
2164 mz_uint rev_code = 0, l, cur_code,
2165 code_size = pTable->m_code_size[sym_index];
2166 if (!code_size)
2167 continue;
2168 cur_code = next_code[code_size]++;
2169 for (l = code_size; l > 0; l--, cur_code >>= 1)
2170 rev_code = (rev_code << 1) | (cur_code & 1);
2171 if (code_size <= TINFL_FAST_LOOKUP_BITS) {
2172 mz_int16 k = (mz_int16)((code_size << 9) | sym_index);
2173 while (rev_code < TINFL_FAST_LOOKUP_SIZE) {
2174 pTable->m_look_up[rev_code] = k;
2175 rev_code += (1 << code_size);
2176 }
2177 continue;
2178 }
2179 if (0 ==
2180 (tree_cur = pTable->m_look_up[rev_code &
2181 (TINFL_FAST_LOOKUP_SIZE - 1)])) {
2182 pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] =
2183 (mz_int16)tree_next;
2184 tree_cur = tree_next;
2185 tree_next -= 2;
2186 }
2187 rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
2188 for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) {
2189 tree_cur -= ((rev_code >>= 1) & 1);
2190 if (!pTable->m_tree[-tree_cur - 1]) {
2191 pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next;
2192 tree_cur = tree_next;
2193 tree_next -= 2;
2194 } else
2195 tree_cur = pTable->m_tree[-tree_cur - 1];
2196 }
2197 rev_code >>= 1;
2198 tree_cur -= (rev_code & 1);
2199 pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
2200 }
2201 if (r->m_type == 2) {
2202 for (counter = 0;
2203 counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) {
2204 mz_uint s;
2205 TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]);
2206 if (dist < 16) {
2207 r->m_len_codes[counter++] = (mz_uint8)dist;
2208 continue;
2209 }
2210 if ((dist == 16) && (!counter)) {
2211 TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
2212 }
2213 num_extra = "\02\03\07"[dist - 16];
2214 TINFL_GET_BITS(18, s, num_extra);
2215 s += "\03\03\013"[dist - 16];
2216 TINFL_MEMSET(r->m_len_codes + counter,
2217 (dist == 16) ? r->m_len_codes[counter - 1] : 0, s);
2218 counter += s;
2219 }
2220 if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) {
2221 TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
2222 }
2223 TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes,
2224 r->m_table_sizes[0]);
2225 TINFL_MEMCPY(r->m_tables[1].m_code_size,
2226 r->m_len_codes + r->m_table_sizes[0],
2227 r->m_table_sizes[1]);
2228 }
2229 }
2230 for (;;) {
2231 mz_uint8 *pSrc;
2232 for (;;) {
2233 if (((pIn_buf_end - pIn_buf_cur) < 4) ||
2234 ((pOut_buf_end - pOut_buf_cur) < 2)) {
2235 TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
2236 if (counter >= 256)
2237 break;
2238 while (pOut_buf_cur >= pOut_buf_end) {
2239 TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT);
2240 }
2241 *pOut_buf_cur++ = (mz_uint8)counter;
2242 } else {
2243 int sym2;
2244 mz_uint code_len;
2245#if TINFL_USE_64BIT_BITBUF
2246 if (num_bits < 30) {
2247 bit_buf |=
2248 (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits);
2249 pIn_buf_cur += 4;
2250 num_bits += 32;
2251 }
2252#else
2253 if (num_bits < 15) {
2254 bit_buf |=
2255 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
2256 pIn_buf_cur += 2;
2257 num_bits += 16;
2258 }
2259#endif
2260 if ((sym2 =
2261 r->m_tables[0]
2262 .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
2263 0)
2264 code_len = sym2 >> 9;
2265 else {
2266 code_len = TINFL_FAST_LOOKUP_BITS;
2267 do {
2268 sym2 = r->m_tables[0]
2269 .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
2270 } while (sym2 < 0);
2271 }
2272 counter = sym2;
2273 bit_buf >>= code_len;
2274 num_bits -= code_len;
2275 if (counter & 256)
2276 break;
2277
2278#if !TINFL_USE_64BIT_BITBUF
2279 if (num_bits < 15) {
2280 bit_buf |=
2281 (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
2282 pIn_buf_cur += 2;
2283 num_bits += 16;
2284 }
2285#endif
2286 if ((sym2 =
2287 r->m_tables[0]
2288 .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >=
2289 0)
2290 code_len = sym2 >> 9;
2291 else {
2292 code_len = TINFL_FAST_LOOKUP_BITS;
2293 do {
2294 sym2 = r->m_tables[0]
2295 .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
2296 } while (sym2 < 0);
2297 }
2298 bit_buf >>= code_len;
2299 num_bits -= code_len;
2300
2301 pOut_buf_cur[0] = (mz_uint8)counter;
2302 if (sym2 & 256) {
2303 pOut_buf_cur++;
2304 counter = sym2;
2305 break;
2306 }
2307 pOut_buf_cur[1] = (mz_uint8)sym2;
2308 pOut_buf_cur += 2;
2309 }
2310 }
2311 if ((counter &= 511) == 256)
2312 break;
2313
2314 num_extra = s_length_extra[counter - 257];
2315 counter = s_length_base[counter - 257];
2316 if (num_extra) {
2317 mz_uint extra_bits;
2318 TINFL_GET_BITS(25, extra_bits, num_extra);
2319 counter += extra_bits;
2320 }
2321
2322 TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
2323 num_extra = s_dist_extra[dist];
2324 dist = s_dist_base[dist];
2325 if (num_extra) {
2326 mz_uint extra_bits;
2327 TINFL_GET_BITS(27, extra_bits, num_extra);
2328 dist += extra_bits;
2329 }
2330
2331 dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
2332 if ((dist > dist_from_out_buf_start) &&
2333 (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) {
2334 TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
2335 }
2336
2337 pSrc = pOut_buf_start +
2338 ((dist_from_out_buf_start - dist) & out_buf_size_mask);
2339
2340 if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) {
2341 while (counter--) {
2342 while (pOut_buf_cur >= pOut_buf_end) {
2343 TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT);
2344 }
2345 *pOut_buf_cur++ =
2346 pOut_buf_start[(dist_from_out_buf_start++ - dist) &
2347 out_buf_size_mask];
2348 }
2349 continue;
2350 }
2351#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
2352 else if ((counter >= 9) && (counter <= dist)) {
2353 const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
2354 do {
2355 ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
2356 ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
2357 pOut_buf_cur += 8;
2358 } while ((pSrc += 8) < pSrc_end);
2359 if ((counter &= 7) < 3) {
2360 if (counter) {
2361 pOut_buf_cur[0] = pSrc[0];
2362 if (counter > 1)
2363 pOut_buf_cur[1] = pSrc[1];
2364 pOut_buf_cur += counter;
2365 }
2366 continue;
2367 }
2368 }
2369#endif
2370 do {
2371 pOut_buf_cur[0] = pSrc[0];
2372 pOut_buf_cur[1] = pSrc[1];
2373 pOut_buf_cur[2] = pSrc[2];
2374 pOut_buf_cur += 3;
2375 pSrc += 3;
2376 } while ((int)(counter -= 3) > 2);
2377 if ((int)counter > 0) {
2378 pOut_buf_cur[0] = pSrc[0];
2379 if ((int)counter > 1)
2380 pOut_buf_cur[1] = pSrc[1];
2381 pOut_buf_cur += counter;
2382 }
2383 }
2384 }
2385 } while (!(r->m_final & 1));
2386 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) {
2387 TINFL_SKIP_BITS(32, num_bits & 7);
2388 for (counter = 0; counter < 4; ++counter) {
2389 mz_uint s;
2390 if (num_bits)
2391 TINFL_GET_BITS(41, s, 8);
2392 else
2393 TINFL_GET_BYTE(42, s);
2394 r->m_z_adler32 = (r->m_z_adler32 << 8) | s;
2395 }
2396 }
2397 TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
2398 TINFL_CR_FINISH
2399
2400common_exit:
2401 r->m_num_bits = num_bits;
2402 r->m_bit_buf = bit_buf;
2403 r->m_dist = dist;
2404 r->m_counter = counter;
2405 r->m_num_extra = num_extra;
2406 r->m_dist_from_out_buf_start = dist_from_out_buf_start;
2407 *pIn_buf_size = pIn_buf_cur - pIn_buf_next;
2408 *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
2409 if ((decomp_flags &
2410 (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) &&
2411 (status >= 0)) {
2412 const mz_uint8 *ptr = pOut_buf_next;
2413 size_t buf_len = *pOut_buf_size;
2414 mz_uint32 i, s1 = r->m_check_adler32 & 0xffff,
2415 s2 = r->m_check_adler32 >> 16;
2416 size_t block_len = buf_len % 5552;
2417 while (buf_len) {
2418 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
2419 s1 += ptr[0], s2 += s1;
2420 s1 += ptr[1], s2 += s1;
2421 s1 += ptr[2], s2 += s1;
2422 s1 += ptr[3], s2 += s1;
2423 s1 += ptr[4], s2 += s1;
2424 s1 += ptr[5], s2 += s1;
2425 s1 += ptr[6], s2 += s1;
2426 s1 += ptr[7], s2 += s1;
2427 }
2428 for (; i < block_len; ++i)
2429 s1 += *ptr++, s2 += s1;
2430 s1 %= 65521U, s2 %= 65521U;
2431 buf_len -= block_len;
2432 block_len = 5552;
2433 }
2434 r->m_check_adler32 = (s2 << 16) + s1;
2435 if ((status == TINFL_STATUS_DONE) &&
2436 (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) &&
2437 (r->m_check_adler32 != r->m_z_adler32))
2438 status = TINFL_STATUS_ADLER32_MISMATCH;
2439 }
2440 return status;
2441}
2442
2443// Higher level helper functions.
2444void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
2445 size_t *pOut_len, int flags) {
2446 tinfl_decompressor decomp;
2447 void *pBuf = NULL, *pNew_buf;
2448 size_t src_buf_ofs = 0, out_buf_capacity = 0;
2449 *pOut_len = 0;
2450 tinfl_init(&decomp);
2451 for (;;) {
2452 size_t src_buf_size = src_buf_len - src_buf_ofs,
2453 dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
2454 tinfl_status status = tinfl_decompress(
2455 &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
2456 (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
2457 &dst_buf_size,
2458 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
2459 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
2460 if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
2461 MZ_FREE(pBuf);
2462 *pOut_len = 0;
2463 return NULL;
2464 }
2465 src_buf_ofs += src_buf_size;
2466 *pOut_len += dst_buf_size;
2467 if (status == TINFL_STATUS_DONE)
2468 break;
2469 new_out_buf_capacity = out_buf_capacity * 2;
2470 if (new_out_buf_capacity < 128)
2471 new_out_buf_capacity = 128;
2472 pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
2473 if (!pNew_buf) {
2474 MZ_FREE(pBuf);
2475 *pOut_len = 0;
2476 return NULL;
2477 }
2478 pBuf = pNew_buf;
2479 out_buf_capacity = new_out_buf_capacity;
2480 }
2481 return pBuf;
2482}
2483
2484size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
2485 const void *pSrc_buf, size_t src_buf_len,
2486 int flags) {
2487 tinfl_decompressor decomp;
2488 tinfl_status status;
2489 tinfl_init(&decomp);
2490 status =
2491 tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len,
2492 (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len,
2493 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
2494 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
2495 return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED
2496 : out_buf_len;
2497}
2498
2499int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
2500 tinfl_put_buf_func_ptr pPut_buf_func,
2501 void *pPut_buf_user, int flags) {
2502 int result = 0;
2503 tinfl_decompressor decomp;
2504 mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE);
2505 size_t in_buf_ofs = 0, dict_ofs = 0;
2506 if (!pDict)
2507 return TINFL_STATUS_FAILED;
2508 tinfl_init(&decomp);
2509 for (;;) {
2510 size_t in_buf_size = *pIn_buf_size - in_buf_ofs,
2511 dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
2512 tinfl_status status =
2513 tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs,
2514 &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
2515 (flags & ~(TINFL_FLAG_HAS_MORE_INPUT |
2516 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
2517 in_buf_ofs += in_buf_size;
2518 if ((dst_buf_size) &&
2519 (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
2520 break;
2521 if (status != TINFL_STATUS_HAS_MORE_OUTPUT) {
2522 result = (status == TINFL_STATUS_DONE);
2523 break;
2524 }
2525 dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
2526 }
2527 MZ_FREE(pDict);
2528 *pIn_buf_size = in_buf_ofs;
2529 return result;
2530}
2531
2532// ------------------- Low-level Compression (independent from all decompression
2533// API's)
2534
2535// Purposely making these tables static for faster init and thread safety.
2536static const mz_uint16 s_tdefl_len_sym[256] = {
2537 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268,
2538 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272,
2539 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274,
2540 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276,
2541 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
2542 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
2543 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279,
2544 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280,
2545 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281,
2546 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
2547 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282,
2548 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
2549 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283,
2550 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
2551 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284,
2552 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
2553 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
2554 285};
2555
2556static const mz_uint8 s_tdefl_len_extra[256] = {
2557 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
2558 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2559 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
2560 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
2561 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
2562 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2563 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2564 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2565 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2566 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2567 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0};
2568
2569static const mz_uint8 s_tdefl_small_dist_sym[512] = {
2570 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8,
2571 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
2572 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
2573 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
2574 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
2575 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
2576 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14,
2577 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
2578 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
2579 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
2580 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
2581 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
2582 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
2583 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2584 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2585 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2586 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2587 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2588 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2589 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
2590 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2591 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2592 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2593 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2594 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2595 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
2596 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17};
2597
2598static const mz_uint8 s_tdefl_small_dist_extra[512] = {
2599 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,
2600 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,
2601 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2602 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2603 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
2604 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2605 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2606 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2607 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2608 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
2609 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,
2610 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2611 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2612 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2613 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2614 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2615 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2616 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2617 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2618 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
2619 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
2620
2621static const mz_uint8 s_tdefl_large_dist_sym[128] = {
2622 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24,
2623 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26,
2624 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27,
2625 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
2626 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
2627 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
2628 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29};
2629
2630static const mz_uint8 s_tdefl_large_dist_extra[128] = {
2631 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11,
2632 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12,
2633 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
2634 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
2635 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
2636 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
2637 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
2638
2639// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted
2640// values.
2641typedef struct {
2642 mz_uint16 m_key, m_sym_index;
2643} tdefl_sym_freq;
2644static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms,
2645 tdefl_sym_freq *pSyms0,
2646 tdefl_sym_freq *pSyms1) {
2647 mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2];
2648 tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1;
2649 MZ_CLEAR_OBJ(hist);
2650 for (i = 0; i < num_syms; i++) {
2651 mz_uint freq = pSyms0[i].m_key;
2652 hist[freq & 0xFF]++;
2653 hist[256 + ((freq >> 8) & 0xFF)]++;
2654 }
2655 while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256]))
2656 total_passes--;
2657 for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) {
2658 const mz_uint32 *pHist = &hist[pass << 8];
2659 mz_uint offsets[256], cur_ofs = 0;
2660 for (i = 0; i < 256; i++) {
2661 offsets[i] = cur_ofs;
2662 cur_ofs += pHist[i];
2663 }
2664 for (i = 0; i < num_syms; i++)
2665 pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] =
2666 pCur_syms[i];
2667 {
2668 tdefl_sym_freq *t = pCur_syms;
2669 pCur_syms = pNew_syms;
2670 pNew_syms = t;
2671 }
2672 }
2673 return pCur_syms;
2674}
2675
2676// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat,
2677// alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
2678static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) {
2679 int root, leaf, next, avbl, used, dpth;
2680 if (n == 0)
2681 return;
2682 else if (n == 1) {
2683 A[0].m_key = 1;
2684 return;
2685 }
2686 A[0].m_key += A[1].m_key;
2687 root = 0;
2688 leaf = 2;
2689 for (next = 1; next < n - 1; next++) {
2690 if (leaf >= n || A[root].m_key < A[leaf].m_key) {
2691 A[next].m_key = A[root].m_key;
2692 A[root++].m_key = (mz_uint16)next;
2693 } else
2694 A[next].m_key = A[leaf++].m_key;
2695 if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) {
2696 A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key);
2697 A[root++].m_key = (mz_uint16)next;
2698 } else
2699 A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
2700 }
2701 A[n - 2].m_key = 0;
2702 for (next = n - 3; next >= 0; next--)
2703 A[next].m_key = A[A[next].m_key].m_key + 1;
2704 avbl = 1;
2705 used = dpth = 0;
2706 root = n - 2;
2707 next = n - 1;
2708 while (avbl > 0) {
2709 while (root >= 0 && (int)A[root].m_key == dpth) {
2710 used++;
2711 root--;
2712 }
2713 while (avbl > used) {
2714 A[next--].m_key = (mz_uint16)(dpth);
2715 avbl--;
2716 }
2717 avbl = 2 * used;
2718 dpth++;
2719 used = 0;
2720 }
2721}
2722
2723// Limits canonical Huffman code table's max code size.
2724enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
2725static void tdefl_huffman_enforce_max_code_size(int *pNum_codes,
2726 int code_list_len,
2727 int max_code_size) {
2728 int i;
2729 mz_uint32 total = 0;
2730 if (code_list_len <= 1)
2731 return;
2732 for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++)
2733 pNum_codes[max_code_size] += pNum_codes[i];
2734 for (i = max_code_size; i > 0; i--)
2735 total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
2736 while (total != (1UL << max_code_size)) {
2737 pNum_codes[max_code_size]--;
2738 for (i = max_code_size - 1; i > 0; i--)
2739 if (pNum_codes[i]) {
2740 pNum_codes[i]--;
2741 pNum_codes[i + 1] += 2;
2742 break;
2743 }
2744 total--;
2745 }
2746}
2747
2748static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num,
2749 int table_len, int code_size_limit,
2750 int static_table) {
2751 int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE];
2752 mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1];
2753 MZ_CLEAR_OBJ(num_codes);
2754 if (static_table) {
2755 for (i = 0; i < table_len; i++)
2756 num_codes[d->m_huff_code_sizes[table_num][i]]++;
2757 } else {
2758 tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS],
2759 *pSyms;
2760 int num_used_syms = 0;
2761 const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
2762 for (i = 0; i < table_len; i++)
2763 if (pSym_count[i]) {
2764 syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i];
2765 syms0[num_used_syms++].m_sym_index = (mz_uint16)i;
2766 }
2767
2768 pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1);
2769 tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
2770
2771 for (i = 0; i < num_used_syms; i++)
2772 num_codes[pSyms[i].m_key]++;
2773
2774 tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms,
2775 code_size_limit);
2776
2777 MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]);
2778 MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);
2779 for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
2780 for (l = num_codes[i]; l > 0; l--)
2781 d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
2782 }
2783
2784 next_code[1] = 0;
2785 for (j = 0, i = 2; i <= code_size_limit; i++)
2786 next_code[i] = j = ((j + num_codes[i - 1]) << 1);
2787
2788 for (i = 0; i < table_len; i++) {
2789 mz_uint rev_code = 0, code, code_size;
2790 if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0)
2791 continue;
2792 code = next_code[code_size]++;
2793 for (l = code_size; l > 0; l--, code >>= 1)
2794 rev_code = (rev_code << 1) | (code & 1);
2795 d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
2796 }
2797}
2798
2799#define TDEFL_PUT_BITS(b, l) \
2800 do { \
2801 mz_uint bits = b; \
2802 mz_uint len = l; \
2803 MZ_ASSERT(bits <= ((1U << len) - 1U)); \
2804 d->m_bit_buffer |= (bits << d->m_bits_in); \
2805 d->m_bits_in += len; \
2806 while (d->m_bits_in >= 8) { \
2807 if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
2808 *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
2809 d->m_bit_buffer >>= 8; \
2810 d->m_bits_in -= 8; \
2811 } \
2812 } \
2813 MZ_MACRO_END
2814
2815#define TDEFL_RLE_PREV_CODE_SIZE() \
2816 { \
2817 if (rle_repeat_count) { \
2818 if (rle_repeat_count < 3) { \
2819 d->m_huff_count[2][prev_code_size] = (mz_uint16)( \
2820 d->m_huff_count[2][prev_code_size] + rle_repeat_count); \
2821 while (rle_repeat_count--) \
2822 packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
2823 } else { \
2824 d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \
2825 packed_code_sizes[num_packed_code_sizes++] = 16; \
2826 packed_code_sizes[num_packed_code_sizes++] = \
2827 (mz_uint8)(rle_repeat_count - 3); \
2828 } \
2829 rle_repeat_count = 0; \
2830 } \
2831 }
2832
2833#define TDEFL_RLE_ZERO_CODE_SIZE() \
2834 { \
2835 if (rle_z_count) { \
2836 if (rle_z_count < 3) { \
2837 d->m_huff_count[2][0] = \
2838 (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \
2839 while (rle_z_count--) \
2840 packed_code_sizes[num_packed_code_sizes++] = 0; \
2841 } else if (rle_z_count <= 10) { \
2842 d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \
2843 packed_code_sizes[num_packed_code_sizes++] = 17; \
2844 packed_code_sizes[num_packed_code_sizes++] = \
2845 (mz_uint8)(rle_z_count - 3); \
2846 } else { \
2847 d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \
2848 packed_code_sizes[num_packed_code_sizes++] = 18; \
2849 packed_code_sizes[num_packed_code_sizes++] = \
2850 (mz_uint8)(rle_z_count - 11); \
2851 } \
2852 rle_z_count = 0; \
2853 } \
2854 }
2855
2856static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = {
2857 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
2858
2859static void tdefl_start_dynamic_block(tdefl_compressor *d) {
2860 int num_lit_codes, num_dist_codes, num_bit_lengths;
2861 mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count,
2862 rle_repeat_count, packed_code_sizes_index;
2863 mz_uint8
2864 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
2865 packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1],
2866 prev_code_size = 0xFF;
2867
2868 d->m_huff_count[0][256] = 1;
2869
2870 tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
2871 tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
2872
2873 for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--)
2874 if (d->m_huff_code_sizes[0][num_lit_codes - 1])
2875 break;
2876 for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--)
2877 if (d->m_huff_code_sizes[1][num_dist_codes - 1])
2878 break;
2879
2880 memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0],
2881 sizeof(mz_uint8) * num_lit_codes);
2882 memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0],
2883 sizeof(mz_uint8) * num_dist_codes);
2884 total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
2885 num_packed_code_sizes = 0;
2886 rle_z_count = 0;
2887 rle_repeat_count = 0;
2888
2889 memset(&d->m_huff_count[2][0], 0,
2890 sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
2891 for (i = 0; i < total_code_sizes_to_pack; i++) {
2892 mz_uint8 code_size = code_sizes_to_pack[i];
2893 if (!code_size) {
2894 TDEFL_RLE_PREV_CODE_SIZE();
2895 if (++rle_z_count == 138) {
2896 TDEFL_RLE_ZERO_CODE_SIZE();
2897 }
2898 } else {
2899 TDEFL_RLE_ZERO_CODE_SIZE();
2900 if (code_size != prev_code_size) {
2901 TDEFL_RLE_PREV_CODE_SIZE();
2902 d->m_huff_count[2][code_size] =
2903 (mz_uint16)(d->m_huff_count[2][code_size] + 1);
2904 packed_code_sizes[num_packed_code_sizes++] = code_size;
2905 } else if (++rle_repeat_count == 6) {
2906 TDEFL_RLE_PREV_CODE_SIZE();
2907 }
2908 }
2909 prev_code_size = code_size;
2910 }
2911 if (rle_repeat_count) {
2912 TDEFL_RLE_PREV_CODE_SIZE();
2913 } else {
2914 TDEFL_RLE_ZERO_CODE_SIZE();
2915 }
2916
2917 tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
2918
2919 TDEFL_PUT_BITS(2, 2);
2920
2921 TDEFL_PUT_BITS(num_lit_codes - 257, 5);
2922 TDEFL_PUT_BITS(num_dist_codes - 1, 5);
2923
2924 for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--)
2925 if (d->m_huff_code_sizes
2926 [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]])
2927 break;
2928 num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1));
2929 TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
2930 for (i = 0; (int)i < num_bit_lengths; i++)
2931 TDEFL_PUT_BITS(
2932 d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
2933
2934 for (packed_code_sizes_index = 0;
2935 packed_code_sizes_index < num_packed_code_sizes;) {
2936 mz_uint code = packed_code_sizes[packed_code_sizes_index++];
2937 MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
2938 TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
2939 if (code >= 16)
2940 TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++],
2941 "\02\03\07"[code - 16]);
2942 }
2943}
2944
2945static void tdefl_start_static_block(tdefl_compressor *d) {
2946 mz_uint i;
2947 mz_uint8 *p = &d->m_huff_code_sizes[0][0];
2948
2949 for (i = 0; i <= 143; ++i)
2950 *p++ = 8;
2951 for (; i <= 255; ++i)
2952 *p++ = 9;
2953 for (; i <= 279; ++i)
2954 *p++ = 7;
2955 for (; i <= 287; ++i)
2956 *p++ = 8;
2957
2958 memset(d->m_huff_code_sizes[1], 5, 32);
2959
2960 tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
2961 tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
2962
2963 TDEFL_PUT_BITS(1, 2);
2964}
2965
2966static const mz_uint mz_bitmasks[17] = {
2967 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
2968 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF};
2969
2970#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \
2971 MINIZ_HAS_64BIT_REGISTERS
2972static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
2973 mz_uint flags;
2974 mz_uint8 *pLZ_codes;
2975 mz_uint8 *pOutput_buf = d->m_pOutput_buf;
2976 mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
2977 mz_uint64 bit_buffer = d->m_bit_buffer;
2978 mz_uint bits_in = d->m_bits_in;
2979
2980#define TDEFL_PUT_BITS_FAST(b, l) \
2981 { \
2982 bit_buffer |= (((mz_uint64)(b)) << bits_in); \
2983 bits_in += (l); \
2984 }
2985
2986 flags = 1;
2987 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end;
2988 flags >>= 1) {
2989 if (flags == 1)
2990 flags = *pLZ_codes++ | 0x100;
2991
2992 if (flags & 1) {
2993 mz_uint s0, s1, n0, n1, sym, num_extra_bits;
2994 mz_uint match_len = pLZ_codes[0],
2995 match_dist = *(const mz_uint16 *)(pLZ_codes + 1);
2996 pLZ_codes += 3;
2997
2998 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
2999 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
3000 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3001 TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
3002 s_tdefl_len_extra[match_len]);
3003
3004 // This sequence coaxes MSVC into using cmov's vs. jmp's.
3005 s0 = s_tdefl_small_dist_sym[match_dist & 511];
3006 n0 = s_tdefl_small_dist_extra[match_dist & 511];
3007 s1 = s_tdefl_large_dist_sym[match_dist >> 8];
3008 n1 = s_tdefl_large_dist_extra[match_dist >> 8];
3009 sym = (match_dist < 512) ? s0 : s1;
3010 num_extra_bits = (match_dist < 512) ? n0 : n1;
3011
3012 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
3013 TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym],
3014 d->m_huff_code_sizes[1][sym]);
3015 TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits],
3016 num_extra_bits);
3017 } else {
3018 mz_uint lit = *pLZ_codes++;
3019 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3020 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3021 d->m_huff_code_sizes[0][lit]);
3022
3023 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
3024 flags >>= 1;
3025 lit = *pLZ_codes++;
3026 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3027 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3028 d->m_huff_code_sizes[0][lit]);
3029
3030 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) {
3031 flags >>= 1;
3032 lit = *pLZ_codes++;
3033 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3034 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit],
3035 d->m_huff_code_sizes[0][lit]);
3036 }
3037 }
3038 }
3039
3040 if (pOutput_buf >= d->m_pOutput_buf_end)
3041 return MZ_FALSE;
3042
3043 *(mz_uint64 *)pOutput_buf = bit_buffer;
3044 pOutput_buf += (bits_in >> 3);
3045 bit_buffer >>= (bits_in & ~7);
3046 bits_in &= 7;
3047 }
3048
3049#undef TDEFL_PUT_BITS_FAST
3050
3051 d->m_pOutput_buf = pOutput_buf;
3052 d->m_bits_in = 0;
3053 d->m_bit_buffer = 0;
3054
3055 while (bits_in) {
3056 mz_uint32 n = MZ_MIN(bits_in, 16);
3057 TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
3058 bit_buffer >>= n;
3059 bits_in -= n;
3060 }
3061
3062 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
3063
3064 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
3065}
3066#else
3067static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) {
3068 mz_uint flags;
3069 mz_uint8 *pLZ_codes;
3070
3071 flags = 1;
3072 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf;
3073 flags >>= 1) {
3074 if (flags == 1)
3075 flags = *pLZ_codes++ | 0x100;
3076 if (flags & 1) {
3077 mz_uint sym, num_extra_bits;
3078 mz_uint match_len = pLZ_codes[0],
3079 match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));
3080 pLZ_codes += 3;
3081
3082 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3083 TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]],
3084 d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
3085 TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]],
3086 s_tdefl_len_extra[match_len]);
3087
3088 if (match_dist < 512) {
3089 sym = s_tdefl_small_dist_sym[match_dist];
3090 num_extra_bits = s_tdefl_small_dist_extra[match_dist];
3091 } else {
3092 sym = s_tdefl_large_dist_sym[match_dist >> 8];
3093 num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
3094 }
3095 TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
3096 TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
3097 } else {
3098 mz_uint lit = *pLZ_codes++;
3099 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
3100 TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
3101 }
3102 }
3103
3104 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
3105
3106 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
3107}
3108#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN &&
3109 // MINIZ_HAS_64BIT_REGISTERS
3110
3111static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) {
3112 if (static_block)
3113 tdefl_start_static_block(d);
3114 else
3115 tdefl_start_dynamic_block(d);
3116 return tdefl_compress_lz_codes(d);
3117}
3118
3119static int tdefl_flush_block(tdefl_compressor *d, int flush) {
3120 mz_uint saved_bit_buf, saved_bits_in;
3121 mz_uint8 *pSaved_output_buf;
3122 mz_bool comp_block_succeeded = MZ_FALSE;
3123 int n, use_raw_block =
3124 ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
3125 (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
3126 mz_uint8 *pOutput_buf_start =
3127 ((d->m_pPut_buf_func == NULL) &&
3128 ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE))
3129 ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs)
3130 : d->m_output_buf;
3131
3132 d->m_pOutput_buf = pOutput_buf_start;
3133 d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
3134
3135 MZ_ASSERT(!d->m_output_flush_remaining);
3136 d->m_output_flush_ofs = 0;
3137 d->m_output_flush_remaining = 0;
3138
3139 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
3140 d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
3141
3142 if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) {
3143 TDEFL_PUT_BITS(0x78, 8);
3144 TDEFL_PUT_BITS(0x01, 8);
3145 }
3146
3147 TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
3148
3149 pSaved_output_buf = d->m_pOutput_buf;
3150 saved_bit_buf = d->m_bit_buffer;
3151 saved_bits_in = d->m_bits_in;
3152
3153 if (!use_raw_block)
3154 comp_block_succeeded =
3155 tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
3156 (d->m_total_lz_bytes < 48));
3157
3158 // If the block gets expanded, forget the current contents of the output
3159 // buffer and send a raw block instead.
3160 if (((use_raw_block) ||
3161 ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >=
3162 d->m_total_lz_bytes))) &&
3163 ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) {
3164 mz_uint i;
3165 d->m_pOutput_buf = pSaved_output_buf;
3166 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
3167 TDEFL_PUT_BITS(0, 2);
3168 if (d->m_bits_in) {
3169 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3170 }
3171 for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) {
3172 TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
3173 }
3174 for (i = 0; i < d->m_total_lz_bytes; ++i) {
3175 TDEFL_PUT_BITS(
3176 d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK],
3177 8);
3178 }
3179 }
3180 // Check for the extremely unlikely (if not impossible) case of the compressed
3181 // block not fitting into the output buffer when using dynamic codes.
3182 else if (!comp_block_succeeded) {
3183 d->m_pOutput_buf = pSaved_output_buf;
3184 d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
3185 tdefl_compress_block(d, MZ_TRUE);
3186 }
3187
3188 if (flush) {
3189 if (flush == TDEFL_FINISH) {
3190 if (d->m_bits_in) {
3191 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3192 }
3193 if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) {
3194 mz_uint i, a = d->m_adler32;
3195 for (i = 0; i < 4; i++) {
3196 TDEFL_PUT_BITS((a >> 24) & 0xFF, 8);
3197 a <<= 8;
3198 }
3199 }
3200 } else {
3201 mz_uint i, z = 0;
3202 TDEFL_PUT_BITS(0, 3);
3203 if (d->m_bits_in) {
3204 TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
3205 }
3206 for (i = 2; i; --i, z ^= 0xFFFF) {
3207 TDEFL_PUT_BITS(z & 0xFFFF, 16);
3208 }
3209 }
3210 }
3211
3212 MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
3213
3214 memset(&d->m_huff_count[0][0], 0,
3215 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
3216 memset(&d->m_huff_count[1][0], 0,
3217 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
3218
3219 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
3220 d->m_pLZ_flags = d->m_lz_code_buf;
3221 d->m_num_flags_left = 8;
3222 d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes;
3223 d->m_total_lz_bytes = 0;
3224 d->m_block_index++;
3225
3226 if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) {
3227 if (d->m_pPut_buf_func) {
3228 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
3229 if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
3230 return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
3231 } else if (pOutput_buf_start == d->m_output_buf) {
3232 int bytes_to_copy = (int)MZ_MIN(
3233 (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
3234 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf,
3235 bytes_to_copy);
3236 d->m_out_buf_ofs += bytes_to_copy;
3237 if ((n -= bytes_to_copy) != 0) {
3238 d->m_output_flush_ofs = bytes_to_copy;
3239 d->m_output_flush_remaining = n;
3240 }
3241 } else {
3242 d->m_out_buf_ofs += n;
3243 }
3244 }
3245
3246 return d->m_output_flush_remaining;
3247}
3248
3249#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
3250#define TDEFL_READ_UNALIGNED_WORD(p) ((p)[0] | (p)[1] << 8)
3251static MZ_FORCEINLINE void
3252tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
3253 mz_uint max_match_len, mz_uint *pMatch_dist,
3254 mz_uint *pMatch_len) {
3255 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
3256 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
3257 probe_len;
3258 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
3259 const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q;
3260 mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]),
3261 s01 = *s;
3262 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
3263 if (max_match_len <= match_len)
3264 return;
3265 for (;;) {
3266 for (;;) {
3267 if (--num_probes_left == 0)
3268 return;
3269#define TDEFL_PROBE \
3270 next_probe_pos = d->m_next[probe_pos]; \
3271 if ((!next_probe_pos) || \
3272 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
3273 return; \
3274 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
3275 if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \
3276 break;
3277 TDEFL_PROBE;
3278 TDEFL_PROBE;
3279 TDEFL_PROBE;
3280 }
3281 if (!dist)
3282 break;
3283 q = (const mz_uint16 *)(d->m_dict + probe_pos);
3284 if (*q != s01)
3285 continue;
3286 p = s;
3287 probe_len = 32;
3288 do {
3289 } while ((*(++p) == *(++q)) && (*(++p) == *(++q)) && (*(++p) == *(++q)) &&
3290 (*(++p) == *(++q)) && (--probe_len > 0));
3291 if (!probe_len) {
3292 *pMatch_dist = dist;
3293 *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN);
3294 break;
3295 } else if ((probe_len = ((mz_uint)(p - s) * 2) +
3296 (mz_uint)(*(const mz_uint8 *)p ==
3297 *(const mz_uint8 *)q)) > match_len) {
3298 *pMatch_dist = dist;
3299 if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) ==
3300 max_match_len)
3301 break;
3302 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
3303 }
3304 }
3305}
3306#else
3307static MZ_FORCEINLINE void
3308tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist,
3309 mz_uint max_match_len, mz_uint *pMatch_dist,
3310 mz_uint *pMatch_len) {
3311 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK,
3312 match_len = *pMatch_len, probe_pos = pos, next_probe_pos,
3313 probe_len;
3314 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
3315 const mz_uint8 *s = d->m_dict + pos, *p, *q;
3316 mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
3317 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
3318 if (max_match_len <= match_len)
3319 return;
3320 for (;;) {
3321 for (;;) {
3322 if (--num_probes_left == 0)
3323 return;
3324#define TDEFL_PROBE \
3325 next_probe_pos = d->m_next[probe_pos]; \
3326 if ((!next_probe_pos) || \
3327 ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
3328 return; \
3329 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
3330 if ((d->m_dict[probe_pos + match_len] == c0) && \
3331 (d->m_dict[probe_pos + match_len - 1] == c1)) \
3332 break;
3333 TDEFL_PROBE;
3334 TDEFL_PROBE;
3335 TDEFL_PROBE;
3336 }
3337 if (!dist)
3338 break;
3339 p = s;
3340 q = d->m_dict + probe_pos;
3341 for (probe_len = 0; probe_len < max_match_len; probe_len++)
3342 if (*p++ != *q++)
3343 break;
3344 if (probe_len > match_len) {
3345 *pMatch_dist = dist;
3346 if ((*pMatch_len = match_len = probe_len) == max_match_len)
3347 return;
3348 c0 = d->m_dict[pos + match_len];
3349 c1 = d->m_dict[pos + match_len - 1];
3350 }
3351 }
3352}
3353#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
3354
3355#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
3356static mz_bool tdefl_compress_fast(tdefl_compressor *d) {
3357 // Faster, minimally featured LZRW1-style match+parse loop with better
3358 // register utilization. Intended for applications where raw throughput is
3359 // valued more highly than ratio.
3360 mz_uint lookahead_pos = d->m_lookahead_pos,
3361 lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size,
3362 total_lz_bytes = d->m_total_lz_bytes,
3363 num_flags_left = d->m_num_flags_left;
3364 mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
3365 mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
3366
3367 while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) {
3368 const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
3369 mz_uint dst_pos =
3370 (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
3371 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
3372 d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
3373 d->m_src_buf_left -= num_bytes_to_process;
3374 lookahead_size += num_bytes_to_process;
3375
3376 while (num_bytes_to_process) {
3377 mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
3378 memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
3379 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
3380 memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc,
3381 MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
3382 d->m_pSrc += n;
3383 dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
3384 num_bytes_to_process -= n;
3385 }
3386
3387 dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
3388 if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE))
3389 break;
3390
3391 while (lookahead_size >= 4) {
3392 mz_uint cur_match_dist, cur_match_len = 1;
3393 mz_uint8 *pCur_dict = d->m_dict + cur_pos;
3394 mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF;
3395 mz_uint hash =
3396 (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) &
3397 TDEFL_LEVEL1_HASH_SIZE_MASK;
3398 mz_uint probe_pos = d->m_hash[hash];
3399 d->m_hash[hash] = (mz_uint16)lookahead_pos;
3400
3401 if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <=
3402 dict_size) &&
3403 ((mz_uint32)(
3404 *(d->m_dict + (probe_pos & TDEFL_LZ_DICT_SIZE_MASK)) |
3405 (*(d->m_dict + ((probe_pos & TDEFL_LZ_DICT_SIZE_MASK) + 1))
3406 << 8) |
3407 (*(d->m_dict + ((probe_pos & TDEFL_LZ_DICT_SIZE_MASK) + 2))
3408 << 16)) == first_trigram)) {
3409 const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
3410 const mz_uint16 *q =
3411 (const mz_uint16 *)(d->m_dict +
3412 (probe_pos & TDEFL_LZ_DICT_SIZE_MASK));
3413 mz_uint32 probe_len = 32;
3414 do {
3415 } while ((*(++p) == *(++q)) && (*(++p) == *(++q)) &&
3416 (*(++p) == *(++q)) && (*(++p) == *(++q)) && (--probe_len > 0));
3417 cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) +
3418 (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
3419 if (!probe_len)
3420 cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
3421
3422 if ((cur_match_len < TDEFL_MIN_MATCH_LEN) ||
3423 ((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
3424 (cur_match_dist >= 8U * 1024U))) {
3425 cur_match_len = 1;
3426 *pLZ_code_buf++ = (mz_uint8)first_trigram;
3427 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3428 d->m_huff_count[0][(mz_uint8)first_trigram]++;
3429 } else {
3430 mz_uint32 s0, s1;
3431 cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
3432
3433 MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) &&
3434 (cur_match_dist >= 1) &&
3435 (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
3436
3437 cur_match_dist--;
3438
3439 pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
3440 *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
3441 pLZ_code_buf += 3;
3442 *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
3443
3444 s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
3445 s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
3446 d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
3447
3448 d->m_huff_count[0][s_tdefl_len_sym[cur_match_len -
3449 TDEFL_MIN_MATCH_LEN]]++;
3450 }
3451 } else {
3452 *pLZ_code_buf++ = (mz_uint8)first_trigram;
3453 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3454 d->m_huff_count[0][(mz_uint8)first_trigram]++;
3455 }
3456
3457 if (--num_flags_left == 0) {
3458 num_flags_left = 8;
3459 pLZ_flags = pLZ_code_buf++;
3460 }
3461
3462 total_lz_bytes += cur_match_len;
3463 lookahead_pos += cur_match_len;
3464 dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE);
3465 cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
3466 MZ_ASSERT(lookahead_size >= cur_match_len);
3467 lookahead_size -= cur_match_len;
3468
3469 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
3470 int n;
3471 d->m_lookahead_pos = lookahead_pos;
3472 d->m_lookahead_size = lookahead_size;
3473 d->m_dict_size = dict_size;
3474 d->m_total_lz_bytes = total_lz_bytes;
3475 d->m_pLZ_code_buf = pLZ_code_buf;
3476 d->m_pLZ_flags = pLZ_flags;
3477 d->m_num_flags_left = num_flags_left;
3478 if ((n = tdefl_flush_block(d, 0)) != 0)
3479 return (n < 0) ? MZ_FALSE : MZ_TRUE;
3480 total_lz_bytes = d->m_total_lz_bytes;
3481 pLZ_code_buf = d->m_pLZ_code_buf;
3482 pLZ_flags = d->m_pLZ_flags;
3483 num_flags_left = d->m_num_flags_left;
3484 }
3485 }
3486
3487 while (lookahead_size) {
3488 mz_uint8 lit = d->m_dict[cur_pos];
3489
3490 total_lz_bytes++;
3491 *pLZ_code_buf++ = lit;
3492 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
3493 if (--num_flags_left == 0) {
3494 num_flags_left = 8;
3495 pLZ_flags = pLZ_code_buf++;
3496 }
3497
3498 d->m_huff_count[0][lit]++;
3499
3500 lookahead_pos++;
3501 dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE);
3502 cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
3503 lookahead_size--;
3504
3505 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) {
3506 int n;
3507 d->m_lookahead_pos = lookahead_pos;
3508 d->m_lookahead_size = lookahead_size;
3509 d->m_dict_size = dict_size;
3510 d->m_total_lz_bytes = total_lz_bytes;
3511 d->m_pLZ_code_buf = pLZ_code_buf;
3512 d->m_pLZ_flags = pLZ_flags;
3513 d->m_num_flags_left = num_flags_left;
3514 if ((n = tdefl_flush_block(d, 0)) != 0)
3515 return (n < 0) ? MZ_FALSE : MZ_TRUE;
3516 total_lz_bytes = d->m_total_lz_bytes;
3517 pLZ_code_buf = d->m_pLZ_code_buf;
3518 pLZ_flags = d->m_pLZ_flags;
3519 num_flags_left = d->m_num_flags_left;
3520 }
3521 }
3522 }
3523
3524 d->m_lookahead_pos = lookahead_pos;
3525 d->m_lookahead_size = lookahead_size;
3526 d->m_dict_size = dict_size;
3527 d->m_total_lz_bytes = total_lz_bytes;
3528 d->m_pLZ_code_buf = pLZ_code_buf;
3529 d->m_pLZ_flags = pLZ_flags;
3530 d->m_num_flags_left = num_flags_left;
3531 return MZ_TRUE;
3532}
3533#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
3534
3535static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d,
3536 mz_uint8 lit) {
3537 d->m_total_lz_bytes++;
3538 *d->m_pLZ_code_buf++ = lit;
3539 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1);
3540 if (--d->m_num_flags_left == 0) {
3541 d->m_num_flags_left = 8;
3542 d->m_pLZ_flags = d->m_pLZ_code_buf++;
3543 }
3544 d->m_huff_count[0][lit]++;
3545}
3546
3547static MZ_FORCEINLINE void
3548tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) {
3549 mz_uint32 s0, s1;
3550
3551 MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) &&
3552 (match_dist <= TDEFL_LZ_DICT_SIZE));
3553
3554 d->m_total_lz_bytes += match_len;
3555
3556 d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
3557
3558 match_dist -= 1;
3559 d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
3560 d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8);
3561 d->m_pLZ_code_buf += 3;
3562
3563 *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80);
3564 if (--d->m_num_flags_left == 0) {
3565 d->m_num_flags_left = 8;
3566 d->m_pLZ_flags = d->m_pLZ_code_buf++;
3567 }
3568
3569 s0 = s_tdefl_small_dist_sym[match_dist & 511];
3570 s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
3571 d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
3572
3573 if (match_len >= TDEFL_MIN_MATCH_LEN)
3574 d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
3575}
3576
3577static mz_bool tdefl_compress_normal(tdefl_compressor *d) {
3578 const mz_uint8 *pSrc = d->m_pSrc;
3579 size_t src_buf_left = d->m_src_buf_left;
3580 tdefl_flush flush = d->m_flush;
3581
3582 while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) {
3583 mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
3584 // Update dictionary and hash chains. Keeps the lookahead size equal to
3585 // TDEFL_MAX_MATCH_LEN.
3586 if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) {
3587 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
3588 TDEFL_LZ_DICT_SIZE_MASK,
3589 ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;
3590 mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
3591 << TDEFL_LZ_HASH_SHIFT) ^
3592 d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];
3593 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(
3594 src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
3595 const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
3596 src_buf_left -= num_bytes_to_process;
3597 d->m_lookahead_size += num_bytes_to_process;
3598 while (pSrc != pSrc_end) {
3599 mz_uint8 c = *pSrc++;
3600 d->m_dict[dst_pos] = c;
3601 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
3602 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
3603 hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
3604 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
3605 d->m_hash[hash] = (mz_uint16)(ins_pos);
3606 dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
3607 ins_pos++;
3608 }
3609 } else {
3610 while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) {
3611 mz_uint8 c = *pSrc++;
3612 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) &
3613 TDEFL_LZ_DICT_SIZE_MASK;
3614 src_buf_left--;
3615 d->m_dict[dst_pos] = c;
3616 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
3617 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
3618 if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) {
3619 mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
3620 mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK]
3621 << (TDEFL_LZ_HASH_SHIFT * 2)) ^
3622 (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]
3623 << TDEFL_LZ_HASH_SHIFT) ^
3624 c) &
3625 (TDEFL_LZ_HASH_SIZE - 1);
3626 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
3627 d->m_hash[hash] = (mz_uint16)(ins_pos);
3628 }
3629 }
3630 }
3631 d->m_dict_size =
3632 MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
3633 if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
3634 break;
3635
3636 // Simple lazy/greedy parsing state machine.
3637 len_to_move = 1;
3638 cur_match_dist = 0;
3639 cur_match_len =
3640 d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1);
3641 cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
3642 if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) {
3643 if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) {
3644 mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
3645 cur_match_len = 0;
3646 while (cur_match_len < d->m_lookahead_size) {
3647 if (d->m_dict[cur_pos + cur_match_len] != c)
3648 break;
3649 cur_match_len++;
3650 }
3651 if (cur_match_len < TDEFL_MIN_MATCH_LEN)
3652 cur_match_len = 0;
3653 else
3654 cur_match_dist = 1;
3655 }
3656 } else {
3657 tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size,
3658 d->m_lookahead_size, &cur_match_dist, &cur_match_len);
3659 }
3660 if (((cur_match_len == TDEFL_MIN_MATCH_LEN) &&
3661 (cur_match_dist >= 8U * 1024U)) ||
3662 (cur_pos == cur_match_dist) ||
3663 ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) {
3664 cur_match_dist = cur_match_len = 0;
3665 }
3666 if (d->m_saved_match_len) {
3667 if (cur_match_len > d->m_saved_match_len) {
3668 tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
3669 if (cur_match_len >= 128) {
3670 tdefl_record_match(d, cur_match_len, cur_match_dist);
3671 d->m_saved_match_len = 0;
3672 len_to_move = cur_match_len;
3673 } else {
3674 d->m_saved_lit = d->m_dict[cur_pos];
3675 d->m_saved_match_dist = cur_match_dist;
3676 d->m_saved_match_len = cur_match_len;
3677 }
3678 } else {
3679 tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
3680 len_to_move = d->m_saved_match_len - 1;
3681 d->m_saved_match_len = 0;
3682 }
3683 } else if (!cur_match_dist)
3684 tdefl_record_literal(d,
3685 d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
3686 else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) ||
3687 (cur_match_len >= 128)) {
3688 tdefl_record_match(d, cur_match_len, cur_match_dist);
3689 len_to_move = cur_match_len;
3690 } else {
3691 d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)];
3692 d->m_saved_match_dist = cur_match_dist;
3693 d->m_saved_match_len = cur_match_len;
3694 }
3695 // Move the lookahead forward by len_to_move bytes.
3696 d->m_lookahead_pos += len_to_move;
3697 MZ_ASSERT(d->m_lookahead_size >= len_to_move);
3698 d->m_lookahead_size -= len_to_move;
3699 d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE);
3700 // Check if it's time to flush the current LZ codes to the internal output
3701 // buffer.
3702 if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
3703 ((d->m_total_lz_bytes > 31 * 1024) &&
3704 (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >=
3705 d->m_total_lz_bytes) ||
3706 (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) {
3707 int n;
3708 d->m_pSrc = pSrc;
3709 d->m_src_buf_left = src_buf_left;
3710 if ((n = tdefl_flush_block(d, 0)) != 0)
3711 return (n < 0) ? MZ_FALSE : MZ_TRUE;
3712 }
3713 }
3714
3715 d->m_pSrc = pSrc;
3716 d->m_src_buf_left = src_buf_left;
3717 return MZ_TRUE;
3718}
3719
3720static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) {
3721 if (d->m_pIn_buf_size) {
3722 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
3723 }
3724
3725 if (d->m_pOut_buf_size) {
3726 size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs,
3727 d->m_output_flush_remaining);
3728 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs,
3729 d->m_output_buf + d->m_output_flush_ofs, n);
3730 d->m_output_flush_ofs += (mz_uint)n;
3731 d->m_output_flush_remaining -= (mz_uint)n;
3732 d->m_out_buf_ofs += n;
3733
3734 *d->m_pOut_buf_size = d->m_out_buf_ofs;
3735 }
3736
3737 return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE
3738 : TDEFL_STATUS_OKAY;
3739}
3740
3741tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf,
3742 size_t *pIn_buf_size, void *pOut_buf,
3743 size_t *pOut_buf_size, tdefl_flush flush) {
3744 if (!d) {
3745 if (pIn_buf_size)
3746 *pIn_buf_size = 0;
3747 if (pOut_buf_size)
3748 *pOut_buf_size = 0;
3749 return TDEFL_STATUS_BAD_PARAM;
3750 }
3751
3752 d->m_pIn_buf = pIn_buf;
3753 d->m_pIn_buf_size = pIn_buf_size;
3754 d->m_pOut_buf = pOut_buf;
3755 d->m_pOut_buf_size = pOut_buf_size;
3756 d->m_pSrc = (const mz_uint8 *)(pIn_buf);
3757 d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
3758 d->m_out_buf_ofs = 0;
3759 d->m_flush = flush;
3760
3761 if (((d->m_pPut_buf_func != NULL) ==
3762 ((pOut_buf != NULL) || (pOut_buf_size != NULL))) ||
3763 (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
3764 (d->m_wants_to_finish && (flush != TDEFL_FINISH)) ||
3765 (pIn_buf_size && *pIn_buf_size && !pIn_buf) ||
3766 (pOut_buf_size && *pOut_buf_size && !pOut_buf)) {
3767 if (pIn_buf_size)
3768 *pIn_buf_size = 0;
3769 if (pOut_buf_size)
3770 *pOut_buf_size = 0;
3771 return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
3772 }
3773 d->m_wants_to_finish |= (flush == TDEFL_FINISH);
3774
3775 if ((d->m_output_flush_remaining) || (d->m_finished))
3776 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
3777
3778#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
3779 if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
3780 ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
3781 ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS |
3782 TDEFL_RLE_MATCHES)) == 0)) {
3783 if (!tdefl_compress_fast(d))
3784 return d->m_prev_return_status;
3785 } else
3786#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
3787 {
3788 if (!tdefl_compress_normal(d))
3789 return d->m_prev_return_status;
3790 }
3791
3792 if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) &&
3793 (pIn_buf))
3794 d->m_adler32 =
3795 (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf,
3796 d->m_pSrc - (const mz_uint8 *)pIn_buf);
3797
3798 if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) &&
3799 (!d->m_output_flush_remaining)) {
3800 if (tdefl_flush_block(d, flush) < 0)
3801 return d->m_prev_return_status;
3802 d->m_finished = (flush == TDEFL_FINISH);
3803 if (flush == TDEFL_FULL_FLUSH) {
3804 MZ_CLEAR_OBJ(d->m_hash);
3805 MZ_CLEAR_OBJ(d->m_next);
3806 d->m_dict_size = 0;
3807 }
3808 }
3809
3810 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
3811}
3812
3813tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf,
3814 size_t in_buf_size, tdefl_flush flush) {
3815 MZ_ASSERT(d->m_pPut_buf_func);
3816 return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
3817}
3818
3819tdefl_status tdefl_init(tdefl_compressor *d,
3820 tdefl_put_buf_func_ptr pPut_buf_func,
3821 void *pPut_buf_user, int flags) {
3822 d->m_pPut_buf_func = pPut_buf_func;
3823 d->m_pPut_buf_user = pPut_buf_user;
3824 d->m_flags = (mz_uint)(flags);
3825 d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3;
3826 d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
3827 d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
3828 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG))
3829 MZ_CLEAR_OBJ(d->m_hash);
3830 d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size =
3831 d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;
3832 d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished =
3833 d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;
3834 d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
3835 d->m_pLZ_flags = d->m_lz_code_buf;
3836 d->m_num_flags_left = 8;
3837 d->m_pOutput_buf = d->m_output_buf;
3838 d->m_pOutput_buf_end = d->m_output_buf;
3839 d->m_prev_return_status = TDEFL_STATUS_OKAY;
3840 d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0;
3841 d->m_adler32 = 1;
3842 d->m_pIn_buf = NULL;
3843 d->m_pOut_buf = NULL;
3844 d->m_pIn_buf_size = NULL;
3845 d->m_pOut_buf_size = NULL;
3846 d->m_flush = TDEFL_NO_FLUSH;
3847 d->m_pSrc = NULL;
3848 d->m_src_buf_left = 0;
3849 d->m_out_buf_ofs = 0;
3850 memset(&d->m_huff_count[0][0], 0,
3851 sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
3852 memset(&d->m_huff_count[1][0], 0,
3853 sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
3854 return TDEFL_STATUS_OKAY;
3855}
3856
3857tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) {
3858 return d->m_prev_return_status;
3859}
3860
3861mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; }
3862
3863mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len,
3864 tdefl_put_buf_func_ptr pPut_buf_func,
3865 void *pPut_buf_user, int flags) {
3866 tdefl_compressor *pComp;
3867 mz_bool succeeded;
3868 if (((buf_len) && (!pBuf)) || (!pPut_buf_func))
3869 return MZ_FALSE;
3870 pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
3871 if (!pComp)
3872 return MZ_FALSE;
3873 succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) ==
3874 TDEFL_STATUS_OKAY);
3875 succeeded =
3876 succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) ==
3877 TDEFL_STATUS_DONE);
3878 MZ_FREE(pComp);
3879 return succeeded;
3880}
3881
3882typedef struct {
3883 size_t m_size, m_capacity;
3884 mz_uint8 *m_pBuf;
3885 mz_bool m_expandable;
3886} tdefl_output_buffer;
3887
3888static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len,
3889 void *pUser) {
3890 tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
3891 size_t new_size = p->m_size + len;
3892 if (new_size > p->m_capacity) {
3893 size_t new_capacity = p->m_capacity;
3894 mz_uint8 *pNew_buf;
3895 if (!p->m_expandable)
3896 return MZ_FALSE;
3897 do {
3898 new_capacity = MZ_MAX(128U, new_capacity << 1U);
3899 } while (new_size > new_capacity);
3900 pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity);
3901 if (!pNew_buf)
3902 return MZ_FALSE;
3903 p->m_pBuf = pNew_buf;
3904 p->m_capacity = new_capacity;
3905 }
3906 memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len);
3907 p->m_size = new_size;
3908 return MZ_TRUE;
3909}
3910
3911void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
3912 size_t *pOut_len, int flags) {
3913 tdefl_output_buffer out_buf;
3914 MZ_CLEAR_OBJ(out_buf);
3915 if (!pOut_len)
3916 return MZ_FALSE;
3917 else
3918 *pOut_len = 0;
3919 out_buf.m_expandable = MZ_TRUE;
3920 if (!tdefl_compress_mem_to_output(
3921 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
3922 return NULL;
3923 *pOut_len = out_buf.m_size;
3924 return out_buf.m_pBuf;
3925}
3926
3927size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len,
3928 const void *pSrc_buf, size_t src_buf_len,
3929 int flags) {
3930 tdefl_output_buffer out_buf;
3931 MZ_CLEAR_OBJ(out_buf);
3932 if (!pOut_buf)
3933 return 0;
3934 out_buf.m_pBuf = (mz_uint8 *)pOut_buf;
3935 out_buf.m_capacity = out_buf_len;
3936 if (!tdefl_compress_mem_to_output(
3937 pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
3938 return 0;
3939 return out_buf.m_size;
3940}
3941
3942#ifndef MINIZ_NO_ZLIB_APIS
3943static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32,
3944 128, 256, 512, 768, 1500};
3945
3946// level may actually range from [0,10] (10 is a "hidden" max level, where we
3947// want a bit more compression and it's fine if throughput to fall off a cliff
3948// on some files).
3949mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
3950 int strategy) {
3951 mz_uint comp_flags =
3952 s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] |
3953 ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
3954 if (window_bits > 0)
3955 comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
3956
3957 if (!level)
3958 comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
3959 else if (strategy == MZ_FILTERED)
3960 comp_flags |= TDEFL_FILTER_MATCHES;
3961 else if (strategy == MZ_HUFFMAN_ONLY)
3962 comp_flags &= ~TDEFL_MAX_PROBES_MASK;
3963 else if (strategy == MZ_FIXED)
3964 comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
3965 else if (strategy == MZ_RLE)
3966 comp_flags |= TDEFL_RLE_MATCHES;
3967
3968 return comp_flags;
3969}
3970#endif // MINIZ_NO_ZLIB_APIS
3971
3972#ifdef _MSC_VER
3973#pragma warning(push)
3974#pragma warning(disable : 4204) // nonstandard extension used : non-constant
3975 // aggregate initializer (also supported by GNU
3976 // C and C99, so no big deal)
3977#endif
3978
3979// Simple PNG writer function by Alex Evans, 2011. Released into the public
3980// domain: https://gist.github.com/908299, more context at
3981// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
3982// This is actually a modification of Alex's original code so PNG files
3983// generated by this function pass pngcheck.
3984void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w,
3985 int h, int num_chans,
3986 size_t *pLen_out,
3987 mz_uint level, mz_bool flip) {
3988 // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was
3989 // defined.
3990 static const mz_uint s_tdefl_png_num_probes[11] = {
3991 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500};
3992 tdefl_compressor *pComp =
3993 (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
3994 tdefl_output_buffer out_buf;
3995 int i, bpl = w * num_chans, y, z;
3996 mz_uint32 c;
3997 *pLen_out = 0;
3998 if (!pComp)
3999 return NULL;
4000 MZ_CLEAR_OBJ(out_buf);
4001 out_buf.m_expandable = MZ_TRUE;
4002 out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h);
4003 if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) {
4004 MZ_FREE(pComp);
4005 return NULL;
4006 }
4007 // write dummy header
4008 for (z = 41; z; --z)
4009 tdefl_output_buffer_putter(&z, 1, &out_buf);
4010 // compress image data
4011 tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf,
4012 s_tdefl_png_num_probes[MZ_MIN(10, level)] |
4013 TDEFL_WRITE_ZLIB_HEADER);
4014 for (y = 0; y < h; ++y) {
4015 tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH);
4016 tdefl_compress_buffer(pComp,
4017 (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl,
4018 bpl, TDEFL_NO_FLUSH);
4019 }
4020 if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) !=
4021 TDEFL_STATUS_DONE) {
4022 MZ_FREE(pComp);
4023 MZ_FREE(out_buf.m_pBuf);
4024 return NULL;
4025 }
4026 // write real header
4027 *pLen_out = out_buf.m_size - 41;
4028 {
4029 static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06};
4030 mz_uint8 pnghdr[41] = {0x89,
4031 0x50,
4032 0x4e,
4033 0x47,
4034 0x0d,
4035 0x0a,
4036 0x1a,
4037 0x0a,
4038 0x00,
4039 0x00,
4040 0x00,
4041 0x0d,
4042 0x49,
4043 0x48,
4044 0x44,
4045 0x52,
4046 0,
4047 0,
4048 (mz_uint8)(w >> 8),
4049 (mz_uint8)w,
4050 0,
4051 0,
4052 (mz_uint8)(h >> 8),
4053 (mz_uint8)h,
4054 8,
4055 chans[num_chans],
4056 0,
4057 0,
4058 0,
4059 0,
4060 0,
4061 0,
4062 0,
4063 (mz_uint8)(*pLen_out >> 24),
4064 (mz_uint8)(*pLen_out >> 16),
4065 (mz_uint8)(*pLen_out >> 8),
4066 (mz_uint8)*pLen_out,
4067 0x49,
4068 0x44,
4069 0x41,
4070 0x54};
4071 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17);
4072 for (i = 0; i < 4; ++i, c <<= 8)
4073 ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24);
4074 memcpy(out_buf.m_pBuf, pnghdr, 41);
4075 }
4076 // write footer (IDAT CRC-32, followed by IEND chunk)
4077 if (!tdefl_output_buffer_putter(
4078 "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) {
4079 *pLen_out = 0;
4080 MZ_FREE(pComp);
4081 MZ_FREE(out_buf.m_pBuf);
4082 return NULL;
4083 }
4084 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4,
4085 *pLen_out + 4);
4086 for (i = 0; i < 4; ++i, c <<= 8)
4087 (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24);
4088 // compute final size of file, grab compressed data buffer and return
4089 *pLen_out += 57;
4090 MZ_FREE(pComp);
4091 return out_buf.m_pBuf;
4092}
4093void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h,
4094 int num_chans, size_t *pLen_out) {
4095 // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we
4096 // can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's
4097 // where #defined out)
4098 return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans,
4099 pLen_out, 6, MZ_FALSE);
4100}
4101
4102#ifdef _MSC_VER
4103#pragma warning(pop)
4104#endif
4105
4106// ------------------- .ZIP archive reading
4107
4108#ifndef MINIZ_NO_ARCHIVE_APIS
4109
4110#ifdef MINIZ_NO_STDIO
4111#define MZ_FILE void *
4112#else
4113#include <stdio.h>
4114#include <sys/stat.h>
4115
4116#if defined(_MSC_VER) || defined(__MINGW32__)
4117
4118#include <windows.h>
4119
4120static wchar_t *str2wstr(const char *str) {
4121 int len = strlen(str) + 1;
4122 wchar_t *wstr = (wchar_t*)malloc(len * sizeof(wchar_t));
4123 MultiByteToWideChar(CP_UTF8, 0, str, len * sizeof(char), wstr, len);
4124 return wstr;
4125}
4126
4127static FILE *mz_fopen(const char *pFilename, const char *pMode) {
4128 wchar_t *wFilename = str2wstr(pFilename);
4129 wchar_t *wMode = str2wstr(pMode);
4130 FILE *pFile = _wfopen(wFilename, wMode);
4131
4132 free(wFilename);
4133 free(wMode);
4134
4135 return pFile;
4136}
4137
4138static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) {
4139 wchar_t *wPath = str2wstr(pPath);
4140 wchar_t *wMode = str2wstr(pMode);
4141 FILE *pFile = _wfreopen(wPath, wMode, pStream);
4142
4143 free(wPath);
4144 free(wMode);
4145
4146 return pFile;
4147}
4148
4149#ifndef MINIZ_NO_TIME
4150#include <sys/utime.h>
4151#endif
4152#define MZ_FILE FILE
4153#define MZ_FOPEN mz_fopen
4154#define MZ_FCLOSE fclose
4155#define MZ_FREAD fread
4156#define MZ_FWRITE fwrite
4157// ZIG_ANDROID_MOD: Zig's mingw64 doesn't have _ftelli64/_fseeki64
4158#if defined(__MINGW64__)
4159#define MZ_FTELL64 ftello
4160#define MZ_FSEEK64 fseeko
4161#else
4162#define MZ_FTELL64 _ftelli64
4163#define MZ_FSEEK64 _fseeki64
4164#endif
4165#define MZ_FILE_STAT_STRUCT _stat
4166#define MZ_FILE_STAT _stat
4167#define MZ_FFLUSH fflush
4168#define MZ_FREOPEN mz_freopen
4169#define MZ_DELETE_FILE remove
4170#elif defined(__MINGW32__)
4171#ifndef MINIZ_NO_TIME
4172#include <sys/utime.h>
4173#endif
4174#define MZ_FILE FILE
4175#define MZ_FOPEN(f, m) mz_fopen
4176#define MZ_FCLOSE fclose
4177#define MZ_FREAD fread
4178#define MZ_FWRITE fwrite
4179#define MZ_FTELL64 ftell
4180#define MZ_FSEEK64 fseek
4181#define MZ_FILE_STAT_STRUCT _stat
4182#define MZ_FILE_STAT _stat
4183#define MZ_FFLUSH fflush
4184#define MZ_FREOPEN(f, m, s) mz_freopen
4185#define MZ_DELETE_FILE remove
4186#elif defined(__TINYC__)
4187#ifndef MINIZ_NO_TIME
4188#include <sys/utime.h>
4189#endif
4190#define MZ_FILE FILE
4191#define MZ_FOPEN(f, m) fopen(f, m)
4192#define MZ_FCLOSE fclose
4193#define MZ_FREAD fread
4194#define MZ_FWRITE fwrite
4195#define MZ_FTELL64 ftell
4196#define MZ_FSEEK64 fseek
4197#define MZ_FILE_STAT_STRUCT stat
4198#define MZ_FILE_STAT stat
4199#define MZ_FFLUSH fflush
4200#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
4201#define MZ_DELETE_FILE remove
4202#elif defined(__GNUC__) && _LARGEFILE64_SOURCE
4203#ifndef MINIZ_NO_TIME
4204#include <utime.h>
4205#endif
4206#define MZ_FILE FILE
4207#define MZ_FOPEN(f, m) fopen64(f, m)
4208#define MZ_FCLOSE fclose
4209#define MZ_FREAD fread
4210#define MZ_FWRITE fwrite
4211#define MZ_FTELL64 ftello64
4212#define MZ_FSEEK64 fseeko64
4213#define MZ_FILE_STAT_STRUCT stat64
4214#define MZ_FILE_STAT stat64
4215#define MZ_FFLUSH fflush
4216#define MZ_FREOPEN(p, m, s) freopen64(p, m, s)
4217#define MZ_DELETE_FILE remove
4218#else
4219#ifndef MINIZ_NO_TIME
4220#include <utime.h>
4221#endif
4222#define MZ_FILE FILE
4223#define MZ_FOPEN(f, m) fopen(f, m)
4224#define MZ_FCLOSE fclose
4225#define MZ_FREAD fread
4226#define MZ_FWRITE fwrite
4227#if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L
4228#define MZ_FTELL64 ftello
4229#define MZ_FSEEK64 fseeko
4230#else
4231#define MZ_FTELL64 ftell
4232#define MZ_FSEEK64 fseek
4233#endif
4234#define MZ_FILE_STAT_STRUCT stat
4235#define MZ_FILE_STAT stat
4236#define MZ_FFLUSH fflush
4237#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
4238#define MZ_DELETE_FILE remove
4239#endif // #ifdef _MSC_VER
4240#endif // #ifdef MINIZ_NO_STDIO
4241
4242#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
4243
4244// Various ZIP archive enums. To completely avoid cross platform compiler
4245// alignment and platform endian issues, miniz.c doesn't use structs for any of
4246// this stuff.
4247enum {
4248 // ZIP archive identifiers and record sizes
4249 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50,
4250 MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50,
4251 MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
4252 MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
4253 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
4254 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
4255
4256 /* ZIP64 archive identifier and record sizes */
4257 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,
4258 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,
4259 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,
4260 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,
4261 MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,
4262 MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,
4263 MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,
4264 MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,
4265
4266 // Central directory header record offsets
4267 MZ_ZIP_CDH_SIG_OFS = 0,
4268 MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
4269 MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6,
4270 MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
4271 MZ_ZIP_CDH_METHOD_OFS = 10,
4272 MZ_ZIP_CDH_FILE_TIME_OFS = 12,
4273 MZ_ZIP_CDH_FILE_DATE_OFS = 14,
4274 MZ_ZIP_CDH_CRC32_OFS = 16,
4275 MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20,
4276 MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24,
4277 MZ_ZIP_CDH_FILENAME_LEN_OFS = 28,
4278 MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
4279 MZ_ZIP_CDH_COMMENT_LEN_OFS = 32,
4280 MZ_ZIP_CDH_DISK_START_OFS = 34,
4281 MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36,
4282 MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38,
4283 MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
4284 // Local directory header offsets
4285 MZ_ZIP_LDH_SIG_OFS = 0,
4286 MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4,
4287 MZ_ZIP_LDH_BIT_FLAG_OFS = 6,
4288 MZ_ZIP_LDH_METHOD_OFS = 8,
4289 MZ_ZIP_LDH_FILE_TIME_OFS = 10,
4290 MZ_ZIP_LDH_FILE_DATE_OFS = 12,
4291 MZ_ZIP_LDH_CRC32_OFS = 14,
4292 MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18,
4293 MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
4294 MZ_ZIP_LDH_FILENAME_LEN_OFS = 26,
4295 MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
4296 // End of central directory offsets
4297 MZ_ZIP_ECDH_SIG_OFS = 0,
4298 MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4,
4299 MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6,
4300 MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
4301 MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10,
4302 MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
4303 MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
4304 MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
4305
4306 /* ZIP64 End of central directory locator offsets */
4307 MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */
4308 MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */
4309 MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */
4310 MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */
4311
4312 /* ZIP64 End of central directory header offsets */
4313 MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */
4314 MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */
4315 MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */
4316 MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */
4317 MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */
4318 MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */
4319 MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */
4320 MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */
4321 MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */
4322 MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */
4323 MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,
4324 MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,
4325 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,
4326 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,
4327 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,
4328 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,
4329 MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11
4330};
4331
4332typedef struct {
4333 void *m_p;
4334 size_t m_size, m_capacity;
4335 mz_uint m_element_size;
4336} mz_zip_array;
4337
4338struct mz_zip_internal_state_tag {
4339 mz_zip_array m_central_dir;
4340 mz_zip_array m_central_dir_offsets;
4341 mz_zip_array m_sorted_central_dir_offsets;
4342
4343 /* The flags passed in when the archive is initially opened. */
4344 uint32_t m_init_flags;
4345
4346 /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc.
4347 */
4348 mz_bool m_zip64;
4349
4350 /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64
4351 * will also be slammed to true too, even if we didn't find a zip64 end of
4352 * central dir header, etc.) */
4353 mz_bool m_zip64_has_extended_info_fields;
4354
4355 /* These fields are used by the file, FILE, memory, and memory/heap read/write
4356 * helpers. */
4357 MZ_FILE *m_pFile;
4358 mz_uint64 m_file_archive_start_ofs;
4359
4360 void *m_pMem;
4361 size_t m_mem_size;
4362 size_t m_mem_capacity;
4363};
4364
4365#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \
4366 (array_ptr)->m_element_size = element_size
4367#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \
4368 ((element_type *)((array_ptr)->m_p))[index]
4369
4370static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip,
4371 mz_zip_array *pArray) {
4372 pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
4373 memset(pArray, 0, sizeof(mz_zip_array));
4374}
4375
4376static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip,
4377 mz_zip_array *pArray,
4378 size_t min_new_capacity,
4379 mz_uint growing) {
4380 void *pNew_p;
4381 size_t new_capacity = min_new_capacity;
4382 MZ_ASSERT(pArray->m_element_size);
4383 if (pArray->m_capacity >= min_new_capacity)
4384 return MZ_TRUE;
4385 if (growing) {
4386 new_capacity = MZ_MAX(1, pArray->m_capacity);
4387 while (new_capacity < min_new_capacity)
4388 new_capacity *= 2;
4389 }
4390 if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p,
4391 pArray->m_element_size, new_capacity)))
4392 return MZ_FALSE;
4393 pArray->m_p = pNew_p;
4394 pArray->m_capacity = new_capacity;
4395 return MZ_TRUE;
4396}
4397
4398static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip,
4399 mz_zip_array *pArray,
4400 size_t new_capacity,
4401 mz_uint growing) {
4402 if (new_capacity > pArray->m_capacity) {
4403 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))
4404 return MZ_FALSE;
4405 }
4406 return MZ_TRUE;
4407}
4408
4409static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip,
4410 mz_zip_array *pArray,
4411 size_t new_size,
4412 mz_uint growing) {
4413 if (new_size > pArray->m_capacity) {
4414 if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))
4415 return MZ_FALSE;
4416 }
4417 pArray->m_size = new_size;
4418 return MZ_TRUE;
4419}
4420
4421static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip,
4422 mz_zip_array *pArray,
4423 size_t n) {
4424 return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
4425}
4426
4427static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip,
4428 mz_zip_array *pArray,
4429 const void *pElements,
4430 size_t n) {
4431 if (0 == n)
4432 return MZ_TRUE;
4433 if (!pElements)
4434 return MZ_FALSE;
4435
4436 size_t orig_size = pArray->m_size;
4437 if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE))
4438 return MZ_FALSE;
4439 memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size,
4440 pElements, n * pArray->m_element_size);
4441 return MZ_TRUE;
4442}
4443
4444#ifndef MINIZ_NO_TIME
4445static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) {
4446 struct tm tm;
4447 memset(&tm, 0, sizeof(tm));
4448 tm.tm_isdst = -1;
4449 tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900;
4450 tm.tm_mon = ((dos_date >> 5) & 15) - 1;
4451 tm.tm_mday = dos_date & 31;
4452 tm.tm_hour = (dos_time >> 11) & 31;
4453 tm.tm_min = (dos_time >> 5) & 63;
4454 tm.tm_sec = (dos_time << 1) & 62;
4455 return mktime(&tm);
4456}
4457
4458#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
4459static void mz_zip_time_t_to_dos_time(time_t time, mz_uint16 *pDOS_time,
4460 mz_uint16 *pDOS_date) {
4461#ifdef _MSC_VER
4462 struct tm tm_struct;
4463 struct tm *tm = &tm_struct;
4464 errno_t err = localtime_s(tm, &time);
4465 if (err) {
4466 *pDOS_date = 0;
4467 *pDOS_time = 0;
4468 return;
4469 }
4470#else
4471 struct tm *tm = localtime(&time);
4472#endif /* #ifdef _MSC_VER */
4473
4474 *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) +
4475 ((tm->tm_sec) >> 1));
4476 *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) +
4477 ((tm->tm_mon + 1) << 5) + tm->tm_mday);
4478}
4479#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */
4480
4481#ifndef MINIZ_NO_STDIO
4482#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
4483static mz_bool mz_zip_get_file_modified_time(const char *pFilename,
4484 time_t *pTime) {
4485 struct MZ_FILE_STAT_STRUCT file_stat;
4486
4487 /* On Linux with x86 glibc, this call will fail on large files (I think >=
4488 * 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */
4489 if (MZ_FILE_STAT(pFilename, &file_stat) != 0)
4490 return MZ_FALSE;
4491
4492 *pTime = file_stat.st_mtime;
4493
4494 return MZ_TRUE;
4495}
4496#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/
4497
4498static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time,
4499 time_t modified_time) {
4500 struct utimbuf t;
4501
4502 memset(&t, 0, sizeof(t));
4503 t.actime = access_time;
4504 t.modtime = modified_time;
4505
4506 return !utime(pFilename, &t);
4507}
4508#endif /* #ifndef MINIZ_NO_STDIO */
4509#endif /* #ifndef MINIZ_NO_TIME */
4510
4511static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip,
4512 mz_zip_error err_num) {
4513 if (pZip)
4514 pZip->m_last_error = err_num;
4515 return MZ_FALSE;
4516}
4517
4518static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
4519 mz_uint32 flags) {
4520 (void)flags;
4521 if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
4522 return MZ_FALSE;
4523
4524 if (!pZip->m_pAlloc)
4525 pZip->m_pAlloc = def_alloc_func;
4526 if (!pZip->m_pFree)
4527 pZip->m_pFree = def_free_func;
4528 if (!pZip->m_pRealloc)
4529 pZip->m_pRealloc = def_realloc_func;
4530
4531 pZip->m_zip_mode = MZ_ZIP_MODE_READING;
4532 pZip->m_archive_size = 0;
4533 pZip->m_central_directory_file_ofs = 0;
4534 pZip->m_total_files = 0;
4535
4536 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
4537 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
4538 return MZ_FALSE;
4539 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
4540 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
4541 sizeof(mz_uint8));
4542 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
4543 sizeof(mz_uint32));
4544 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
4545 sizeof(mz_uint32));
4546 return MZ_TRUE;
4547}
4548
4549static MZ_FORCEINLINE mz_bool
4550mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array,
4551 const mz_zip_array *pCentral_dir_offsets,
4552 mz_uint l_index, mz_uint r_index) {
4553 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
4554 pCentral_dir_array, mz_uint8,
4555 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
4556 l_index)),
4557 *pE;
4558 const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(
4559 pCentral_dir_array, mz_uint8,
4560 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
4561 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS),
4562 r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);
4563 mz_uint8 l = 0, r = 0;
4564 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
4565 pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
4566 pE = pL + MZ_MIN(l_len, r_len);
4567 while (pL < pE) {
4568 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
4569 break;
4570 pL++;
4571 pR++;
4572 }
4573 return (pL == pE) ? (l_len < r_len) : (l < r);
4574}
4575
4576#define MZ_SWAP_UINT32(a, b) \
4577 do { \
4578 mz_uint32 t = a; \
4579 a = b; \
4580 b = t; \
4581 } \
4582 MZ_MACRO_END
4583
4584// Heap sort of lowercased filenames, used to help accelerate plain central
4585// directory searches by mz_zip_reader_locate_file(). (Could also use qsort(),
4586// but it could allocate memory.)
4587static void
4588mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) {
4589 mz_zip_internal_state *pState = pZip->m_pState;
4590 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
4591 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
4592 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
4593 &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
4594 const int size = pZip->m_total_files;
4595 int start = (size - 2) >> 1, end;
4596 while (start >= 0) {
4597 int child, root = start;
4598 for (;;) {
4599 if ((child = (root << 1) + 1) >= size)
4600 break;
4601 child +=
4602 (((child + 1) < size) &&
4603 (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4604 pIndices[child], pIndices[child + 1])));
4605 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4606 pIndices[root], pIndices[child]))
4607 break;
4608 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
4609 root = child;
4610 }
4611 start--;
4612 }
4613
4614 end = size - 1;
4615 while (end > 0) {
4616 int child, root = 0;
4617 MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
4618 for (;;) {
4619 if ((child = (root << 1) + 1) >= end)
4620 break;
4621 child +=
4622 (((child + 1) < end) &&
4623 mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4624 pIndices[child], pIndices[child + 1]));
4625 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets,
4626 pIndices[root], pIndices[child]))
4627 break;
4628 MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
4629 root = child;
4630 }
4631 end--;
4632 }
4633}
4634
4635static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip,
4636 mz_uint32 record_sig,
4637 mz_uint32 record_size,
4638 mz_int64 *pOfs) {
4639 mz_int64 cur_file_ofs;
4640 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
4641 mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
4642
4643 /* Basic sanity checks - reject files which are too small */
4644 if (pZip->m_archive_size < record_size)
4645 return MZ_FALSE;
4646
4647 /* Find the record by scanning the file from the end towards the beginning. */
4648 cur_file_ofs =
4649 MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
4650 for (;;) {
4651 int i,
4652 n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
4653
4654 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
4655 return MZ_FALSE;
4656
4657 for (i = n - 4; i >= 0; --i) {
4658 mz_uint s = MZ_READ_LE32(pBuf + i);
4659 if (s == record_sig) {
4660 if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)
4661 break;
4662 }
4663 }
4664
4665 if (i >= 0) {
4666 cur_file_ofs += i;
4667 break;
4668 }
4669
4670 /* Give up if we've searched the entire file, or we've gone back "too far"
4671 * (~64kb) */
4672 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
4673 (MZ_UINT16_MAX + record_size)))
4674 return MZ_FALSE;
4675
4676 cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
4677 }
4678
4679 *pOfs = cur_file_ofs;
4680 return MZ_TRUE;
4681}
4682
4683static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
4684 mz_uint flags) {
4685 mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0,
4686 cdir_disk_index = 0;
4687 mz_uint64 cdir_ofs = 0;
4688 mz_int64 cur_file_ofs = 0;
4689 const mz_uint8 *p;
4690
4691 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
4692 mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
4693 mz_bool sort_central_dir =
4694 ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
4695 mz_uint32 zip64_end_of_central_dir_locator_u32
4696 [(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) /
4697 sizeof(mz_uint32)];
4698 mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;
4699
4700 mz_uint32 zip64_end_of_central_dir_header_u32
4701 [(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
4702 sizeof(mz_uint32)];
4703 mz_uint8 *pZip64_end_of_central_dir =
4704 (mz_uint8 *)zip64_end_of_central_dir_header_u32;
4705
4706 mz_uint64 zip64_end_of_central_dir_ofs = 0;
4707
4708 /* Basic sanity checks - reject files which are too small, and check the first
4709 * 4 bytes of the file to make sure a local header is there. */
4710 if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
4711 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
4712
4713 if (!mz_zip_reader_locate_header_sig(
4714 pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG,
4715 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))
4716 return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);
4717
4718 /* Read and verify the end of central directory record. */
4719 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
4720 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
4721 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
4722 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
4723
4724 if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
4725 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
4726 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
4727
4728 if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE +
4729 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) {
4730 if (pZip->m_pRead(pZip->m_pIO_opaque,
4731 cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE,
4732 pZip64_locator,
4733 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ==
4734 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) {
4735 if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) ==
4736 MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) {
4737 zip64_end_of_central_dir_ofs = MZ_READ_LE64(
4738 pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);
4739 if (zip64_end_of_central_dir_ofs >
4740 (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
4741 return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
4742
4743 if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs,
4744 pZip64_end_of_central_dir,
4745 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ==
4746 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) {
4747 if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) ==
4748 MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) {
4749 pZip->m_pState->m_zip64 = MZ_TRUE;
4750 }
4751 }
4752 }
4753 }
4754 }
4755
4756 pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);
4757 cdir_entries_on_this_disk =
4758 MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
4759 num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
4760 cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
4761 cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);
4762 cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
4763
4764 if (pZip->m_pState->m_zip64) {
4765 mz_uint32 zip64_total_num_of_disks =
4766 MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);
4767 mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(
4768 pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);
4769 mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(
4770 pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
4771 mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(
4772 pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);
4773 mz_uint64 zip64_size_of_central_directory =
4774 MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);
4775
4776 if (zip64_size_of_end_of_central_dir_record <
4777 (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))
4778 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4779
4780 if (zip64_total_num_of_disks != 1U)
4781 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
4782
4783 /* Check for miniz's practical limits */
4784 if (zip64_cdir_total_entries > MZ_UINT32_MAX)
4785 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
4786
4787 pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;
4788
4789 if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)
4790 return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
4791
4792 cdir_entries_on_this_disk =
4793 (mz_uint32)zip64_cdir_total_entries_on_this_disk;
4794
4795 /* Check for miniz's current practical limits (sorry, this should be enough
4796 * for millions of files) */
4797 if (zip64_size_of_central_directory > MZ_UINT32_MAX)
4798 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
4799
4800 cdir_size = (mz_uint32)zip64_size_of_central_directory;
4801
4802 num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir +
4803 MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);
4804
4805 cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir +
4806 MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);
4807
4808 cdir_ofs =
4809 MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);
4810 }
4811
4812 if (pZip->m_total_files != cdir_entries_on_this_disk)
4813 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
4814
4815 if (((num_this_disk | cdir_disk_index) != 0) &&
4816 ((num_this_disk != 1) || (cdir_disk_index != 1)))
4817 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
4818
4819 if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
4820 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4821
4822 if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
4823 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4824
4825 pZip->m_central_directory_file_ofs = cdir_ofs;
4826
4827 if (pZip->m_total_files) {
4828 mz_uint i, n;
4829 /* Read the entire central directory into a heap block, and allocate another
4830 * heap block to hold the unsorted central dir file record offsets, and
4831 * possibly another to hold the sorted indices. */
4832 if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
4833 MZ_FALSE)) ||
4834 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
4835 pZip->m_total_files, MZ_FALSE)))
4836 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4837
4838 if (sort_central_dir) {
4839 if (!mz_zip_array_resize(pZip,
4840 &pZip->m_pState->m_sorted_central_dir_offsets,
4841 pZip->m_total_files, MZ_FALSE))
4842 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4843 }
4844
4845 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
4846 pZip->m_pState->m_central_dir.m_p,
4847 cdir_size) != cdir_size)
4848 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
4849
4850 /* Now create an index into the central directory file records, do some
4851 * basic sanity checking on each record */
4852 p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
4853 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
4854 mz_uint total_header_size, disk_index, bit_flags, filename_size,
4855 ext_data_size;
4856 mz_uint64 comp_size, decomp_size, local_header_ofs;
4857
4858 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
4859 (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
4860 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4861
4862 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
4863 i) =
4864 (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
4865
4866 if (sort_central_dir)
4867 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
4868 mz_uint32, i) = i;
4869
4870 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
4871 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
4872 local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
4873 filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
4874 ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
4875
4876 if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&
4877 (ext_data_size) &&
4878 (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) ==
4879 MZ_UINT32_MAX)) {
4880 /* Attempt to find zip64 extended information field in the entry's extra
4881 * data */
4882 mz_uint32 extra_size_remaining = ext_data_size;
4883
4884 if (extra_size_remaining) {
4885 const mz_uint8 *pExtra_data;
4886 void *buf = NULL;
4887
4888 if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size >
4889 n) {
4890 buf = MZ_MALLOC(ext_data_size);
4891 if (buf == NULL)
4892 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4893
4894 if (pZip->m_pRead(pZip->m_pIO_opaque,
4895 cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
4896 filename_size,
4897 buf, ext_data_size) != ext_data_size) {
4898 MZ_FREE(buf);
4899 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
4900 }
4901
4902 pExtra_data = (mz_uint8 *)buf;
4903 } else {
4904 pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
4905 }
4906
4907 do {
4908 mz_uint32 field_id;
4909 mz_uint32 field_data_size;
4910
4911 if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
4912 MZ_FREE(buf);
4913 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4914 }
4915
4916 field_id = MZ_READ_LE16(pExtra_data);
4917 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
4918
4919 if ((field_data_size + sizeof(mz_uint16) * 2) >
4920 extra_size_remaining) {
4921 MZ_FREE(buf);
4922 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4923 }
4924
4925 if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
4926 /* Ok, the archive didn't have any zip64 headers but it uses a
4927 * zip64 extended information field so mark it as zip64 anyway
4928 * (this can occur with infozip's zip util when it reads
4929 * compresses files from stdin). */
4930 pZip->m_pState->m_zip64 = MZ_TRUE;
4931 pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;
4932 break;
4933 }
4934
4935 pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
4936 extra_size_remaining =
4937 extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
4938 } while (extra_size_remaining);
4939
4940 MZ_FREE(buf);
4941 }
4942 }
4943
4944 /* I've seen archives that aren't marked as zip64 that uses zip64 ext
4945 * data, argh */
4946 if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) {
4947 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
4948 (decomp_size != comp_size)) ||
4949 (decomp_size && !comp_size))
4950 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4951 }
4952
4953 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
4954 if ((disk_index == MZ_UINT16_MAX) ||
4955 ((disk_index != num_this_disk) && (disk_index != 1)))
4956 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
4957
4958 if (comp_size != MZ_UINT32_MAX) {
4959 if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
4960 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
4961 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4962 }
4963
4964 bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
4965 if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)
4966 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
4967
4968 if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
4969 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
4970 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
4971 MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
4972 n)
4973 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
4974
4975 n -= total_header_size;
4976 p += total_header_size;
4977 }
4978 }
4979
4980 if (sort_central_dir)
4981 mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
4982
4983 return MZ_TRUE;
4984}
4985
4986mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size,
4987 mz_uint32 flags) {
4988 if ((!pZip) || (!pZip->m_pRead))
4989 return MZ_FALSE;
4990 if (!mz_zip_reader_init_internal(pZip, flags))
4991 return MZ_FALSE;
4992 pZip->m_archive_size = size;
4993 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
4994 mz_zip_reader_end(pZip);
4995 return MZ_FALSE;
4996 }
4997 return MZ_TRUE;
4998}
4999
5000static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs,
5001 void *pBuf, size_t n) {
5002 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5003 size_t s = (file_ofs >= pZip->m_archive_size)
5004 ? 0
5005 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
5006 memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
5007 return s;
5008}
5009
5010mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem,
5011 size_t size, mz_uint32 flags) {
5012 if (!mz_zip_reader_init_internal(pZip, flags))
5013 return MZ_FALSE;
5014 pZip->m_archive_size = size;
5015 pZip->m_pRead = mz_zip_mem_read_func;
5016 pZip->m_pIO_opaque = pZip;
5017#ifdef __cplusplus
5018 pZip->m_pState->m_pMem = const_cast<void *>(pMem);
5019#else
5020 pZip->m_pState->m_pMem = (void *)pMem;
5021#endif
5022 pZip->m_pState->m_mem_size = size;
5023 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
5024 mz_zip_reader_end(pZip);
5025 return MZ_FALSE;
5026 }
5027 return MZ_TRUE;
5028}
5029
5030#ifndef MINIZ_NO_STDIO
5031static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs,
5032 void *pBuf, size_t n) {
5033 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5034 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
5035 if (((mz_int64)file_ofs < 0) ||
5036 (((cur_ofs != (mz_int64)file_ofs)) &&
5037 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
5038 return 0;
5039 return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
5040}
5041
5042mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename,
5043 mz_uint32 flags) {
5044 mz_uint64 file_size;
5045 MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb");
5046 if (!pFile)
5047 return MZ_FALSE;
5048 if (MZ_FSEEK64(pFile, 0, SEEK_END)) {
5049 MZ_FCLOSE(pFile);
5050 return MZ_FALSE;
5051 }
5052 file_size = MZ_FTELL64(pFile);
5053 if (!mz_zip_reader_init_internal(pZip, flags)) {
5054 MZ_FCLOSE(pFile);
5055 return MZ_FALSE;
5056 }
5057 pZip->m_pRead = mz_zip_file_read_func;
5058 pZip->m_pIO_opaque = pZip;
5059 pZip->m_pState->m_pFile = pFile;
5060 pZip->m_archive_size = file_size;
5061 if (!mz_zip_reader_read_central_dir(pZip, flags)) {
5062 mz_zip_reader_end(pZip);
5063 return MZ_FALSE;
5064 }
5065 return MZ_TRUE;
5066}
5067#endif // #ifndef MINIZ_NO_STDIO
5068
5069mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) {
5070 return pZip ? pZip->m_total_files : 0;
5071}
5072
5073static MZ_FORCEINLINE const mz_uint8 *
5074mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) {
5075 if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) ||
5076 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5077 return NULL;
5078 return &MZ_ZIP_ARRAY_ELEMENT(
5079 &pZip->m_pState->m_central_dir, mz_uint8,
5080 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5081 file_index));
5082}
5083
5084mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip,
5085 mz_uint file_index) {
5086 mz_uint m_bit_flag;
5087 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5088 if (!p)
5089 return MZ_FALSE;
5090 m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
5091 return (m_bit_flag & 1);
5092}
5093
5094mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip,
5095 mz_uint file_index) {
5096 mz_uint filename_len, external_attr;
5097 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5098 if (!p)
5099 return MZ_FALSE;
5100
5101 // First see if the filename ends with a '/' character.
5102 filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5103 if (filename_len) {
5104 if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
5105 return MZ_TRUE;
5106 }
5107
5108 // Bugfix: This code was also checking if the internal attribute was non-zero,
5109 // which wasn't correct. Most/all zip writers (hopefully) set DOS
5110 // file/directory attributes in the low 16-bits, so check for the DOS
5111 // directory flag and ignore the source OS ID in the created by field.
5112 // FIXME: Remove this check? Is it necessary - we already check the filename.
5113 external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
5114 if ((external_attr & 0x10) != 0)
5115 return MZ_TRUE;
5116
5117 return MZ_FALSE;
5118}
5119
5120mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
5121 mz_zip_archive_file_stat *pStat) {
5122 mz_uint n;
5123 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5124 if ((!p) || (!pStat))
5125 return MZ_FALSE;
5126
5127 // Unpack the central directory record.
5128 pStat->m_file_index = file_index;
5129 pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(
5130 &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
5131 pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
5132 pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
5133 pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
5134 pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
5135#ifndef MINIZ_NO_TIME
5136 pStat->m_time =
5137 mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS),
5138 MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));
5139#endif
5140 pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
5141 pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5142 pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5143 pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
5144 pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
5145 pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
5146
5147 // Copy as much of the filename and comment as possible.
5148 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5149 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
5150 memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
5151 pStat->m_filename[n] = '\0';
5152
5153 n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
5154 n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
5155 pStat->m_comment_size = n;
5156 memcpy(pStat->m_comment,
5157 p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
5158 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
5159 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
5160 n);
5161 pStat->m_comment[n] = '\0';
5162
5163 return MZ_TRUE;
5164}
5165
5166mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index,
5167 char *pFilename, mz_uint filename_buf_size) {
5168 mz_uint n;
5169 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5170 if (!p) {
5171 if (filename_buf_size)
5172 pFilename[0] = '\0';
5173 return 0;
5174 }
5175 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5176 if (filename_buf_size) {
5177 n = MZ_MIN(n, filename_buf_size - 1);
5178 memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
5179 pFilename[n] = '\0';
5180 }
5181 return n + 1;
5182}
5183
5184static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA,
5185 const char *pB,
5186 mz_uint len,
5187 mz_uint flags) {
5188 mz_uint i;
5189 if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE)
5190 return 0 == memcmp(pA, pB, len);
5191 for (i = 0; i < len; ++i)
5192 if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i]))
5193 return MZ_FALSE;
5194 return MZ_TRUE;
5195}
5196
5197static MZ_FORCEINLINE int
5198mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array,
5199 const mz_zip_array *pCentral_dir_offsets,
5200 mz_uint l_index, const char *pR, mz_uint r_len) {
5201 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(
5202 pCentral_dir_array, mz_uint8,
5203 MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32,
5204 l_index)),
5205 *pE;
5206 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5207 mz_uint8 l = 0, r = 0;
5208 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5209 pE = pL + MZ_MIN(l_len, r_len);
5210 while (pL < pE) {
5211 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
5212 break;
5213 pL++;
5214 pR++;
5215 }
5216 return (pL == pE) ? (int)(l_len - r_len) : (l - r);
5217}
5218
5219static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip,
5220 const char *pFilename) {
5221 mz_zip_internal_state *pState = pZip->m_pState;
5222 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
5223 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
5224 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(
5225 &pState->m_sorted_central_dir_offsets, mz_uint32, 0);
5226 const int size = pZip->m_total_files;
5227 const mz_uint filename_len = (mz_uint)strlen(pFilename);
5228 int l = 0, h = size - 1;
5229 while (l <= h) {
5230 int m = (l + h) >> 1, file_index = pIndices[m],
5231 comp =
5232 mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets,
5233 file_index, pFilename, filename_len);
5234 if (!comp)
5235 return file_index;
5236 else if (comp < 0)
5237 l = m + 1;
5238 else
5239 h = m - 1;
5240 }
5241 return -1;
5242}
5243
5244int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName,
5245 const char *pComment, mz_uint flags) {
5246 mz_uint file_index;
5247 size_t name_len, comment_len;
5248 if ((!pZip) || (!pZip->m_pState) || (!pName) ||
5249 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5250 return -1;
5251 if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) &&
5252 (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))
5253 return mz_zip_reader_locate_file_binary_search(pZip, pName);
5254 name_len = strlen(pName);
5255 if (name_len > 0xFFFF)
5256 return -1;
5257 comment_len = pComment ? strlen(pComment) : 0;
5258 if (comment_len > 0xFFFF)
5259 return -1;
5260 for (file_index = 0; file_index < pZip->m_total_files; file_index++) {
5261 const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(
5262 &pZip->m_pState->m_central_dir, mz_uint8,
5263 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
5264 file_index));
5265 mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
5266 const char *pFilename =
5267 (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5268 if (filename_len < name_len)
5269 continue;
5270 if (comment_len) {
5271 mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS),
5272 file_comment_len =
5273 MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);
5274 const char *pFile_comment = pFilename + filename_len + file_extra_len;
5275 if ((file_comment_len != comment_len) ||
5276 (!mz_zip_reader_string_equal(pComment, pFile_comment,
5277 file_comment_len, flags)))
5278 continue;
5279 }
5280 if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) {
5281 int ofs = filename_len - 1;
5282 do {
5283 if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') ||
5284 (pFilename[ofs] == ':'))
5285 break;
5286 } while (--ofs >= 0);
5287 ofs++;
5288 pFilename += ofs;
5289 filename_len -= ofs;
5290 }
5291 if ((filename_len == name_len) &&
5292 (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags)))
5293 return file_index;
5294 }
5295 return -1;
5296}
5297
5298mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip,
5299 mz_uint file_index, void *pBuf,
5300 size_t buf_size, mz_uint flags,
5301 void *pUser_read_buf,
5302 size_t user_read_buf_size) {
5303 int status = TINFL_STATUS_DONE;
5304 mz_uint64 needed_size, cur_file_ofs, comp_remaining,
5305 out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
5306 mz_zip_archive_file_stat file_stat;
5307 void *pRead_buf;
5308 mz_uint32
5309 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5310 sizeof(mz_uint32)];
5311 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
5312 tinfl_decompressor inflator;
5313
5314 if ((buf_size) && (!pBuf))
5315 return MZ_FALSE;
5316
5317 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
5318 return MZ_FALSE;
5319
5320 // Empty file, or a directory (but not always a directory - I've seen odd zips
5321 // with directories that have compressed data which inflates to 0 bytes)
5322 if (!file_stat.m_comp_size)
5323 return MZ_TRUE;
5324
5325 // Entry is a subdirectory (I've seen old zips with dir entries which have
5326 // compressed deflate data which inflates to 0 bytes, but these entries claim
5327 // to uncompress to 512 bytes in the headers). I'm torn how to handle this
5328 // case - should it fail instead?
5329 if (mz_zip_reader_is_file_a_directory(pZip, file_index))
5330 return MZ_TRUE;
5331
5332 // Encryption and patch files are not supported.
5333 if (file_stat.m_bit_flag & (1 | 32))
5334 return MZ_FALSE;
5335
5336 // This function only supports stored and deflate.
5337 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
5338 (file_stat.m_method != MZ_DEFLATED))
5339 return MZ_FALSE;
5340
5341 // Ensure supplied output buffer is large enough.
5342 needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size
5343 : file_stat.m_uncomp_size;
5344 if (buf_size < needed_size)
5345 return MZ_FALSE;
5346
5347 // Read and parse the local directory entry.
5348 cur_file_ofs = file_stat.m_local_header_ofs;
5349 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
5350 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
5351 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
5352 return MZ_FALSE;
5353 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
5354 return MZ_FALSE;
5355
5356 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5357 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
5358 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
5359 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
5360 return MZ_FALSE;
5361
5362 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
5363 // The file is stored or the caller has requested the compressed data.
5364 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
5365 (size_t)needed_size) != needed_size)
5366 return MZ_FALSE;
5367 return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) ||
5368 (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
5369 (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32);
5370 }
5371
5372 // Decompress the file either directly from memory or from a file input
5373 // buffer.
5374 tinfl_init(&inflator);
5375
5376 if (pZip->m_pState->m_pMem) {
5377 // Read directly from the archive in memory.
5378 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
5379 read_buf_size = read_buf_avail = file_stat.m_comp_size;
5380 comp_remaining = 0;
5381 } else if (pUser_read_buf) {
5382 // Use a user provided read buffer.
5383 if (!user_read_buf_size)
5384 return MZ_FALSE;
5385 pRead_buf = (mz_uint8 *)pUser_read_buf;
5386 read_buf_size = user_read_buf_size;
5387 read_buf_avail = 0;
5388 comp_remaining = file_stat.m_comp_size;
5389 } else {
5390 // Temporarily allocate a read buffer.
5391 read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);
5392 if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
5393 return MZ_FALSE;
5394
5395 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5396 (size_t)read_buf_size)))
5397 return MZ_FALSE;
5398 read_buf_avail = 0;
5399 comp_remaining = file_stat.m_comp_size;
5400 }
5401
5402 do {
5403 size_t in_buf_size,
5404 out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
5405 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
5406 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5407 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5408 (size_t)read_buf_avail) != read_buf_avail) {
5409 status = TINFL_STATUS_FAILED;
5410 break;
5411 }
5412 cur_file_ofs += read_buf_avail;
5413 comp_remaining -= read_buf_avail;
5414 read_buf_ofs = 0;
5415 }
5416 in_buf_size = (size_t)read_buf_avail;
5417 status = tinfl_decompress(
5418 &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
5419 (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size,
5420 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF |
5421 (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));
5422 read_buf_avail -= in_buf_size;
5423 read_buf_ofs += in_buf_size;
5424 out_buf_ofs += out_buf_size;
5425 } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
5426
5427 if (status == TINFL_STATUS_DONE) {
5428 // Make sure the entire file was decompressed, and check its CRC.
5429 if ((out_buf_ofs != file_stat.m_uncomp_size) ||
5430 (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf,
5431 (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32))
5432 status = TINFL_STATUS_FAILED;
5433 }
5434
5435 if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
5436 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
5437
5438 return status == TINFL_STATUS_DONE;
5439}
5440
5441mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(
5442 mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size,
5443 mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) {
5444 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5445 if (file_index < 0)
5446 return MZ_FALSE;
5447 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size,
5448 flags, pUser_read_buf,
5449 user_read_buf_size);
5450}
5451
5452mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index,
5453 void *pBuf, size_t buf_size,
5454 mz_uint flags) {
5455 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size,
5456 flags, NULL, 0);
5457}
5458
5459mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip,
5460 const char *pFilename, void *pBuf,
5461 size_t buf_size, mz_uint flags) {
5462 return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf,
5463 buf_size, flags, NULL, 0);
5464}
5465
5466void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index,
5467 size_t *pSize, mz_uint flags) {
5468 mz_uint64 comp_size, uncomp_size, alloc_size;
5469 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
5470 void *pBuf;
5471
5472 if (pSize)
5473 *pSize = 0;
5474 if (!p)
5475 return NULL;
5476
5477 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5478 uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5479
5480 alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
5481 if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
5482 return NULL;
5483 if (NULL ==
5484 (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))
5485 return NULL;
5486
5487 if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size,
5488 flags)) {
5489 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
5490 return NULL;
5491 }
5492
5493 if (pSize)
5494 *pSize = (size_t)alloc_size;
5495 return pBuf;
5496}
5497
5498void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip,
5499 const char *pFilename, size_t *pSize,
5500 mz_uint flags) {
5501 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5502 if (file_index < 0) {
5503 if (pSize)
5504 *pSize = 0;
5505 return MZ_FALSE;
5506 }
5507 return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
5508}
5509
5510mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip,
5511 mz_uint file_index,
5512 mz_file_write_func pCallback,
5513 void *pOpaque, mz_uint flags) {
5514 int status = TINFL_STATUS_DONE;
5515 mz_uint file_crc32 = MZ_CRC32_INIT;
5516 mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining,
5517 out_buf_ofs = 0, cur_file_ofs;
5518 mz_zip_archive_file_stat file_stat;
5519 void *pRead_buf = NULL;
5520 void *pWrite_buf = NULL;
5521 mz_uint32
5522 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
5523 sizeof(mz_uint32)];
5524 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
5525
5526 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
5527 return MZ_FALSE;
5528
5529 // Empty file, or a directory (but not always a directory - I've seen odd zips
5530 // with directories that have compressed data which inflates to 0 bytes)
5531 if (!file_stat.m_comp_size)
5532 return MZ_TRUE;
5533
5534 // Entry is a subdirectory (I've seen old zips with dir entries which have
5535 // compressed deflate data which inflates to 0 bytes, but these entries claim
5536 // to uncompress to 512 bytes in the headers). I'm torn how to handle this
5537 // case - should it fail instead?
5538 if (mz_zip_reader_is_file_a_directory(pZip, file_index))
5539 return MZ_TRUE;
5540
5541 // Encryption and patch files are not supported.
5542 if (file_stat.m_bit_flag & (1 | 32))
5543 return MZ_FALSE;
5544
5545 // This function only supports stored and deflate.
5546 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) &&
5547 (file_stat.m_method != MZ_DEFLATED))
5548 return MZ_FALSE;
5549
5550 // Read and parse the local directory entry.
5551 cur_file_ofs = file_stat.m_local_header_ofs;
5552 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header,
5553 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
5554 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
5555 return MZ_FALSE;
5556 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
5557 return MZ_FALSE;
5558
5559 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
5560 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
5561 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
5562 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
5563 return MZ_FALSE;
5564
5565 // Decompress the file either directly from memory or from a file input
5566 // buffer.
5567 if (pZip->m_pState->m_pMem) {
5568 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
5569 read_buf_size = read_buf_avail = file_stat.m_comp_size;
5570 comp_remaining = 0;
5571 } else {
5572 read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);
5573 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5574 (size_t)read_buf_size)))
5575 return MZ_FALSE;
5576 read_buf_avail = 0;
5577 comp_remaining = file_stat.m_comp_size;
5578 }
5579
5580 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) {
5581 // The file is stored or the caller has requested the compressed data.
5582 if (pZip->m_pState->m_pMem) {
5583 if (((sizeof(size_t) == sizeof(mz_uint32))) &&
5584 (file_stat.m_comp_size > 0xFFFFFFFF))
5585 return MZ_FALSE;
5586
5587 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
5588 (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)
5589 status = TINFL_STATUS_FAILED;
5590 else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
5591 file_crc32 =
5592 (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf,
5593 (size_t)file_stat.m_comp_size);
5594 // cur_file_ofs += file_stat.m_comp_size;
5595 out_buf_ofs += file_stat.m_comp_size;
5596 // comp_remaining = 0;
5597 } else {
5598 while (comp_remaining) {
5599 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5600 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5601 (size_t)read_buf_avail) != read_buf_avail) {
5602 status = TINFL_STATUS_FAILED;
5603 break;
5604 }
5605
5606 if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
5607 file_crc32 = (mz_uint32)mz_crc32(
5608 file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
5609
5610 if (pCallback(pOpaque, out_buf_ofs, pRead_buf,
5611 (size_t)read_buf_avail) != read_buf_avail) {
5612 status = TINFL_STATUS_FAILED;
5613 break;
5614 }
5615 cur_file_ofs += read_buf_avail;
5616 out_buf_ofs += read_buf_avail;
5617 comp_remaining -= read_buf_avail;
5618 }
5619 }
5620 } else {
5621 tinfl_decompressor inflator;
5622 tinfl_init(&inflator);
5623
5624 if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
5625 TINFL_LZ_DICT_SIZE)))
5626 status = TINFL_STATUS_FAILED;
5627 else {
5628 do {
5629 mz_uint8 *pWrite_buf_cur =
5630 (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5631 size_t in_buf_size,
5632 out_buf_size =
5633 TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
5634 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) {
5635 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
5636 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf,
5637 (size_t)read_buf_avail) != read_buf_avail) {
5638 status = TINFL_STATUS_FAILED;
5639 break;
5640 }
5641 cur_file_ofs += read_buf_avail;
5642 comp_remaining -= read_buf_avail;
5643 read_buf_ofs = 0;
5644 }
5645
5646 in_buf_size = (size_t)read_buf_avail;
5647 status = tinfl_decompress(
5648 &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size,
5649 (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size,
5650 comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
5651 read_buf_avail -= in_buf_size;
5652 read_buf_ofs += in_buf_size;
5653
5654 if (out_buf_size) {
5655 if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) !=
5656 out_buf_size) {
5657 status = TINFL_STATUS_FAILED;
5658 break;
5659 }
5660 file_crc32 =
5661 (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
5662 if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) {
5663 status = TINFL_STATUS_FAILED;
5664 break;
5665 }
5666 }
5667 } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) ||
5668 (status == TINFL_STATUS_HAS_MORE_OUTPUT));
5669 }
5670 }
5671
5672 if ((status == TINFL_STATUS_DONE) &&
5673 (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) {
5674 // Make sure the entire file was decompressed, and check its CRC.
5675 if ((out_buf_ofs != file_stat.m_uncomp_size) ||
5676 (file_crc32 != file_stat.m_crc32))
5677 status = TINFL_STATUS_FAILED;
5678 }
5679
5680 if (!pZip->m_pState->m_pMem)
5681 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
5682 if (pWrite_buf)
5683 pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
5684
5685 return status == TINFL_STATUS_DONE;
5686}
5687
5688mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip,
5689 const char *pFilename,
5690 mz_file_write_func pCallback,
5691 void *pOpaque, mz_uint flags) {
5692 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
5693 if (file_index < 0)
5694 return MZ_FALSE;
5695 return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque,
5696 flags);
5697}
5698
5699#ifndef MINIZ_NO_STDIO
5700static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs,
5701 const void *pBuf, size_t n) {
5702 (void)ofs;
5703 return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque);
5704}
5705
5706mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index,
5707 const char *pDst_filename,
5708 mz_uint flags) {
5709 mz_bool status;
5710 mz_zip_archive_file_stat file_stat;
5711 MZ_FILE *pFile;
5712 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
5713 return MZ_FALSE;
5714
5715 pFile = MZ_FOPEN(pDst_filename, "wb");
5716 if (!pFile)
5717 return MZ_FALSE;
5718 status = mz_zip_reader_extract_to_callback(
5719 pZip, file_index, mz_zip_file_write_callback, pFile, flags);
5720 if (MZ_FCLOSE(pFile) == EOF)
5721 return MZ_FALSE;
5722#ifndef MINIZ_NO_TIME
5723 if (status) {
5724 mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
5725 }
5726#endif
5727
5728 return status;
5729}
5730#endif // #ifndef MINIZ_NO_STDIO
5731
5732mz_bool mz_zip_reader_end(mz_zip_archive *pZip) {
5733 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
5734 (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5735 return MZ_FALSE;
5736
5737 mz_zip_internal_state *pState = pZip->m_pState;
5738 pZip->m_pState = NULL;
5739 mz_zip_array_clear(pZip, &pState->m_central_dir);
5740 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
5741 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
5742
5743#ifndef MINIZ_NO_STDIO
5744 if (pState->m_pFile) {
5745 MZ_FCLOSE(pState->m_pFile);
5746 pState->m_pFile = NULL;
5747 }
5748#endif // #ifndef MINIZ_NO_STDIO
5749
5750 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
5751
5752 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
5753
5754 return MZ_TRUE;
5755}
5756
5757#ifndef MINIZ_NO_STDIO
5758mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip,
5759 const char *pArchive_filename,
5760 const char *pDst_filename,
5761 mz_uint flags) {
5762 int file_index =
5763 mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags);
5764 if (file_index < 0)
5765 return MZ_FALSE;
5766 return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
5767}
5768#endif
5769
5770// ------------------- .ZIP archive writing
5771
5772#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
5773
5774static void mz_write_le16(mz_uint8 *p, mz_uint16 v) {
5775 p[0] = (mz_uint8)v;
5776 p[1] = (mz_uint8)(v >> 8);
5777}
5778static void mz_write_le32(mz_uint8 *p, mz_uint32 v) {
5779 p[0] = (mz_uint8)v;
5780 p[1] = (mz_uint8)(v >> 8);
5781 p[2] = (mz_uint8)(v >> 16);
5782 p[3] = (mz_uint8)(v >> 24);
5783}
5784#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
5785#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
5786
5787mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) {
5788 if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) ||
5789 (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
5790 return MZ_FALSE;
5791
5792 if (pZip->m_file_offset_alignment) {
5793 // Ensure user specified file offset alignment is a power of 2.
5794 if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
5795 return MZ_FALSE;
5796 }
5797
5798 if (!pZip->m_pAlloc)
5799 pZip->m_pAlloc = def_alloc_func;
5800 if (!pZip->m_pFree)
5801 pZip->m_pFree = def_free_func;
5802 if (!pZip->m_pRealloc)
5803 pZip->m_pRealloc = def_realloc_func;
5804
5805 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
5806 pZip->m_archive_size = existing_size;
5807 pZip->m_central_directory_file_ofs = 0;
5808 pZip->m_total_files = 0;
5809
5810 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(
5811 pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
5812 return MZ_FALSE;
5813 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
5814 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
5815 sizeof(mz_uint8));
5816 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
5817 sizeof(mz_uint32));
5818 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
5819 sizeof(mz_uint32));
5820 return MZ_TRUE;
5821}
5822
5823static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs,
5824 const void *pBuf, size_t n) {
5825 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5826 mz_zip_internal_state *pState = pZip->m_pState;
5827 mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
5828
5829 if ((!n) ||
5830 ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
5831 return 0;
5832
5833 if (new_size > pState->m_mem_capacity) {
5834 void *pNew_block;
5835 size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity);
5836 while (new_capacity < new_size)
5837 new_capacity *= 2;
5838 if (NULL == (pNew_block = pZip->m_pRealloc(
5839 pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))
5840 return 0;
5841 pState->m_pMem = pNew_block;
5842 pState->m_mem_capacity = new_capacity;
5843 }
5844 memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
5845 pState->m_mem_size = (size_t)new_size;
5846 return n;
5847}
5848
5849mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip,
5850 size_t size_to_reserve_at_beginning,
5851 size_t initial_allocation_size) {
5852 pZip->m_pWrite = mz_zip_heap_write_func;
5853 pZip->m_pIO_opaque = pZip;
5854 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning))
5855 return MZ_FALSE;
5856 if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size,
5857 size_to_reserve_at_beginning))) {
5858 if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(
5859 pZip->m_pAlloc_opaque, 1, initial_allocation_size))) {
5860 mz_zip_writer_end(pZip);
5861 return MZ_FALSE;
5862 }
5863 pZip->m_pState->m_mem_capacity = initial_allocation_size;
5864 }
5865 return MZ_TRUE;
5866}
5867
5868#ifndef MINIZ_NO_STDIO
5869static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs,
5870 const void *pBuf, size_t n) {
5871 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
5872 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
5873 if (((mz_int64)file_ofs < 0) ||
5874 (((cur_ofs != (mz_int64)file_ofs)) &&
5875 (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
5876 return 0;
5877 return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
5878}
5879
5880mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename,
5881 mz_uint64 size_to_reserve_at_beginning) {
5882 MZ_FILE *pFile;
5883 pZip->m_pWrite = mz_zip_file_write_func;
5884 pZip->m_pIO_opaque = pZip;
5885 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning))
5886 return MZ_FALSE;
5887 if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) {
5888 mz_zip_writer_end(pZip);
5889 return MZ_FALSE;
5890 }
5891 pZip->m_pState->m_pFile = pFile;
5892 if (size_to_reserve_at_beginning) {
5893 mz_uint64 cur_ofs = 0;
5894 char buf[4096];
5895 MZ_CLEAR_OBJ(buf);
5896 do {
5897 size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
5898 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) {
5899 mz_zip_writer_end(pZip);
5900 return MZ_FALSE;
5901 }
5902 cur_ofs += n;
5903 size_to_reserve_at_beginning -= n;
5904 } while (size_to_reserve_at_beginning);
5905 }
5906 return MZ_TRUE;
5907}
5908#endif // #ifndef MINIZ_NO_STDIO
5909
5910mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip,
5911 const char *pFilename) {
5912 mz_zip_internal_state *pState;
5913 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
5914 return MZ_FALSE;
5915 // No sense in trying to write to an archive that's already at the support max
5916 // size
5917 if ((pZip->m_total_files == 0xFFFF) ||
5918 ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
5919 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
5920 return MZ_FALSE;
5921
5922 pState = pZip->m_pState;
5923
5924 if (pState->m_pFile) {
5925#ifdef MINIZ_NO_STDIO
5926 pFilename;
5927 return MZ_FALSE;
5928#else
5929 // Archive is being read from stdio - try to reopen as writable.
5930 if (pZip->m_pIO_opaque != pZip)
5931 return MZ_FALSE;
5932 if (!pFilename)
5933 return MZ_FALSE;
5934 pZip->m_pWrite = mz_zip_file_write_func;
5935 if (NULL ==
5936 (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) {
5937 // The mz_zip_archive is now in a bogus state because pState->m_pFile is
5938 // NULL, so just close it.
5939 mz_zip_reader_end(pZip);
5940 return MZ_FALSE;
5941 }
5942#endif // #ifdef MINIZ_NO_STDIO
5943 } else if (pState->m_pMem) {
5944 // Archive lives in a memory block. Assume it's from the heap that we can
5945 // resize using the realloc callback.
5946 if (pZip->m_pIO_opaque != pZip)
5947 return MZ_FALSE;
5948 pState->m_mem_capacity = pState->m_mem_size;
5949 pZip->m_pWrite = mz_zip_heap_write_func;
5950 }
5951 // Archive is being read via a user provided read function - make sure the
5952 // user has specified a write function too.
5953 else if (!pZip->m_pWrite)
5954 return MZ_FALSE;
5955
5956 // Start writing new files at the archive's current central directory
5957 // location.
5958 pZip->m_archive_size = pZip->m_central_directory_file_ofs;
5959 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
5960 pZip->m_central_directory_file_ofs = 0;
5961
5962 return MZ_TRUE;
5963}
5964
5965mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name,
5966 const void *pBuf, size_t buf_size,
5967 mz_uint level_and_flags) {
5968 return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0,
5969 level_and_flags, 0, 0);
5970}
5971
5972typedef struct {
5973 mz_zip_archive *m_pZip;
5974 mz_uint64 m_cur_archive_file_ofs;
5975 mz_uint64 m_comp_size;
5976} mz_zip_writer_add_state;
5977
5978static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len,
5979 void *pUser) {
5980 mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
5981 if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque,
5982 pState->m_cur_archive_file_ofs, pBuf,
5983 len) != len)
5984 return MZ_FALSE;
5985 pState->m_cur_archive_file_ofs += len;
5986 pState->m_comp_size += len;
5987 return MZ_TRUE;
5988}
5989
5990static mz_bool mz_zip_writer_create_local_dir_header(
5991 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
5992 mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
5993 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
5994 mz_uint16 dos_time, mz_uint16 dos_date) {
5995 (void)pZip;
5996 memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
5997 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
5998 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
5999 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
6000 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
6001 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
6002 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
6003 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
6004 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size);
6005 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
6006 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
6007 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
6008 return MZ_TRUE;
6009}
6010
6011static mz_bool mz_zip_writer_create_central_dir_header(
6012 mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size,
6013 mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size,
6014 mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method,
6015 mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,
6016 mz_uint64 local_header_ofs, mz_uint32 ext_attributes) {
6017 (void)pZip;
6018 mz_uint16 version_made_by = 10 * MZ_VER_MAJOR + MZ_VER_MINOR;
6019 version_made_by |= (MZ_PLATFORM << 8);
6020
6021 memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
6022 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
6023 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_MADE_BY_OFS, version_made_by);
6024 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
6025 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
6026 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
6027 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
6028 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
6029 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
6030 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size);
6031 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
6032 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
6033 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
6034 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
6035 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
6036 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs);
6037 return MZ_TRUE;
6038}
6039
6040static mz_bool mz_zip_writer_add_to_central_dir(
6041 mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size,
6042 const void *pExtra, mz_uint16 extra_size, const void *pComment,
6043 mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size,
6044 mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags,
6045 mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs,
6046 mz_uint32 ext_attributes) {
6047 mz_zip_internal_state *pState = pZip->m_pState;
6048 mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
6049 size_t orig_central_dir_size = pState->m_central_dir.m_size;
6050 mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
6051
6052 // No zip64 support yet
6053 if ((local_header_ofs > 0xFFFFFFFF) ||
6054 (((mz_uint64)pState->m_central_dir.m_size +
6055 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size +
6056 comment_size) > 0xFFFFFFFF))
6057 return MZ_FALSE;
6058
6059 if (!mz_zip_writer_create_central_dir_header(
6060 pZip, central_dir_header, filename_size, extra_size, comment_size,
6061 uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time,
6062 dos_date, local_header_ofs, ext_attributes))
6063 return MZ_FALSE;
6064
6065 if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header,
6066 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
6067 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename,
6068 filename_size)) ||
6069 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra,
6070 extra_size)) ||
6071 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment,
6072 comment_size)) ||
6073 (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets,
6074 &central_dir_ofs, 1))) {
6075 // Try to push the central directory array back into its original state.
6076 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6077 MZ_FALSE);
6078 return MZ_FALSE;
6079 }
6080
6081 return MZ_TRUE;
6082}
6083
6084static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) {
6085 // Basic ZIP archive filename validity checks: Valid filenames cannot start
6086 // with a forward slash, cannot contain a drive letter, and cannot use
6087 // DOS-style backward slashes.
6088 if (*pArchive_name == '/')
6089 return MZ_FALSE;
6090 while (*pArchive_name) {
6091 if ((*pArchive_name == '\\') || (*pArchive_name == ':'))
6092 return MZ_FALSE;
6093 pArchive_name++;
6094 }
6095 return MZ_TRUE;
6096}
6097
6098static mz_uint
6099mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) {
6100 mz_uint32 n;
6101 if (!pZip->m_file_offset_alignment)
6102 return 0;
6103 n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
6104 return (pZip->m_file_offset_alignment - n) &
6105 (pZip->m_file_offset_alignment - 1);
6106}
6107
6108static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip,
6109 mz_uint64 cur_file_ofs, mz_uint32 n) {
6110 char buf[4096];
6111 memset(buf, 0, MZ_MIN(sizeof(buf), n));
6112 while (n) {
6113 mz_uint32 s = MZ_MIN(sizeof(buf), n);
6114 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
6115 return MZ_FALSE;
6116 cur_file_ofs += s;
6117 n -= s;
6118 }
6119 return MZ_TRUE;
6120}
6121
6122mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip,
6123 const char *pArchive_name, const void *pBuf,
6124 size_t buf_size, const void *pComment,
6125 mz_uint16 comment_size,
6126 mz_uint level_and_flags, mz_uint64 uncomp_size,
6127 mz_uint32 uncomp_crc32) {
6128 mz_uint32 ext_attributes = 0;
6129 mz_uint16 method = 0, dos_time = 0, dos_date = 0;
6130 mz_uint level, num_alignment_padding_bytes;
6131 mz_uint64 local_dir_header_ofs, cur_archive_file_ofs, comp_size = 0;
6132 size_t archive_name_size;
6133 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
6134 tdefl_compressor *pComp = NULL;
6135 mz_bool store_data_uncompressed;
6136 mz_zip_internal_state *pState;
6137
6138 if ((int)level_and_flags < 0)
6139 level_and_flags = MZ_DEFAULT_LEVEL;
6140 level = level_and_flags & 0xF;
6141 store_data_uncompressed =
6142 ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
6143
6144 if ((!pZip) || (!pZip->m_pState) ||
6145 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) ||
6146 (!pArchive_name) || ((comment_size) && (!pComment)) ||
6147 (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION))
6148 return MZ_FALSE;
6149
6150 local_dir_header_ofs = cur_archive_file_ofs = pZip->m_archive_size;
6151 pState = pZip->m_pState;
6152
6153 if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
6154 return MZ_FALSE;
6155 // No zip64 support yet
6156 if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF))
6157 return MZ_FALSE;
6158 if (!mz_zip_writer_validate_archive_name(pArchive_name))
6159 return MZ_FALSE;
6160
6161#ifndef MINIZ_NO_TIME
6162 {
6163 time_t cur_time;
6164 time(&cur_time);
6165 mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date);
6166 }
6167#endif // #ifndef MINIZ_NO_TIME
6168
6169 archive_name_size = strlen(pArchive_name);
6170 if (archive_name_size > 0xFFFF)
6171 return MZ_FALSE;
6172
6173 num_alignment_padding_bytes =
6174 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6175
6176 // no zip64 support yet
6177 if ((pZip->m_total_files == 0xFFFF) ||
6178 ((pZip->m_archive_size + num_alignment_padding_bytes +
6179 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6180 comment_size + archive_name_size) > 0xFFFFFFFF))
6181 return MZ_FALSE;
6182
6183 if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) {
6184 // Set DOS Subdirectory attribute bit.
6185 ext_attributes |= 0x10;
6186 // Subdirectories cannot contain data.
6187 if ((buf_size) || (uncomp_size))
6188 return MZ_FALSE;
6189 }
6190
6191 // Try to do any allocations before writing to the archive, so if an
6192 // allocation fails the file remains unmodified. (A good idea if we're doing
6193 // an in-place modification.)
6194 if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir,
6195 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6196 archive_name_size + comment_size)) ||
6197 (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))
6198 return MZ_FALSE;
6199
6200 if ((!store_data_uncompressed) && (buf_size)) {
6201 if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(
6202 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
6203 return MZ_FALSE;
6204 }
6205
6206 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs,
6207 num_alignment_padding_bytes +
6208 sizeof(local_dir_header))) {
6209 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6210 return MZ_FALSE;
6211 }
6212 local_dir_header_ofs += num_alignment_padding_bytes;
6213 if (pZip->m_file_offset_alignment) {
6214 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6215 0);
6216 }
6217 cur_archive_file_ofs +=
6218 num_alignment_padding_bytes + sizeof(local_dir_header);
6219
6220 MZ_CLEAR_OBJ(local_dir_header);
6221 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
6222 archive_name_size) != archive_name_size) {
6223 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6224 return MZ_FALSE;
6225 }
6226 cur_archive_file_ofs += archive_name_size;
6227
6228 if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) {
6229 uncomp_crc32 =
6230 (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
6231 uncomp_size = buf_size;
6232 if (uncomp_size <= 3) {
6233 level = 0;
6234 store_data_uncompressed = MZ_TRUE;
6235 }
6236 }
6237
6238 if (store_data_uncompressed) {
6239 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf,
6240 buf_size) != buf_size) {
6241 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6242 return MZ_FALSE;
6243 }
6244
6245 cur_archive_file_ofs += buf_size;
6246 comp_size = buf_size;
6247
6248 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
6249 method = MZ_DEFLATED;
6250 } else if (buf_size) {
6251 mz_zip_writer_add_state state;
6252
6253 state.m_pZip = pZip;
6254 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
6255 state.m_comp_size = 0;
6256
6257 if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
6258 tdefl_create_comp_flags_from_zip_params(
6259 level, -15, MZ_DEFAULT_STRATEGY)) !=
6260 TDEFL_STATUS_OKAY) ||
6261 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) !=
6262 TDEFL_STATUS_DONE)) {
6263 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6264 return MZ_FALSE;
6265 }
6266
6267 comp_size = state.m_comp_size;
6268 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
6269
6270 method = MZ_DEFLATED;
6271 }
6272
6273 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6274 pComp = NULL;
6275
6276 // no zip64 support yet
6277 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
6278 return MZ_FALSE;
6279
6280 if (!mz_zip_writer_create_local_dir_header(
6281 pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size,
6282 comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
6283 return MZ_FALSE;
6284
6285 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header,
6286 sizeof(local_dir_header)) != sizeof(local_dir_header))
6287 return MZ_FALSE;
6288
6289 if (!mz_zip_writer_add_to_central_dir(
6290 pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment,
6291 comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0,
6292 dos_time, dos_date, local_dir_header_ofs, ext_attributes))
6293 return MZ_FALSE;
6294
6295 pZip->m_total_files++;
6296 pZip->m_archive_size = cur_archive_file_ofs;
6297
6298 return MZ_TRUE;
6299}
6300
6301#ifndef MINIZ_NO_STDIO
6302mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name,
6303 const char *pSrc_filename, const void *pComment,
6304 mz_uint16 comment_size, mz_uint level_and_flags,
6305 mz_uint32 ext_attributes) {
6306 mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
6307 mz_uint16 method = 0, dos_time = 0, dos_date = 0;
6308#ifndef MINIZ_NO_TIME
6309 time_t file_modified_time;
6310#endif
6311
6312 mz_uint64 local_dir_header_ofs, cur_archive_file_ofs, uncomp_size = 0,
6313 comp_size = 0;
6314 size_t archive_name_size;
6315 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
6316 MZ_FILE *pSrc_file = NULL;
6317
6318 if ((int)level_and_flags < 0)
6319 level_and_flags = MZ_DEFAULT_LEVEL;
6320 level = level_and_flags & 0xF;
6321
6322 if ((!pZip) || (!pZip->m_pState) ||
6323 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) ||
6324 ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
6325 return MZ_FALSE;
6326
6327 local_dir_header_ofs = cur_archive_file_ofs = pZip->m_archive_size;
6328
6329 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
6330 return MZ_FALSE;
6331 if (!mz_zip_writer_validate_archive_name(pArchive_name))
6332 return MZ_FALSE;
6333
6334 archive_name_size = strlen(pArchive_name);
6335 if (archive_name_size > 0xFFFF)
6336 return MZ_FALSE;
6337
6338 num_alignment_padding_bytes =
6339 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6340
6341 // no zip64 support yet
6342 if ((pZip->m_total_files == 0xFFFF) ||
6343 ((pZip->m_archive_size + num_alignment_padding_bytes +
6344 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
6345 comment_size + archive_name_size) > 0xFFFFFFFF))
6346 return MZ_FALSE;
6347
6348#ifndef MINIZ_NO_TIME
6349 memset(&file_modified_time, 0, sizeof(file_modified_time));
6350 if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time))
6351 return MZ_FALSE;
6352 mz_zip_time_t_to_dos_time(file_modified_time, &dos_time, &dos_date);
6353#endif
6354
6355 pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
6356 if (!pSrc_file)
6357 return MZ_FALSE;
6358 MZ_FSEEK64(pSrc_file, 0, SEEK_END);
6359 uncomp_size = MZ_FTELL64(pSrc_file);
6360 MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
6361
6362 if (uncomp_size > 0xFFFFFFFF) {
6363 // No zip64 support yet
6364 MZ_FCLOSE(pSrc_file);
6365 return MZ_FALSE;
6366 }
6367 if (uncomp_size <= 3)
6368 level = 0;
6369
6370 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs,
6371 num_alignment_padding_bytes +
6372 sizeof(local_dir_header))) {
6373 MZ_FCLOSE(pSrc_file);
6374 return MZ_FALSE;
6375 }
6376 local_dir_header_ofs += num_alignment_padding_bytes;
6377 if (pZip->m_file_offset_alignment) {
6378 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6379 0);
6380 }
6381 cur_archive_file_ofs +=
6382 num_alignment_padding_bytes + sizeof(local_dir_header);
6383
6384 MZ_CLEAR_OBJ(local_dir_header);
6385 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name,
6386 archive_name_size) != archive_name_size) {
6387 MZ_FCLOSE(pSrc_file);
6388 return MZ_FALSE;
6389 }
6390 cur_archive_file_ofs += archive_name_size;
6391
6392 if (uncomp_size) {
6393 mz_uint64 uncomp_remaining = uncomp_size;
6394 void *pRead_buf =
6395 pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
6396 if (!pRead_buf) {
6397 MZ_FCLOSE(pSrc_file);
6398 return MZ_FALSE;
6399 }
6400
6401 if (!level) {
6402 while (uncomp_remaining) {
6403 mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
6404 if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) ||
6405 (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf,
6406 n) != n)) {
6407 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6408 MZ_FCLOSE(pSrc_file);
6409 return MZ_FALSE;
6410 }
6411 uncomp_crc32 =
6412 (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
6413 uncomp_remaining -= n;
6414 cur_archive_file_ofs += n;
6415 }
6416 comp_size = uncomp_size;
6417 } else {
6418 mz_bool result = MZ_FALSE;
6419 mz_zip_writer_add_state state;
6420 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(
6421 pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
6422 if (!pComp) {
6423 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6424 MZ_FCLOSE(pSrc_file);
6425 return MZ_FALSE;
6426 }
6427
6428 state.m_pZip = pZip;
6429 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
6430 state.m_comp_size = 0;
6431
6432 if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state,
6433 tdefl_create_comp_flags_from_zip_params(
6434 level, -15, MZ_DEFAULT_STRATEGY)) !=
6435 TDEFL_STATUS_OKAY) {
6436 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6437 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6438 MZ_FCLOSE(pSrc_file);
6439 return MZ_FALSE;
6440 }
6441
6442 for (;;) {
6443 size_t in_buf_size =
6444 (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE);
6445 tdefl_status status;
6446
6447 if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size)
6448 break;
6449
6450 uncomp_crc32 = (mz_uint32)mz_crc32(
6451 uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
6452 uncomp_remaining -= in_buf_size;
6453
6454 status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size,
6455 uncomp_remaining ? TDEFL_NO_FLUSH
6456 : TDEFL_FINISH);
6457 if (status == TDEFL_STATUS_DONE) {
6458 result = MZ_TRUE;
6459 break;
6460 } else if (status != TDEFL_STATUS_OKAY)
6461 break;
6462 }
6463
6464 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
6465
6466 if (!result) {
6467 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6468 MZ_FCLOSE(pSrc_file);
6469 return MZ_FALSE;
6470 }
6471
6472 comp_size = state.m_comp_size;
6473 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
6474
6475 method = MZ_DEFLATED;
6476 }
6477
6478 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6479 }
6480
6481 MZ_FCLOSE(pSrc_file);
6482 pSrc_file = NULL;
6483
6484 // no zip64 support yet
6485 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
6486 return MZ_FALSE;
6487
6488 if (!mz_zip_writer_create_local_dir_header(
6489 pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size,
6490 comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
6491 return MZ_FALSE;
6492
6493 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header,
6494 sizeof(local_dir_header)) != sizeof(local_dir_header))
6495 return MZ_FALSE;
6496
6497 if (!mz_zip_writer_add_to_central_dir(
6498 pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment,
6499 comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0,
6500 dos_time, dos_date, local_dir_header_ofs, ext_attributes))
6501 return MZ_FALSE;
6502
6503 pZip->m_total_files++;
6504 pZip->m_archive_size = cur_archive_file_ofs;
6505
6506 return MZ_TRUE;
6507}
6508#endif // #ifndef MINIZ_NO_STDIO
6509
6510mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip,
6511 mz_zip_archive *pSource_zip,
6512 mz_uint file_index) {
6513 mz_uint n, bit_flags, num_alignment_padding_bytes;
6514 mz_uint64 comp_bytes_remaining, local_dir_header_ofs;
6515 mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
6516 mz_uint32
6517 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
6518 sizeof(mz_uint32)];
6519 mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
6520 mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
6521 size_t orig_central_dir_size;
6522 mz_zip_internal_state *pState;
6523 void *pBuf;
6524 const mz_uint8 *pSrc_central_header;
6525
6526 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
6527 return MZ_FALSE;
6528 if (NULL ==
6529 (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index)))
6530 return MZ_FALSE;
6531 pState = pZip->m_pState;
6532
6533 num_alignment_padding_bytes =
6534 mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
6535
6536 // no zip64 support yet
6537 if ((pZip->m_total_files == 0xFFFF) ||
6538 ((pZip->m_archive_size + num_alignment_padding_bytes +
6539 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) >
6540 0xFFFFFFFF))
6541 return MZ_FALSE;
6542
6543 cur_src_file_ofs =
6544 MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
6545 cur_dst_file_ofs = pZip->m_archive_size;
6546
6547 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs,
6548 pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
6549 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
6550 return MZ_FALSE;
6551 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
6552 return MZ_FALSE;
6553 cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
6554
6555 if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs,
6556 num_alignment_padding_bytes))
6557 return MZ_FALSE;
6558 cur_dst_file_ofs += num_alignment_padding_bytes;
6559 local_dir_header_ofs = cur_dst_file_ofs;
6560 if (pZip->m_file_offset_alignment) {
6561 MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) ==
6562 0);
6563 }
6564
6565 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header,
6566 MZ_ZIP_LOCAL_DIR_HEADER_SIZE) !=
6567 MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
6568 return MZ_FALSE;
6569 cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
6570
6571 n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) +
6572 MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
6573 comp_bytes_remaining =
6574 n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
6575
6576 if (NULL ==
6577 (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
6578 (size_t)MZ_MAX(sizeof(mz_uint32) * 4,
6579 MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE,
6580 comp_bytes_remaining)))))
6581 return MZ_FALSE;
6582
6583 while (comp_bytes_remaining) {
6584 n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining);
6585 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
6586 n) != n) {
6587 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6588 return MZ_FALSE;
6589 }
6590 cur_src_file_ofs += n;
6591
6592 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
6593 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6594 return MZ_FALSE;
6595 }
6596 cur_dst_file_ofs += n;
6597
6598 comp_bytes_remaining -= n;
6599 }
6600
6601 bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
6602 if (bit_flags & 8) {
6603 // Copy data descriptor
6604 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf,
6605 sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) {
6606 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6607 return MZ_FALSE;
6608 }
6609
6610 n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3);
6611 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) {
6612 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6613 return MZ_FALSE;
6614 }
6615
6616 // cur_src_file_ofs += n;
6617 cur_dst_file_ofs += n;
6618 }
6619 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6620
6621 // no zip64 support yet
6622 if (cur_dst_file_ofs > 0xFFFFFFFF)
6623 return MZ_FALSE;
6624
6625 orig_central_dir_size = pState->m_central_dir.m_size;
6626
6627 memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
6628 MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS,
6629 local_dir_header_ofs);
6630 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header,
6631 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
6632 return MZ_FALSE;
6633
6634 n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
6635 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
6636 MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
6637 if (!mz_zip_array_push_back(
6638 pZip, &pState->m_central_dir,
6639 pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) {
6640 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6641 MZ_FALSE);
6642 return MZ_FALSE;
6643 }
6644
6645 if (pState->m_central_dir.m_size > 0xFFFFFFFF)
6646 return MZ_FALSE;
6647 n = (mz_uint32)orig_central_dir_size;
6648 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) {
6649 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size,
6650 MZ_FALSE);
6651 return MZ_FALSE;
6652 }
6653
6654 pZip->m_total_files++;
6655 pZip->m_archive_size = cur_dst_file_ofs;
6656
6657 return MZ_TRUE;
6658}
6659
6660mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) {
6661 mz_zip_internal_state *pState;
6662 mz_uint64 central_dir_ofs, central_dir_size;
6663 mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE];
6664
6665 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
6666 return MZ_FALSE;
6667
6668 pState = pZip->m_pState;
6669
6670 // no zip64 support yet
6671 if ((pZip->m_total_files > 0xFFFF) ||
6672 ((pZip->m_archive_size + pState->m_central_dir.m_size +
6673 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
6674 return MZ_FALSE;
6675
6676 central_dir_ofs = 0;
6677 central_dir_size = 0;
6678 if (pZip->m_total_files) {
6679 // Write central directory
6680 central_dir_ofs = pZip->m_archive_size;
6681 central_dir_size = pState->m_central_dir.m_size;
6682 pZip->m_central_directory_file_ofs = central_dir_ofs;
6683 if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs,
6684 pState->m_central_dir.m_p,
6685 (size_t)central_dir_size) != central_dir_size)
6686 return MZ_FALSE;
6687 pZip->m_archive_size += central_dir_size;
6688 }
6689
6690 // Write end of central directory record
6691 MZ_CLEAR_OBJ(hdr);
6692 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS,
6693 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
6694 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS,
6695 pZip->m_total_files);
6696 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
6697 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size);
6698 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs);
6699
6700 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr,
6701 sizeof(hdr)) != sizeof(hdr))
6702 return MZ_FALSE;
6703#ifndef MINIZ_NO_STDIO
6704 if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))
6705 return MZ_FALSE;
6706#endif // #ifndef MINIZ_NO_STDIO
6707
6708 pZip->m_archive_size += sizeof(hdr);
6709
6710 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
6711 return MZ_TRUE;
6712}
6713
6714mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf,
6715 size_t *pSize) {
6716 if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize))
6717 return MZ_FALSE;
6718 if (pZip->m_pWrite != mz_zip_heap_write_func)
6719 return MZ_FALSE;
6720 if (!mz_zip_writer_finalize_archive(pZip))
6721 return MZ_FALSE;
6722
6723 *pBuf = pZip->m_pState->m_pMem;
6724 *pSize = pZip->m_pState->m_mem_size;
6725 pZip->m_pState->m_pMem = NULL;
6726 pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
6727 return MZ_TRUE;
6728}
6729
6730mz_bool mz_zip_writer_end(mz_zip_archive *pZip) {
6731 mz_zip_internal_state *pState;
6732 mz_bool status = MZ_TRUE;
6733 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) ||
6734 ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) &&
6735 (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)))
6736 return MZ_FALSE;
6737
6738 pState = pZip->m_pState;
6739 pZip->m_pState = NULL;
6740 mz_zip_array_clear(pZip, &pState->m_central_dir);
6741 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
6742 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
6743
6744#ifndef MINIZ_NO_STDIO
6745 if (pState->m_pFile) {
6746 MZ_FCLOSE(pState->m_pFile);
6747 pState->m_pFile = NULL;
6748 }
6749#endif // #ifndef MINIZ_NO_STDIO
6750
6751 if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) {
6752 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
6753 pState->m_pMem = NULL;
6754 }
6755
6756 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
6757 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
6758 return status;
6759}
6760
6761#ifndef MINIZ_NO_STDIO
6762mz_bool mz_zip_add_mem_to_archive_file_in_place(
6763 const char *pZip_filename, const char *pArchive_name, const void *pBuf,
6764 size_t buf_size, const void *pComment, mz_uint16 comment_size,
6765 mz_uint level_and_flags) {
6766 mz_bool status, created_new_archive = MZ_FALSE;
6767 mz_zip_archive zip_archive;
6768 struct MZ_FILE_STAT_STRUCT file_stat;
6769 MZ_CLEAR_OBJ(zip_archive);
6770 if ((int)level_and_flags < 0)
6771 level_and_flags = MZ_DEFAULT_LEVEL;
6772 if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) ||
6773 ((comment_size) && (!pComment)) ||
6774 ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
6775 return MZ_FALSE;
6776 if (!mz_zip_writer_validate_archive_name(pArchive_name))
6777 return MZ_FALSE;
6778 if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) {
6779 // Create a new archive.
6780 if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0))
6781 return MZ_FALSE;
6782 created_new_archive = MZ_TRUE;
6783 } else {
6784 // Append to an existing archive.
6785 if (!mz_zip_reader_init_file(&zip_archive, pZip_filename,
6786 level_and_flags |
6787 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
6788 return MZ_FALSE;
6789 if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) {
6790 mz_zip_reader_end(&zip_archive);
6791 return MZ_FALSE;
6792 }
6793 }
6794 status =
6795 mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size,
6796 pComment, comment_size, level_and_flags, 0, 0);
6797 // Always finalize, even if adding failed for some reason, so we have a valid
6798 // central directory. (This may not always succeed, but we can try.)
6799 if (!mz_zip_writer_finalize_archive(&zip_archive))
6800 status = MZ_FALSE;
6801 if (!mz_zip_writer_end(&zip_archive))
6802 status = MZ_FALSE;
6803 if ((!status) && (created_new_archive)) {
6804 // It's a new archive and something went wrong, so just delete it.
6805 int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
6806 (void)ignoredStatus;
6807 }
6808 return status;
6809}
6810
6811void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
6812 const char *pArchive_name,
6813 size_t *pSize, mz_uint flags) {
6814 int file_index;
6815 mz_zip_archive zip_archive;
6816 void *p = NULL;
6817
6818 if (pSize)
6819 *pSize = 0;
6820
6821 if ((!pZip_filename) || (!pArchive_name))
6822 return NULL;
6823
6824 MZ_CLEAR_OBJ(zip_archive);
6825 if (!mz_zip_reader_init_file(&zip_archive, pZip_filename,
6826 flags |
6827 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
6828 return NULL;
6829
6830 if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL,
6831 flags)) >= 0)
6832 p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
6833
6834 mz_zip_reader_end(&zip_archive);
6835 return p;
6836}
6837
6838#endif // #ifndef MINIZ_NO_STDIO
6839
6840#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
6841
6842#endif // #ifndef MINIZ_NO_ARCHIVE_APIS
6843
6844#ifdef __cplusplus
6845}
6846#endif
6847
6848#endif // MINIZ_HEADER_FILE_ONLY
6849
6850/*
6851 This is free and unencumbered software released into the public domain.
6852
6853 Anyone is free to copy, modify, publish, use, compile, sell, or
6854 distribute this software, either in source code form or as a compiled
6855 binary, for any purpose, commercial or non-commercial, and by any
6856 means.
6857
6858 In jurisdictions that recognize copyright laws, the author or authors
6859 of this software dedicate any and all copyright interest in the
6860 software to the public domain. We make this dedication for the benefit
6861 of the public at large and to the detriment of our heirs and
6862 successors. We intend this dedication to be an overt act of
6863 relinquishment in perpetuity of all present and future rights to this
6864 software under copyright law.
6865
6866 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
6867 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
6868 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
6869 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
6870 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
6871 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
6872 OTHER DEALINGS IN THE SOFTWARE.
6873
6874 For more information, please refer to <http://unlicense.org/>
6875*/
test/standalone/issue_9812/vendor/kuba-zip/zip.c deleted-1622
...@@ -1,1622 +0,0 @@
1/*
2 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
3 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
5 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
6 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
7 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
8 * OTHER DEALINGS IN THE SOFTWARE.
9 */
10#define __STDC_WANT_LIB_EXT1__ 1
11
12#include <errno.h>
13#include <sys/stat.h>
14#include <time.h>
15
16#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
17 defined(__MINGW32__)
18/* Win32, DOS, MSVC, MSVS */
19#include <direct.h>
20
21#define MKDIR(DIRNAME) _mkdir(DIRNAME)
22#define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL)
23#define HAS_DEVICE(P) \
24 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \
25 (P)[1] == ':')
26#define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0)
27
28#else
29
30#include <unistd.h> // needed for symlink()
31
32#define MKDIR(DIRNAME) mkdir(DIRNAME, 0755)
33#define STRCLONE(STR) ((STR) ? strdup(STR) : NULL)
34
35#endif
36
37#ifdef __MINGW32__
38#include <sys/types.h>
39#include <unistd.h>
40#endif
41
42#include "miniz.h"
43#include "zip.h"
44
45#ifdef _MSC_VER
46#include <io.h>
47
48#define ftruncate(fd, sz) (-(_chsize_s((fd), (sz)) != 0))
49#define fileno _fileno
50#endif
51
52#ifndef HAS_DEVICE
53#define HAS_DEVICE(P) 0
54#endif
55
56#ifndef FILESYSTEM_PREFIX_LEN
57#define FILESYSTEM_PREFIX_LEN(P) 0
58#endif
59
60#ifndef ISSLASH
61#define ISSLASH(C) ((C) == '/' || (C) == '\\')
62#endif
63
64#define CLEANUP(ptr) \
65 do { \
66 if (ptr) { \
67 free((void *)ptr); \
68 ptr = NULL; \
69 } \
70 } while (0)
71
72struct zip_entry_t {
73 int index;
74 char *name;
75 mz_uint64 uncomp_size;
76 mz_uint64 comp_size;
77 mz_uint32 uncomp_crc32;
78 mz_uint64 offset;
79 mz_uint8 header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
80 mz_uint64 header_offset;
81 mz_uint16 method;
82 mz_zip_writer_add_state state;
83 tdefl_compressor comp;
84 mz_uint32 external_attr;
85 time_t m_time;
86};
87
88struct zip_t {
89 mz_zip_archive archive;
90 mz_uint level;
91 struct zip_entry_t entry;
92};
93
94enum zip_modify_t {
95 MZ_KEEP = 0,
96 MZ_DELETE = 1,
97 MZ_MOVE = 2,
98};
99
100struct zip_entry_mark_t {
101 int file_index;
102 enum zip_modify_t type;
103 mz_uint64 m_local_header_ofs;
104 mz_uint64 lf_length;
105};
106
107static const char *const zip_errlist[30] = {
108 NULL,
109 "not initialized\0",
110 "invalid entry name\0",
111 "entry not found\0",
112 "invalid zip mode\0",
113 "invalid compression level\0",
114 "no zip 64 support\0",
115 "memset error\0",
116 "cannot write data to entry\0",
117 "cannot initialize tdefl compressor\0",
118 "invalid index\0",
119 "header not found\0",
120 "cannot flush tdefl buffer\0",
121 "cannot write entry header\0",
122 "cannot create entry header\0",
123 "cannot write to central dir\0",
124 "cannot open file\0",
125 "invalid entry type\0",
126 "extracting data using no memory allocation\0",
127 "file not found\0",
128 "no permission\0",
129 "out of memory\0",
130 "invalid zip archive name\0",
131 "make dir error\0",
132 "symlink error\0",
133 "close archive error\0",
134 "capacity size too small\0",
135 "fseek error\0",
136 "fread error\0",
137 "fwrite error\0",
138};
139
140const char *zip_strerror(int errnum) {
141 errnum = -errnum;
142 if (errnum <= 0 || errnum >= 30) {
143 return NULL;
144 }
145
146 return zip_errlist[errnum];
147}
148
149static const char *zip_basename(const char *name) {
150 char const *p;
151 char const *base = name += FILESYSTEM_PREFIX_LEN(name);
152 int all_slashes = 1;
153
154 for (p = name; *p; p++) {
155 if (ISSLASH(*p))
156 base = p + 1;
157 else
158 all_slashes = 0;
159 }
160
161 /* If NAME is all slashes, arrange to return `/'. */
162 if (*base == '\0' && ISSLASH(*name) && all_slashes)
163 --base;
164
165 return base;
166}
167
168static int zip_mkpath(char *path) {
169 char *p;
170 char npath[MAX_PATH + 1];
171 int len = 0;
172 int has_device = HAS_DEVICE(path);
173
174 memset(npath, 0, MAX_PATH + 1);
175 if (has_device) {
176 // only on windows
177 npath[0] = path[0];
178 npath[1] = path[1];
179 len = 2;
180 }
181 for (p = path + len; *p && len < MAX_PATH; p++) {
182 if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) {
183#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
184 defined(__MINGW32__)
185#else
186 if ('\\' == *p) {
187 *p = '/';
188 }
189#endif
190
191 if (MKDIR(npath) == -1) {
192 if (errno != EEXIST) {
193 return ZIP_EMKDIR;
194 }
195 }
196 }
197 npath[len++] = *p;
198 }
199
200 return 0;
201}
202
203static char *zip_strrpl(const char *str, size_t n, char oldchar, char newchar) {
204 char c;
205 size_t i;
206 char *rpl = (char *)calloc((1 + n), sizeof(char));
207 char *begin = rpl;
208 if (!rpl) {
209 return NULL;
210 }
211
212 for (i = 0; (i < n) && (c = *str++); ++i) {
213 if (c == oldchar) {
214 c = newchar;
215 }
216 *rpl++ = c;
217 }
218
219 return begin;
220}
221
222static char *zip_name_normalize(char *name, char *const nname, size_t len) {
223 size_t offn = 0;
224 size_t offnn = 0, ncpy = 0;
225
226 if (name == NULL || nname == NULL || len <= 0) {
227 return NULL;
228 }
229 // skip trailing '/'
230 while (ISSLASH(*name))
231 name++;
232
233 for (; offn < len; offn++) {
234 if (ISSLASH(name[offn])) {
235 if (ncpy > 0 && strcmp(&nname[offnn], ".\0") &&
236 strcmp(&nname[offnn], "..\0")) {
237 offnn += ncpy;
238 nname[offnn++] = name[offn]; // append '/'
239 }
240 ncpy = 0;
241 } else {
242 nname[offnn + ncpy] = name[offn];
243 ncpy++;
244 }
245 }
246
247 // at the end, extra check what we've already copied
248 if (ncpy == 0 || !strcmp(&nname[offnn], ".\0") ||
249 !strcmp(&nname[offnn], "..\0")) {
250 nname[offnn] = 0;
251 }
252 return nname;
253}
254
255static mz_bool zip_name_match(const char *name1, const char *name2) {
256 int len2 = strlen(name2);
257 char *nname2 = zip_strrpl(name2, len2, '\\', '/');
258 if (!nname2) {
259 return MZ_FALSE;
260 }
261
262 mz_bool res = (strcmp(name1, nname2) == 0) ? MZ_TRUE : MZ_FALSE;
263 CLEANUP(nname2);
264 return res;
265}
266
267static int zip_archive_truncate(mz_zip_archive *pzip) {
268 mz_zip_internal_state *pState = pzip->m_pState;
269 mz_uint64 file_size = pzip->m_archive_size;
270 if ((pzip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) {
271 return 0;
272 }
273 if (pzip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED) {
274 if (pState->m_pFile) {
275 int fd = fileno(pState->m_pFile);
276 return ftruncate(fd, file_size);
277 }
278 }
279 return 0;
280}
281
282static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir,
283 int (*on_extract)(const char *filename,
284 void *arg),
285 void *arg) {
286 int err = 0;
287 mz_uint i, n;
288 char path[MAX_PATH + 1];
289 char symlink_to[MAX_PATH + 1];
290 mz_zip_archive_file_stat info;
291 size_t dirlen = 0;
292 mz_uint32 xattr = 0;
293
294 memset(path, 0, sizeof(path));
295 memset(symlink_to, 0, sizeof(symlink_to));
296
297 dirlen = strlen(dir);
298 if (dirlen + 1 > MAX_PATH) {
299 return ZIP_EINVENTNAME;
300 }
301
302 memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat));
303
304#if defined(_MSC_VER)
305 strcpy_s(path, MAX_PATH, dir);
306#else
307 strcpy(path, dir);
308#endif
309
310 if (!ISSLASH(path[dirlen - 1])) {
311#if defined(_WIN32) || defined(__WIN32__)
312 path[dirlen] = '\\';
313#else
314 path[dirlen] = '/';
315#endif
316 ++dirlen;
317 }
318
319 // Get and print information about each file in the archive.
320 n = mz_zip_reader_get_num_files(zip_archive);
321 for (i = 0; i < n; ++i) {
322 if (!mz_zip_reader_file_stat(zip_archive, i, &info)) {
323 // Cannot get information about zip archive;
324 err = ZIP_ENOENT;
325 goto out;
326 }
327
328 if (!zip_name_normalize(info.m_filename, info.m_filename,
329 strlen(info.m_filename))) {
330 // Cannot normalize file name;
331 err = ZIP_EINVENTNAME;
332 goto out;
333 }
334#if defined(_MSC_VER)
335 strncpy_s(&path[dirlen], MAX_PATH - dirlen, info.m_filename,
336 MAX_PATH - dirlen);
337#else
338 strncpy(&path[dirlen], info.m_filename, MAX_PATH - dirlen);
339#endif
340 err = zip_mkpath(path);
341 if (err < 0) {
342 // Cannot make a path
343 goto out;
344 }
345
346 if ((((info.m_version_made_by >> 8) == 3) ||
347 ((info.m_version_made_by >> 8) ==
348 19)) // if zip is produced on Unix or macOS (3 and 19 from
349 // section 4.4.2.2 of zip standard)
350 && info.m_external_attr &
351 (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40
352 // is directory)
353#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
354 defined(__MINGW32__)
355#else
356 if (info.m_uncomp_size > MAX_PATH ||
357 !mz_zip_reader_extract_to_mem_no_alloc(zip_archive, i, symlink_to,
358 MAX_PATH, 0, NULL, 0)) {
359 err = ZIP_EMEMNOALLOC;
360 goto out;
361 }
362 symlink_to[info.m_uncomp_size] = '\0';
363 if (symlink(symlink_to, path) != 0) {
364 err = ZIP_ESYMLINK;
365 goto out;
366 }
367#endif
368 } else {
369 if (!mz_zip_reader_is_file_a_directory(zip_archive, i)) {
370 if (!mz_zip_reader_extract_to_file(zip_archive, i, path, 0)) {
371 // Cannot extract zip archive to file
372 err = ZIP_ENOFILE;
373 goto out;
374 }
375 }
376
377#if defined(_MSC_VER)
378 (void)xattr; // unused
379#else
380 xattr = (info.m_external_attr >> 16) & 0xFFFF;
381 if (xattr > 0) {
382 if (chmod(path, (mode_t)xattr) < 0) {
383 err = ZIP_ENOPERM;
384 goto out;
385 }
386 }
387#endif
388 }
389
390 if (on_extract) {
391 if (on_extract(path, arg) < 0) {
392 goto out;
393 }
394 }
395 }
396
397out:
398 // Close the archive, freeing any resources it was using
399 if (!mz_zip_reader_end(zip_archive)) {
400 // Cannot end zip reader
401 err = ZIP_ECLSZIP;
402 }
403 return err;
404}
405
406static inline void zip_archive_finalize(mz_zip_archive *pzip) {
407 mz_zip_writer_finalize_archive(pzip);
408 zip_archive_truncate(pzip);
409}
410
411static int zip_entry_mark(struct zip_t *zip,
412 struct zip_entry_mark_t *entry_mark, int n,
413 char *const entries[], const size_t len) {
414 int err = 0;
415 if (!zip || !entry_mark || !entries) {
416 return ZIP_ENOINIT;
417 }
418
419 mz_zip_archive_file_stat file_stat;
420 mz_uint64 d_pos = ~0;
421 for (int i = 0; i < n; ++i) {
422
423 if ((err = zip_entry_openbyindex(zip, i))) {
424 return err;
425 }
426
427 mz_bool name_matches = MZ_FALSE;
428 for (int j = 0; j < (const int)len; ++j) {
429 if (zip_name_match(zip->entry.name, entries[j])) {
430 name_matches = MZ_TRUE;
431 break;
432 }
433 }
434 if (name_matches) {
435 entry_mark[i].type = MZ_DELETE;
436 } else {
437 entry_mark[i].type = MZ_KEEP;
438 }
439
440 if (!mz_zip_reader_file_stat(&zip->archive, i, &file_stat)) {
441 return ZIP_ENOENT;
442 }
443
444 zip_entry_close(zip);
445
446 entry_mark[i].m_local_header_ofs = file_stat.m_local_header_ofs;
447 entry_mark[i].file_index = -1;
448 entry_mark[i].lf_length = 0;
449 if ((entry_mark[i].type) == MZ_DELETE &&
450 (d_pos > entry_mark[i].m_local_header_ofs)) {
451 d_pos = entry_mark[i].m_local_header_ofs;
452 }
453 }
454 for (int i = 0; i < n; ++i) {
455 if ((entry_mark[i].m_local_header_ofs > d_pos) &&
456 (entry_mark[i].type != MZ_DELETE)) {
457 entry_mark[i].type = MZ_MOVE;
458 }
459 }
460 return err;
461}
462
463static int zip_index_next(mz_uint64 *local_header_ofs_array, int cur_index) {
464 int new_index = 0;
465 for (int i = cur_index - 1; i >= 0; --i) {
466 if (local_header_ofs_array[cur_index] > local_header_ofs_array[i]) {
467 new_index = i + 1;
468 return new_index;
469 }
470 }
471 return new_index;
472}
473
474static int zip_sort(mz_uint64 *local_header_ofs_array, int cur_index) {
475 int nxt_index = zip_index_next(local_header_ofs_array, cur_index);
476
477 if (nxt_index != cur_index) {
478 mz_uint64 temp = local_header_ofs_array[cur_index];
479 for (int i = cur_index; i > nxt_index; i--) {
480 local_header_ofs_array[i] = local_header_ofs_array[i - 1];
481 }
482 local_header_ofs_array[nxt_index] = temp;
483 }
484 return nxt_index;
485}
486
487static int zip_index_update(struct zip_entry_mark_t *entry_mark, int last_index,
488 int nxt_index) {
489 for (int j = 0; j < last_index; j++) {
490 if (entry_mark[j].file_index >= nxt_index) {
491 entry_mark[j].file_index += 1;
492 }
493 }
494 entry_mark[nxt_index].file_index = last_index;
495 return 0;
496}
497
498static int zip_entry_finalize(struct zip_t *zip,
499 struct zip_entry_mark_t *entry_mark,
500 const int n) {
501
502 mz_uint64 *local_header_ofs_array = (mz_uint64 *)calloc(n, sizeof(mz_uint64));
503 if (!local_header_ofs_array) {
504 return ZIP_EOOMEM;
505 }
506
507 for (int i = 0; i < n; ++i) {
508 local_header_ofs_array[i] = entry_mark[i].m_local_header_ofs;
509 int index = zip_sort(local_header_ofs_array, i);
510
511 if (index != i) {
512 zip_index_update(entry_mark, i, index);
513 }
514 entry_mark[i].file_index = index;
515 }
516
517 mz_uint64 *length = (mz_uint64 *)calloc(n, sizeof(mz_uint64));
518 if (!length) {
519 CLEANUP(local_header_ofs_array);
520 return ZIP_EOOMEM;
521 }
522 for (int i = 0; i < n - 1; i++) {
523 length[i] = local_header_ofs_array[i + 1] - local_header_ofs_array[i];
524 }
525 length[n - 1] = zip->archive.m_archive_size - local_header_ofs_array[n - 1];
526
527 for (int i = 0; i < n; i++) {
528 entry_mark[i].lf_length = length[entry_mark[i].file_index];
529 }
530
531 CLEANUP(length);
532 CLEANUP(local_header_ofs_array);
533 return 0;
534}
535
536static int zip_entry_set(struct zip_t *zip, struct zip_entry_mark_t *entry_mark,
537 int n, char *const entries[], const size_t len) {
538 int err = 0;
539
540 if ((err = zip_entry_mark(zip, entry_mark, n, entries, len)) < 0) {
541 return err;
542 }
543 if ((err = zip_entry_finalize(zip, entry_mark, n)) < 0) {
544 return err;
545 }
546 return 0;
547}
548
549static mz_int64 zip_file_move(MZ_FILE *m_pFile, const mz_uint64 to,
550 const mz_uint64 from, const mz_uint64 length,
551 mz_uint8 *move_buf,
552 const mz_int64 capacity_size) {
553 if ((mz_int64)length > capacity_size) {
554 return ZIP_ECAPSIZE;
555 }
556 if (MZ_FSEEK64(m_pFile, from, SEEK_SET)) {
557 MZ_FCLOSE(m_pFile);
558 return ZIP_EFSEEK;
559 }
560
561 if (fread(move_buf, 1, length, m_pFile) != length) {
562 MZ_FCLOSE(m_pFile);
563 return ZIP_EFREAD;
564 }
565 if (MZ_FSEEK64(m_pFile, to, SEEK_SET)) {
566 MZ_FCLOSE(m_pFile);
567 return ZIP_EFSEEK;
568 }
569 if (fwrite(move_buf, 1, length, m_pFile) != length) {
570 MZ_FCLOSE(m_pFile);
571 return ZIP_EFWRITE;
572 }
573 return (mz_int64)length;
574}
575
576static mz_int64 zip_files_move(MZ_FILE *m_pFile, mz_uint64 writen_num,
577 mz_uint64 read_num, mz_uint64 length) {
578 int n = 0;
579 const mz_int64 page_size = 1 << 12; // 4K
580 mz_uint8 *move_buf = (mz_uint8 *)calloc(1, page_size);
581 if (move_buf == NULL) {
582 return ZIP_EOOMEM;
583 }
584
585 mz_int64 moved_length = 0;
586 mz_int64 move_count = 0;
587 while ((mz_int64)length > 0) {
588 move_count = ((mz_int64)length >= page_size) ? page_size : (mz_int64)length;
589 n = zip_file_move(m_pFile, writen_num, read_num, move_count, move_buf,
590 page_size);
591 if (n < 0) {
592 moved_length = n;
593 goto cleanup;
594 }
595
596 if (n != move_count) {
597 goto cleanup;
598 }
599
600 writen_num += move_count;
601 read_num += move_count;
602 length -= move_count;
603 moved_length += move_count;
604 }
605
606cleanup:
607 CLEANUP(move_buf);
608 return moved_length;
609}
610
611static int zip_central_dir_move(mz_zip_internal_state *pState, int begin,
612 int end, int entry_num) {
613 if (begin == entry_num) {
614 return 0;
615 }
616
617 mz_uint64 l_size = 0;
618 mz_uint64 r_size = 0;
619 mz_uint64 d_size = 0;
620 mz_uint8 *next = NULL;
621 mz_uint8 *deleted = &MZ_ZIP_ARRAY_ELEMENT(
622 &pState->m_central_dir, mz_uint8,
623 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, begin));
624 l_size = (mz_uint32)(deleted - (mz_uint8 *)(pState->m_central_dir.m_p));
625 if (end == entry_num) {
626 r_size = 0;
627 } else {
628 next = &MZ_ZIP_ARRAY_ELEMENT(
629 &pState->m_central_dir, mz_uint8,
630 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, end));
631 r_size = pState->m_central_dir.m_size -
632 (mz_uint32)(next - (mz_uint8 *)(pState->m_central_dir.m_p));
633 d_size = next - deleted;
634 }
635
636 if (l_size == 0) {
637 memmove(pState->m_central_dir.m_p, next, r_size);
638 pState->m_central_dir.m_p = MZ_REALLOC(pState->m_central_dir.m_p, r_size);
639 for (int i = end; i < entry_num; i++) {
640 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i) -=
641 d_size;
642 }
643 }
644
645 if (l_size * r_size != 0) {
646 memmove(deleted, next, r_size);
647 for (int i = end; i < entry_num; i++) {
648 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i) -=
649 d_size;
650 }
651 }
652
653 pState->m_central_dir.m_size = l_size + r_size;
654 return 0;
655}
656
657static int zip_central_dir_delete(mz_zip_internal_state *pState,
658 int *deleted_entry_index_array,
659 int entry_num) {
660 int i = 0;
661 int begin = 0;
662 int end = 0;
663 int d_num = 0;
664 while (i < entry_num) {
665 while ((!deleted_entry_index_array[i]) && (i < entry_num)) {
666 i++;
667 }
668 begin = i;
669
670 while ((deleted_entry_index_array[i]) && (i < entry_num)) {
671 i++;
672 }
673 end = i;
674 zip_central_dir_move(pState, begin, end, entry_num);
675 }
676
677 i = 0;
678 while (i < entry_num) {
679 while ((!deleted_entry_index_array[i]) && (i < entry_num)) {
680 i++;
681 }
682 begin = i;
683 if (begin == entry_num) {
684 break;
685 }
686 while ((deleted_entry_index_array[i]) && (i < entry_num)) {
687 i++;
688 }
689 end = i;
690 int k = 0;
691 for (int j = end; j < entry_num; j++) {
692 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32,
693 begin + k) =
694 (mz_uint32)MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets,
695 mz_uint32, j);
696 k++;
697 }
698 d_num += end - begin;
699 }
700
701 pState->m_central_dir_offsets.m_size =
702 sizeof(mz_uint32) * (entry_num - d_num);
703 return 0;
704}
705
706static int zip_entries_delete_mark(struct zip_t *zip,
707 struct zip_entry_mark_t *entry_mark,
708 int entry_num) {
709 mz_uint64 writen_num = 0;
710 mz_uint64 read_num = 0;
711 mz_uint64 deleted_length = 0;
712 mz_uint64 move_length = 0;
713 int i = 0;
714 int deleted_entry_num = 0;
715 int n = 0;
716
717 mz_bool *deleted_entry_flag_array =
718 (mz_bool *)calloc(entry_num, sizeof(mz_bool));
719 if (deleted_entry_flag_array == NULL) {
720 return ZIP_EOOMEM;
721 }
722
723 mz_zip_internal_state *pState = zip->archive.m_pState;
724 zip->archive.m_zip_mode = MZ_ZIP_MODE_WRITING;
725
726 if (MZ_FSEEK64(pState->m_pFile, 0, SEEK_SET)) {
727 CLEANUP(deleted_entry_flag_array);
728 return ZIP_ENOENT;
729 }
730
731 while (i < entry_num) {
732 while ((entry_mark[i].type == MZ_KEEP) && (i < entry_num)) {
733 writen_num += entry_mark[i].lf_length;
734 read_num = writen_num;
735 i++;
736 }
737
738 while ((entry_mark[i].type == MZ_DELETE) && (i < entry_num)) {
739 deleted_entry_flag_array[i] = MZ_TRUE;
740 read_num += entry_mark[i].lf_length;
741 deleted_length += entry_mark[i].lf_length;
742 i++;
743 deleted_entry_num++;
744 }
745
746 while ((entry_mark[i].type == MZ_MOVE) && (i < entry_num)) {
747 move_length += entry_mark[i].lf_length;
748 mz_uint8 *p = &MZ_ZIP_ARRAY_ELEMENT(
749 &pState->m_central_dir, mz_uint8,
750 MZ_ZIP_ARRAY_ELEMENT(&pState->m_central_dir_offsets, mz_uint32, i));
751 if (!p) {
752 CLEANUP(deleted_entry_flag_array);
753 return ZIP_ENOENT;
754 }
755 mz_uint32 offset = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
756 offset -= (mz_uint32)deleted_length;
757 MZ_WRITE_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS, offset);
758 i++;
759 }
760
761 n = zip_files_move(pState->m_pFile, writen_num, read_num, move_length);
762 if (n != (mz_int64)move_length) {
763 CLEANUP(deleted_entry_flag_array);
764 return n;
765 }
766 writen_num += move_length;
767 read_num += move_length;
768 }
769
770 zip->archive.m_archive_size -= deleted_length;
771 zip->archive.m_total_files = entry_num - deleted_entry_num;
772
773 zip_central_dir_delete(pState, deleted_entry_flag_array, entry_num);
774 CLEANUP(deleted_entry_flag_array);
775
776 return deleted_entry_num;
777}
778
779struct zip_t *zip_open(const char *zipname, int level, char mode) {
780 struct zip_t *zip = NULL;
781
782 if (!zipname || strlen(zipname) < 1) {
783 // zip_t archive name is empty or NULL
784 goto cleanup;
785 }
786
787 if (level < 0)
788 level = MZ_DEFAULT_LEVEL;
789 if ((level & 0xF) > MZ_UBER_COMPRESSION) {
790 // Wrong compression level
791 goto cleanup;
792 }
793
794 zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
795 if (!zip)
796 goto cleanup;
797
798 zip->level = (mz_uint)level;
799 switch (mode) {
800 case 'w':
801 // Create a new archive.
802 if (!mz_zip_writer_init_file(&(zip->archive), zipname, 0)) {
803 // Cannot initialize zip_archive writer
804 goto cleanup;
805 }
806 break;
807
808 case 'r':
809 case 'a':
810 case 'd':
811 if (!mz_zip_reader_init_file(
812 &(zip->archive), zipname,
813 zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) {
814 // An archive file does not exist or cannot initialize
815 // zip_archive reader
816 goto cleanup;
817 }
818 if ((mode == 'a' || mode == 'd') &&
819 !mz_zip_writer_init_from_reader(&(zip->archive), zipname)) {
820 mz_zip_reader_end(&(zip->archive));
821 goto cleanup;
822 }
823 break;
824
825 default:
826 goto cleanup;
827 }
828
829 return zip;
830
831cleanup:
832 CLEANUP(zip);
833 return NULL;
834}
835
836void zip_close(struct zip_t *zip) {
837 if (zip) {
838 // Always finalize, even if adding failed for some reason, so we have a
839 // valid central directory.
840 mz_zip_writer_finalize_archive(&(zip->archive));
841 zip_archive_truncate(&(zip->archive));
842 mz_zip_writer_end(&(zip->archive));
843 mz_zip_reader_end(&(zip->archive));
844
845 CLEANUP(zip);
846 }
847}
848
849int zip_is64(struct zip_t *zip) {
850 if (!zip || !zip->archive.m_pState) {
851 // zip_t handler or zip state is not initialized
852 return ZIP_ENOINIT;
853 }
854
855 return (int)zip->archive.m_pState->m_zip64;
856}
857
858int zip_entry_open(struct zip_t *zip, const char *entryname) {
859 size_t entrylen = 0;
860 mz_zip_archive *pzip = NULL;
861 mz_uint num_alignment_padding_bytes, level;
862 mz_zip_archive_file_stat stats;
863 int err = 0;
864
865 if (!zip) {
866 return ZIP_ENOINIT;
867 }
868
869 if (!entryname) {
870 return ZIP_EINVENTNAME;
871 }
872
873 entrylen = strlen(entryname);
874 if (entrylen == 0) {
875 return ZIP_EINVENTNAME;
876 }
877
878 /*
879 .ZIP File Format Specification Version: 6.3.3
880
881 4.4.17.1 The name of the file, with optional relative path.
882 The path stored MUST not contain a drive or
883 device letter, or a leading slash. All slashes
884 MUST be forward slashes '/' as opposed to
885 backwards slashes '\' for compatibility with Amiga
886 and UNIX file systems etc. If input came from standard
887 input, there is no file name field.
888 */
889 if (zip->entry.name) {
890 CLEANUP(zip->entry.name);
891 }
892 zip->entry.name = zip_strrpl(entryname, entrylen, '\\', '/');
893 if (!zip->entry.name) {
894 // Cannot parse zip entry name
895 return ZIP_EINVENTNAME;
896 }
897
898 pzip = &(zip->archive);
899 if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) {
900 zip->entry.index =
901 mz_zip_reader_locate_file(pzip, zip->entry.name, NULL, 0);
902 if (zip->entry.index < 0) {
903 err = ZIP_ENOENT;
904 goto cleanup;
905 }
906
907 if (!mz_zip_reader_file_stat(pzip, (mz_uint)zip->entry.index, &stats)) {
908 err = ZIP_ENOENT;
909 goto cleanup;
910 }
911
912 zip->entry.comp_size = stats.m_comp_size;
913 zip->entry.uncomp_size = stats.m_uncomp_size;
914 zip->entry.uncomp_crc32 = stats.m_crc32;
915 zip->entry.offset = stats.m_central_dir_ofs;
916 zip->entry.header_offset = stats.m_local_header_ofs;
917 zip->entry.method = stats.m_method;
918 zip->entry.external_attr = stats.m_external_attr;
919#ifndef MINIZ_NO_TIME
920 zip->entry.m_time = stats.m_time;
921#endif
922
923 return 0;
924 }
925
926 zip->entry.index = (int)zip->archive.m_total_files;
927 zip->entry.comp_size = 0;
928 zip->entry.uncomp_size = 0;
929 zip->entry.uncomp_crc32 = MZ_CRC32_INIT;
930 zip->entry.offset = zip->archive.m_archive_size;
931 zip->entry.header_offset = zip->archive.m_archive_size;
932 memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
933 zip->entry.method = 0;
934
935 // UNIX or APPLE
936#if MZ_PLATFORM == 3 || MZ_PLATFORM == 19
937 // regular file with rw-r--r-- persmissions
938 zip->entry.external_attr = (mz_uint32)(0100644) << 16;
939#else
940 zip->entry.external_attr = 0;
941#endif
942
943 num_alignment_padding_bytes =
944 mz_zip_writer_compute_padding_needed_for_file_alignment(pzip);
945
946 if (!pzip->m_pState || (pzip->m_zip_mode != MZ_ZIP_MODE_WRITING)) {
947 // Invalid zip mode
948 err = ZIP_EINVMODE;
949 goto cleanup;
950 }
951 if (zip->level & MZ_ZIP_FLAG_COMPRESSED_DATA) {
952 // Invalid zip compression level
953 err = ZIP_EINVLVL;
954 goto cleanup;
955 }
956 // no zip64 support yet
957 if ((pzip->m_total_files == 0xFFFF) ||
958 ((pzip->m_archive_size + num_alignment_padding_bytes +
959 MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
960 entrylen) > 0xFFFFFFFF)) {
961 // No zip64 support yet
962 err = ZIP_ENOSUP64;
963 goto cleanup;
964 }
965 if (!mz_zip_writer_write_zeros(pzip, zip->entry.offset,
966 num_alignment_padding_bytes +
967 sizeof(zip->entry.header))) {
968 // Cannot memset zip entry header
969 err = ZIP_EMEMSET;
970 goto cleanup;
971 }
972
973 zip->entry.header_offset += num_alignment_padding_bytes;
974 if (pzip->m_file_offset_alignment) {
975 MZ_ASSERT(
976 (zip->entry.header_offset & (pzip->m_file_offset_alignment - 1)) == 0);
977 }
978 zip->entry.offset += num_alignment_padding_bytes + sizeof(zip->entry.header);
979
980 if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, zip->entry.name,
981 entrylen) != entrylen) {
982 // Cannot write data to zip entry
983 err = ZIP_EWRTENT;
984 goto cleanup;
985 }
986
987 zip->entry.offset += entrylen;
988 level = zip->level & 0xF;
989 if (level) {
990 zip->entry.state.m_pZip = pzip;
991 zip->entry.state.m_cur_archive_file_ofs = zip->entry.offset;
992 zip->entry.state.m_comp_size = 0;
993
994 if (tdefl_init(&(zip->entry.comp), mz_zip_writer_add_put_buf_callback,
995 &(zip->entry.state),
996 (int)tdefl_create_comp_flags_from_zip_params(
997 (int)level, -15, MZ_DEFAULT_STRATEGY)) !=
998 TDEFL_STATUS_OKAY) {
999 // Cannot initialize the zip compressor
1000 err = ZIP_ETDEFLINIT;
1001 goto cleanup;
1002 }
1003 }
1004
1005 zip->entry.m_time = time(NULL);
1006
1007 return 0;
1008
1009cleanup:
1010 CLEANUP(zip->entry.name);
1011 return err;
1012}
1013
1014int zip_entry_openbyindex(struct zip_t *zip, int index) {
1015 mz_zip_archive *pZip = NULL;
1016 mz_zip_archive_file_stat stats;
1017 mz_uint namelen;
1018 const mz_uint8 *pHeader;
1019 const char *pFilename;
1020
1021 if (!zip) {
1022 // zip_t handler is not initialized
1023 return ZIP_ENOINIT;
1024 }
1025
1026 pZip = &(zip->archive);
1027 if (pZip->m_zip_mode != MZ_ZIP_MODE_READING) {
1028 // open by index requires readonly mode
1029 return ZIP_EINVMODE;
1030 }
1031
1032 if (index < 0 || (mz_uint)index >= pZip->m_total_files) {
1033 // index out of range
1034 return ZIP_EINVIDX;
1035 }
1036
1037 if (!(pHeader = &MZ_ZIP_ARRAY_ELEMENT(
1038 &pZip->m_pState->m_central_dir, mz_uint8,
1039 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets,
1040 mz_uint32, index)))) {
1041 // cannot find header in central directory
1042 return ZIP_ENOHDR;
1043 }
1044
1045 namelen = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
1046 pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
1047
1048 /*
1049 .ZIP File Format Specification Version: 6.3.3
1050
1051 4.4.17.1 The name of the file, with optional relative path.
1052 The path stored MUST not contain a drive or
1053 device letter, or a leading slash. All slashes
1054 MUST be forward slashes '/' as opposed to
1055 backwards slashes '\' for compatibility with Amiga
1056 and UNIX file systems etc. If input came from standard
1057 input, there is no file name field.
1058 */
1059 if (zip->entry.name) {
1060 CLEANUP(zip->entry.name);
1061 }
1062 zip->entry.name = zip_strrpl(pFilename, namelen, '\\', '/');
1063 if (!zip->entry.name) {
1064 // local entry name is NULL
1065 return ZIP_EINVENTNAME;
1066 }
1067
1068 if (!mz_zip_reader_file_stat(pZip, (mz_uint)index, &stats)) {
1069 return ZIP_ENOENT;
1070 }
1071
1072 zip->entry.index = index;
1073 zip->entry.comp_size = stats.m_comp_size;
1074 zip->entry.uncomp_size = stats.m_uncomp_size;
1075 zip->entry.uncomp_crc32 = stats.m_crc32;
1076 zip->entry.offset = stats.m_central_dir_ofs;
1077 zip->entry.header_offset = stats.m_local_header_ofs;
1078 zip->entry.method = stats.m_method;
1079 zip->entry.external_attr = stats.m_external_attr;
1080#ifndef MINIZ_NO_TIME
1081 zip->entry.m_time = stats.m_time;
1082#endif
1083
1084 return 0;
1085}
1086
1087int zip_entry_close(struct zip_t *zip) {
1088 mz_zip_archive *pzip = NULL;
1089 mz_uint level;
1090 tdefl_status done;
1091 mz_uint16 entrylen;
1092 mz_uint16 dos_time = 0, dos_date = 0;
1093 int err = 0;
1094
1095 if (!zip) {
1096 // zip_t handler is not initialized
1097 err = ZIP_ENOINIT;
1098 goto cleanup;
1099 }
1100
1101 pzip = &(zip->archive);
1102 if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) {
1103 goto cleanup;
1104 }
1105
1106 level = zip->level & 0xF;
1107 if (level) {
1108 done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH);
1109 if (done != TDEFL_STATUS_DONE && done != TDEFL_STATUS_OKAY) {
1110 // Cannot flush compressed buffer
1111 err = ZIP_ETDEFLBUF;
1112 goto cleanup;
1113 }
1114 zip->entry.comp_size = zip->entry.state.m_comp_size;
1115 zip->entry.offset = zip->entry.state.m_cur_archive_file_ofs;
1116 zip->entry.method = MZ_DEFLATED;
1117 }
1118
1119 entrylen = (mz_uint16)strlen(zip->entry.name);
1120 if ((zip->entry.comp_size > 0xFFFFFFFF) || (zip->entry.offset > 0xFFFFFFFF)) {
1121 // No zip64 support, yet
1122 err = ZIP_ENOSUP64;
1123 goto cleanup;
1124 }
1125
1126#ifndef MINIZ_NO_TIME
1127 mz_zip_time_t_to_dos_time(zip->entry.m_time, &dos_time, &dos_date);
1128#endif
1129
1130 if (!mz_zip_writer_create_local_dir_header(
1131 pzip, zip->entry.header, entrylen, 0, zip->entry.uncomp_size,
1132 zip->entry.comp_size, zip->entry.uncomp_crc32, zip->entry.method, 0,
1133 dos_time, dos_date)) {
1134 // Cannot create zip entry header
1135 err = ZIP_ECRTHDR;
1136 goto cleanup;
1137 }
1138
1139 if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset,
1140 zip->entry.header,
1141 sizeof(zip->entry.header)) != sizeof(zip->entry.header)) {
1142 // Cannot write zip entry header
1143 err = ZIP_EWRTHDR;
1144 goto cleanup;
1145 }
1146
1147 if (!mz_zip_writer_add_to_central_dir(
1148 pzip, zip->entry.name, entrylen, NULL, 0, "", 0,
1149 zip->entry.uncomp_size, zip->entry.comp_size, zip->entry.uncomp_crc32,
1150 zip->entry.method, 0, dos_time, dos_date, zip->entry.header_offset,
1151 zip->entry.external_attr)) {
1152 // Cannot write to zip central dir
1153 err = ZIP_EWRTDIR;
1154 goto cleanup;
1155 }
1156
1157 pzip->m_total_files++;
1158 pzip->m_archive_size = zip->entry.offset;
1159
1160cleanup:
1161 if (zip) {
1162 zip->entry.m_time = 0;
1163 CLEANUP(zip->entry.name);
1164 }
1165 return err;
1166}
1167
1168const char *zip_entry_name(struct zip_t *zip) {
1169 if (!zip) {
1170 // zip_t handler is not initialized
1171 return NULL;
1172 }
1173
1174 return zip->entry.name;
1175}
1176
1177int zip_entry_index(struct zip_t *zip) {
1178 if (!zip) {
1179 // zip_t handler is not initialized
1180 return ZIP_ENOINIT;
1181 }
1182
1183 return zip->entry.index;
1184}
1185
1186int zip_entry_isdir(struct zip_t *zip) {
1187 if (!zip) {
1188 // zip_t handler is not initialized
1189 return ZIP_ENOINIT;
1190 }
1191
1192 if (zip->entry.index < 0) {
1193 // zip entry is not opened
1194 return ZIP_EINVIDX;
1195 }
1196
1197 return (int)mz_zip_reader_is_file_a_directory(&zip->archive,
1198 (mz_uint)zip->entry.index);
1199}
1200
1201unsigned long long zip_entry_size(struct zip_t *zip) {
1202 return zip ? zip->entry.uncomp_size : 0;
1203}
1204
1205unsigned int zip_entry_crc32(struct zip_t *zip) {
1206 return zip ? zip->entry.uncomp_crc32 : 0;
1207}
1208
1209int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) {
1210 mz_uint level;
1211 mz_zip_archive *pzip = NULL;
1212 tdefl_status status;
1213
1214 if (!zip) {
1215 // zip_t handler is not initialized
1216 return ZIP_ENOINIT;
1217 }
1218
1219 pzip = &(zip->archive);
1220 if (buf && bufsize > 0) {
1221 zip->entry.uncomp_size += bufsize;
1222 zip->entry.uncomp_crc32 = (mz_uint32)mz_crc32(
1223 zip->entry.uncomp_crc32, (const mz_uint8 *)buf, bufsize);
1224
1225 level = zip->level & 0xF;
1226 if (!level) {
1227 if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, buf,
1228 bufsize) != bufsize)) {
1229 // Cannot write buffer
1230 return ZIP_EWRTENT;
1231 }
1232 zip->entry.offset += bufsize;
1233 zip->entry.comp_size += bufsize;
1234 } else {
1235 status = tdefl_compress_buffer(&(zip->entry.comp), buf, bufsize,
1236 TDEFL_NO_FLUSH);
1237 if (status != TDEFL_STATUS_DONE && status != TDEFL_STATUS_OKAY) {
1238 // Cannot compress buffer
1239 return ZIP_ETDEFLBUF;
1240 }
1241 }
1242 }
1243
1244 return 0;
1245}
1246
1247int zip_entry_fwrite(struct zip_t *zip, const char *filename) {
1248 int err = 0;
1249 size_t n = 0;
1250 FILE *stream = NULL;
1251 mz_uint8 buf[MZ_ZIP_MAX_IO_BUF_SIZE];
1252 struct MZ_FILE_STAT_STRUCT file_stat;
1253
1254 if (!zip) {
1255 // zip_t handler is not initialized
1256 return ZIP_ENOINIT;
1257 }
1258
1259 memset(buf, 0, MZ_ZIP_MAX_IO_BUF_SIZE);
1260 memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT));
1261 if (MZ_FILE_STAT(filename, &file_stat) != 0) {
1262 // problem getting information - check errno
1263 return ZIP_ENOENT;
1264 }
1265
1266 if ((file_stat.st_mode & 0200) == 0) {
1267 // MS-DOS read-only attribute
1268 zip->entry.external_attr |= 0x01;
1269 }
1270 zip->entry.external_attr |= (mz_uint32)((file_stat.st_mode & 0xFFFF) << 16);
1271 zip->entry.m_time = file_stat.st_mtime;
1272
1273#if defined(_MSC_VER)
1274 if (fopen_s(&stream, filename, "rb"))
1275#else
1276 if (!(stream = fopen(filename, "rb")))
1277#endif
1278 {
1279 // Cannot open filename
1280 return ZIP_EOPNFILE;
1281 }
1282
1283 while ((n = fread(buf, sizeof(mz_uint8), MZ_ZIP_MAX_IO_BUF_SIZE, stream)) >
1284 0) {
1285 if (zip_entry_write(zip, buf, n) < 0) {
1286 err = ZIP_EWRTENT;
1287 break;
1288 }
1289 }
1290 fclose(stream);
1291
1292 return err;
1293}
1294
1295ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) {
1296 mz_zip_archive *pzip = NULL;
1297 mz_uint idx;
1298 size_t size = 0;
1299
1300 if (!zip) {
1301 // zip_t handler is not initialized
1302 return (ssize_t)ZIP_ENOINIT;
1303 }
1304
1305 pzip = &(zip->archive);
1306 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) {
1307 // the entry is not found or we do not have read access
1308 return (ssize_t)ZIP_ENOENT;
1309 }
1310
1311 idx = (mz_uint)zip->entry.index;
1312 if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
1313 // the entry is a directory
1314 return (ssize_t)ZIP_EINVENTTYPE;
1315 }
1316
1317 *buf = mz_zip_reader_extract_to_heap(pzip, idx, &size, 0);
1318 if (*buf && bufsize) {
1319 *bufsize = size;
1320 }
1321 return (ssize_t)size;
1322}
1323
1324ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
1325 mz_zip_archive *pzip = NULL;
1326
1327 if (!zip) {
1328 // zip_t handler is not initialized
1329 return (ssize_t)ZIP_ENOINIT;
1330 }
1331
1332 pzip = &(zip->archive);
1333 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) {
1334 // the entry is not found or we do not have read access
1335 return (ssize_t)ZIP_ENOENT;
1336 }
1337
1338 if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index,
1339 buf, bufsize, 0, NULL, 0)) {
1340 return (ssize_t)ZIP_EMEMNOALLOC;
1341 }
1342
1343 return (ssize_t)zip->entry.uncomp_size;
1344}
1345
1346int zip_entry_fread(struct zip_t *zip, const char *filename) {
1347 mz_zip_archive *pzip = NULL;
1348 mz_uint idx;
1349 mz_uint32 xattr = 0;
1350 mz_zip_archive_file_stat info;
1351
1352 if (!zip) {
1353 // zip_t handler is not initialized
1354 return ZIP_ENOINIT;
1355 }
1356
1357 memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat));
1358 pzip = &(zip->archive);
1359 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) {
1360 // the entry is not found or we do not have read access
1361 return ZIP_ENOENT;
1362 }
1363
1364 idx = (mz_uint)zip->entry.index;
1365 if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
1366 // the entry is a directory
1367 return ZIP_EINVENTTYPE;
1368 }
1369
1370 if (!mz_zip_reader_extract_to_file(pzip, idx, filename, 0)) {
1371 return ZIP_ENOFILE;
1372 }
1373
1374#if defined(_MSC_VER)
1375 (void)xattr; // unused
1376#else
1377 if (!mz_zip_reader_file_stat(pzip, idx, &info)) {
1378 // Cannot get information about zip archive;
1379 return ZIP_ENOFILE;
1380 }
1381
1382 xattr = (info.m_external_attr >> 16) & 0xFFFF;
1383 if (xattr > 0) {
1384 if (chmod(filename, (mode_t)xattr) < 0) {
1385 return ZIP_ENOPERM;
1386 }
1387 }
1388#endif
1389
1390 return 0;
1391}
1392
1393int zip_entry_extract(struct zip_t *zip,
1394 size_t (*on_extract)(void *arg, unsigned long long offset,
1395 const void *buf, size_t bufsize),
1396 void *arg) {
1397 mz_zip_archive *pzip = NULL;
1398 mz_uint idx;
1399
1400 if (!zip) {
1401 // zip_t handler is not initialized
1402 return ZIP_ENOINIT;
1403 }
1404
1405 pzip = &(zip->archive);
1406 if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) {
1407 // the entry is not found or we do not have read access
1408 return ZIP_ENOENT;
1409 }
1410
1411 idx = (mz_uint)zip->entry.index;
1412 return (mz_zip_reader_extract_to_callback(pzip, idx, on_extract, arg, 0))
1413 ? 0
1414 : ZIP_EINVIDX;
1415}
1416
1417int zip_entries_total(struct zip_t *zip) {
1418 if (!zip) {
1419 // zip_t handler is not initialized
1420 return ZIP_ENOINIT;
1421 }
1422
1423 return (int)zip->archive.m_total_files;
1424}
1425
1426int zip_entries_delete(struct zip_t *zip, char *const entries[],
1427 const size_t len) {
1428 int n = 0;
1429 int err = 0;
1430 struct zip_entry_mark_t *entry_mark = NULL;
1431
1432 if (zip == NULL || (entries == NULL && len != 0)) {
1433 return ZIP_ENOINIT;
1434 }
1435
1436 if (entries == NULL && len == 0) {
1437 return 0;
1438 }
1439
1440 n = zip_entries_total(zip);
1441
1442 entry_mark =
1443 (struct zip_entry_mark_t *)calloc(n, sizeof(struct zip_entry_mark_t));
1444 if (!entry_mark) {
1445 return ZIP_EOOMEM;
1446 }
1447
1448 zip->archive.m_zip_mode = MZ_ZIP_MODE_READING;
1449
1450 err = zip_entry_set(zip, entry_mark, n, entries, len);
1451 if (err < 0) {
1452 CLEANUP(entry_mark);
1453 return err;
1454 }
1455
1456 err = zip_entries_delete_mark(zip, entry_mark, n);
1457 CLEANUP(entry_mark);
1458 return err;
1459}
1460
1461int zip_stream_extract(const char *stream, size_t size, const char *dir,
1462 int (*on_extract)(const char *filename, void *arg),
1463 void *arg) {
1464 mz_zip_archive zip_archive;
1465 if (!stream || !dir) {
1466 // Cannot parse zip archive stream
1467 return ZIP_ENOINIT;
1468 }
1469 if (!memset(&zip_archive, 0, sizeof(mz_zip_archive))) {
1470 // Cannot memset zip archive
1471 return ZIP_EMEMSET;
1472 }
1473 if (!mz_zip_reader_init_mem(&zip_archive, stream, size, 0)) {
1474 // Cannot initialize zip_archive reader
1475 return ZIP_ENOINIT;
1476 }
1477
1478 return zip_archive_extract(&zip_archive, dir, on_extract, arg);
1479}
1480
1481struct zip_t *zip_stream_open(const char *stream, size_t size, int level,
1482 char mode) {
1483 struct zip_t *zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
1484 if (!zip) {
1485 return NULL;
1486 }
1487
1488 if (level < 0) {
1489 level = MZ_DEFAULT_LEVEL;
1490 }
1491 if ((level & 0xF) > MZ_UBER_COMPRESSION) {
1492 // Wrong compression level
1493 goto cleanup;
1494 }
1495 zip->level = (mz_uint)level;
1496
1497 if ((stream != NULL) && (size > 0) && (mode == 'r')) {
1498 if (!mz_zip_reader_init_mem(&(zip->archive), stream, size, 0)) {
1499 goto cleanup;
1500 }
1501 } else if ((stream == NULL) && (size == 0) && (mode == 'w')) {
1502 // Create a new archive.
1503 if (!mz_zip_writer_init_heap(&(zip->archive), 0, 1024)) {
1504 // Cannot initialize zip_archive writer
1505 goto cleanup;
1506 }
1507 } else {
1508 goto cleanup;
1509 }
1510 return zip;
1511
1512cleanup:
1513 CLEANUP(zip);
1514 return NULL;
1515}
1516
1517ssize_t zip_stream_copy(struct zip_t *zip, void **buf, size_t *bufsize) {
1518 if (!zip) {
1519 return (ssize_t)ZIP_ENOINIT;
1520 }
1521
1522 zip_archive_finalize(&(zip->archive));
1523
1524 if (bufsize != NULL) {
1525 *bufsize = (size_t)zip->archive.m_archive_size;
1526 }
1527 *buf = calloc(sizeof(unsigned char), zip->archive.m_archive_size);
1528 memcpy(*buf, zip->archive.m_pState->m_pMem, zip->archive.m_archive_size);
1529
1530 return (ssize_t)zip->archive.m_archive_size;
1531}
1532
1533void zip_stream_close(struct zip_t *zip) {
1534 if (zip) {
1535 mz_zip_writer_end(&(zip->archive));
1536 mz_zip_reader_end(&(zip->archive));
1537 CLEANUP(zip);
1538 }
1539}
1540
1541int zip_create(const char *zipname, const char *filenames[], size_t len) {
1542 int err = 0;
1543 size_t i;
1544 mz_zip_archive zip_archive;
1545 struct MZ_FILE_STAT_STRUCT file_stat;
1546 mz_uint32 ext_attributes = 0;
1547
1548 if (!zipname || strlen(zipname) < 1) {
1549 // zip_t archive name is empty or NULL
1550 return ZIP_EINVZIPNAME;
1551 }
1552
1553 // Create a new archive.
1554 if (!memset(&(zip_archive), 0, sizeof(zip_archive))) {
1555 // Cannot memset zip archive
1556 return ZIP_EMEMSET;
1557 }
1558
1559 if (!mz_zip_writer_init_file(&zip_archive, zipname, 0)) {
1560 // Cannot initialize zip_archive writer
1561 return ZIP_ENOINIT;
1562 }
1563
1564 if (!memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT))) {
1565 return ZIP_EMEMSET;
1566 }
1567
1568 for (i = 0; i < len; ++i) {
1569 const char *name = filenames[i];
1570 if (!name) {
1571 err = ZIP_EINVENTNAME;
1572 break;
1573 }
1574
1575 if (MZ_FILE_STAT(name, &file_stat) != 0) {
1576 // problem getting information - check errno
1577 err = ZIP_ENOFILE;
1578 break;
1579 }
1580
1581 if ((file_stat.st_mode & 0200) == 0) {
1582 // MS-DOS read-only attribute
1583 ext_attributes |= 0x01;
1584 }
1585 ext_attributes |= (mz_uint32)((file_stat.st_mode & 0xFFFF) << 16);
1586
1587 if (!mz_zip_writer_add_file(&zip_archive, zip_basename(name), name, "", 0,
1588 ZIP_DEFAULT_COMPRESSION_LEVEL,
1589 ext_attributes)) {
1590 // Cannot add file to zip_archive
1591 err = ZIP_ENOFILE;
1592 break;
1593 }
1594 }
1595
1596 mz_zip_writer_finalize_archive(&zip_archive);
1597 mz_zip_writer_end(&zip_archive);
1598 return err;
1599}
1600
1601int zip_extract(const char *zipname, const char *dir,
1602 int (*on_extract)(const char *filename, void *arg), void *arg) {
1603 mz_zip_archive zip_archive;
1604
1605 if (!zipname || !dir) {
1606 // Cannot parse zip archive name
1607 return ZIP_EINVZIPNAME;
1608 }
1609
1610 if (!memset(&zip_archive, 0, sizeof(mz_zip_archive))) {
1611 // Cannot memset zip archive
1612 return ZIP_EMEMSET;
1613 }
1614
1615 // Now try to open the archive.
1616 if (!mz_zip_reader_init_file(&zip_archive, zipname, 0)) {
1617 // Cannot initialize zip_archive reader
1618 return ZIP_ENOINIT;
1619 }
1620
1621 return zip_archive_extract(&zip_archive, dir, on_extract, arg);
1622}
test/standalone/issue_9812/vendor/kuba-zip/zip.h deleted-433
...@@ -1,433 +0,0 @@
1/*
2 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
3 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
5 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
6 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
7 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
8 * OTHER DEALINGS IN THE SOFTWARE.
9 */
10
11#pragma once
12#ifndef ZIP_H
13#define ZIP_H
14
15#include <string.h>
16#include <sys/types.h>
17
18#ifndef ZIP_SHARED
19# define ZIP_EXPORT
20#else
21# ifdef _WIN32
22# ifdef ZIP_BUILD_SHARED
23# define ZIP_EXPORT __declspec(dllexport)
24# else
25# define ZIP_EXPORT __declspec(dllimport)
26# endif
27# else
28# define ZIP_EXPORT __attribute__ ((visibility ("default")))
29# endif
30#endif
31
32#ifdef __cplusplus
33extern "C" {
34#endif
35
36#if !defined(_POSIX_C_SOURCE) && defined(_MSC_VER)
37// 64-bit Windows is the only mainstream platform
38// where sizeof(long) != sizeof(void*)
39#ifdef _WIN64
40typedef long long ssize_t; /* byte count or error */
41#else
42typedef long ssize_t; /* byte count or error */
43#endif
44#endif
45
46#ifndef MAX_PATH
47#define MAX_PATH 32767 /* # chars in a path name including NULL */
48#endif
49
50/**
51 * @mainpage
52 *
53 * Documenation for @ref zip.
54 */
55
56/**
57 * @addtogroup zip
58 * @{
59 */
60
61/**
62 * Default zip compression level.
63 */
64#define ZIP_DEFAULT_COMPRESSION_LEVEL 6
65
66/**
67 * Error codes
68 */
69#define ZIP_ENOINIT -1 // not initialized
70#define ZIP_EINVENTNAME -2 // invalid entry name
71#define ZIP_ENOENT -3 // entry not found
72#define ZIP_EINVMODE -4 // invalid zip mode
73#define ZIP_EINVLVL -5 // invalid compression level
74#define ZIP_ENOSUP64 -6 // no zip 64 support
75#define ZIP_EMEMSET -7 // memset error
76#define ZIP_EWRTENT -8 // cannot write data to entry
77#define ZIP_ETDEFLINIT -9 // cannot initialize tdefl compressor
78#define ZIP_EINVIDX -10 // invalid index
79#define ZIP_ENOHDR -11 // header not found
80#define ZIP_ETDEFLBUF -12 // cannot flush tdefl buffer
81#define ZIP_ECRTHDR -13 // cannot create entry header
82#define ZIP_EWRTHDR -14 // cannot write entry header
83#define ZIP_EWRTDIR -15 // cannot write to central dir
84#define ZIP_EOPNFILE -16 // cannot open file
85#define ZIP_EINVENTTYPE -17 // invalid entry type
86#define ZIP_EMEMNOALLOC -18 // extracting data using no memory allocation
87#define ZIP_ENOFILE -19 // file not found
88#define ZIP_ENOPERM -20 // no permission
89#define ZIP_EOOMEM -21 // out of memory
90#define ZIP_EINVZIPNAME -22 // invalid zip archive name
91#define ZIP_EMKDIR -23 // make dir error
92#define ZIP_ESYMLINK -24 // symlink error
93#define ZIP_ECLSZIP -25 // close archive error
94#define ZIP_ECAPSIZE -26 // capacity size too small
95#define ZIP_EFSEEK -27 // fseek error
96#define ZIP_EFREAD -28 // fread error
97#define ZIP_EFWRITE -29 // fwrite error
98
99/**
100 * Looks up the error message string coresponding to an error number.
101 * @param errnum error number
102 * @return error message string coresponding to errnum or NULL if error is not
103 * found.
104 */
105extern ZIP_EXPORT const char *zip_strerror(int errnum);
106
107/**
108 * @struct zip_t
109 *
110 * This data structure is used throughout the library to represent zip archive -
111 * forward declaration.
112 */
113struct zip_t;
114
115/**
116 * Opens zip archive with compression level using the given mode.
117 *
118 * @param zipname zip archive file name.
119 * @param level compression level (0-9 are the standard zlib-style levels).
120 * @param mode file access mode.
121 * - 'r': opens a file for reading/extracting (the file must exists).
122 * - 'w': creates an empty file for writing.
123 * - 'a': appends to an existing archive.
124 *
125 * @return the zip archive handler or NULL on error
126 */
127extern ZIP_EXPORT struct zip_t *zip_open(const char *zipname, int level,
128 char mode);
129
130/**
131 * Closes the zip archive, releases resources - always finalize.
132 *
133 * @param zip zip archive handler.
134 */
135extern ZIP_EXPORT void zip_close(struct zip_t *zip);
136
137/**
138 * Determines if the archive has a zip64 end of central directory headers.
139 *
140 * @param zip zip archive handler.
141 *
142 * @return the return code - 1 (true), 0 (false), negative number (< 0) on
143 * error.
144 */
145extern ZIP_EXPORT int zip_is64(struct zip_t *zip);
146
147/**
148 * Opens an entry by name in the zip archive.
149 *
150 * For zip archive opened in 'w' or 'a' mode the function will append
151 * a new entry. In readonly mode the function tries to locate the entry
152 * in global dictionary.
153 *
154 * @param zip zip archive handler.
155 * @param entryname an entry name in local dictionary.
156 *
157 * @return the return code - 0 on success, negative number (< 0) on error.
158 */
159extern ZIP_EXPORT int zip_entry_open(struct zip_t *zip, const char *entryname);
160
161/**
162 * Opens a new entry by index in the zip archive.
163 *
164 * This function is only valid if zip archive was opened in 'r' (readonly) mode.
165 *
166 * @param zip zip archive handler.
167 * @param index index in local dictionary.
168 *
169 * @return the return code - 0 on success, negative number (< 0) on error.
170 */
171extern ZIP_EXPORT int zip_entry_openbyindex(struct zip_t *zip, int index);
172
173/**
174 * Closes a zip entry, flushes buffer and releases resources.
175 *
176 * @param zip zip archive handler.
177 *
178 * @return the return code - 0 on success, negative number (< 0) on error.
179 */
180extern ZIP_EXPORT int zip_entry_close(struct zip_t *zip);
181
182/**
183 * Returns a local name of the current zip entry.
184 *
185 * The main difference between user's entry name and local entry name
186 * is optional relative path.
187 * Following .ZIP File Format Specification - the path stored MUST not contain
188 * a drive or device letter, or a leading slash.
189 * All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
190 * for compatibility with Amiga and UNIX file systems etc.
191 *
192 * @param zip: zip archive handler.
193 *
194 * @return the pointer to the current zip entry name, or NULL on error.
195 */
196extern ZIP_EXPORT const char *zip_entry_name(struct zip_t *zip);
197
198/**
199 * Returns an index of the current zip entry.
200 *
201 * @param zip zip archive handler.
202 *
203 * @return the index on success, negative number (< 0) on error.
204 */
205extern ZIP_EXPORT int zip_entry_index(struct zip_t *zip);
206
207/**
208 * Determines if the current zip entry is a directory entry.
209 *
210 * @param zip zip archive handler.
211 *
212 * @return the return code - 1 (true), 0 (false), negative number (< 0) on
213 * error.
214 */
215extern ZIP_EXPORT int zip_entry_isdir(struct zip_t *zip);
216
217/**
218 * Returns an uncompressed size of the current zip entry.
219 *
220 * @param zip zip archive handler.
221 *
222 * @return the uncompressed size in bytes.
223 */
224extern ZIP_EXPORT unsigned long long zip_entry_size(struct zip_t *zip);
225
226/**
227 * Returns CRC-32 checksum of the current zip entry.
228 *
229 * @param zip zip archive handler.
230 *
231 * @return the CRC-32 checksum.
232 */
233extern ZIP_EXPORT unsigned int zip_entry_crc32(struct zip_t *zip);
234
235/**
236 * Compresses an input buffer for the current zip entry.
237 *
238 * @param zip zip archive handler.
239 * @param buf input buffer.
240 * @param bufsize input buffer size (in bytes).
241 *
242 * @return the return code - 0 on success, negative number (< 0) on error.
243 */
244extern ZIP_EXPORT int zip_entry_write(struct zip_t *zip, const void *buf,
245 size_t bufsize);
246
247/**
248 * Compresses a file for the current zip entry.
249 *
250 * @param zip zip archive handler.
251 * @param filename input file.
252 *
253 * @return the return code - 0 on success, negative number (< 0) on error.
254 */
255extern ZIP_EXPORT int zip_entry_fwrite(struct zip_t *zip, const char *filename);
256
257/**
258 * Extracts the current zip entry into output buffer.
259 *
260 * The function allocates sufficient memory for a output buffer.
261 *
262 * @param zip zip archive handler.
263 * @param buf output buffer.
264 * @param bufsize output buffer size (in bytes).
265 *
266 * @note remember to release memory allocated for a output buffer.
267 * for large entries, please take a look at zip_entry_extract function.
268 *
269 * @return the return code - the number of bytes actually read on success.
270 * Otherwise a negative number (< 0) on error.
271 */
272extern ZIP_EXPORT ssize_t zip_entry_read(struct zip_t *zip, void **buf,
273 size_t *bufsize);
274
275/**
276 * Extracts the current zip entry into a memory buffer using no memory
277 * allocation.
278 *
279 * @param zip zip archive handler.
280 * @param buf preallocated output buffer.
281 * @param bufsize output buffer size (in bytes).
282 *
283 * @note ensure supplied output buffer is large enough.
284 * zip_entry_size function (returns uncompressed size for the current
285 * entry) can be handy to estimate how big buffer is needed.
286 * For large entries, please take a look at zip_entry_extract function.
287 *
288 * @return the return code - the number of bytes actually read on success.
289 * Otherwise a negative number (< 0) on error (e.g. bufsize is not large enough).
290 */
291extern ZIP_EXPORT ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
292 size_t bufsize);
293
294/**
295 * Extracts the current zip entry into output file.
296 *
297 * @param zip zip archive handler.
298 * @param filename output file.
299 *
300 * @return the return code - 0 on success, negative number (< 0) on error.
301 */
302extern ZIP_EXPORT int zip_entry_fread(struct zip_t *zip, const char *filename);
303
304/**
305 * Extracts the current zip entry using a callback function (on_extract).
306 *
307 * @param zip zip archive handler.
308 * @param on_extract callback function.
309 * @param arg opaque pointer (optional argument, which you can pass to the
310 * on_extract callback)
311 *
312 * @return the return code - 0 on success, negative number (< 0) on error.
313 */
314extern ZIP_EXPORT int
315zip_entry_extract(struct zip_t *zip,
316 size_t (*on_extract)(void *arg, unsigned long long offset,
317 const void *data, size_t size),
318 void *arg);
319
320/**
321 * Returns the number of all entries (files and directories) in the zip archive.
322 *
323 * @param zip zip archive handler.
324 *
325 * @return the return code - the number of entries on success, negative number
326 * (< 0) on error.
327 */
328extern ZIP_EXPORT int zip_entries_total(struct zip_t *zip);
329
330/**
331 * Deletes zip archive entries.
332 *
333 * @param zip zip archive handler.
334 * @param entries array of zip archive entries to be deleted.
335 * @param len the number of entries to be deleted.
336 * @return the number of deleted entries, or negative number (< 0) on error.
337 */
338extern ZIP_EXPORT int zip_entries_delete(struct zip_t *zip,
339 char *const entries[], size_t len);
340
341/**
342 * Extracts a zip archive stream into directory.
343 *
344 * If on_extract is not NULL, the callback will be called after
345 * successfully extracted each zip entry.
346 * Returning a negative value from the callback will cause abort and return an
347 * error. The last argument (void *arg) is optional, which you can use to pass
348 * data to the on_extract callback.
349 *
350 * @param stream zip archive stream.
351 * @param size stream size.
352 * @param dir output directory.
353 * @param on_extract on extract callback.
354 * @param arg opaque pointer.
355 *
356 * @return the return code - 0 on success, negative number (< 0) on error.
357 */
358extern ZIP_EXPORT int
359zip_stream_extract(const char *stream, size_t size, const char *dir,
360 int (*on_extract)(const char *filename, void *arg),
361 void *arg);
362
363/**
364 * Opens zip archive stream into memory.
365 *
366 * @param stream zip archive stream.
367 * @param size stream size.
368 *
369 * @return the zip archive handler or NULL on error
370 */
371extern ZIP_EXPORT struct zip_t *zip_stream_open(const char *stream, size_t size,
372 int level, char mode);
373
374/**
375 * Copy zip archive stream output buffer.
376 *
377 * @param zip zip archive handler.
378 * @param buf output buffer. User should free buf.
379 * @param bufsize output buffer size (in bytes).
380 *
381 * @return copy size
382 */
383extern ZIP_EXPORT ssize_t zip_stream_copy(struct zip_t *zip, void **buf,
384 size_t *bufsize);
385
386/**
387 * Close zip archive releases resources.
388 *
389 * @param zip zip archive handler.
390 *
391 * @return
392 */
393extern ZIP_EXPORT void zip_stream_close(struct zip_t *zip);
394
395/**
396 * Creates a new archive and puts files into a single zip archive.
397 *
398 * @param zipname zip archive file.
399 * @param filenames input files.
400 * @param len: number of input files.
401 *
402 * @return the return code - 0 on success, negative number (< 0) on error.
403 */
404extern ZIP_EXPORT int zip_create(const char *zipname, const char *filenames[],
405 size_t len);
406
407/**
408 * Extracts a zip archive file into directory.
409 *
410 * If on_extract_entry is not NULL, the callback will be called after
411 * successfully extracted each zip entry.
412 * Returning a negative value from the callback will cause abort and return an
413 * error. The last argument (void *arg) is optional, which you can use to pass
414 * data to the on_extract_entry callback.
415 *
416 * @param zipname zip archive file.
417 * @param dir output directory.
418 * @param on_extract_entry on extract callback.
419 * @param arg opaque pointer.
420 *
421 * @return the return code - 0 on success, negative number (< 0) on error.
422 */
423extern ZIP_EXPORT int zip_extract(const char *zipname, const char *dir,
424 int (*on_extract_entry)(const char *filename,
425 void *arg),
426 void *arg);
427
428/** @} */
429#ifdef __cplusplus
430}
431#endif
432
433#endif