3 #ifndef MINIZ_HEADER_FILE_ONLY
5 typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1];
6 typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1];
7 typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1];
12 #define MZ_ASSERT(x) assert(x)
14 #ifdef MINIZ_NO_MALLOC
15 #define MZ_MALLOC(x) NULL
16 #define MZ_FREE(x) (void)x, ((void)0)
17 #define MZ_REALLOC(p, x) NULL
19 #define MZ_MALLOC(x) malloc(x)
20 #define MZ_FREE(x) free(x)
21 #define MZ_REALLOC(p, x) realloc(p, x)
24 #define MZ_MAX(a,b) (((a)>(b))?(a):(b))
25 #define MZ_MIN(a,b) (((a)<(b))?(a):(b))
26 #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
28 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
29 #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
30 #define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
32 #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
33 #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
37 #define MZ_FORCEINLINE __forceinline
38 #elif defined(__GNUC__)
39 #define MZ_FORCEINLINE inline __attribute__((__always_inline__))
41 #define MZ_FORCEINLINE inline
48 // ------------------- zlib-style API's
50 mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len)
52 mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552;
53 if (!ptr) return MZ_ADLER32_INIT;
55 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
56 s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
57 s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
59 for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
60 s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
62 return (s2 << 16) + s1;
65 // Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/
66 mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
68 static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
69 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
70 mz_uint32 crcu32 = (mz_uint32)crc;
71 if (!ptr) return MZ_CRC32_INIT;
72 crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; }
81 #ifndef MINIZ_NO_ZLIB_APIS
83 static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); }
84 static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); }
85 static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); }
87 const char *mz_version(void)
92 int mz_deflateInit(mz_streamp pStream, int level)
94 return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY);
97 int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy)
99 tdefl_compressor *pComp;
100 mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
102 if (!pStream) return MZ_STREAM_ERROR;
103 if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR;
105 pStream->data_type = 0;
106 pStream->adler = MZ_ADLER32_INIT;
108 pStream->reserved = 0;
109 pStream->total_in = 0;
110 pStream->total_out = 0;
111 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
112 if (!pStream->zfree) pStream->zfree = def_free_func;
114 pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor));
118 pStream->state = (struct mz_internal_state *)pComp;
120 if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY)
122 mz_deflateEnd(pStream);
123 return MZ_PARAM_ERROR;
129 int mz_deflateReset(mz_streamp pStream)
131 if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR;
132 pStream->total_in = pStream->total_out = 0;
133 tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags);
137 int mz_deflate(mz_streamp pStream, int flush)
139 size_t in_bytes, out_bytes;
140 mz_ulong orig_total_in, orig_total_out;
141 int mz_status = MZ_OK;
143 if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR;
144 if (!pStream->avail_out) return MZ_BUF_ERROR;
146 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
148 if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE)
149 return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
151 orig_total_in = pStream->total_in; orig_total_out = pStream->total_out;
154 tdefl_status defl_status;
155 in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
157 defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush);
158 pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
159 pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state);
161 pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes;
162 pStream->total_out += (mz_uint)out_bytes;
166 mz_status = MZ_STREAM_ERROR;
169 else if (defl_status == TDEFL_STATUS_DONE)
171 mz_status = MZ_STREAM_END;
174 else if (!pStream->avail_out)
176 else if ((!pStream->avail_in) && (flush != MZ_FINISH))
178 if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out))
180 return MZ_BUF_ERROR; // Can't make forward progress without some input.
186 int mz_deflateEnd(mz_streamp pStream)
188 if (!pStream) return MZ_STREAM_ERROR;
191 pStream->zfree(pStream->opaque, pStream->state);
192 pStream->state = NULL;
197 mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len)
200 // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.)
201 return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
204 int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level)
208 memset(&stream, 0, sizeof(stream));
210 // In case mz_ulong is 64-bits (argh I hate longs).
211 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
213 stream.next_in = pSource;
214 stream.avail_in = (mz_uint32)source_len;
215 stream.next_out = pDest;
216 stream.avail_out = (mz_uint32)*pDest_len;
218 status = mz_deflateInit(&stream, level);
219 if (status != MZ_OK) return status;
221 status = mz_deflate(&stream, MZ_FINISH);
222 if (status != MZ_STREAM_END)
224 mz_deflateEnd(&stream);
225 return (status == MZ_OK) ? MZ_BUF_ERROR : status;
228 *pDest_len = stream.total_out;
229 return mz_deflateEnd(&stream);
232 int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
234 return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION);
237 mz_ulong mz_compressBound(mz_ulong source_len)
239 return mz_deflateBound(NULL, source_len);
244 tinfl_decompressor m_decomp;
245 mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits;
246 mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
247 tinfl_status m_last_status;
250 int mz_inflateInit2(mz_streamp pStream, int window_bits)
252 inflate_state *pDecomp;
253 if (!pStream) return MZ_STREAM_ERROR;
254 if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR;
256 pStream->data_type = 0;
259 pStream->total_in = 0;
260 pStream->total_out = 0;
261 pStream->reserved = 0;
262 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
263 if (!pStream->zfree) pStream->zfree = def_free_func;
265 pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));
266 if (!pDecomp) return MZ_MEM_ERROR;
268 pStream->state = (struct mz_internal_state *)pDecomp;
270 tinfl_init(&pDecomp->m_decomp);
271 pDecomp->m_dict_ofs = 0;
272 pDecomp->m_dict_avail = 0;
273 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
274 pDecomp->m_first_call = 1;
275 pDecomp->m_has_flushed = 0;
276 pDecomp->m_window_bits = window_bits;
281 int mz_inflateInit(mz_streamp pStream)
283 return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
286 int mz_inflate(mz_streamp pStream, int flush)
288 inflate_state* pState;
289 mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
290 size_t in_bytes, out_bytes, orig_avail_in;
293 if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
294 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
295 if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
297 pState = (inflate_state*)pStream->state;
298 if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
299 orig_avail_in = pStream->avail_in;
301 first_call = pState->m_first_call; pState->m_first_call = 0;
302 if (pState->m_last_status < 0) return MZ_DATA_ERROR;
304 if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
305 pState->m_has_flushed |= (flush == MZ_FINISH);
307 if ((flush == MZ_FINISH) && (first_call))
309 // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file.
310 decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
311 in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
312 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);
313 pState->m_last_status = status;
314 pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes;
315 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
316 pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes;
319 return MZ_DATA_ERROR;
320 else if (status != TINFL_STATUS_DONE)
322 pState->m_last_status = TINFL_STATUS_FAILED;
325 return MZ_STREAM_END;
327 // flush != MZ_FINISH then we must assume there's more input.
328 if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
330 if (pState->m_dict_avail)
332 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
333 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
334 pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
335 pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
336 return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
341 in_bytes = pStream->avail_in;
342 out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
344 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
345 pState->m_last_status = status;
347 pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
348 pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp);
350 pState->m_dict_avail = (mz_uint)out_bytes;
352 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
353 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
354 pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
355 pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
358 return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well).
359 else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
360 return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH.
361 else if (flush == MZ_FINISH)
363 // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH.
364 if (status == TINFL_STATUS_DONE)
365 return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
366 // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong.
367 else if (!pStream->avail_out)
370 else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))
374 return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
377 int mz_inflateEnd(mz_streamp pStream)
380 return MZ_STREAM_ERROR;
383 pStream->zfree(pStream->opaque, pStream->state);
384 pStream->state = NULL;
389 int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
393 memset(&stream, 0, sizeof(stream));
395 // In case mz_ulong is 64-bits (argh I hate longs).
396 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
398 stream.next_in = pSource;
399 stream.avail_in = (mz_uint32)source_len;
400 stream.next_out = pDest;
401 stream.avail_out = (mz_uint32)*pDest_len;
403 status = mz_inflateInit(&stream);
407 status = mz_inflate(&stream, MZ_FINISH);
408 if (status != MZ_STREAM_END)
410 mz_inflateEnd(&stream);
411 return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status;
413 *pDest_len = stream.total_out;
415 return mz_inflateEnd(&stream);
418 const char *mz_error(int err)
420 static struct { int m_err; const char *m_pDesc; } s_error_descs[] =
422 { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" },
423 { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" }
425 mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc;
429 #endif //MINIZ_NO_ZLIB_APIS
431 // ------------------- Low-level Decompression (completely independent from all compression API's)
433 #define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
434 #define TINFL_MEMSET(p, c, l) memset(p, c, l)
436 #define TINFL_CR_BEGIN switch(r->m_state) { case 0:
437 #define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
438 #define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
439 #define TINFL_CR_FINISH }
441 // TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never
442 // reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
443 #define TINFL_GET_BYTE(state_index, c) do { \
444 if (pIn_buf_cur >= pIn_buf_end) { \
446 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
447 TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
448 if (pIn_buf_cur < pIn_buf_end) { \
449 c = *pIn_buf_cur++; \
457 } else c = *pIn_buf_cur++; } MZ_MACRO_END
459 #define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
460 #define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
461 #define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
463 // TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
464 // It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a
465 // Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the
466 // bit buffer contains >=15 bits (deflate's max. Huffman code size).
467 #define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
469 temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
471 code_len = temp >> 9; \
472 if ((code_len) && (num_bits >= code_len)) \
474 } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
475 code_len = TINFL_FAST_LOOKUP_BITS; \
477 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
478 } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
479 } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
480 } while (num_bits < 15);
482 // TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read
483 // beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully
484 // decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32.
485 // The slow path is only executed at the very end of the input buffer.
486 #define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
487 int temp; mz_uint code_len, c; \
488 if (num_bits < 15) { \
489 if ((pIn_buf_end - pIn_buf_cur) < 2) { \
490 TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
492 bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
495 if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
496 code_len = temp >> 9, temp &= 511; \
498 code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
499 } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
501 tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
503 static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
504 static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
505 static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
506 static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
507 static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
508 static const int s_min_table_sizes[3] = { 257, 1, 4 };
510 tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
511 const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
512 mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
513 size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
515 // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter).
516 if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
518 num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
521 bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
522 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
524 TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
525 counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
526 if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
527 if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
532 TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
535 TINFL_SKIP_BITS(5, num_bits & 7);
536 for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
537 if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
538 while ((counter) && (num_bits))
540 TINFL_GET_BITS(51, dist, 8);
541 while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
542 *pOut_buf_cur++ = (mz_uint8)dist;
547 size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
548 while (pIn_buf_cur >= pIn_buf_end)
550 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
552 TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
556 TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
559 n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
560 TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
563 else if (r->m_type == 3)
565 TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
571 mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
572 r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
573 for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
577 for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
578 MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
579 r->m_table_sizes[2] = 19;
581 for ( ; (int)r->m_type >= 0; r->m_type--)
583 int tree_next, tree_cur; tinfl_huff_table *pTable;
584 mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
585 for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
586 used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
587 for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
588 if ((65536 != total) && (used_syms > 1))
590 TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
592 for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
594 mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
595 cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
596 if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
597 if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
598 rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
599 for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
601 tree_cur -= ((rev_code >>= 1) & 1);
602 if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
604 tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
608 for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
610 mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
611 if ((dist == 16) && (!counter))
613 TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
615 num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
616 TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
618 if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
620 TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
622 TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
630 if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
632 TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
635 while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
636 *pOut_buf_cur++ = (mz_uint8)counter;
640 int sym2; mz_uint code_len;
641 #if TINFL_USE_64BIT_BITBUF
642 if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
644 if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
646 if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
647 code_len = sym2 >> 9;
650 code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
652 counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
656 #if !TINFL_USE_64BIT_BITBUF
657 if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
659 if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
660 code_len = sym2 >> 9;
663 code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
665 bit_buf >>= code_len; num_bits -= code_len;
667 pOut_buf_cur[0] = (mz_uint8)counter;
674 pOut_buf_cur[1] = (mz_uint8)sym2;
678 if ((counter &= 511) == 256) break;
680 num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
681 if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
683 TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
684 num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
685 if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
687 dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
688 if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
690 TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
693 pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
695 if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
699 while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
700 *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
704 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
705 else if ((counter >= 9) && (counter <= dist))
707 const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
710 ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
711 ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
713 } while ((pSrc += 8) < pSrc_end);
714 if ((counter &= 7) < 3)
718 pOut_buf_cur[0] = pSrc[0];
720 pOut_buf_cur[1] = pSrc[1];
721 pOut_buf_cur += counter;
729 pOut_buf_cur[0] = pSrc[0];
730 pOut_buf_cur[1] = pSrc[1];
731 pOut_buf_cur[2] = pSrc[2];
732 pOut_buf_cur += 3; pSrc += 3;
733 } while ((int)(counter -= 3) > 2);
734 if ((int)counter > 0)
736 pOut_buf_cur[0] = pSrc[0];
737 if ((int)counter > 1)
738 pOut_buf_cur[1] = pSrc[1];
739 pOut_buf_cur += counter;
743 } while (!(r->m_final & 1));
744 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
746 TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
748 TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
752 r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
753 *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
754 if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
756 const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
757 mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
760 for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
762 s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
763 s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
765 for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
766 s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
768 r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
773 // Higher level helper functions.
774 void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
776 tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
781 size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
782 tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size,
783 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
784 if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
786 MZ_FREE(pBuf); *pOut_len = 0; return NULL;
788 src_buf_ofs += src_buf_size;
789 *pOut_len += dst_buf_size;
790 if (status == TINFL_STATUS_DONE) break;
791 new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
792 pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
795 MZ_FREE(pBuf); *pOut_len = 0; return NULL;
797 pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
802 size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
804 tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
805 status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
806 return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
809 int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
812 tinfl_decompressor decomp;
813 mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
815 return TINFL_STATUS_FAILED;
819 size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
820 tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
821 (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
822 in_buf_ofs += in_buf_size;
823 if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
825 if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
827 result = (status == TINFL_STATUS_DONE);
830 dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
833 *pIn_buf_size = in_buf_ofs;
837 // ------------------- Low-level Compression (independent from all decompression API's)
839 // Purposely making these tables static for faster init and thread safety.
840 static const mz_uint16 s_tdefl_len_sym[256] = {
841 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272,
842 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276,
843 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,
844 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,
845 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,
846 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,
847 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,
848 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 };
850 static const mz_uint8 s_tdefl_len_extra[256] = {
851 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
852 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
853 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
854 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 };
856 static const mz_uint8 s_tdefl_small_dist_sym[512] = {
857 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,
858 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,
859 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,
860 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
861 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
862 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,
863 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
864 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
865 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
866 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
867 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
868 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 };
870 static const mz_uint8 s_tdefl_small_dist_extra[512] = {
871 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,
872 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
873 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
874 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
875 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
876 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
877 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
880 static const mz_uint8 s_tdefl_large_dist_sym[128] = {
881 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,
882 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,
883 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 };
885 static const mz_uint8 s_tdefl_large_dist_extra[128] = {
886 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
887 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
888 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 };
890 // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values.
891 typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq;
892 static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1)
894 mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist);
895 for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; }
896 while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--;
897 for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8)
899 const mz_uint32* pHist = &hist[pass << 8];
900 mz_uint offsets[256], cur_ofs = 0;
901 for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; }
902 for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i];
903 { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; }
908 // tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
909 static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n)
911 int root, leaf, next, avbl, used, dpth;
912 if (n==0) return; else if (n==1) { A[0].m_key = 1; return; }
913 A[0].m_key += A[1].m_key; root = 0; leaf = 2;
914 for (next=1; next < n-1; next++)
916 if (leaf>=n || A[root].m_key<A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = (mz_uint16)next; } else A[next].m_key = A[leaf++].m_key;
917 if (leaf>=n || (root<next && A[root].m_key<A[leaf].m_key)) { A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); A[root++].m_key = (mz_uint16)next; } else A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
919 A[n-2].m_key = 0; for (next=n-3; next>=0; next--) A[next].m_key = A[A[next].m_key].m_key+1;
920 avbl = 1; used = dpth = 0; root = n-2; next = n-1;
923 while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; }
924 while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; }
925 avbl = 2*used; dpth++; used = 0;
929 // Limits canonical Huffman code table's max code size.
930 enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
931 static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size)
933 int i; mz_uint32 total = 0; if (code_list_len <= 1) return;
934 for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i];
935 for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
936 while (total != (1UL << max_code_size))
938 pNum_codes[max_code_size]--;
939 for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; }
944 static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table)
946 int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes);
949 for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++;
953 tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms;
954 int num_used_syms = 0;
955 const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
956 for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; }
958 pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
960 for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++;
962 tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit);
964 MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);
965 for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
966 for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
969 next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1);
971 for (i = 0; i < table_len; i++)
973 mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue;
974 code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1);
975 d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
979 #define TDEFL_PUT_BITS(b, l) do { \
980 mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \
981 d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \
982 while (d->m_bits_in >= 8) { \
983 if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
984 *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
985 d->m_bit_buffer >>= 8; \
990 #define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \
991 if (rle_repeat_count < 3) { \
992 d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \
993 while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
995 d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \
996 } rle_repeat_count = 0; } }
998 #define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \
999 if (rle_z_count < 3) { \
1000 d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \
1001 } else if (rle_z_count <= 10) { \
1002 d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \
1004 d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \
1005 } rle_z_count = 0; } }
1007 static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
1009 static void tdefl_start_dynamic_block(tdefl_compressor *d)
1011 int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index;
1012 mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF;
1014 d->m_huff_count[0][256] = 1;
1016 tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
1017 tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
1019 for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break;
1020 for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break;
1022 memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
1023 memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes);
1024 total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0;
1026 memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
1027 for (i = 0; i < total_code_sizes_to_pack; i++)
1029 mz_uint8 code_size = code_sizes_to_pack[i];
1032 TDEFL_RLE_PREV_CODE_SIZE();
1033 if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); }
1037 TDEFL_RLE_ZERO_CODE_SIZE();
1038 if (code_size != prev_code_size)
1040 TDEFL_RLE_PREV_CODE_SIZE();
1041 d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size;
1043 else if (++rle_repeat_count == 6)
1045 TDEFL_RLE_PREV_CODE_SIZE();
1048 prev_code_size = code_size;
1050 if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); }
1052 tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
1054 TDEFL_PUT_BITS(2, 2);
1056 TDEFL_PUT_BITS(num_lit_codes - 257, 5);
1057 TDEFL_PUT_BITS(num_dist_codes - 1, 5);
1059 for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break;
1060 num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
1061 for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
1063 for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; )
1065 mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
1066 TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
1067 if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]);
1071 static void tdefl_start_static_block(tdefl_compressor *d)
1074 mz_uint8 *p = &d->m_huff_code_sizes[0][0];
1076 for (i = 0; i <= 143; ++i) *p++ = 8;
1077 for ( ; i <= 255; ++i) *p++ = 9;
1078 for ( ; i <= 279; ++i) *p++ = 7;
1079 for ( ; i <= 287; ++i) *p++ = 8;
1081 memset(d->m_huff_code_sizes[1], 5, 32);
1083 tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
1084 tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
1086 TDEFL_PUT_BITS(1, 2);
1089 static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
1091 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
1092 static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
1095 mz_uint8 *pLZ_codes;
1096 mz_uint8 *pOutput_buf = d->m_pOutput_buf;
1097 mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
1098 mz_uint64 bit_buffer = d->m_bit_buffer;
1099 mz_uint bits_in = d->m_bits_in;
1101 #define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); }
1104 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1)
1107 flags = *pLZ_codes++ | 0x100;
1111 mz_uint s0, s1, n0, n1, sym, num_extra_bits;
1112 mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3;
1114 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
1115 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
1116 TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
1118 // This sequence coaxes MSVC into using cmov's vs. jmp's.
1119 s0 = s_tdefl_small_dist_sym[match_dist & 511];
1120 n0 = s_tdefl_small_dist_extra[match_dist & 511];
1121 s1 = s_tdefl_large_dist_sym[match_dist >> 8];
1122 n1 = s_tdefl_large_dist_extra[match_dist >> 8];
1123 sym = (match_dist < 512) ? s0 : s1;
1124 num_extra_bits = (match_dist < 512) ? n0 : n1;
1126 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
1127 TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
1128 TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
1132 mz_uint lit = *pLZ_codes++;
1133 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1134 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
1136 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
1140 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1141 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
1143 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
1147 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1148 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
1153 if (pOutput_buf >= d->m_pOutput_buf_end)
1156 *(mz_uint64*)pOutput_buf = bit_buffer;
1157 pOutput_buf += (bits_in >> 3);
1158 bit_buffer >>= (bits_in & ~7);
1162 #undef TDEFL_PUT_BITS_FAST
1164 d->m_pOutput_buf = pOutput_buf;
1166 d->m_bit_buffer = 0;
1170 mz_uint32 n = MZ_MIN(bits_in, 16);
1171 TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
1176 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
1178 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
1181 static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
1184 mz_uint8 *pLZ_codes;
1187 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1)
1190 flags = *pLZ_codes++ | 0x100;
1193 mz_uint sym, num_extra_bits;
1194 mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3;
1196 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
1197 TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
1198 TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
1200 if (match_dist < 512)
1202 sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist];
1206 sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
1208 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
1209 TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
1210 TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
1214 mz_uint lit = *pLZ_codes++;
1215 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
1216 TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
1220 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
1222 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
1224 #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
1226 static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block)
1229 tdefl_start_static_block(d);
1231 tdefl_start_dynamic_block(d);
1232 return tdefl_compress_lz_codes(d);
1235 static int tdefl_flush_block(tdefl_compressor *d, int flush)
1237 mz_uint saved_bit_buf, saved_bits_in;
1238 mz_uint8 *pSaved_output_buf;
1239 mz_bool comp_block_succeeded = MZ_FALSE;
1240 int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
1241 mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf;
1243 d->m_pOutput_buf = pOutput_buf_start;
1244 d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
1246 MZ_ASSERT(!d->m_output_flush_remaining);
1247 d->m_output_flush_ofs = 0;
1248 d->m_output_flush_remaining = 0;
1250 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
1251 d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
1253 if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index))
1255 TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8);
1258 TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
1260 pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in;
1263 comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48));
1265 // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead.
1266 if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) &&
1267 ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) )
1269 mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
1270 TDEFL_PUT_BITS(0, 2);
1271 if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); }
1272 for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF)
1274 TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
1276 for (i = 0; i < d->m_total_lz_bytes; ++i)
1278 TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8);
1281 // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes.
1282 else if (!comp_block_succeeded)
1284 d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
1285 tdefl_compress_block(d, MZ_TRUE);
1290 if (flush == TDEFL_FINISH)
1292 if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); }
1293 if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } }
1297 mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); }
1301 MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
1303 memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
1304 memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
1306 d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++;
1308 if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0)
1310 if (d->m_pPut_buf_func)
1312 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
1313 if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
1314 return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
1316 else if (pOutput_buf_start == d->m_output_buf)
1318 int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
1319 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy);
1320 d->m_out_buf_ofs += bytes_to_copy;
1321 if ((n -= bytes_to_copy) != 0)
1323 d->m_output_flush_ofs = bytes_to_copy;
1324 d->m_output_flush_remaining = n;
1329 d->m_out_buf_ofs += n;
1333 return d->m_output_flush_remaining;
1336 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
1337 #define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p)
1338 static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)
1340 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
1341 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
1342 const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q;
1343 mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s);
1344 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return;
1349 if (--num_probes_left == 0) return;
1350 #define TDEFL_PROBE \
1351 next_probe_pos = d->m_next[probe_pos]; \
1352 if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \
1353 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
1354 if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break;
1355 TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE;
1357 if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32;
1358 do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
1359 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) );
1362 *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break;
1364 else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len)
1366 *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break;
1367 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
1372 static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)
1374 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
1375 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
1376 const mz_uint8 *s = d->m_dict + pos, *p, *q;
1377 mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
1378 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return;
1383 if (--num_probes_left == 0) return;
1384 #define TDEFL_PROBE \
1385 next_probe_pos = d->m_next[probe_pos]; \
1386 if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \
1387 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
1388 if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break;
1389 TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE;
1391 if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break;
1392 if (probe_len > match_len)
1394 *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return;
1395 c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1];
1399 #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
1401 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1402 static mz_bool tdefl_compress_fast(tdefl_compressor *d)
1404 // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio.
1405 mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left;
1406 mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
1407 mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
1409 while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size)))
1411 const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
1412 mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
1413 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
1414 d->m_src_buf_left -= num_bytes_to_process;
1415 lookahead_size += num_bytes_to_process;
1417 while (num_bytes_to_process)
1419 mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
1420 memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
1421 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
1422 memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
1424 dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
1425 num_bytes_to_process -= n;
1428 dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
1429 if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break;
1431 while (lookahead_size >= 4)
1433 mz_uint cur_match_dist, cur_match_len = 1;
1434 mz_uint8 *pCur_dict = d->m_dict + cur_pos;
1435 mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF;
1436 mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK;
1437 mz_uint probe_pos = d->m_hash[hash];
1438 d->m_hash[hash] = (mz_uint16)lookahead_pos;
1440 if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram))
1442 const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
1443 const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
1444 mz_uint32 probe_len = 32;
1445 do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
1446 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) );
1447 cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
1449 cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
1451 if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)))
1454 *pLZ_code_buf++ = (mz_uint8)first_trigram;
1455 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
1456 d->m_huff_count[0][(mz_uint8)first_trigram]++;
1461 cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
1463 MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
1467 pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
1468 *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
1470 *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
1472 s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
1473 s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
1474 d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
1476 d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++;
1481 *pLZ_code_buf++ = (mz_uint8)first_trigram;
1482 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
1483 d->m_huff_count[0][(mz_uint8)first_trigram]++;
1486 if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; }
1488 total_lz_bytes += cur_match_len;
1489 lookahead_pos += cur_match_len;
1490 dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE);
1491 cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
1492 MZ_ASSERT(lookahead_size >= cur_match_len);
1493 lookahead_size -= cur_match_len;
1495 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
1498 d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
1499 d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
1500 if ((n = tdefl_flush_block(d, 0)) != 0)
1501 return (n < 0) ? MZ_FALSE : MZ_TRUE;
1502 total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left;
1506 while (lookahead_size)
1508 mz_uint8 lit = d->m_dict[cur_pos];
1511 *pLZ_code_buf++ = lit;
1512 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
1513 if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; }
1515 d->m_huff_count[0][lit]++;
1518 dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE);
1519 cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
1522 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
1525 d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
1526 d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
1527 if ((n = tdefl_flush_block(d, 0)) != 0)
1528 return (n < 0) ? MZ_FALSE : MZ_TRUE;
1529 total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left;
1534 d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
1535 d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
1538 #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1540 static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit)
1542 d->m_total_lz_bytes++;
1543 *d->m_pLZ_code_buf++ = lit;
1544 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; }
1545 d->m_huff_count[0][lit]++;
1548 static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist)
1552 MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE));
1554 d->m_total_lz_bytes += match_len;
1556 d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
1559 d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
1560 d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3;
1562 *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; }
1564 s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
1565 d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
1567 if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
1570 static mz_bool tdefl_compress_normal(tdefl_compressor *d)
1572 const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left;
1573 tdefl_flush flush = d->m_flush;
1575 while ((src_buf_left) || ((flush) && (d->m_lookahead_size)))
1577 mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
1578 // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN.
1579 if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1))
1581 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;
1582 mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];
1583 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
1584 const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
1585 src_buf_left -= num_bytes_to_process;
1586 d->m_lookahead_size += num_bytes_to_process;
1587 while (pSrc != pSrc_end)
1589 mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
1590 hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
1591 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos);
1592 dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++;
1597 while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
1599 mz_uint8 c = *pSrc++;
1600 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
1602 d->m_dict[dst_pos] = c;
1603 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
1604 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
1605 if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN)
1607 mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
1608 mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
1609 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos);
1613 d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
1614 if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
1617 // Simple lazy/greedy parsing state machine.
1618 len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
1619 if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS))
1621 if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))
1623 mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
1624 cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; }
1625 if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1;
1630 tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len);
1632 if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5)))
1634 cur_match_dist = cur_match_len = 0;
1636 if (d->m_saved_match_len)
1638 if (cur_match_len > d->m_saved_match_len)
1640 tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
1641 if (cur_match_len >= 128)
1643 tdefl_record_match(d, cur_match_len, cur_match_dist);
1644 d->m_saved_match_len = 0; len_to_move = cur_match_len;
1648 d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len;
1653 tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
1654 len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0;
1657 else if (!cur_match_dist)
1658 tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
1659 else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128))
1661 tdefl_record_match(d, cur_match_len, cur_match_dist);
1662 len_to_move = cur_match_len;
1666 d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len;
1668 // Move the lookahead forward by len_to_move bytes.
1669 d->m_lookahead_pos += len_to_move;
1670 MZ_ASSERT(d->m_lookahead_size >= len_to_move);
1671 d->m_lookahead_size -= len_to_move;
1672 d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE);
1673 // Check if it's time to flush the current LZ codes to the internal output buffer.
1674 if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
1675 ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) )
1678 d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left;
1679 if ((n = tdefl_flush_block(d, 0)) != 0)
1680 return (n < 0) ? MZ_FALSE : MZ_TRUE;
1684 d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left;
1688 static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d)
1690 if (d->m_pIn_buf_size)
1692 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
1695 if (d->m_pOut_buf_size)
1697 size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining);
1698 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n);
1699 d->m_output_flush_ofs += (mz_uint)n;
1700 d->m_output_flush_remaining -= (mz_uint)n;
1701 d->m_out_buf_ofs += n;
1703 *d->m_pOut_buf_size = d->m_out_buf_ofs;
1706 return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY;
1709 tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush)
1713 if (pIn_buf_size) *pIn_buf_size = 0;
1714 if (pOut_buf_size) *pOut_buf_size = 0;
1715 return TDEFL_STATUS_BAD_PARAM;
1718 d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size;
1719 d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size;
1720 d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
1721 d->m_out_buf_ofs = 0;
1724 if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
1725 (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) )
1727 if (pIn_buf_size) *pIn_buf_size = 0;
1728 if (pOut_buf_size) *pOut_buf_size = 0;
1729 return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
1731 d->m_wants_to_finish |= (flush == TDEFL_FINISH);
1733 if ((d->m_output_flush_remaining) || (d->m_finished))
1734 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
1736 #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1737 if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
1738 ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
1739 ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0))
1741 if (!tdefl_compress_fast(d))
1742 return d->m_prev_return_status;
1745 #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
1747 if (!tdefl_compress_normal(d))
1748 return d->m_prev_return_status;
1751 if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf))
1752 d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf);
1754 if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining))
1756 if (tdefl_flush_block(d, flush) < 0)
1757 return d->m_prev_return_status;
1758 d->m_finished = (flush == TDEFL_FINISH);
1759 if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; }
1762 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
1765 tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush)
1767 MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
1770 tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
1772 d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user;
1773 d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
1774 d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
1775 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash);
1776 d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;
1777 d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;
1778 d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8;
1779 d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY;
1780 d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1;
1781 d->m_pIn_buf = NULL; d->m_pOut_buf = NULL;
1782 d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL;
1783 d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0;
1784 memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
1785 memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
1786 return TDEFL_STATUS_OKAY;
1789 tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d)
1791 return d->m_prev_return_status;
1794 mz_uint32 tdefl_get_adler32(tdefl_compressor *d)
1796 return d->m_adler32;
1799 mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
1801 tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE;
1802 pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE;
1803 succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY);
1804 succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE);
1805 MZ_FREE(pComp); return succeeded;
1810 size_t m_size, m_capacity;
1812 mz_bool m_expandable;
1813 } tdefl_output_buffer;
1815 static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser)
1817 tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
1818 size_t new_size = p->m_size + len;
1819 if (new_size > p->m_capacity)
1821 size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE;
1822 do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity);
1823 pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE;
1824 p->m_pBuf = pNew_buf; p->m_capacity = new_capacity;
1826 memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size;
1830 void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
1832 tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf);
1833 if (!pOut_len) return MZ_FALSE; else *pOut_len = 0;
1834 out_buf.m_expandable = MZ_TRUE;
1835 if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL;
1836 *pOut_len = out_buf.m_size; return out_buf.m_pBuf;
1839 size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
1841 tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf);
1842 if (!pOut_buf) return 0;
1843 out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len;
1844 if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0;
1845 return out_buf.m_size;
1848 #ifndef MINIZ_NO_ZLIB_APIS
1849 static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };
1851 // level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files).
1852 mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy)
1854 mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
1855 if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
1857 if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
1858 else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES;
1859 else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK;
1860 else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
1861 else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES;
1865 #endif //MINIZ_NO_ZLIB_APIS
1868 #pragma warning (push)
1869 #pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal)
1872 // Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at
1873 // http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
1874 // This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck.
1875 void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip)
1877 // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined.
1878 static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };
1879 tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0;
1880 if (!pComp) return NULL;
1881 MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; }
1882 // write dummy header
1883 for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf);
1884 // compress image data
1885 tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
1886 for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); }
1887 if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
1888 // write real header
1889 *pLen_out = out_buf.m_size-41;
1891 static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06};
1892 mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
1893 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8,chans[num_chans],0,0,0,0,0,0,0,
1894 (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54};
1895 c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24);
1896 memcpy(out_buf.m_pBuf, pnghdr, 41);
1898 // write footer (IDAT CRC-32, followed by IEND chunk)
1899 if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
1900 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24);
1901 // compute final size of file, grab compressed data buffer and return
1902 *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf;
1904 void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out)
1906 // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out)
1907 return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE);
1911 #pragma warning (pop)
1914 // ------------------- .ZIP archive reading
1916 #ifndef MINIZ_NO_ARCHIVE_APIS
1918 #ifdef MINIZ_NO_STDIO
1919 #define MZ_FILE void *
1922 #include <sys/stat.h>
1924 #if defined(_MSC_VER) || defined(__MINGW64__)
1925 static FILE *mz_fopen(const char *pFilename, const char *pMode)
1928 fopen_s(&pFile, pFilename, pMode);
1931 static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream)
1934 if (freopen_s(&pFile, pPath, pMode, pStream))
1938 #ifndef MINIZ_NO_TIME
1939 #include <sys/utime.h>
1941 #define MZ_FILE FILE
1942 #define MZ_FOPEN mz_fopen
1943 #define MZ_FCLOSE fclose
1944 #define MZ_FREAD fread
1945 #define MZ_FWRITE fwrite
1946 #define MZ_FTELL64 _ftelli64
1947 #define MZ_FSEEK64 _fseeki64
1948 #define MZ_FILE_STAT_STRUCT _stat
1949 #define MZ_FILE_STAT _stat
1950 #define MZ_FFLUSH fflush
1951 #define MZ_FREOPEN mz_freopen
1952 #define MZ_DELETE_FILE remove
1953 #elif defined(__MINGW32__)
1954 #ifndef MINIZ_NO_TIME
1955 #include <sys/utime.h>
1957 #define MZ_FILE FILE
1958 #define MZ_FOPEN(f, m) fopen(f, m)
1959 #define MZ_FCLOSE fclose
1960 #define MZ_FREAD fread
1961 #define MZ_FWRITE fwrite
1962 #define MZ_FTELL64 ftello64
1963 #define MZ_FSEEK64 fseeko64
1964 #define MZ_FILE_STAT_STRUCT _stat
1965 #define MZ_FILE_STAT _stat
1966 #define MZ_FFLUSH fflush
1967 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
1968 #define MZ_DELETE_FILE remove
1969 #elif defined(__TINYC__)
1970 #ifndef MINIZ_NO_TIME
1971 #include <sys/utime.h>
1973 #define MZ_FILE FILE
1974 #define MZ_FOPEN(f, m) fopen(f, m)
1975 #define MZ_FCLOSE fclose
1976 #define MZ_FREAD fread
1977 #define MZ_FWRITE fwrite
1978 #define MZ_FTELL64 ftell
1979 #define MZ_FSEEK64 fseek
1980 #define MZ_FILE_STAT_STRUCT stat
1981 #define MZ_FILE_STAT stat
1982 #define MZ_FFLUSH fflush
1983 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
1984 #define MZ_DELETE_FILE remove
1985 #elif defined(__GNUC__) && _LARGEFILE64_SOURCE
1986 #ifndef MINIZ_NO_TIME
1989 #define MZ_FILE FILE
1990 #define MZ_FOPEN(f, m) fopen64(f, m)
1991 #define MZ_FCLOSE fclose
1992 #define MZ_FREAD fread
1993 #define MZ_FWRITE fwrite
1994 #define MZ_FTELL64 ftello64
1995 #define MZ_FSEEK64 fseeko64
1996 #define MZ_FILE_STAT_STRUCT stat64
1997 #define MZ_FILE_STAT stat64
1998 #define MZ_FFLUSH fflush
1999 #define MZ_FREOPEN(p, m, s) freopen64(p, m, s)
2000 #define MZ_DELETE_FILE remove
2002 #ifndef MINIZ_NO_TIME
2005 #define MZ_FILE FILE
2006 #define MZ_FOPEN(f, m) fopen(f, m)
2007 #define MZ_FCLOSE fclose
2008 #define MZ_FREAD fread
2009 #define MZ_FWRITE fwrite
2010 #define MZ_FTELL64 ftello
2011 #define MZ_FSEEK64 fseeko
2012 #define MZ_FILE_STAT_STRUCT stat
2013 #define MZ_FILE_STAT stat
2014 #define MZ_FFLUSH fflush
2015 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
2016 #define MZ_DELETE_FILE remove
2017 #endif // #ifdef _MSC_VER
2018 #endif // #ifdef MINIZ_NO_STDIO
2020 #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
2022 // Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff.
2025 // ZIP archive identifiers and record sizes
2026 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
2027 MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
2028 // Central directory header record offsets
2029 MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
2030 MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16,
2031 MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
2032 MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
2033 // Local directory header offsets
2034 MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10,
2035 MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
2036 MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
2037 // End of central directory offsets
2038 MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
2039 MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
2045 size_t m_size, m_capacity;
2046 mz_uint m_element_size;
2049 struct mz_zip_internal_state_tag
2051 mz_zip_array m_central_dir;
2052 mz_zip_array m_central_dir_offsets;
2053 mz_zip_array m_sorted_central_dir_offsets;
2057 size_t m_mem_capacity;
2060 #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size
2061 #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index]
2063 static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)
2065 pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
2066 memset(pArray, 0, sizeof(mz_zip_array));
2069 static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing)
2071 void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE;
2072 if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; }
2073 if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE;
2074 pArray->m_p = pNew_p; pArray->m_capacity = new_capacity;
2078 static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing)
2080 if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; }
2084 static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)
2086 if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; }
2087 pArray->m_size = new_size;
2091 static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n)
2093 return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
2096 static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n)
2098 size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE;
2099 memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size);
2103 #ifndef MINIZ_NO_TIME
2104 static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date)
2107 memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1;
2108 tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31;
2109 tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62;
2113 static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)
2116 struct tm tm_struct;
2117 struct tm *tm = &tm_struct;
2118 errno_t err = localtime_s(tm, &time);
2121 *pDOS_date = 0; *pDOS_time = 0;
2125 struct tm *tm = localtime(&time);
2127 *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1));
2128 *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday);
2132 #ifndef MINIZ_NO_STDIO
2133 static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)
2135 #ifdef MINIZ_NO_TIME
2136 (void)pFilename; *pDOS_date = *pDOS_time = 0;
2138 struct MZ_FILE_STAT_STRUCT file_stat;
2139 // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh.
2140 if (MZ_FILE_STAT(pFilename, &file_stat) != 0)
2142 mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date);
2143 #endif // #ifdef MINIZ_NO_TIME
2147 #ifndef MINIZ_NO_TIME
2148 static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time)
2150 struct utimbuf t; t.actime = access_time; t.modtime = modified_time;
2151 return !utime(pFilename, &t);
2153 #endif // #ifndef MINIZ_NO_TIME
2154 #endif // #ifndef MINIZ_NO_STDIO
2156 static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags)
2159 if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
2162 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
2163 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
2164 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
2166 pZip->m_zip_mode = MZ_ZIP_MODE_READING;
2167 pZip->m_archive_size = 0;
2168 pZip->m_central_directory_file_ofs = 0;
2169 pZip->m_total_files = 0;
2171 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
2173 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
2174 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
2175 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
2176 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
2180 static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index)
2182 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;
2183 const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
2184 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);
2185 mz_uint8 l = 0, r = 0;
2186 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
2187 pE = pL + MZ_MIN(l_len, r_len);
2190 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
2194 return (pL == pE) ? (l_len < r_len) : (l < r);
2197 #define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END
2199 // Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.)
2200 static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip)
2202 mz_zip_internal_state *pState = pZip->m_pState;
2203 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
2204 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
2205 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
2206 const int size = pZip->m_total_files;
2207 int start = (size - 2) >> 1, end;
2210 int child, root = start;
2213 if ((child = (root << 1) + 1) >= size)
2215 child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])));
2216 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
2218 MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child;
2226 int child, root = 0;
2227 MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
2230 if ((child = (root << 1) + 1) >= end)
2232 child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]));
2233 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
2235 MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child;
2241 static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags)
2243 mz_uint cdir_size, num_this_disk, cdir_disk_index;
2245 mz_int64 cur_file_ofs;
2247 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
2248 mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
2249 // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there.
2250 if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
2252 // Find the end of central directory record by scanning the file from the end towards the beginning.
2253 cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
2256 int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
2257 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
2259 for (i = n - 4; i >= 0; --i)
2260 if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
2267 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
2269 cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
2271 // Read and verify the end of central directory record.
2272 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
2274 if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
2275 ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
2278 num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
2279 cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
2280 if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1)))
2283 if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
2286 cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
2287 if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
2290 pZip->m_central_directory_file_ofs = cdir_ofs;
2292 if (pZip->m_total_files)
2296 // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices.
2297 if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) ||
2298 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE)))
2301 if (sort_central_dir)
2303 if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE))
2307 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size)
2310 // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported).
2311 p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
2312 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i)
2314 mz_uint total_header_size, comp_size, decomp_size, disk_index;
2315 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
2317 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
2318 if (sort_central_dir)
2319 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i;
2320 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
2321 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
2322 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF))
2324 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
2325 if ((disk_index != num_this_disk) && (disk_index != 1))
2327 if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
2329 if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n)
2331 n -= total_header_size; p += total_header_size;
2335 if (sort_central_dir)
2336 mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
2341 mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags)
2343 if ((!pZip) || (!pZip->m_pRead))
2345 if (!mz_zip_reader_init_internal(pZip, flags))
2347 pZip->m_archive_size = size;
2348 if (!mz_zip_reader_read_central_dir(pZip, flags))
2350 mz_zip_reader_end(pZip);
2356 static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
2358 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
2359 size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
2360 memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
2364 mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags)
2366 if (!mz_zip_reader_init_internal(pZip, flags))
2368 pZip->m_archive_size = size;
2369 pZip->m_pRead = mz_zip_mem_read_func;
2370 pZip->m_pIO_opaque = pZip;
2372 pZip->m_pState->m_pMem = const_cast<void *>(pMem);
2374 pZip->m_pState->m_pMem = (void *)pMem;
2376 pZip->m_pState->m_mem_size = size;
2377 if (!mz_zip_reader_read_central_dir(pZip, flags))
2379 mz_zip_reader_end(pZip);
2385 #ifndef MINIZ_NO_STDIO
2386 static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
2388 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
2389 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
2390 if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
2392 return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
2395 mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags)
2397 mz_uint64 file_size;
2398 MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb");
2401 if (MZ_FSEEK64(pFile, 0, SEEK_END))
2406 file_size = MZ_FTELL64(pFile);
2407 if (!mz_zip_reader_init_internal(pZip, flags))
2412 pZip->m_pRead = mz_zip_file_read_func;
2413 pZip->m_pIO_opaque = pZip;
2414 pZip->m_pState->m_pFile = pFile;
2415 pZip->m_archive_size = file_size;
2416 if (!mz_zip_reader_read_central_dir(pZip, flags))
2418 mz_zip_reader_end(pZip);
2423 #endif // #ifndef MINIZ_NO_STDIO
2425 mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip)
2427 return pZip ? pZip->m_total_files : 0;
2430 static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index)
2432 if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
2434 return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index));
2437 mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index)
2440 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
2443 m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
2444 return (m_bit_flag & 1);
2447 mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index)
2449 mz_uint filename_len, external_attr;
2450 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
2454 // First see if the filename ends with a '/' character.
2455 filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
2458 if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
2462 // Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct.
2463 // Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field.
2464 // FIXME: Remove this check? Is it necessary - we already check the filename.
2465 external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
2466 if ((external_attr & 0x10) != 0)
2472 mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat)
2475 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
2476 if ((!p) || (!pStat))
2479 // Unpack the central directory record.
2480 pStat->m_file_index = file_index;
2481 pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
2482 pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
2483 pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
2484 pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
2485 pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
2486 #ifndef MINIZ_NO_TIME
2487 pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));
2489 pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
2490 pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
2491 pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
2492 pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
2493 pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
2494 pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
2496 // Copy as much of the filename and comment as possible.
2497 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
2498 memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0';
2500 n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
2501 pStat->m_comment_size = n;
2502 memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0';
2507 mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size)
2510 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
2511 if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; }
2512 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
2513 if (filename_buf_size)
2515 n = MZ_MIN(n, filename_buf_size - 1);
2516 memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
2517 pFilename[n] = '\0';
2522 static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags)
2525 if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE)
2526 return 0 == memcmp(pA, pB, len);
2527 for (i = 0; i < len; ++i)
2528 if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i]))
2533 static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len)
2535 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;
2536 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
2537 mz_uint8 l = 0, r = 0;
2538 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
2539 pE = pL + MZ_MIN(l_len, r_len);
2542 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
2546 return (pL == pE) ? (int)(l_len - r_len) : (l - r);
2549 static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename)
2551 mz_zip_internal_state *pState = pZip->m_pState;
2552 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
2553 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
2554 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
2555 const int size = pZip->m_total_files;
2556 const mz_uint filename_len = (mz_uint)strlen(pFilename);
2557 int l = 0, h = size - 1;
2560 int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len);
2571 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags)
2573 mz_uint file_index; size_t name_len, comment_len;
2574 if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
2576 if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))
2577 return mz_zip_reader_locate_file_binary_search(pZip, pName);
2578 name_len = strlen(pName); if (name_len > 0xFFFF) return -1;
2579 comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1;
2580 for (file_index = 0; file_index < pZip->m_total_files; file_index++)
2582 const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index));
2583 mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
2584 const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
2585 if (filename_len < name_len)
2589 mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);
2590 const char *pFile_comment = pFilename + filename_len + file_extra_len;
2591 if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags)))
2594 if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len))
2596 int ofs = filename_len - 1;
2599 if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':'))
2601 } while (--ofs >= 0);
2603 pFilename += ofs; filename_len -= ofs;
2605 if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags)))
2611 mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)
2613 int status = TINFL_STATUS_DONE;
2614 mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
2615 mz_zip_archive_file_stat file_stat;
2617 mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
2618 tinfl_decompressor inflator;
2620 if ((buf_size) && (!pBuf))
2623 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
2626 // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes)
2627 if (!file_stat.m_comp_size)
2630 // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers).
2631 // I'm torn how to handle this case - should it fail instead?
2632 if (mz_zip_reader_is_file_a_directory(pZip, file_index))
2635 // Encryption and patch files are not supported.
2636 if (file_stat.m_bit_flag & (1 | 32))
2639 // This function only supports stored and deflate.
2640 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
2643 // Ensure supplied output buffer is large enough.
2644 needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size;
2645 if (buf_size < needed_size)
2648 // Read and parse the local directory entry.
2649 cur_file_ofs = file_stat.m_local_header_ofs;
2650 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
2652 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
2655 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
2656 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
2659 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
2661 // The file is stored or the caller has requested the compressed data.
2662 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size)
2664 return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32);
2667 // Decompress the file either directly from memory or from a file input buffer.
2668 tinfl_init(&inflator);
2670 if (pZip->m_pState->m_pMem)
2672 // Read directly from the archive in memory.
2673 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
2674 read_buf_size = read_buf_avail = file_stat.m_comp_size;
2677 else if (pUser_read_buf)
2679 // Use a user provided read buffer.
2680 if (!user_read_buf_size)
2682 pRead_buf = (mz_uint8 *)pUser_read_buf;
2683 read_buf_size = user_read_buf_size;
2685 comp_remaining = file_stat.m_comp_size;
2689 // Temporarily allocate a read buffer.
2690 read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);
2692 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
2694 if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
2697 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
2700 comp_remaining = file_stat.m_comp_size;
2705 size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
2706 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
2708 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
2709 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
2711 status = TINFL_STATUS_FAILED;
2714 cur_file_ofs += read_buf_avail;
2715 comp_remaining -= read_buf_avail;
2718 in_buf_size = (size_t)read_buf_avail;
2719 status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));
2720 read_buf_avail -= in_buf_size;
2721 read_buf_ofs += in_buf_size;
2722 out_buf_ofs += out_buf_size;
2723 } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
2725 if (status == TINFL_STATUS_DONE)
2727 // Make sure the entire file was decompressed, and check its CRC.
2728 if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32))
2729 status = TINFL_STATUS_FAILED;
2732 if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
2733 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
2735 return status == TINFL_STATUS_DONE;
2738 mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)
2740 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
2743 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size);
2746 mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags)
2748 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0);
2751 mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags)
2753 return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0);
2756 void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags)
2758 mz_uint64 comp_size, uncomp_size, alloc_size;
2759 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
2767 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
2768 uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
2770 alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
2772 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
2774 if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
2777 if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))
2780 if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags))
2782 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
2786 if (pSize) *pSize = (size_t)alloc_size;
2790 void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags)
2792 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
2795 if (pSize) *pSize = 0;
2798 return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
2801 mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)
2803 int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT;
2804 mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs;
2805 mz_zip_archive_file_stat file_stat;
2806 void *pRead_buf = NULL; void *pWrite_buf = NULL;
2807 mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
2809 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
2812 // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes)
2813 if (!file_stat.m_comp_size)
2816 // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers).
2817 // I'm torn how to handle this case - should it fail instead?
2818 if (mz_zip_reader_is_file_a_directory(pZip, file_index))
2821 // Encryption and patch files are not supported.
2822 if (file_stat.m_bit_flag & (1 | 32))
2825 // This function only supports stored and deflate.
2826 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
2829 // Read and parse the local directory entry.
2830 cur_file_ofs = file_stat.m_local_header_ofs;
2831 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
2833 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
2836 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
2837 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
2840 // Decompress the file either directly from memory or from a file input buffer.
2841 if (pZip->m_pState->m_pMem)
2843 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
2844 read_buf_size = read_buf_avail = file_stat.m_comp_size;
2849 read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);
2850 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
2853 comp_remaining = file_stat.m_comp_size;
2856 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
2858 // The file is stored or the caller has requested the compressed data.
2859 if (pZip->m_pState->m_pMem)
2862 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF))
2864 if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF))
2867 if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)
2868 status = TINFL_STATUS_FAILED;
2869 else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
2870 file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size);
2871 cur_file_ofs += file_stat.m_comp_size;
2872 out_buf_ofs += file_stat.m_comp_size;
2877 while (comp_remaining)
2879 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
2880 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
2882 status = TINFL_STATUS_FAILED;
2886 if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
2887 file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
2889 if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
2891 status = TINFL_STATUS_FAILED;
2894 cur_file_ofs += read_buf_avail;
2895 out_buf_ofs += read_buf_avail;
2896 comp_remaining -= read_buf_avail;
2902 tinfl_decompressor inflator;
2903 tinfl_init(&inflator);
2905 if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE)))
2906 status = TINFL_STATUS_FAILED;
2911 mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
2912 size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
2913 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
2915 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
2916 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
2918 status = TINFL_STATUS_FAILED;
2921 cur_file_ofs += read_buf_avail;
2922 comp_remaining -= read_buf_avail;
2926 in_buf_size = (size_t)read_buf_avail;
2927 status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
2928 read_buf_avail -= in_buf_size;
2929 read_buf_ofs += in_buf_size;
2933 if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size)
2935 status = TINFL_STATUS_FAILED;
2938 file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
2939 if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size)
2941 status = TINFL_STATUS_FAILED;
2945 } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT));
2949 if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
2951 // Make sure the entire file was decompressed, and check its CRC.
2952 if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32))
2953 status = TINFL_STATUS_FAILED;
2956 if (!pZip->m_pState->m_pMem)
2957 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
2959 pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
2961 return status == TINFL_STATUS_DONE;
2964 mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)
2966 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
2969 return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags);
2972 #ifndef MINIZ_NO_STDIO
2973 static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n)
2975 (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque);
2978 mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags)
2981 mz_zip_archive_file_stat file_stat;
2983 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
2985 pFile = MZ_FOPEN(pDst_filename, "wb");
2988 status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);
2989 if (MZ_FCLOSE(pFile) == EOF)
2991 #ifndef MINIZ_NO_TIME
2993 mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
2997 #endif // #ifndef MINIZ_NO_STDIO
2999 mz_bool mz_zip_reader_end(mz_zip_archive *pZip)
3001 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
3006 mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL;
3007 mz_zip_array_clear(pZip, &pState->m_central_dir);
3008 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
3009 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
3011 #ifndef MINIZ_NO_STDIO
3012 if (pState->m_pFile)
3014 MZ_FCLOSE(pState->m_pFile);
3015 pState->m_pFile = NULL;
3017 #endif // #ifndef MINIZ_NO_STDIO
3019 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
3021 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
3026 #ifndef MINIZ_NO_STDIO
3027 mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags)
3029 int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags);
3032 return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
3036 // ------------------- .ZIP archive writing
3038 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
3040 static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); }
3041 static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); }
3042 #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
3043 #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
3045 mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size)
3047 if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
3050 if (pZip->m_file_offset_alignment)
3052 // Ensure user specified file offset alignment is a power of 2.
3053 if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
3057 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
3058 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
3059 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
3061 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
3062 pZip->m_archive_size = existing_size;
3063 pZip->m_central_directory_file_ofs = 0;
3064 pZip->m_total_files = 0;
3066 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
3068 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
3069 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
3070 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
3071 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
3075 static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
3077 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
3078 mz_zip_internal_state *pState = pZip->m_pState;
3079 mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
3081 if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
3083 if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
3086 if (new_size > pState->m_mem_capacity)
3089 size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2;
3090 if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))
3092 pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity;
3094 memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
3095 pState->m_mem_size = (size_t)new_size;
3099 mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size)
3101 pZip->m_pWrite = mz_zip_heap_write_func;
3102 pZip->m_pIO_opaque = pZip;
3103 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning))
3105 if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning)))
3107 if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size)))
3109 mz_zip_writer_end(pZip);
3112 pZip->m_pState->m_mem_capacity = initial_allocation_size;
3117 #ifndef MINIZ_NO_STDIO
3118 static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
3120 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
3121 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
3122 if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
3124 return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
3127 mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning)
3130 pZip->m_pWrite = mz_zip_file_write_func;
3131 pZip->m_pIO_opaque = pZip;
3132 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning))
3134 if (NULL == (pFile = MZ_FOPEN(pFilename, "wb")))
3136 mz_zip_writer_end(pZip);
3139 pZip->m_pState->m_pFile = pFile;
3140 if (size_to_reserve_at_beginning)
3142 mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf);
3145 size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
3146 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n)
3148 mz_zip_writer_end(pZip);
3151 cur_ofs += n; size_to_reserve_at_beginning -= n;
3152 } while (size_to_reserve_at_beginning);
3156 #endif // #ifndef MINIZ_NO_STDIO
3158 mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename)
3160 mz_zip_internal_state *pState;
3161 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
3163 // No sense in trying to write to an archive that's already at the support max size
3164 if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
3167 pState = pZip->m_pState;
3169 if (pState->m_pFile)
3171 #ifdef MINIZ_NO_STDIO
3172 pFilename; return MZ_FALSE;
3174 // Archive is being read from stdio - try to reopen as writable.
3175 if (pZip->m_pIO_opaque != pZip)
3179 pZip->m_pWrite = mz_zip_file_write_func;
3180 if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile)))
3182 // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it.
3183 mz_zip_reader_end(pZip);
3186 #endif // #ifdef MINIZ_NO_STDIO
3188 else if (pState->m_pMem)
3190 // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback.
3191 if (pZip->m_pIO_opaque != pZip)
3193 pState->m_mem_capacity = pState->m_mem_size;
3194 pZip->m_pWrite = mz_zip_heap_write_func;
3196 // Archive is being read via a user provided read function - make sure the user has specified a write function too.
3197 else if (!pZip->m_pWrite)
3200 // Start writing new files at the archive's current central directory location.
3201 pZip->m_archive_size = pZip->m_central_directory_file_ofs;
3202 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
3203 pZip->m_central_directory_file_ofs = 0;
3208 mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags)
3210 return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0);
3215 mz_zip_archive *m_pZip;
3216 mz_uint64 m_cur_archive_file_ofs;
3217 mz_uint64 m_comp_size;
3218 } mz_zip_writer_add_state;
3220 static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser)
3222 mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
3223 if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len)
3225 pState->m_cur_archive_file_ofs += len;
3226 pState->m_comp_size += len;
3230 static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date)
3233 memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
3234 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
3235 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
3236 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
3237 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
3238 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
3239 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
3240 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
3241 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size);
3242 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
3243 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
3244 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
3248 static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes)
3251 memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
3252 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
3253 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
3254 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
3255 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
3256 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
3257 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
3258 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
3259 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size);
3260 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
3261 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
3262 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
3263 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
3264 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
3265 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs);
3269 static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes)
3271 mz_zip_internal_state *pState = pZip->m_pState;
3272 mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
3273 size_t orig_central_dir_size = pState->m_central_dir.m_size;
3274 mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
3276 // No zip64 support yet
3277 if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF))
3280 if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes))
3283 if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
3284 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) ||
3285 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) ||
3286 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) ||
3287 (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1)))
3289 // Try to push the central directory array back into its original state.
3290 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
3297 static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name)
3299 // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes.
3300 if (*pArchive_name == '/')
3302 while (*pArchive_name)
3304 if ((*pArchive_name == '\\') || (*pArchive_name == ':'))
3311 static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip)
3314 if (!pZip->m_file_offset_alignment)
3316 n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
3317 return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1);
3320 static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n)
3323 memset(buf, 0, MZ_MIN(sizeof(buf), n));
3326 mz_uint32 s = MZ_MIN(sizeof(buf), n);
3327 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
3329 cur_file_ofs += s; n -= s;
3334 mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32)
3336 mz_uint16 method = 0, dos_time = 0, dos_date = 0;
3337 mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
3338 mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
3339 size_t archive_name_size;
3340 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
3341 tdefl_compressor *pComp = NULL;
3342 mz_bool store_data_uncompressed;
3343 mz_zip_internal_state *pState;
3345 if ((int)level_and_flags < 0)
3346 level_and_flags = MZ_DEFAULT_LEVEL;
3347 level = level_and_flags & 0xF;
3348 store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
3350 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION))
3353 pState = pZip->m_pState;
3355 if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
3357 // No zip64 support yet
3358 if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF))
3360 if (!mz_zip_writer_validate_archive_name(pArchive_name))
3363 #ifndef MINIZ_NO_TIME
3365 time_t cur_time; time(&cur_time);
3366 mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date);
3368 #endif // #ifndef MINIZ_NO_TIME
3370 archive_name_size = strlen(pArchive_name);
3371 if (archive_name_size > 0xFFFF)
3374 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
3376 // no zip64 support yet
3377 if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF))
3380 if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/'))
3382 // Set DOS Subdirectory attribute bit.
3383 ext_attributes |= 0x10;
3384 // Subdirectories cannot contain data.
3385 if ((buf_size) || (uncomp_size))
3389 // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.)
3390 if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))
3393 if ((!store_data_uncompressed) && (buf_size))
3395 if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
3399 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header)))
3401 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3404 local_dir_header_ofs += num_alignment_padding_bytes;
3405 if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
3406 cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header);
3408 MZ_CLEAR_OBJ(local_dir_header);
3409 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
3411 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3414 cur_archive_file_ofs += archive_name_size;
3416 if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
3418 uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size);
3419 uncomp_size = buf_size;
3420 if (uncomp_size <= 3)
3423 store_data_uncompressed = MZ_TRUE;
3427 if (store_data_uncompressed)
3429 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size)
3431 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3435 cur_archive_file_ofs += buf_size;
3436 comp_size = buf_size;
3438 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
3439 method = MZ_DEFLATED;
3443 mz_zip_writer_add_state state;
3445 state.m_pZip = pZip;
3446 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
3447 state.m_comp_size = 0;
3449 if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) ||
3450 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE))
3452 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3456 comp_size = state.m_comp_size;
3457 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
3459 method = MZ_DEFLATED;
3462 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3465 // no zip64 support yet
3466 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
3469 if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
3472 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
3475 if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes))
3478 pZip->m_total_files++;
3479 pZip->m_archive_size = cur_archive_file_ofs;
3484 #ifndef MINIZ_NO_STDIO
3485 mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
3487 mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
3488 mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
3489 mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0;
3490 size_t archive_name_size;
3491 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
3492 MZ_FILE *pSrc_file = NULL;
3494 if ((int)level_and_flags < 0)
3495 level_and_flags = MZ_DEFAULT_LEVEL;
3496 level = level_and_flags & 0xF;
3498 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
3500 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
3502 if (!mz_zip_writer_validate_archive_name(pArchive_name))
3505 archive_name_size = strlen(pArchive_name);
3506 if (archive_name_size > 0xFFFF)
3509 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
3511 // no zip64 support yet
3512 if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF))
3515 if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date))
3518 pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
3521 MZ_FSEEK64(pSrc_file, 0, SEEK_END);
3522 uncomp_size = MZ_FTELL64(pSrc_file);
3523 MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
3525 if (uncomp_size > 0xFFFFFFFF)
3527 // No zip64 support yet
3528 MZ_FCLOSE(pSrc_file);
3531 if (uncomp_size <= 3)
3534 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header)))
3536 MZ_FCLOSE(pSrc_file);
3539 local_dir_header_ofs += num_alignment_padding_bytes;
3540 if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
3541 cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header);
3543 MZ_CLEAR_OBJ(local_dir_header);
3544 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
3546 MZ_FCLOSE(pSrc_file);
3549 cur_archive_file_ofs += archive_name_size;
3553 mz_uint64 uncomp_remaining = uncomp_size;
3554 void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
3557 MZ_FCLOSE(pSrc_file);
3563 while (uncomp_remaining)
3565 mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
3566 if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n))
3568 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3569 MZ_FCLOSE(pSrc_file);
3572 uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
3573 uncomp_remaining -= n;
3574 cur_archive_file_ofs += n;
3576 comp_size = uncomp_size;
3580 mz_bool result = MZ_FALSE;
3581 mz_zip_writer_add_state state;
3582 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
3585 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3586 MZ_FCLOSE(pSrc_file);
3590 state.m_pZip = pZip;
3591 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
3592 state.m_comp_size = 0;
3594 if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY)
3596 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3597 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3598 MZ_FCLOSE(pSrc_file);
3604 size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE);
3605 tdefl_status status;
3607 if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size)
3610 uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
3611 uncomp_remaining -= in_buf_size;
3613 status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH);
3614 if (status == TDEFL_STATUS_DONE)
3619 else if (status != TDEFL_STATUS_OKAY)
3623 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3627 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3628 MZ_FCLOSE(pSrc_file);
3632 comp_size = state.m_comp_size;
3633 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
3635 method = MZ_DEFLATED;
3638 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3641 MZ_FCLOSE(pSrc_file); pSrc_file = NULL;
3643 // no zip64 support yet
3644 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
3647 if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
3650 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
3653 if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes))
3656 pZip->m_total_files++;
3657 pZip->m_archive_size = cur_archive_file_ofs;
3661 #endif // #ifndef MINIZ_NO_STDIO
3663 mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index)
3665 mz_uint n, bit_flags, num_alignment_padding_bytes;
3666 mz_uint64 comp_bytes_remaining, local_dir_header_ofs;
3667 mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
3668 mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
3669 mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
3670 size_t orig_central_dir_size;
3671 mz_zip_internal_state *pState;
3672 void *pBuf; const mz_uint8 *pSrc_central_header;
3674 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
3676 if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index)))
3678 pState = pZip->m_pState;
3680 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
3682 // no zip64 support yet
3683 if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
3686 cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
3687 cur_dst_file_ofs = pZip->m_archive_size;
3689 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
3691 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
3693 cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
3695 if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes))
3697 cur_dst_file_ofs += num_alignment_padding_bytes;
3698 local_dir_header_ofs = cur_dst_file_ofs;
3699 if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
3701 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
3703 cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
3705 n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
3706 comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
3708 if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining)))))
3711 while (comp_bytes_remaining)
3713 n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining);
3714 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n)
3716 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
3719 cur_src_file_ofs += n;
3721 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
3723 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
3726 cur_dst_file_ofs += n;
3728 comp_bytes_remaining -= n;
3731 bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
3734 // Copy data descriptor
3735 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4)
3737 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
3741 n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3);
3742 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
3744 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
3748 cur_src_file_ofs += n;
3749 cur_dst_file_ofs += n;
3751 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
3753 // no zip64 support yet
3754 if (cur_dst_file_ofs > 0xFFFFFFFF)
3757 orig_central_dir_size = pState->m_central_dir.m_size;
3759 memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
3760 MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs);
3761 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
3764 n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
3765 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n))
3767 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
3771 if (pState->m_central_dir.m_size > 0xFFFFFFFF)
3773 n = (mz_uint32)orig_central_dir_size;
3774 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1))
3776 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
3780 pZip->m_total_files++;
3781 pZip->m_archive_size = cur_dst_file_ofs;
3786 mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip)
3788 mz_zip_internal_state *pState;
3789 mz_uint64 central_dir_ofs, central_dir_size;
3790 mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE];
3792 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
3795 pState = pZip->m_pState;
3797 // no zip64 support yet
3798 if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
3801 central_dir_ofs = 0;
3802 central_dir_size = 0;
3803 if (pZip->m_total_files)
3805 // Write central directory
3806 central_dir_ofs = pZip->m_archive_size;
3807 central_dir_size = pState->m_central_dir.m_size;
3808 pZip->m_central_directory_file_ofs = central_dir_ofs;
3809 if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size)
3811 pZip->m_archive_size += central_dir_size;
3814 // Write end of central directory record
3816 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
3817 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files);
3818 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
3819 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size);
3820 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs);
3822 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr))
3824 #ifndef MINIZ_NO_STDIO
3825 if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))
3827 #endif // #ifndef MINIZ_NO_STDIO
3829 pZip->m_archive_size += sizeof(hdr);
3831 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
3835 mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize)
3837 if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize))
3839 if (pZip->m_pWrite != mz_zip_heap_write_func)
3841 if (!mz_zip_writer_finalize_archive(pZip))
3844 *pBuf = pZip->m_pState->m_pMem;
3845 *pSize = pZip->m_pState->m_mem_size;
3846 pZip->m_pState->m_pMem = NULL;
3847 pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
3851 mz_bool mz_zip_writer_end(mz_zip_archive *pZip)
3853 mz_zip_internal_state *pState;
3854 mz_bool status = MZ_TRUE;
3855 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)))
3858 pState = pZip->m_pState;
3859 pZip->m_pState = NULL;
3860 mz_zip_array_clear(pZip, &pState->m_central_dir);
3861 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
3862 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
3864 #ifndef MINIZ_NO_STDIO
3865 if (pState->m_pFile)
3867 MZ_FCLOSE(pState->m_pFile);
3868 pState->m_pFile = NULL;
3870 #endif // #ifndef MINIZ_NO_STDIO
3872 if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem))
3874 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
3875 pState->m_pMem = NULL;
3878 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
3879 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
3883 #ifndef MINIZ_NO_STDIO
3884 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
3886 mz_bool status, created_new_archive = MZ_FALSE;
3887 mz_zip_archive zip_archive;
3888 struct MZ_FILE_STAT_STRUCT file_stat;
3889 MZ_CLEAR_OBJ(zip_archive);
3890 if ((int)level_and_flags < 0)
3891 level_and_flags = MZ_DEFAULT_LEVEL;
3892 if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
3894 if (!mz_zip_writer_validate_archive_name(pArchive_name))
3896 if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0)
3898 // Create a new archive.
3899 if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0))
3901 created_new_archive = MZ_TRUE;
3905 // Append to an existing archive.
3906 if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
3908 if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename))
3910 mz_zip_reader_end(&zip_archive);
3914 status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0);
3915 // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.)
3916 if (!mz_zip_writer_finalize_archive(&zip_archive))
3918 if (!mz_zip_writer_end(&zip_archive))
3920 if ((!status) && (created_new_archive))
3922 // It's a new archive and something went wrong, so just delete it.
3923 int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
3924 (void)ignoredStatus;
3929 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags)
3932 mz_zip_archive zip_archive;
3938 if ((!pZip_filename) || (!pArchive_name))
3941 MZ_CLEAR_OBJ(zip_archive);
3942 if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
3945 if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0)
3946 p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
3948 mz_zip_reader_end(&zip_archive);
3952 #endif // #ifndef MINIZ_NO_STDIO
3954 #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
3956 #endif // #ifndef MINIZ_NO_ARCHIVE_APIS
3962 #endif // MINIZ_HEADER_FILE_ONLY
3965 This is free and unencumbered software released into the public domain.
3967 Anyone is free to copy, modify, publish, use, compile, sell, or
3968 distribute this software, either in source code form or as a compiled
3969 binary, for any purpose, commercial or non-commercial, and by any
3972 In jurisdictions that recognize copyright laws, the author or authors
3973 of this software dedicate any and all copyright interest in the
3974 software to the public domain. We make this dedication for the benefit
3975 of the public at large and to the detriment of our heirs and
3976 successors. We intend this dedication to be an overt act of
3977 relinquishment in perpetuity of all present and future rights to this
3978 software under copyright law.
3980 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
3981 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
3982 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
3983 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
3984 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
3985 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
3986 OTHER DEALINGS IN THE SOFTWARE.
3988 For more information, please refer to <http://unlicense.org/>