pytorch
7831 строка · 319.4 Кб
1/**************************************************************************
2*
3* Copyright 2013-2014 RAD Game Tools and Valve Software
4* Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5* All Rights Reserved.
6*
7* Permission is hereby granted, free of charge, to any person obtaining a copy
8* of this software and associated documentation files (the "Software"), to deal
9* in the Software without restriction, including without limitation the rights
10* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11* copies of the Software, and to permit persons to whom the Software is
12* furnished to do so, subject to the following conditions:
13*
14* The above copyright notice and this permission notice shall be included in
15* all copies or substantial portions of the Software.
16*
17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23* THE SOFTWARE.
24*
25**************************************************************************/
26
27#include "miniz.h"28
29typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];30typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];31typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];32
33#ifdef __cplusplus34extern "C" {35#endif36
37/* ------------------- zlib-style API's */
38
39mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len)40{
41// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,cppcoreguidelines-init-variables)42mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16);43size_t block_len = buf_len % 5552;44if (!ptr)45return MZ_ADLER32_INIT;46while (buf_len)47{48for (i = 0; i + 7 < block_len; i += 8, ptr += 8)49{50s1 += ptr[0], s2 += s1;51s1 += ptr[1], s2 += s1;52s1 += ptr[2], s2 += s1;53s1 += ptr[3], s2 += s1;54s1 += ptr[4], s2 += s1;55s1 += ptr[5], s2 += s1;56s1 += ptr[6], s2 += s1;57s1 += ptr[7], s2 += s1;58}59for (; i < block_len; ++i)60s1 += *ptr++, s2 += s1;61s1 %= 65521U, s2 %= 65521U;62buf_len -= block_len;63block_len = 5552;64}65return (s2 << 16) + s1;66}
67
68/* 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/ */
69#if 070mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)71{72static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,730xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };74mz_uint32 crcu32 = (mz_uint32)crc;75if (!ptr)76return MZ_CRC32_INIT;77crcu32 = ~crcu32;78while (buf_len--)79{80mz_uint8 b = *ptr++;81crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];82crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];83}84return ~crcu32;85}86#elif defined(USE_EXTERNAL_MZCRC)87/* If USE_EXTERNAL_CRC is defined, an external module will export the
88* mz_crc32() symbol for us to use, e.g. an SSE-accelerated version.
89* Depending on the impl, it may be necessary to ~ the input/output crc values.
90*/
91mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len);92#else93/* Faster, but larger CPU cache footprint.
94*/
95mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)96{
97static const mz_uint32 s_crc_table[256] =98{990x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,1000x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,1010xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,1020x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,1030x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,1040xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,1050xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,1060x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,1070x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,1080xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,1090x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB,1100x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,1110x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA,1120xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE,1130xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,1140x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,1150x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409,1160xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,1170xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739,1180x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,1190xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268,1200x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0,1210x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8,1220xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,1230xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,1240x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,1250x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,1260xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,1270x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE,1280x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,1290x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6,1300xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,1310xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D,1320x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,1330x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,1340xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,1350xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D136};137
138mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF;139const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr;140
141while (buf_len >= 4)142{143crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];144crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF];145crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF];146crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF];147pByte_buf += 4;148buf_len -= 4;149}150
151while (buf_len)152{153crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];154++pByte_buf;155--buf_len;156}157
158return ~crc32;159}
160#endif161
162void mz_free(void *p)163{
164MZ_FREE(p);165}
166
167void *miniz_def_alloc_func(void *opaque, size_t items, size_t size)168{
169(void)opaque, (void)items, (void)size;170return MZ_MALLOC(items * size);171}
172void miniz_def_free_func(void *opaque, void *address)173{
174(void)opaque, (void)address;175MZ_FREE(address);176}
177void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size)178{
179(void)opaque, (void)address, (void)items, (void)size;180return MZ_REALLOC(address, items * size);181}
182
183const char *mz_version(void)184{
185return MZ_VERSION;186}
187
188#ifndef MINIZ_NO_ZLIB_APIS189
190int mz_deflateInit(mz_streamp pStream, int level)191{
192return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY);193}
194
195int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy)196{
197// NOLINTNEXTLINE(cppcoreguidelines-init-variables)198tdefl_compressor *pComp;199mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);200
201if (!pStream)202return MZ_STREAM_ERROR;203if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)))204return MZ_PARAM_ERROR;205
206pStream->data_type = 0;207pStream->adler = MZ_ADLER32_INIT;208pStream->msg = NULL;209pStream->reserved = 0;210pStream->total_in = 0;211pStream->total_out = 0;212if (!pStream->zalloc)213pStream->zalloc = miniz_def_alloc_func;214if (!pStream->zfree)215pStream->zfree = miniz_def_free_func;216
217pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor));218if (!pComp)219return MZ_MEM_ERROR;220
221pStream->state = (struct mz_internal_state *)pComp;222
223if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY)224{225mz_deflateEnd(pStream);226return MZ_PARAM_ERROR;227}228
229return MZ_OK;230}
231
232int mz_deflateReset(mz_streamp pStream)233{
234if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree))235return MZ_STREAM_ERROR;236pStream->total_in = pStream->total_out = 0;237tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags);238return MZ_OK;239}
240
241int mz_deflate(mz_streamp pStream, int flush)242{
243// NOLINTNEXTLINE(cppcoreguidelines-init-variables)244size_t in_bytes, out_bytes;245// NOLINTNEXTLINE(cppcoreguidelines-init-variables)246mz_ulong orig_total_in, orig_total_out;247int mz_status = MZ_OK;248
249if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out))250return MZ_STREAM_ERROR;251if (!pStream->avail_out)252return MZ_BUF_ERROR;253
254if (flush == MZ_PARTIAL_FLUSH)255flush = MZ_SYNC_FLUSH;256
257if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE)258return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;259
260orig_total_in = pStream->total_in;261orig_total_out = pStream->total_out;262for (;;)263{264// NOLINTNEXTLINE(cppcoreguidelines-init-variables)265tdefl_status defl_status;266in_bytes = pStream->avail_in;267out_bytes = pStream->avail_out;268
269defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush);270pStream->next_in += (mz_uint)in_bytes;271pStream->avail_in -= (mz_uint)in_bytes;272pStream->total_in += (mz_uint)in_bytes;273pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state);274
275pStream->next_out += (mz_uint)out_bytes;276pStream->avail_out -= (mz_uint)out_bytes;277pStream->total_out += (mz_uint)out_bytes;278
279if (defl_status < 0)280{281mz_status = MZ_STREAM_ERROR;282break;283}284else if (defl_status == TDEFL_STATUS_DONE)285{286mz_status = MZ_STREAM_END;287break;288}289else if (!pStream->avail_out)290break;291else if ((!pStream->avail_in) && (flush != MZ_FINISH))292{293if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out))294break;295return MZ_BUF_ERROR; /* Can't make forward progress without some input.296*/
297}298}299return mz_status;300}
301
302int mz_deflateEnd(mz_streamp pStream)303{
304if (!pStream)305return MZ_STREAM_ERROR;306if (pStream->state)307{308pStream->zfree(pStream->opaque, pStream->state);309pStream->state = NULL;310}311return MZ_OK;312}
313
314mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len)315{
316(void)pStream;317/* 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.) */318return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);319}
320
321int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level)322{
323// NOLINTNEXTLINE(cppcoreguidelines-init-variables)324int status;325mz_stream stream;326memset(&stream, 0, sizeof(stream));327
328/* In case mz_ulong is 64-bits (argh I hate longs). */329if ((source_len | *pDest_len) > 0xFFFFFFFFU)330return MZ_PARAM_ERROR;331
332stream.next_in = pSource;333stream.avail_in = (mz_uint32)source_len;334stream.next_out = pDest;335stream.avail_out = (mz_uint32)*pDest_len;336
337status = mz_deflateInit(&stream, level);338if (status != MZ_OK)339return status;340
341status = mz_deflate(&stream, MZ_FINISH);342if (status != MZ_STREAM_END)343{344mz_deflateEnd(&stream);345return (status == MZ_OK) ? MZ_BUF_ERROR : status;346}347
348*pDest_len = stream.total_out;349return mz_deflateEnd(&stream);350}
351
352int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)353{
354return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION);355}
356
357mz_ulong mz_compressBound(mz_ulong source_len)358{
359return mz_deflateBound(NULL, source_len);360}
361
362typedef struct363{
364tinfl_decompressor m_decomp;365mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed;366int m_window_bits;367mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];368tinfl_status m_last_status;369} inflate_state;370
371int mz_inflateInit2(mz_streamp pStream, int window_bits)372{
373// NOLINTNEXTLINE(cppcoreguidelines-init-variables)374inflate_state *pDecomp;375if (!pStream)376return MZ_STREAM_ERROR;377if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))378return MZ_PARAM_ERROR;379
380pStream->data_type = 0;381pStream->adler = 0;382pStream->msg = NULL;383pStream->total_in = 0;384pStream->total_out = 0;385pStream->reserved = 0;386if (!pStream->zalloc)387pStream->zalloc = miniz_def_alloc_func;388if (!pStream->zfree)389pStream->zfree = miniz_def_free_func;390
391pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));392if (!pDecomp)393return MZ_MEM_ERROR;394
395pStream->state = (struct mz_internal_state *)pDecomp;396
397tinfl_init(&pDecomp->m_decomp);398pDecomp->m_dict_ofs = 0;399pDecomp->m_dict_avail = 0;400pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;401pDecomp->m_first_call = 1;402pDecomp->m_has_flushed = 0;403pDecomp->m_window_bits = window_bits;404
405return MZ_OK;406}
407
408int mz_inflateInit(mz_streamp pStream)409{
410return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);411}
412
413int mz_inflateReset(mz_streamp pStream)414{
415// NOLINTNEXTLINE(cppcoreguidelines-init-variables)416inflate_state *pDecomp;417if (!pStream)418return MZ_STREAM_ERROR;419
420pStream->data_type = 0;421pStream->adler = 0;422pStream->msg = NULL;423pStream->total_in = 0;424pStream->total_out = 0;425pStream->reserved = 0;426
427pDecomp = (inflate_state *)pStream->state;428
429tinfl_init(&pDecomp->m_decomp);430pDecomp->m_dict_ofs = 0;431pDecomp->m_dict_avail = 0;432pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;433pDecomp->m_first_call = 1;434pDecomp->m_has_flushed = 0;435/* pDecomp->m_window_bits = window_bits */;436
437return MZ_OK;438}
439
440int mz_inflate(mz_streamp pStream, int flush)441{
442// NOLINTNEXTLINE(cppcoreguidelines-init-variables)443inflate_state *pState;444// NOLINTNEXTLINE(cppcoreguidelines-init-variables)445mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;446// NOLINTNEXTLINE(cppcoreguidelines-init-variables)447size_t in_bytes, out_bytes, orig_avail_in;448// NOLINTNEXTLINE(cppcoreguidelines-init-variables)449tinfl_status status;450
451if ((!pStream) || (!pStream->state))452return MZ_STREAM_ERROR;453if (flush == MZ_PARTIAL_FLUSH)454flush = MZ_SYNC_FLUSH;455if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH))456return MZ_STREAM_ERROR;457
458pState = (inflate_state *)pStream->state;459if (pState->m_window_bits > 0)460decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;461orig_avail_in = pStream->avail_in;462
463first_call = pState->m_first_call;464pState->m_first_call = 0;465if (pState->m_last_status < 0)466return MZ_DATA_ERROR;467
468if (pState->m_has_flushed && (flush != MZ_FINISH))469return MZ_STREAM_ERROR;470pState->m_has_flushed |= (flush == MZ_FINISH);471
472if ((flush == MZ_FINISH) && (first_call))473{474/* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */475decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;476in_bytes = pStream->avail_in;477out_bytes = pStream->avail_out;478status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);479pState->m_last_status = status;480pStream->next_in += (mz_uint)in_bytes;481pStream->avail_in -= (mz_uint)in_bytes;482pStream->total_in += (mz_uint)in_bytes;483pStream->adler = tinfl_get_adler32(&pState->m_decomp);484pStream->next_out += (mz_uint)out_bytes;485pStream->avail_out -= (mz_uint)out_bytes;486pStream->total_out += (mz_uint)out_bytes;487
488if (status < 0)489return MZ_DATA_ERROR;490else if (status != TINFL_STATUS_DONE)491{492pState->m_last_status = TINFL_STATUS_FAILED;493return MZ_BUF_ERROR;494}495return MZ_STREAM_END;496}497/* flush != MZ_FINISH then we must assume there's more input. */498if (flush != MZ_FINISH)499decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;500
501if (pState->m_dict_avail)502{503n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);504memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);505pStream->next_out += n;506pStream->avail_out -= n;507pStream->total_out += n;508pState->m_dict_avail -= n;509pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);510return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;511}512
513for (;;)514{515in_bytes = pStream->avail_in;516out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;517
518status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);519pState->m_last_status = status;520
521pStream->next_in += (mz_uint)in_bytes;522pStream->avail_in -= (mz_uint)in_bytes;523pStream->total_in += (mz_uint)in_bytes;524pStream->adler = tinfl_get_adler32(&pState->m_decomp);525
526pState->m_dict_avail = (mz_uint)out_bytes;527
528n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);529memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);530pStream->next_out += n;531pStream->avail_out -= n;532pStream->total_out += n;533pState->m_dict_avail -= n;534pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);535
536if (status < 0)537return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */538else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))539return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */540else if (flush == MZ_FINISH)541{542/* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */543if (status == TINFL_STATUS_DONE)544return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;545/* 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. */546else if (!pStream->avail_out)547return MZ_BUF_ERROR;548}549else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))550break;551}552
553return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;554}
555
556int mz_inflateEnd(mz_streamp pStream)557{
558if (!pStream)559return MZ_STREAM_ERROR;560if (pStream->state)561{562pStream->zfree(pStream->opaque, pStream->state);563pStream->state = NULL;564}565return MZ_OK;566}
567
568int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)569{
570mz_stream stream;571// NOLINTNEXTLINE(cppcoreguidelines-init-variables)572int status;573memset(&stream, 0, sizeof(stream));574
575/* In case mz_ulong is 64-bits (argh I hate longs). */576if ((source_len | *pDest_len) > 0xFFFFFFFFU)577return MZ_PARAM_ERROR;578
579stream.next_in = pSource;580stream.avail_in = (mz_uint32)source_len;581stream.next_out = pDest;582stream.avail_out = (mz_uint32)*pDest_len;583
584status = mz_inflateInit(&stream);585if (status != MZ_OK)586return status;587
588status = mz_inflate(&stream, MZ_FINISH);589if (status != MZ_STREAM_END)590{591mz_inflateEnd(&stream);592return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status;593}594*pDest_len = stream.total_out;595
596return mz_inflateEnd(&stream);597}
598
599const char *mz_error(int err)600{
601static struct602{603int m_err;604const char *m_pDesc;605} s_error_descs[] =606{607{ MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { 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" }608};609// NOLINTNEXTLINE(cppcoreguidelines-init-variables)610mz_uint i;611for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i)612if (s_error_descs[i].m_err == err)613return s_error_descs[i].m_pDesc;614return NULL;615}
616
617#endif /*MINIZ_NO_ZLIB_APIS */618
619#ifdef __cplusplus620}
621#endif622
623/*
624This is free and unencumbered software released into the public domain.
625
626Anyone is free to copy, modify, publish, use, compile, sell, or
627distribute this software, either in source code form or as a compiled
628binary, for any purpose, commercial or non-commercial, and by any
629means.
630
631In jurisdictions that recognize copyright laws, the author or authors
632of this software dedicate any and all copyright interest in the
633software to the public domain. We make this dedication for the benefit
634of the public at large and to the detriment of our heirs and
635successors. We intend this dedication to be an overt act of
636relinquishment in perpetuity of all present and future rights to this
637software under copyright law.
638
639THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
640EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
641MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
642IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
643OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
644ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
645OTHER DEALINGS IN THE SOFTWARE.
646
647For more information, please refer to <http://unlicense.org/>
648*/
649/**************************************************************************
650*
651* Copyright 2013-2014 RAD Game Tools and Valve Software
652* Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
653* All Rights Reserved.
654*
655* Permission is hereby granted, free of charge, to any person obtaining a copy
656* of this software and associated documentation files (the "Software"), to deal
657* in the Software without restriction, including without limitation the rights
658* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
659* copies of the Software, and to permit persons to whom the Software is
660* furnished to do so, subject to the following conditions:
661*
662* The above copyright notice and this permission notice shall be included in
663* all copies or substantial portions of the Software.
664*
665* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
666* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
667* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
668* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
669* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
670* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
671* THE SOFTWARE.
672*
673**************************************************************************/
674
675
676
677
678#ifdef __cplusplus679extern "C" {680#endif681
682/* ------------------- Low-level Compression (independent from all decompression API's) */
683
684/* Purposely making these tables static for faster init and thread safety. */
685static const mz_uint16 s_tdefl_len_sym[256] =686{687257, 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,688273, 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,689277, 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,690279, 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,691281, 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,692282, 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,693283, 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,694284, 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, 285695};696
697static const mz_uint8 s_tdefl_len_extra[256] =698{6990, 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,7004, 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,7015, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,7025, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0703};704
705static const mz_uint8 s_tdefl_small_dist_sym[512] =706{7070, 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,70811, 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,70913, 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,71014, 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,71114, 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,71215, 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,71316, 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,71416, 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,71516, 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,71617, 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,71717, 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,71817, 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, 17719};720
721static const mz_uint8 s_tdefl_small_dist_extra[512] =722{7230, 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,7245, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 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,7256, 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,7266, 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,7277, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,7287, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,7297, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,7307, 7, 7, 7, 7, 7, 7, 7731};732
733static const mz_uint8 s_tdefl_large_dist_sym[128] =734{7350, 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,73626, 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,73728, 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, 29738};739
740static const mz_uint8 s_tdefl_large_dist_extra[128] =741{7420, 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,74312, 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,74413, 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, 13745};746
747/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */
748typedef struct749{
750mz_uint16 m_key, m_sym_index;751} tdefl_sym_freq;752static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1)753{
754// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,cppcoreguidelines-init-variables)755mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2];756tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1;757MZ_CLEAR_OBJ(hist);758for (i = 0; i < num_syms; i++)759{760mz_uint freq = pSyms0[i].m_key;761hist[freq & 0xFF]++;762hist[256 + ((freq >> 8) & 0xFF)]++;763}764while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256]))765total_passes--;766for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8)767{768const mz_uint32 *pHist = &hist[pass << 8];769mz_uint offsets[256], cur_ofs = 0;770for (i = 0; i < 256; i++)771{772offsets[i] = cur_ofs;773cur_ofs += pHist[i];774}775for (i = 0; i < num_syms; i++)776pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i];777{778tdefl_sym_freq *t = pCur_syms;779pCur_syms = pNew_syms;780pNew_syms = t;781}782}783return pCur_syms;784}
785
786/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */
787static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n)788{
789// NOLINTNEXTLINE(cppcoreguidelines-init-variables)790int root, leaf, next, avbl, used, dpth;791if (n == 0)792return;793else if (n == 1)794{795A[0].m_key = 1;796return;797}798A[0].m_key += A[1].m_key;799root = 0;800leaf = 2;801for (next = 1; next < n - 1; next++)802{803if (leaf >= n || A[root].m_key < A[leaf].m_key)804{805A[next].m_key = A[root].m_key;806A[root++].m_key = (mz_uint16)next;807}808else809A[next].m_key = A[leaf++].m_key;810if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key))811{812A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key);813A[root++].m_key = (mz_uint16)next;814}815else816A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);817}818A[n - 2].m_key = 0;819for (next = n - 3; next >= 0; next--)820A[next].m_key = A[A[next].m_key].m_key + 1;821avbl = 1;822used = dpth = 0;823root = n - 2;824next = n - 1;825while (avbl > 0)826{827while (root >= 0 && (int)A[root].m_key == dpth)828{829used++;830root--;831}832while (avbl > used)833{834A[next--].m_key = (mz_uint16)(dpth);835avbl--;836}837avbl = 2 * used;838dpth++;839used = 0;840}841}
842
843/* Limits canonical Huffman code table's max code size. */
844enum
845{
846TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32847};848static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size)849{
850// NOLINTNEXTLINE(cppcoreguidelines-init-variables)851int i;852mz_uint32 total = 0;853if (code_list_len <= 1)854return;855for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++)856pNum_codes[max_code_size] += pNum_codes[i];857for (i = max_code_size; i > 0; i--)858total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));859while (total != (1UL << max_code_size))860{861pNum_codes[max_code_size]--;862for (i = max_code_size - 1; i > 0; i--)863if (pNum_codes[i])864{865pNum_codes[i]--;866pNum_codes[i + 1] += 2;867break;868}869total--;870}871}
872
873static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table)874{
875// NOLINTNEXTLINE(cppcoreguidelines-init-variables)876int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE];877mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1];878MZ_CLEAR_OBJ(num_codes);879if (static_table)880{881for (i = 0; i < table_len; i++)882num_codes[d->m_huff_code_sizes[table_num][i]]++;883}884else885{886// NOLINTNEXTLINE(cppcoreguidelines-init-variables)887tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms;888int num_used_syms = 0;889const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];890for (i = 0; i < table_len; i++)891if (pSym_count[i])892{893syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i];894syms0[num_used_syms++].m_sym_index = (mz_uint16)i;895}896
897pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1);898tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);899
900for (i = 0; i < num_used_syms; i++)901num_codes[pSyms[i].m_key]++;902
903tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit);904
905MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]);906MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);907for (i = 1, j = num_used_syms; i <= code_size_limit; i++)908for (l = num_codes[i]; l > 0; l--)909d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);910}911
912next_code[1] = 0;913for (j = 0, i = 2; i <= code_size_limit; i++)914next_code[i] = j = ((j + num_codes[i - 1]) << 1);915
916for (i = 0; i < table_len; i++)917{918// NOLINTNEXTLINE(cppcoreguidelines-init-variables)919mz_uint rev_code = 0, code, code_size;920if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0)921continue;922code = next_code[code_size]++;923for (l = code_size; l > 0; l--, code >>= 1)924rev_code = (rev_code << 1) | (code & 1);925d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;926}927}
928
929#define TDEFL_PUT_BITS(b, l) \930do \931{ \932mz_uint bits = b; \933mz_uint len = l; \934MZ_ASSERT(bits <= ((1U << len) - 1U)); \935d->m_bit_buffer |= (bits << d->m_bits_in); \936d->m_bits_in += len; \937while (d->m_bits_in >= 8) \938{ \939if (d->m_pOutput_buf < d->m_pOutput_buf_end) \940*d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \941d->m_bit_buffer >>= 8; \942d->m_bits_in -= 8; \943} \944} \945MZ_MACRO_END946
947#define TDEFL_RLE_PREV_CODE_SIZE() \948{ \949if (rle_repeat_count) \950{ \951if (rle_repeat_count < 3) \952{ \953d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \954while (rle_repeat_count--) \955packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \956} \957else \958{ \959d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \960packed_code_sizes[num_packed_code_sizes++] = 16; \961packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \962} \963rle_repeat_count = 0; \964} \965}966
967#define TDEFL_RLE_ZERO_CODE_SIZE() \968{ \969if (rle_z_count) \970{ \971if (rle_z_count < 3) \972{ \973d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \974while (rle_z_count--) \975packed_code_sizes[num_packed_code_sizes++] = 0; \976} \977else if (rle_z_count <= 10) \978{ \979d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \980packed_code_sizes[num_packed_code_sizes++] = 17; \981packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \982} \983else \984{ \985d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \986packed_code_sizes[num_packed_code_sizes++] = 18; \987packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \988} \989rle_z_count = 0; \990} \991}992
993// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables,cppcoreguidelines-avoid-magic-numbers)
994static 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 };995
996static void tdefl_start_dynamic_block(tdefl_compressor *d)997{
998// NOLINTNEXTLINE(cppcoreguidelines-init-variables)999int num_lit_codes, num_dist_codes, num_bit_lengths;1000// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1001mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index;1002mz_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;1003
1004d->m_huff_count[0][256] = 1;1005
1006tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);1007tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);1008
1009for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--)1010if (d->m_huff_code_sizes[0][num_lit_codes - 1])1011break;1012for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--)1013if (d->m_huff_code_sizes[1][num_dist_codes - 1])1014break;1015
1016memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);1017memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes);1018total_code_sizes_to_pack = num_lit_codes + num_dist_codes;1019num_packed_code_sizes = 0;1020rle_z_count = 0;1021rle_repeat_count = 0;1022
1023memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);1024for (i = 0; i < total_code_sizes_to_pack; i++)1025{1026mz_uint8 code_size = code_sizes_to_pack[i];1027if (!code_size)1028{1029TDEFL_RLE_PREV_CODE_SIZE();1030if (++rle_z_count == 138)1031{1032TDEFL_RLE_ZERO_CODE_SIZE();1033}1034}1035else1036{1037TDEFL_RLE_ZERO_CODE_SIZE();1038if (code_size != prev_code_size)1039{1040TDEFL_RLE_PREV_CODE_SIZE();1041d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1);1042packed_code_sizes[num_packed_code_sizes++] = code_size;1043}1044else if (++rle_repeat_count == 6)1045{1046TDEFL_RLE_PREV_CODE_SIZE();1047}1048}1049prev_code_size = code_size;1050}1051if (rle_repeat_count)1052{1053TDEFL_RLE_PREV_CODE_SIZE();1054}1055else1056{1057TDEFL_RLE_ZERO_CODE_SIZE();1058}1059
1060tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);1061
1062TDEFL_PUT_BITS(2, 2);1063
1064TDEFL_PUT_BITS(num_lit_codes - 257, 5);1065TDEFL_PUT_BITS(num_dist_codes - 1, 5);1066
1067for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--)1068if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]])1069break;1070num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1));1071TDEFL_PUT_BITS(num_bit_lengths - 4, 4);1072for (i = 0; (int)i < num_bit_lengths; i++)1073TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);1074
1075for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;)1076{1077mz_uint code = packed_code_sizes[packed_code_sizes_index++];1078MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);1079TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);1080if (code >= 16)1081// NOLINTNEXTLINE(bugprone-signed-char-misuse)1082TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]);1083}1084}
1085
1086static void tdefl_start_static_block(tdefl_compressor *d)1087{
1088// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1089mz_uint i;1090mz_uint8 *p = &d->m_huff_code_sizes[0][0];1091
1092for (i = 0; i <= 143; ++i)1093*p++ = 8;1094for (; i <= 255; ++i)1095*p++ = 9;1096for (; i <= 279; ++i)1097*p++ = 7;1098for (; i <= 287; ++i)1099*p++ = 8;1100
1101memset(d->m_huff_code_sizes[1], 5, 32);1102
1103tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);1104tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);1105
1106TDEFL_PUT_BITS(1, 2);1107}
1108
1109static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };1110
1111#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS1112static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)1113{
1114mz_uint flags;1115mz_uint8 *pLZ_codes;1116mz_uint8 *pOutput_buf = d->m_pOutput_buf;1117mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;1118mz_uint64 bit_buffer = d->m_bit_buffer;1119mz_uint bits_in = d->m_bits_in;1120
1121#define TDEFL_PUT_BITS_FAST(b, l) \1122{ \1123bit_buffer |= (((mz_uint64)(b)) << bits_in); \1124bits_in += (l); \1125}1126
1127flags = 1;1128for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1)1129{1130if (flags == 1)1131flags = *pLZ_codes++ | 0x100;1132
1133if (flags & 1)1134{1135mz_uint s0, s1, n0, n1, sym, num_extra_bits;1136mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1);1137pLZ_codes += 3;1138
1139MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);1140TDEFL_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]]);1141TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);1142
1143/* This sequence coaxes MSVC into using cmov's vs. jmp's. */1144s0 = s_tdefl_small_dist_sym[match_dist & 511];1145n0 = s_tdefl_small_dist_extra[match_dist & 511];1146s1 = s_tdefl_large_dist_sym[match_dist >> 8];1147n1 = s_tdefl_large_dist_extra[match_dist >> 8];1148sym = (match_dist < 512) ? s0 : s1;1149num_extra_bits = (match_dist < 512) ? n0 : n1;1150
1151MZ_ASSERT(d->m_huff_code_sizes[1][sym]);1152TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);1153TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);1154}1155else1156{1157mz_uint lit = *pLZ_codes++;1158MZ_ASSERT(d->m_huff_code_sizes[0][lit]);1159TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);1160
1161if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))1162{1163flags >>= 1;1164lit = *pLZ_codes++;1165MZ_ASSERT(d->m_huff_code_sizes[0][lit]);1166TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);1167
1168if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))1169{1170flags >>= 1;1171lit = *pLZ_codes++;1172MZ_ASSERT(d->m_huff_code_sizes[0][lit]);1173TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);1174}1175}1176}1177
1178if (pOutput_buf >= d->m_pOutput_buf_end)1179return MZ_FALSE;1180
1181*(mz_uint64 *)pOutput_buf = bit_buffer;1182pOutput_buf += (bits_in >> 3);1183bit_buffer >>= (bits_in & ~7);1184bits_in &= 7;1185}1186
1187#undef TDEFL_PUT_BITS_FAST1188
1189d->m_pOutput_buf = pOutput_buf;1190d->m_bits_in = 0;1191d->m_bit_buffer = 0;1192
1193while (bits_in)1194{1195mz_uint32 n = MZ_MIN(bits_in, 16);1196TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);1197bit_buffer >>= n;1198bits_in -= n;1199}1200
1201TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);1202
1203return (d->m_pOutput_buf < d->m_pOutput_buf_end);1204}
1205#else1206static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)1207{
1208// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1209mz_uint flags;1210// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1211mz_uint8 *pLZ_codes;1212
1213flags = 1;1214for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1)1215{1216if (flags == 1)1217flags = *pLZ_codes++ | 0x100;1218if (flags & 1)1219{1220// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1221mz_uint sym, num_extra_bits;1222mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));1223pLZ_codes += 3;1224
1225MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);1226TDEFL_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]]);1227TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);1228
1229if (match_dist < 512)1230{1231sym = s_tdefl_small_dist_sym[match_dist];1232num_extra_bits = s_tdefl_small_dist_extra[match_dist];1233}1234else1235{1236sym = s_tdefl_large_dist_sym[match_dist >> 8];1237num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];1238}1239MZ_ASSERT(d->m_huff_code_sizes[1][sym]);1240TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);1241TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);1242}1243else1244{1245mz_uint lit = *pLZ_codes++;1246MZ_ASSERT(d->m_huff_code_sizes[0][lit]);1247TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);1248}1249}1250
1251TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);1252
1253return (d->m_pOutput_buf < d->m_pOutput_buf_end);1254}
1255#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */1256
1257static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block)1258{
1259if (static_block)1260tdefl_start_static_block(d);1261else1262tdefl_start_dynamic_block(d);1263return tdefl_compress_lz_codes(d);1264}
1265
1266static int tdefl_flush_block(tdefl_compressor *d, int flush)1267{
1268// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1269mz_uint saved_bit_buf, saved_bits_in;1270// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1271mz_uint8 *pSaved_output_buf;1272mz_bool comp_block_succeeded = MZ_FALSE;1273// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1274int 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;1275mz_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;1276
1277d->m_pOutput_buf = pOutput_buf_start;1278d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;1279
1280MZ_ASSERT(!d->m_output_flush_remaining);1281d->m_output_flush_ofs = 0;1282d->m_output_flush_remaining = 0;1283
1284*d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);1285d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);1286
1287if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index))1288{1289TDEFL_PUT_BITS(0x78, 8);1290TDEFL_PUT_BITS(0x01, 8);1291}1292
1293TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);1294
1295pSaved_output_buf = d->m_pOutput_buf;1296saved_bit_buf = d->m_bit_buffer;1297saved_bits_in = d->m_bits_in;1298
1299if (!use_raw_block)1300comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48));1301
1302/* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */1303if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) &&1304((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size))1305{1306// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1307mz_uint i;1308d->m_pOutput_buf = pSaved_output_buf;1309d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;1310TDEFL_PUT_BITS(0, 2);1311if (d->m_bits_in)1312{1313TDEFL_PUT_BITS(0, 8 - d->m_bits_in);1314}1315for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF)1316{1317TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);1318}1319for (i = 0; i < d->m_total_lz_bytes; ++i)1320{1321TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8);1322}1323}1324/* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */1325else if (!comp_block_succeeded)1326{1327d->m_pOutput_buf = pSaved_output_buf;1328d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;1329tdefl_compress_block(d, MZ_TRUE);1330}1331
1332if (flush)1333{1334if (flush == TDEFL_FINISH)1335{1336if (d->m_bits_in)1337{1338TDEFL_PUT_BITS(0, 8 - d->m_bits_in);1339}1340if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER)1341{1342// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1343mz_uint i, a = d->m_adler32;1344for (i = 0; i < 4; i++)1345{1346TDEFL_PUT_BITS((a >> 24) & 0xFF, 8);1347a <<= 8;1348}1349}1350}1351else1352{1353// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1354mz_uint i, z = 0;1355TDEFL_PUT_BITS(0, 3);1356if (d->m_bits_in)1357{1358TDEFL_PUT_BITS(0, 8 - d->m_bits_in);1359}1360for (i = 2; i; --i, z ^= 0xFFFF)1361{1362TDEFL_PUT_BITS(z & 0xFFFF, 16);1363}1364}1365}1366
1367MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);1368
1369memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);1370memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);1371
1372d->m_pLZ_code_buf = d->m_lz_code_buf + 1;1373d->m_pLZ_flags = d->m_lz_code_buf;1374d->m_num_flags_left = 8;1375d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes;1376d->m_total_lz_bytes = 0;1377d->m_block_index++;1378
1379if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0)1380{1381if (d->m_pPut_buf_func)1382{1383*d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;1384if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))1385return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);1386}1387else if (pOutput_buf_start == d->m_output_buf)1388{1389int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));1390memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy);1391d->m_out_buf_ofs += bytes_to_copy;1392if ((n -= bytes_to_copy) != 0)1393{1394d->m_output_flush_ofs = bytes_to_copy;1395d->m_output_flush_remaining = n;1396}1397}1398else1399{1400d->m_out_buf_ofs += n;1401}1402}1403
1404return d->m_output_flush_remaining;1405}
1406
1407#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES1408#ifdef MINIZ_UNALIGNED_USE_MEMCPY1409static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p)1410{
1411mz_uint16 ret;1412memcpy(&ret, p, sizeof(mz_uint16));1413return ret;1414}
1415static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p)1416{
1417mz_uint16 ret;1418memcpy(&ret, p, sizeof(mz_uint16));1419return ret;1420}
1421#else1422#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p)1423#define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p)1424#endif1425static 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)1426{
1427// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1428mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;1429mz_uint num_probes_left = d->m_max_probes[match_len >= 32];1430// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1431const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q;1432// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1433mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD2(s);1434MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);1435if (max_match_len <= match_len)1436return;1437for (;;)1438{1439for (;;)1440{1441if (--num_probes_left == 0)1442return;1443#define TDEFL_PROBE \1444next_probe_pos = d->m_next[probe_pos]; \1445if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \1446return; \1447probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \1448if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \1449break;1450TDEFL_PROBE;1451TDEFL_PROBE;1452TDEFL_PROBE;1453}1454if (!dist)1455break;1456q = (const mz_uint16 *)(d->m_dict + probe_pos);1457if (TDEFL_READ_UNALIGNED_WORD2(q) != s01)1458continue;1459p = s;1460probe_len = 32;1461do1462{1463} while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&1464(TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0));1465if (!probe_len)1466{1467*pMatch_dist = dist;1468*pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN);1469break;1470}1471else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len)1472{1473*pMatch_dist = dist;1474if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len)1475break;1476c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);1477}1478}1479}
1480#else1481static 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)1482{
1483mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;1484mz_uint num_probes_left = d->m_max_probes[match_len >= 32];1485const mz_uint8 *s = d->m_dict + pos, *p, *q;1486mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];1487MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);1488if (max_match_len <= match_len)1489return;1490for (;;)1491{1492for (;;)1493{1494if (--num_probes_left == 0)1495return;1496#define TDEFL_PROBE \1497next_probe_pos = d->m_next[probe_pos]; \1498if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \1499return; \1500probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \1501if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \1502break;1503TDEFL_PROBE;1504TDEFL_PROBE;1505TDEFL_PROBE;1506}1507if (!dist)1508break;1509p = s;1510q = d->m_dict + probe_pos;1511for (probe_len = 0; probe_len < max_match_len; probe_len++)1512if (*p++ != *q++)1513break;1514if (probe_len > match_len)1515{1516*pMatch_dist = dist;1517if ((*pMatch_len = match_len = probe_len) == max_match_len)1518return;1519c0 = d->m_dict[pos + match_len];1520c1 = d->m_dict[pos + match_len - 1];1521}1522}1523}
1524#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */1525
1526#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN1527#ifdef MINIZ_UNALIGNED_USE_MEMCPY1528static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8* p)1529{
1530mz_uint32 ret;1531memcpy(&ret, p, sizeof(mz_uint32));1532return ret;1533}
1534#else1535#define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p)1536#endif1537static mz_bool tdefl_compress_fast(tdefl_compressor *d)1538{
1539/* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */1540mz_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;1541mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;1542mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;1543
1544while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size)))1545{1546const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;1547mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;1548mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);1549d->m_src_buf_left -= num_bytes_to_process;1550lookahead_size += num_bytes_to_process;1551
1552while (num_bytes_to_process)1553{1554mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);1555memcpy(d->m_dict + dst_pos, d->m_pSrc, n);1556if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))1557memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));1558d->m_pSrc += n;1559dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;1560num_bytes_to_process -= n;1561}1562
1563dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);1564if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE))1565break;1566
1567while (lookahead_size >= 4)1568{1569mz_uint cur_match_dist, cur_match_len = 1;1570mz_uint8 *pCur_dict = d->m_dict + cur_pos;1571mz_uint first_trigram = TDEFL_READ_UNALIGNED_WORD32(pCur_dict) & 0xFFFFFF;1572mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK;1573mz_uint probe_pos = d->m_hash[hash];1574d->m_hash[hash] = (mz_uint16)lookahead_pos;1575
1576if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((TDEFL_READ_UNALIGNED_WORD32(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram))1577{1578const mz_uint16 *p = (const mz_uint16 *)pCur_dict;1579const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);1580mz_uint32 probe_len = 32;1581do1582{1583} while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) &&1584(TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0));1585cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);1586if (!probe_len)1587cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;1588
1589if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)))1590{1591cur_match_len = 1;1592*pLZ_code_buf++ = (mz_uint8)first_trigram;1593*pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);1594d->m_huff_count[0][(mz_uint8)first_trigram]++;1595}1596else1597{1598mz_uint32 s0, s1;1599cur_match_len = MZ_MIN(cur_match_len, lookahead_size);1600
1601MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE));1602
1603cur_match_dist--;1604
1605pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);1606#ifdef MINIZ_UNALIGNED_USE_MEMCPY1607memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist));1608#else1609*(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;1610#endif1611pLZ_code_buf += 3;1612*pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);1613
1614s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];1615s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];1616d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;1617
1618d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++;1619}1620}1621else1622{1623*pLZ_code_buf++ = (mz_uint8)first_trigram;1624*pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);1625d->m_huff_count[0][(mz_uint8)first_trigram]++;1626}1627
1628if (--num_flags_left == 0)1629{1630num_flags_left = 8;1631pLZ_flags = pLZ_code_buf++;1632}1633
1634total_lz_bytes += cur_match_len;1635lookahead_pos += cur_match_len;1636dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE);1637cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;1638MZ_ASSERT(lookahead_size >= cur_match_len);1639lookahead_size -= cur_match_len;1640
1641if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])1642{1643int n;1644d->m_lookahead_pos = lookahead_pos;1645d->m_lookahead_size = lookahead_size;1646d->m_dict_size = dict_size;1647d->m_total_lz_bytes = total_lz_bytes;1648d->m_pLZ_code_buf = pLZ_code_buf;1649d->m_pLZ_flags = pLZ_flags;1650d->m_num_flags_left = num_flags_left;1651if ((n = tdefl_flush_block(d, 0)) != 0)1652return (n < 0) ? MZ_FALSE : MZ_TRUE;1653total_lz_bytes = d->m_total_lz_bytes;1654pLZ_code_buf = d->m_pLZ_code_buf;1655pLZ_flags = d->m_pLZ_flags;1656num_flags_left = d->m_num_flags_left;1657}1658}1659
1660while (lookahead_size)1661{1662mz_uint8 lit = d->m_dict[cur_pos];1663
1664total_lz_bytes++;1665*pLZ_code_buf++ = lit;1666*pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);1667if (--num_flags_left == 0)1668{1669num_flags_left = 8;1670pLZ_flags = pLZ_code_buf++;1671}1672
1673d->m_huff_count[0][lit]++;1674
1675lookahead_pos++;1676dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE);1677cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;1678lookahead_size--;1679
1680if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])1681{1682int n;1683d->m_lookahead_pos = lookahead_pos;1684d->m_lookahead_size = lookahead_size;1685d->m_dict_size = dict_size;1686d->m_total_lz_bytes = total_lz_bytes;1687d->m_pLZ_code_buf = pLZ_code_buf;1688d->m_pLZ_flags = pLZ_flags;1689d->m_num_flags_left = num_flags_left;1690if ((n = tdefl_flush_block(d, 0)) != 0)1691return (n < 0) ? MZ_FALSE : MZ_TRUE;1692total_lz_bytes = d->m_total_lz_bytes;1693pLZ_code_buf = d->m_pLZ_code_buf;1694pLZ_flags = d->m_pLZ_flags;1695num_flags_left = d->m_num_flags_left;1696}1697}1698}1699
1700d->m_lookahead_pos = lookahead_pos;1701d->m_lookahead_size = lookahead_size;1702d->m_dict_size = dict_size;1703d->m_total_lz_bytes = total_lz_bytes;1704d->m_pLZ_code_buf = pLZ_code_buf;1705d->m_pLZ_flags = pLZ_flags;1706d->m_num_flags_left = num_flags_left;1707return MZ_TRUE;1708}
1709#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */1710
1711static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit)1712{
1713d->m_total_lz_bytes++;1714*d->m_pLZ_code_buf++ = lit;1715// NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)1716*d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1);1717if (--d->m_num_flags_left == 0)1718{1719d->m_num_flags_left = 8;1720d->m_pLZ_flags = d->m_pLZ_code_buf++;1721}1722d->m_huff_count[0][lit]++;1723}
1724
1725static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist)1726{
1727// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1728mz_uint32 s0, s1;1729
1730MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE));1731
1732d->m_total_lz_bytes += match_len;1733
1734d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);1735
1736match_dist -= 1;1737d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);1738d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8);1739d->m_pLZ_code_buf += 3;1740
1741*d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80);1742if (--d->m_num_flags_left == 0)1743{1744d->m_num_flags_left = 8;1745d->m_pLZ_flags = d->m_pLZ_code_buf++;1746}1747
1748s0 = s_tdefl_small_dist_sym[match_dist & 511];1749s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];1750d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;1751
1752if (match_len >= TDEFL_MIN_MATCH_LEN)1753d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;1754}
1755
1756static mz_bool tdefl_compress_normal(tdefl_compressor *d)1757{
1758const mz_uint8 *pSrc = d->m_pSrc;1759size_t src_buf_left = d->m_src_buf_left;1760tdefl_flush flush = d->m_flush;1761
1762while ((src_buf_left) || ((flush) && (d->m_lookahead_size)))1763{1764// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1765mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;1766/* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */1767if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1))1768{1769mz_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;1770mz_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];1771mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);1772const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;1773src_buf_left -= num_bytes_to_process;1774d->m_lookahead_size += num_bytes_to_process;1775while (pSrc != pSrc_end)1776{1777mz_uint8 c = *pSrc++;1778d->m_dict[dst_pos] = c;1779if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))1780d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;1781hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);1782d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];1783d->m_hash[hash] = (mz_uint16)(ins_pos);1784dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;1785ins_pos++;1786}1787}1788else1789{1790while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))1791{1792mz_uint8 c = *pSrc++;1793mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;1794src_buf_left--;1795d->m_dict[dst_pos] = c;1796if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))1797d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;1798if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN)1799{1800mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;1801mz_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);1802d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];1803d->m_hash[hash] = (mz_uint16)(ins_pos);1804}1805}1806}1807d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);1808if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))1809break;1810
1811/* Simple lazy/greedy parsing state machine. */1812len_to_move = 1;1813cur_match_dist = 0;1814cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1);1815cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;1816if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS))1817{1818if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))1819{1820mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];1821cur_match_len = 0;1822while (cur_match_len < d->m_lookahead_size)1823{1824if (d->m_dict[cur_pos + cur_match_len] != c)1825break;1826cur_match_len++;1827}1828if (cur_match_len < TDEFL_MIN_MATCH_LEN)1829cur_match_len = 0;1830else1831cur_match_dist = 1;1832}1833}1834else1835{1836tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len);1837}1838if (((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)))1839{1840cur_match_dist = cur_match_len = 0;1841}1842if (d->m_saved_match_len)1843{1844if (cur_match_len > d->m_saved_match_len)1845{1846tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);1847if (cur_match_len >= 128)1848{1849tdefl_record_match(d, cur_match_len, cur_match_dist);1850d->m_saved_match_len = 0;1851len_to_move = cur_match_len;1852}1853else1854{1855d->m_saved_lit = d->m_dict[cur_pos];1856d->m_saved_match_dist = cur_match_dist;1857d->m_saved_match_len = cur_match_len;1858}1859}1860else1861{1862tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);1863len_to_move = d->m_saved_match_len - 1;1864d->m_saved_match_len = 0;1865}1866}1867else if (!cur_match_dist)1868tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);1869else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128))1870{1871tdefl_record_match(d, cur_match_len, cur_match_dist);1872len_to_move = cur_match_len;1873}1874else1875{1876d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)];1877d->m_saved_match_dist = cur_match_dist;1878d->m_saved_match_len = cur_match_len;1879}1880/* Move the lookahead forward by len_to_move bytes. */1881d->m_lookahead_pos += len_to_move;1882MZ_ASSERT(d->m_lookahead_size >= len_to_move);1883d->m_lookahead_size -= len_to_move;1884d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE);1885/* Check if it's time to flush the current LZ codes to the internal output buffer. */1886if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||1887((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))))1888{1889// NOLINTNEXTLINE(cppcoreguidelines-init-variables)1890int n;1891d->m_pSrc = pSrc;1892d->m_src_buf_left = src_buf_left;1893if ((n = tdefl_flush_block(d, 0)) != 0)1894return (n < 0) ? MZ_FALSE : MZ_TRUE;1895}1896}1897
1898d->m_pSrc = pSrc;1899d->m_src_buf_left = src_buf_left;1900return MZ_TRUE;1901}
1902
1903static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d)1904{
1905if (d->m_pIn_buf_size)1906{1907*d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;1908}1909
1910if (d->m_pOut_buf_size)1911{1912size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining);1913memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n);1914d->m_output_flush_ofs += (mz_uint)n;1915d->m_output_flush_remaining -= (mz_uint)n;1916d->m_out_buf_ofs += n;1917
1918*d->m_pOut_buf_size = d->m_out_buf_ofs;1919}1920
1921return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY;1922}
1923
1924tdefl_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)1925{
1926if (!d)1927{1928if (pIn_buf_size)1929*pIn_buf_size = 0;1930if (pOut_buf_size)1931*pOut_buf_size = 0;1932return TDEFL_STATUS_BAD_PARAM;1933}1934
1935d->m_pIn_buf = pIn_buf;1936d->m_pIn_buf_size = pIn_buf_size;1937d->m_pOut_buf = pOut_buf;1938d->m_pOut_buf_size = pOut_buf_size;1939d->m_pSrc = (const mz_uint8 *)(pIn_buf);1940d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;1941d->m_out_buf_ofs = 0;1942d->m_flush = flush;1943
1944if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||1945(d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf))1946{1947if (pIn_buf_size)1948*pIn_buf_size = 0;1949if (pOut_buf_size)1950*pOut_buf_size = 0;1951return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);1952}1953d->m_wants_to_finish |= (flush == TDEFL_FINISH);1954
1955if ((d->m_output_flush_remaining) || (d->m_finished))1956return (d->m_prev_return_status = tdefl_flush_output_buffer(d));1957
1958#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN1959if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&1960((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&1961((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0))1962{1963if (!tdefl_compress_fast(d))1964return d->m_prev_return_status;1965}1966else1967#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */1968{1969if (!tdefl_compress_normal(d))1970return d->m_prev_return_status;1971}1972
1973if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf))1974d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf);1975
1976if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining))1977{1978if (tdefl_flush_block(d, flush) < 0)1979return d->m_prev_return_status;1980d->m_finished = (flush == TDEFL_FINISH);1981if (flush == TDEFL_FULL_FLUSH)1982{1983MZ_CLEAR_OBJ(d->m_hash);1984MZ_CLEAR_OBJ(d->m_next);1985d->m_dict_size = 0;1986}1987}1988
1989return (d->m_prev_return_status = tdefl_flush_output_buffer(d));1990}
1991
1992tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush)1993{
1994MZ_ASSERT(d->m_pPut_buf_func);1995return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);1996}
1997
1998tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)1999{
2000d->m_pPut_buf_func = pPut_buf_func;2001d->m_pPut_buf_user = pPut_buf_user;2002d->m_flags = (mz_uint)(flags);2003d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3;2004d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;2005d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;2006if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG))2007MZ_CLEAR_OBJ(d->m_hash);2008d->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;2009d->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;2010d->m_pLZ_code_buf = d->m_lz_code_buf + 1;2011d->m_pLZ_flags = d->m_lz_code_buf;2012d->m_num_flags_left = 8;2013d->m_pOutput_buf = d->m_output_buf;2014d->m_pOutput_buf_end = d->m_output_buf;2015d->m_prev_return_status = TDEFL_STATUS_OKAY;2016d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0;2017d->m_adler32 = 1;2018d->m_pIn_buf = NULL;2019d->m_pOut_buf = NULL;2020d->m_pIn_buf_size = NULL;2021d->m_pOut_buf_size = NULL;2022d->m_flush = TDEFL_NO_FLUSH;2023d->m_pSrc = NULL;2024d->m_src_buf_left = 0;2025d->m_out_buf_ofs = 0;2026if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG))2027MZ_CLEAR_OBJ(d->m_dict);2028memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);2029memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);2030return TDEFL_STATUS_OKAY;2031}
2032
2033tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d)2034{
2035return d->m_prev_return_status;2036}
2037
2038mz_uint32 tdefl_get_adler32(tdefl_compressor *d)2039{
2040return d->m_adler32;2041}
2042
2043mz_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)2044{
2045// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2046tdefl_compressor *pComp;2047// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2048mz_bool succeeded;2049if (((buf_len) && (!pBuf)) || (!pPut_buf_func))2050return MZ_FALSE;2051pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));2052if (!pComp)2053return MZ_FALSE;2054succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY);2055succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE);2056MZ_FREE(pComp);2057return succeeded;2058}
2059
2060typedef struct2061{
2062size_t m_size, m_capacity;2063mz_uint8 *m_pBuf;2064mz_bool m_expandable;2065} tdefl_output_buffer;2066
2067static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser)2068{
2069tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;2070size_t new_size = p->m_size + len;2071if (new_size > p->m_capacity)2072{2073size_t new_capacity = p->m_capacity;2074// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2075mz_uint8 *pNew_buf;2076if (!p->m_expandable)2077return MZ_FALSE;2078do2079{2080new_capacity = MZ_MAX(128U, new_capacity << 1U);2081} while (new_size > new_capacity);2082pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity);2083if (!pNew_buf)2084return MZ_FALSE;2085p->m_pBuf = pNew_buf;2086p->m_capacity = new_capacity;2087}2088memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len);2089p->m_size = new_size;2090return MZ_TRUE;2091}
2092
2093void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)2094{
2095tdefl_output_buffer out_buf;2096MZ_CLEAR_OBJ(out_buf);2097if (!pOut_len)2098return MZ_FALSE;2099else2100*pOut_len = 0;2101out_buf.m_expandable = MZ_TRUE;2102if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))2103return NULL;2104*pOut_len = out_buf.m_size;2105return out_buf.m_pBuf;2106}
2107
2108size_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)2109{
2110tdefl_output_buffer out_buf;2111MZ_CLEAR_OBJ(out_buf);2112if (!pOut_buf)2113return 0;2114out_buf.m_pBuf = (mz_uint8 *)pOut_buf;2115out_buf.m_capacity = out_buf_len;2116if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))2117return 0;2118return out_buf.m_size;2119}
2120
2121static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };2122
2123/* 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). */
2124mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy)2125{
2126mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);2127if (window_bits > 0)2128comp_flags |= TDEFL_WRITE_ZLIB_HEADER;2129
2130if (!level)2131comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;2132else if (strategy == MZ_FILTERED)2133comp_flags |= TDEFL_FILTER_MATCHES;2134else if (strategy == MZ_HUFFMAN_ONLY)2135comp_flags &= ~TDEFL_MAX_PROBES_MASK;2136else if (strategy == MZ_FIXED)2137comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;2138else if (strategy == MZ_RLE)2139comp_flags |= TDEFL_RLE_MATCHES;2140
2141return comp_flags;2142}
2143
2144#ifdef _MSC_VER2145#pragma warning(push)2146#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */2147#endif2148
2149/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at
2150http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
2151This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */
2152void *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)2153{
2154/* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */2155static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };2156tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));2157tdefl_output_buffer out_buf;2158// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2159int i, bpl = w * num_chans, y, z;2160// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2161mz_uint32 c;2162*pLen_out = 0;2163if (!pComp)2164return NULL;2165MZ_CLEAR_OBJ(out_buf);2166out_buf.m_expandable = MZ_TRUE;2167out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h);2168if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity)))2169{2170MZ_FREE(pComp);2171return NULL;2172}2173/* write dummy header */2174for (z = 41; z; --z)2175tdefl_output_buffer_putter(&z, 1, &out_buf);2176/* compress image data */2177// NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)2178tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);2179for (y = 0; y < h; ++y)2180{2181tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH);2182tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH);2183}2184if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE)2185{2186MZ_FREE(pComp);2187MZ_FREE(out_buf.m_pBuf);2188return NULL;2189}2190/* write real header */2191*pLen_out = out_buf.m_size - 41;2192{2193static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 };2194mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d,21950x0a, 0x1a, 0x0a, 0x00, 0x00,21960x00, 0x0d, 0x49, 0x48, 0x44,21970x52, 0x00, 0x00, 0x00, 0x00,21980x00, 0x00, 0x00, 0x00, 0x08,21990x00, 0x00, 0x00, 0x00, 0x00,22000x00, 0x00, 0x00, 0x00, 0x00,22010x00, 0x00, 0x49, 0x44, 0x41,22020x54 };2203pnghdr[18] = (mz_uint8)(w >> 8);2204pnghdr[19] = (mz_uint8)w;2205pnghdr[22] = (mz_uint8)(h >> 8);2206pnghdr[23] = (mz_uint8)h;2207pnghdr[25] = chans[num_chans];2208pnghdr[33] = (mz_uint8)(*pLen_out >> 24);2209pnghdr[34] = (mz_uint8)(*pLen_out >> 16);2210pnghdr[35] = (mz_uint8)(*pLen_out >> 8);2211pnghdr[36] = (mz_uint8)*pLen_out;2212c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17);2213for (i = 0; i < 4; ++i, c <<= 8)2214((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24);2215memcpy(out_buf.m_pBuf, pnghdr, 41);2216}2217/* write footer (IDAT CRC-32, followed by IEND chunk) */2218if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf))2219{2220*pLen_out = 0;2221MZ_FREE(pComp);2222MZ_FREE(out_buf.m_pBuf);2223return NULL;2224}2225c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4);2226for (i = 0; i < 4; ++i, c <<= 8)2227(out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24);2228/* compute final size of file, grab compressed data buffer and return */2229*pLen_out += 57;2230MZ_FREE(pComp);2231return out_buf.m_pBuf;2232}
2233void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out)2234{
2235/* 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) */2236return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE);2237}
2238
2239#ifndef MINIZ_NO_MALLOC2240/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */
2241/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */
2242/* structure size and allocation mechanism. */
2243tdefl_compressor *tdefl_compressor_alloc(void)2244{
2245return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));2246}
2247
2248void tdefl_compressor_free(tdefl_compressor *pComp)2249{
2250MZ_FREE(pComp);2251}
2252#endif2253
2254#ifdef _MSC_VER2255#pragma warning(pop)2256#endif2257
2258#ifdef __cplusplus2259}
2260#endif2261/**************************************************************************
2262*
2263* Copyright 2013-2014 RAD Game Tools and Valve Software
2264* Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
2265* All Rights Reserved.
2266*
2267* Permission is hereby granted, free of charge, to any person obtaining a copy
2268* of this software and associated documentation files (the "Software"), to deal
2269* in the Software without restriction, including without limitation the rights
2270* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2271* copies of the Software, and to permit persons to whom the Software is
2272* furnished to do so, subject to the following conditions:
2273*
2274* The above copyright notice and this permission notice shall be included in
2275* all copies or substantial portions of the Software.
2276*
2277* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2278* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2279* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2280* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2281* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2282* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2283* THE SOFTWARE.
2284*
2285**************************************************************************/
2286
2287
2288
2289#ifdef __cplusplus2290extern "C" {2291#endif2292
2293/* ------------------- Low-level Decompression (completely independent from all compression API's) */
2294
2295#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)2296#define TINFL_MEMSET(p, c, l) memset(p, c, l)2297
2298#define TINFL_CR_BEGIN \2299switch (r->m_state) \2300{ \2301case 0:2302#define TINFL_CR_RETURN(state_index, result) \2303do \2304{ \2305status = result; \2306r->m_state = state_index; \2307goto common_exit; \2308case state_index:; \2309} \2310MZ_MACRO_END2311#define TINFL_CR_RETURN_FOREVER(state_index, result) \2312do \2313{ \2314for (;;) \2315{ \2316TINFL_CR_RETURN(state_index, result); \2317} \2318} \2319MZ_MACRO_END2320#define TINFL_CR_FINISH }2321
2322#define TINFL_GET_BYTE(state_index, c) \2323do \2324{ \2325while (pIn_buf_cur >= pIn_buf_end) \2326{ \2327TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \2328} \2329c = *pIn_buf_cur++; \2330} \2331MZ_MACRO_END2332
2333#define TINFL_NEED_BITS(state_index, n) \2334do \2335{ \2336mz_uint c; \2337TINFL_GET_BYTE(state_index, c); \2338bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \2339num_bits += 8; \2340} while (num_bits < (mz_uint)(n))2341#define TINFL_SKIP_BITS(state_index, n) \2342do \2343{ \2344if (num_bits < (mz_uint)(n)) \2345{ \2346TINFL_NEED_BITS(state_index, n); \2347} \2348bit_buf >>= (n); \2349num_bits -= (n); \2350} \2351MZ_MACRO_END2352#define TINFL_GET_BITS(state_index, b, n) \2353do \2354{ \2355if (num_bits < (mz_uint)(n)) \2356{ \2357TINFL_NEED_BITS(state_index, n); \2358} \2359b = bit_buf & ((1 << (n)) - 1); \2360bit_buf >>= (n); \2361num_bits -= (n); \2362} \2363MZ_MACRO_END2364
2365/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */
2366/* 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 */
2367/* 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 */
2368/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */
2369#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \2370do \2371{ \2372temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \2373if (temp >= 0) \2374{ \2375code_len = temp >> 9; \2376if ((code_len) && (num_bits >= code_len)) \2377break; \2378} \2379else if (num_bits > TINFL_FAST_LOOKUP_BITS) \2380{ \2381code_len = TINFL_FAST_LOOKUP_BITS; \2382do \2383{ \2384temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \2385} while ((temp < 0) && (num_bits >= (code_len + 1))); \2386if (temp >= 0) \2387break; \2388} \2389TINFL_GET_BYTE(state_index, c); \2390bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \2391num_bits += 8; \2392} while (num_bits < 15);2393
2394/* 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 */
2395/* 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 */
2396/* 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. */
2397/* The slow path is only executed at the very end of the input buffer. */
2398/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */
2399/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */
2400#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \2401do \2402{ \2403int temp; \2404mz_uint code_len, c; \2405if (num_bits < 15) \2406{ \2407if ((pIn_buf_end - pIn_buf_cur) < 2) \2408{ \2409TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \2410} \2411else \2412{ \2413bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \2414pIn_buf_cur += 2; \2415num_bits += 16; \2416} \2417} \2418if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \2419code_len = temp >> 9, temp &= 511; \2420else \2421{ \2422code_len = TINFL_FAST_LOOKUP_BITS; \2423do \2424{ \2425temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \2426} while (temp < 0); \2427} \2428sym = temp; \2429bit_buf >>= code_len; \2430num_bits -= code_len; \2431} \2432MZ_MACRO_END2433
2434tinfl_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)2435{
2436static 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 };2437static 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 };2438static 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 };2439static 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 };2440static 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 };2441static const int s_min_table_sizes[3] = { 257, 1, 4 };2442
2443tinfl_status status = TINFL_STATUS_FAILED;2444// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2445mz_uint32 num_bits, dist, counter, num_extra;2446// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2447tinfl_bit_buf_t bit_buf;2448const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;2449mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;2450// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2451size_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;2452
2453/* 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). */2454if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start))2455{2456*pIn_buf_size = *pOut_buf_size = 0;2457return TINFL_STATUS_BAD_PARAM;2458}2459
2460num_bits = r->m_num_bits;2461bit_buf = r->m_bit_buf;2462dist = r->m_dist;2463counter = r->m_counter;2464num_extra = r->m_num_extra;2465dist_from_out_buf_start = r->m_dist_from_out_buf_start;2466TINFL_CR_BEGIN
2467
2468bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0;2469r->m_z_adler32 = r->m_check_adler32 = 1;2470if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)2471{2472TINFL_GET_BYTE(1, r->m_zhdr0);2473TINFL_GET_BYTE(2, r->m_zhdr1);2474counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));2475if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))2476// NOLINTNEXTLINE(bugprone-misplaced-widening-cast,cppcoreguidelines-avoid-magic-numbers)2477counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));2478if (counter)2479{2480TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED);2481}2482}2483
2484do2485{2486TINFL_GET_BITS(3, r->m_final, 3);2487r->m_type = r->m_final >> 1;2488if (r->m_type == 0)2489{2490TINFL_SKIP_BITS(5, num_bits & 7);2491for (counter = 0; counter < 4; ++counter)2492{2493if (num_bits)2494TINFL_GET_BITS(6, r->m_raw_header[counter], 8);2495else2496TINFL_GET_BYTE(7, r->m_raw_header[counter]);2497}2498if ((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))))2499{2500TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED);2501}2502while ((counter) && (num_bits))2503{2504TINFL_GET_BITS(51, dist, 8);2505while (pOut_buf_cur >= pOut_buf_end)2506{2507TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT);2508}2509*pOut_buf_cur++ = (mz_uint8)dist;2510counter--;2511}2512while (counter)2513{2514// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2515size_t n;2516while (pOut_buf_cur >= pOut_buf_end)2517{2518TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT);2519}2520while (pIn_buf_cur >= pIn_buf_end)2521{2522TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS);2523}2524n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);2525TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n);2526pIn_buf_cur += n;2527pOut_buf_cur += n;2528counter -= (mz_uint)n;2529}2530}2531else if (r->m_type == 3)2532{2533TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);2534}2535else2536{2537if (r->m_type == 1)2538{2539mz_uint8 *p = r->m_tables[0].m_code_size;2540// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2541mz_uint i;2542r->m_table_sizes[0] = 288;2543r->m_table_sizes[1] = 32;2544TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);2545for (i = 0; i <= 143; ++i)2546*p++ = 8;2547for (; i <= 255; ++i)2548*p++ = 9;2549for (; i <= 279; ++i)2550*p++ = 7;2551for (; i <= 287; ++i)2552*p++ = 8;2553}2554else2555{2556for (counter = 0; counter < 3; counter++)2557{2558TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]);2559r->m_table_sizes[counter] += s_min_table_sizes[counter];2560}2561MZ_CLEAR_OBJ(r->m_tables[2].m_code_size);2562for (counter = 0; counter < r->m_table_sizes[2]; counter++)2563{2564// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2565mz_uint s;2566TINFL_GET_BITS(14, s, 3);2567r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s;2568}2569r->m_table_sizes[2] = 19;2570}2571for (; (int)r->m_type >= 0; r->m_type--)2572{2573// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2574int tree_next, tree_cur;2575// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2576tinfl_huff_table *pTable;2577// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,cppcoreguidelines-init-variables)2578mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16];2579pTable = &r->m_tables[r->m_type];2580MZ_CLEAR_OBJ(total_syms);2581MZ_CLEAR_OBJ(pTable->m_look_up);2582MZ_CLEAR_OBJ(pTable->m_tree);2583for (i = 0; i < r->m_table_sizes[r->m_type]; ++i)2584total_syms[pTable->m_code_size[i]]++;2585used_syms = 0, total = 0;2586next_code[0] = next_code[1] = 0;2587for (i = 1; i <= 15; ++i)2588{2589used_syms += total_syms[i];2590next_code[i + 1] = (total = ((total + total_syms[i]) << 1));2591}2592if ((65536 != total) && (used_syms > 1))2593{2594TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);2595}2596for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)2597{2598// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2599mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index];2600if (!code_size)2601continue;2602cur_code = next_code[code_size]++;2603for (l = code_size; l > 0; l--, cur_code >>= 1)2604rev_code = (rev_code << 1) | (cur_code & 1);2605if (code_size <= TINFL_FAST_LOOKUP_BITS)2606{2607mz_int16 k = (mz_int16)((code_size << 9) | sym_index);2608while (rev_code < TINFL_FAST_LOOKUP_SIZE)2609{2610pTable->m_look_up[rev_code] = k;2611rev_code += (1 << code_size);2612}2613continue;2614}2615if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)]))2616{2617pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next;2618tree_cur = tree_next;2619tree_next -= 2;2620}2621rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);2622for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)2623{2624// NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)2625tree_cur -= ((rev_code >>= 1) & 1);2626if (!pTable->m_tree[-tree_cur - 1])2627{2628pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next;2629tree_cur = tree_next;2630tree_next -= 2;2631}2632else2633tree_cur = pTable->m_tree[-tree_cur - 1];2634}2635// NOLINTNEXTLINE(bugprone-narrowing-conversions,clang-analyzer-deadcode.DeadStores,cppcoreguidelines-narrowing-conversions)2636tree_cur -= ((rev_code >>= 1) & 1);2637pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;2638}2639if (r->m_type == 2)2640{2641for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);)2642{2643// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2644mz_uint s;2645TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]);2646if (dist < 16)2647{2648r->m_len_codes[counter++] = (mz_uint8)dist;2649continue;2650}2651if ((dist == 16) && (!counter))2652{2653TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);2654}2655// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,bugprone-signed-char-misuse)2656num_extra = "\02\03\07"[dist - 16];2657TINFL_GET_BITS(18, s, num_extra);2658s += "\03\03\013"[dist - 16];2659TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s);2660counter += s;2661}2662if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)2663{2664TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);2665}2666TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]);2667TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);2668}2669}2670for (;;)2671{2672// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2673mz_uint8 *pSrc;2674for (;;)2675{2676if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))2677{2678TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);2679if (counter >= 256)2680break;2681while (pOut_buf_cur >= pOut_buf_end)2682{2683TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT);2684}2685*pOut_buf_cur++ = (mz_uint8)counter;2686}2687else2688{2689// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2690int sym2;2691// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2692mz_uint code_len;2693#if TINFL_USE_64BIT_BITBUF2694if (num_bits < 30)2695{2696bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits);2697pIn_buf_cur += 4;2698num_bits += 32;2699}2700#else2701if (num_bits < 15)2702{2703bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);2704pIn_buf_cur += 2;2705num_bits += 16;2706}2707#endif2708if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)2709code_len = sym2 >> 9;2710else2711{2712code_len = TINFL_FAST_LOOKUP_BITS;2713do2714{2715sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];2716} while (sym2 < 0);2717}2718counter = sym2;2719bit_buf >>= code_len;2720num_bits -= code_len;2721if (counter & 256)2722break;2723
2724#if !TINFL_USE_64BIT_BITBUF2725if (num_bits < 15)2726{2727bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);2728pIn_buf_cur += 2;2729num_bits += 16;2730}2731#endif2732if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)2733code_len = sym2 >> 9;2734else2735{2736code_len = TINFL_FAST_LOOKUP_BITS;2737do2738{2739sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];2740} while (sym2 < 0);2741}2742bit_buf >>= code_len;2743num_bits -= code_len;2744
2745pOut_buf_cur[0] = (mz_uint8)counter;2746if (sym2 & 256)2747{2748pOut_buf_cur++;2749counter = sym2;2750break;2751}2752pOut_buf_cur[1] = (mz_uint8)sym2;2753pOut_buf_cur += 2;2754}2755}2756if ((counter &= 511) == 256)2757break;2758
2759num_extra = s_length_extra[counter - 257];2760counter = s_length_base[counter - 257];2761if (num_extra)2762{2763// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2764mz_uint extra_bits;2765TINFL_GET_BITS(25, extra_bits, num_extra);2766counter += extra_bits;2767}2768
2769TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);2770num_extra = s_dist_extra[dist];2771dist = s_dist_base[dist];2772if (num_extra)2773{2774// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2775mz_uint extra_bits;2776TINFL_GET_BITS(27, extra_bits, num_extra);2777dist += extra_bits;2778}2779
2780dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;2781if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))2782{2783TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);2784}2785
2786pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);2787
2788if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)2789{2790while (counter--)2791{2792while (pOut_buf_cur >= pOut_buf_end)2793{2794TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT);2795}2796*pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];2797}2798continue;2799}2800#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES2801else if ((counter >= 9) && (counter <= dist))2802{2803const mz_uint8 *pSrc_end = pSrc + (counter & ~7);2804do2805{2806#ifdef MINIZ_UNALIGNED_USE_MEMCPY2807memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32)*2);2808#else2809((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];2810((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];2811#endif2812pOut_buf_cur += 8;2813} while ((pSrc += 8) < pSrc_end);2814if ((counter &= 7) < 3)2815{2816if (counter)2817{2818pOut_buf_cur[0] = pSrc[0];2819if (counter > 1)2820pOut_buf_cur[1] = pSrc[1];2821pOut_buf_cur += counter;2822}2823continue;2824}2825}2826#endif2827while(counter>2)2828{2829pOut_buf_cur[0] = pSrc[0];2830pOut_buf_cur[1] = pSrc[1];2831pOut_buf_cur[2] = pSrc[2];2832pOut_buf_cur += 3;2833pSrc += 3;2834counter -= 3;2835}2836if (counter > 0)2837{2838pOut_buf_cur[0] = pSrc[0];2839if (counter > 1)2840pOut_buf_cur[1] = pSrc[1];2841pOut_buf_cur += counter;2842}2843}2844}2845} while (!(r->m_final & 1));2846
2847/* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */2848/* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */2849TINFL_SKIP_BITS(32, num_bits & 7);2850while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8))2851{2852--pIn_buf_cur;2853num_bits -= 8;2854}2855bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1);2856MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */2857
2858if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)2859{2860for (counter = 0; counter < 4; ++counter)2861{2862// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2863mz_uint s;2864if (num_bits)2865TINFL_GET_BITS(41, s, 8);2866else2867TINFL_GET_BYTE(42, s);2868r->m_z_adler32 = (r->m_z_adler32 << 8) | s;2869}2870}2871TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);2872
2873TINFL_CR_FINISH
2874
2875common_exit:2876/* As long as we aren't telling the caller that we NEED more input to make forward progress: */2877/* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */2878/* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */2879if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS))2880{2881while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8))2882{2883--pIn_buf_cur;2884num_bits -= 8;2885}2886}2887r->m_num_bits = num_bits;2888r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1);2889r->m_dist = dist;2890r->m_counter = counter;2891r->m_num_extra = num_extra;2892r->m_dist_from_out_buf_start = dist_from_out_buf_start;2893*pIn_buf_size = pIn_buf_cur - pIn_buf_next;2894*pOut_buf_size = pOut_buf_cur - pOut_buf_next;2895if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))2896{2897const mz_uint8 *ptr = pOut_buf_next;2898size_t buf_len = *pOut_buf_size;2899// NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,cppcoreguidelines-init-variables)2900mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16;2901size_t block_len = buf_len % 5552;2902while (buf_len)2903{2904for (i = 0; i + 7 < block_len; i += 8, ptr += 8)2905{2906s1 += ptr[0], s2 += s1;2907s1 += ptr[1], s2 += s1;2908s1 += ptr[2], s2 += s1;2909s1 += ptr[3], s2 += s1;2910s1 += ptr[4], s2 += s1;2911s1 += ptr[5], s2 += s1;2912s1 += ptr[6], s2 += s1;2913s1 += ptr[7], s2 += s1;2914}2915for (; i < block_len; ++i)2916s1 += *ptr++, s2 += s1;2917s1 %= 65521U, s2 %= 65521U;2918buf_len -= block_len;2919block_len = 5552;2920}2921r->m_check_adler32 = (s2 << 16) + s1;2922if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32))2923status = TINFL_STATUS_ADLER32_MISMATCH;2924}2925return status;2926}
2927
2928/* Higher level helper functions. */
2929void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)2930{
2931tinfl_decompressor decomp;2932// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2933void *pBuf = NULL, *pNew_buf;2934size_t src_buf_ofs = 0, out_buf_capacity = 0;2935*pOut_len = 0;2936tinfl_init(&decomp);2937for (;;)2938{2939// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2940size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;2941tinfl_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,2942(flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);2943if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))2944{2945MZ_FREE(pBuf);2946*pOut_len = 0;2947return NULL;2948}2949src_buf_ofs += src_buf_size;2950*pOut_len += dst_buf_size;2951if (status == TINFL_STATUS_DONE)2952break;2953new_out_buf_capacity = out_buf_capacity * 2;2954if (new_out_buf_capacity < 128)2955new_out_buf_capacity = 128;2956pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);2957if (!pNew_buf)2958{2959MZ_FREE(pBuf);2960*pOut_len = 0;2961return NULL;2962}2963pBuf = pNew_buf;2964out_buf_capacity = new_out_buf_capacity;2965}2966return pBuf;2967}
2968
2969size_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)2970{
2971tinfl_decompressor decomp;2972// NOLINTNEXTLINE(cppcoreguidelines-init-variables)2973tinfl_status status;2974tinfl_init(&decomp);2975status = 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);2976return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;2977}
2978
2979int 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)2980{
2981int result = 0;2982tinfl_decompressor decomp;2983mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE);2984size_t in_buf_ofs = 0, dict_ofs = 0;2985if (!pDict)2986return TINFL_STATUS_FAILED;2987tinfl_init(&decomp);2988for (;;)2989{2990size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;2991tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,2992(flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));2993in_buf_ofs += in_buf_size;2994if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))2995break;2996if (status != TINFL_STATUS_HAS_MORE_OUTPUT)2997{2998result = (status == TINFL_STATUS_DONE);2999break;3000}3001dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);3002}3003MZ_FREE(pDict);3004*pIn_buf_size = in_buf_ofs;3005return result;3006}
3007
3008#ifndef MINIZ_NO_MALLOC3009tinfl_decompressor *tinfl_decompressor_alloc(void)3010{
3011tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor));3012if (pDecomp)3013tinfl_init(pDecomp);3014return pDecomp;3015}
3016
3017void tinfl_decompressor_free(tinfl_decompressor *pDecomp)3018{
3019MZ_FREE(pDecomp);3020}
3021#endif3022
3023#ifdef __cplusplus3024}
3025#endif3026/**************************************************************************
3027*
3028* Copyright 2013-2014 RAD Game Tools and Valve Software
3029* Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
3030* Copyright 2016 Martin Raiber
3031* All Rights Reserved.
3032*
3033* Permission is hereby granted, free of charge, to any person obtaining a copy
3034* of this software and associated documentation files (the "Software"), to deal
3035* in the Software without restriction, including without limitation the rights
3036* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3037* copies of the Software, and to permit persons to whom the Software is
3038* furnished to do so, subject to the following conditions:
3039*
3040* The above copyright notice and this permission notice shall be included in
3041* all copies or substantial portions of the Software.
3042*
3043* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3044* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3045* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3046* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3047* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3048* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3049* THE SOFTWARE.
3050*
3051**************************************************************************/
3052
3053
3054#ifndef MINIZ_NO_ARCHIVE_APIS3055
3056#ifdef __cplusplus3057extern "C" {3058#endif3059
3060/* ------------------- .ZIP archive reading */
3061
3062#ifdef MINIZ_NO_STDIO3063#define MZ_FILE void *3064#else3065#include <sys/stat.h>3066
3067#if defined(_MSC_VER) || defined(__MINGW64__)3068static FILE *mz_fopen(const char *pFilename, const char *pMode)3069{
3070FILE *pFile = NULL;3071fopen_s(&pFile, pFilename, pMode);3072return pFile;3073}
3074static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream)3075{
3076FILE *pFile = NULL;3077if (freopen_s(&pFile, pPath, pMode, pStream))3078return NULL;3079return pFile;3080}
3081#ifndef MINIZ_NO_TIME3082#include <sys/utime.h>3083#endif3084#define MZ_FOPEN mz_fopen3085#define MZ_FCLOSE fclose3086#define MZ_FREAD fread3087#define MZ_FWRITE fwrite3088#define MZ_FTELL64 _ftelli643089#define MZ_FSEEK64 _fseeki643090#define MZ_FILE_STAT_STRUCT _stat643091#define MZ_FILE_STAT _stat643092#define MZ_FFLUSH fflush3093#define MZ_FREOPEN mz_freopen3094#define MZ_DELETE_FILE remove3095#elif defined(__MINGW32__)3096#ifndef MINIZ_NO_TIME3097#include <sys/utime.h>3098#endif3099#define MZ_FOPEN(f, m) fopen(f, m)3100#define MZ_FCLOSE fclose3101#define MZ_FREAD fread3102#define MZ_FWRITE fwrite3103#define MZ_FTELL64 ftello643104#define MZ_FSEEK64 fseeko643105#define MZ_FILE_STAT_STRUCT _stat3106#define MZ_FILE_STAT _stat3107#define MZ_FFLUSH fflush3108#define MZ_FREOPEN(f, m, s) freopen(f, m, s)3109#define MZ_DELETE_FILE remove3110#elif defined(__TINYC__)3111#ifndef MINIZ_NO_TIME3112#include <sys/utime.h>3113#endif3114#define MZ_FOPEN(f, m) fopen(f, m)3115#define MZ_FCLOSE fclose3116#define MZ_FREAD fread3117#define MZ_FWRITE fwrite3118#define MZ_FTELL64 ftell3119#define MZ_FSEEK64 fseek3120#define MZ_FILE_STAT_STRUCT stat3121#define MZ_FILE_STAT stat3122#define MZ_FFLUSH fflush3123#define MZ_FREOPEN(f, m, s) freopen(f, m, s)3124#define MZ_DELETE_FILE remove3125#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE)3126#ifndef MINIZ_NO_TIME3127#include <utime.h>3128#endif3129#define MZ_FOPEN(f, m) fopen64(f, m)3130#define MZ_FCLOSE fclose3131#define MZ_FREAD fread3132#define MZ_FWRITE fwrite3133#define MZ_FTELL64 ftello643134#define MZ_FSEEK64 fseeko643135#define MZ_FILE_STAT_STRUCT stat643136#define MZ_FILE_STAT stat643137#define MZ_FFLUSH fflush3138#define MZ_FREOPEN(p, m, s) freopen64(p, m, s)3139#define MZ_DELETE_FILE remove3140#elif defined(__APPLE__)3141#ifndef MINIZ_NO_TIME3142#include <utime.h>3143#endif3144#define MZ_FOPEN(f, m) fopen(f, m)3145#define MZ_FCLOSE fclose3146#define MZ_FREAD fread3147#define MZ_FWRITE fwrite3148#define MZ_FTELL64 ftello3149#define MZ_FSEEK64 fseeko3150#define MZ_FILE_STAT_STRUCT stat3151#define MZ_FILE_STAT stat3152#define MZ_FFLUSH fflush3153#define MZ_FREOPEN(p, m, s) freopen(p, m, s)3154#define MZ_DELETE_FILE remove3155
3156#else3157#pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.")3158#ifndef MINIZ_NO_TIME3159#include <utime.h>3160#endif3161#define MZ_FOPEN(f, m) fopen(f, m)3162#define MZ_FCLOSE fclose3163#define MZ_FREAD fread3164#define MZ_FWRITE fwrite3165#ifdef __STRICT_ANSI__3166#define MZ_FTELL64 ftell3167#define MZ_FSEEK64 fseek3168#else3169#define MZ_FTELL64 ftello3170#define MZ_FSEEK64 fseeko3171#endif3172#define MZ_FILE_STAT_STRUCT stat3173#define MZ_FILE_STAT stat3174#define MZ_FFLUSH fflush3175#define MZ_FREOPEN(f, m, s) freopen(f, m, s)3176#define MZ_DELETE_FILE remove3177#endif /* #ifdef _MSC_VER */3178#endif /* #ifdef MINIZ_NO_STDIO */3179
3180#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))3181
3182/* 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. */
3183enum
3184{
3185/* ZIP archive identifiers and record sizes */3186MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50,3187MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50,3188MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,3189MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,3190MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,3191MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,3192
3193/* ZIP64 archive identifier and record sizes */3194MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,3195MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,3196MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,3197MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,3198MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,3199MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,3200MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,3201MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,3202
3203/* Central directory header record offsets */3204MZ_ZIP_CDH_SIG_OFS = 0,3205MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,3206MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6,3207MZ_ZIP_CDH_BIT_FLAG_OFS = 8,3208MZ_ZIP_CDH_METHOD_OFS = 10,3209MZ_ZIP_CDH_FILE_TIME_OFS = 12,3210MZ_ZIP_CDH_FILE_DATE_OFS = 14,3211MZ_ZIP_CDH_CRC32_OFS = 16,3212MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20,3213MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24,3214MZ_ZIP_CDH_FILENAME_LEN_OFS = 28,3215MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,3216MZ_ZIP_CDH_COMMENT_LEN_OFS = 32,3217MZ_ZIP_CDH_DISK_START_OFS = 34,3218MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36,3219MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38,3220MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,3221
3222/* Local directory header offsets */3223MZ_ZIP_LDH_SIG_OFS = 0,3224MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4,3225MZ_ZIP_LDH_BIT_FLAG_OFS = 6,3226MZ_ZIP_LDH_METHOD_OFS = 8,3227MZ_ZIP_LDH_FILE_TIME_OFS = 10,3228MZ_ZIP_LDH_FILE_DATE_OFS = 12,3229MZ_ZIP_LDH_CRC32_OFS = 14,3230MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18,3231MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,3232MZ_ZIP_LDH_FILENAME_LEN_OFS = 26,3233MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,3234MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3,3235
3236/* End of central directory offsets */3237MZ_ZIP_ECDH_SIG_OFS = 0,3238MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4,3239MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6,3240MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,3241MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10,3242MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,3243MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,3244MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,3245
3246/* ZIP64 End of central directory locator offsets */3247MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */3248MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */3249MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */3250MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */3251
3252/* ZIP64 End of central directory header offsets */3253MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */3254MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */3255MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */3256MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */3257MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */3258MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */3259MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */3260MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */3261MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */3262MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */3263MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,3264MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,3265MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,3266MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,3267MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,3268MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,3269MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 113270};3271
3272typedef struct3273{
3274void *m_p;3275size_t m_size, m_capacity;3276mz_uint m_element_size;3277} mz_zip_array;3278
3279struct mz_zip_internal_state_tag3280{
3281mz_zip_array m_central_dir;3282mz_zip_array m_central_dir_offsets;3283mz_zip_array m_sorted_central_dir_offsets;3284
3285/* The flags passed in when the archive is initially opened. */3286uint32_t m_init_flags;3287
3288/* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */3289mz_bool m_zip64;3290
3291/* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */3292mz_bool m_zip64_has_extended_info_fields;3293
3294/* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */3295MZ_FILE *m_pFile;3296mz_uint64 m_file_archive_start_ofs;3297
3298void *m_pMem;3299size_t m_mem_size;3300size_t m_mem_capacity;3301};3302
3303#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size3304
3305#if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG)3306static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index)3307{
3308MZ_ASSERT(index < pArray->m_size);3309return index;3310}
3311#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)]3312#else3313#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index]3314#endif3315
3316static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size)3317{
3318memset(pArray, 0, sizeof(mz_zip_array));3319pArray->m_element_size = element_size;3320}
3321
3322static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)3323{
3324pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);3325memset(pArray, 0, sizeof(mz_zip_array));3326}
3327
3328static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing)3329{
3330// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3331void *pNew_p;3332size_t new_capacity = min_new_capacity;3333MZ_ASSERT(pArray->m_element_size);3334if (pArray->m_capacity >= min_new_capacity)3335return MZ_TRUE;3336if (growing)3337{3338new_capacity = MZ_MAX(1, pArray->m_capacity);3339while (new_capacity < min_new_capacity)3340new_capacity *= 2;3341}3342if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity)))3343return MZ_FALSE;3344pArray->m_p = pNew_p;3345pArray->m_capacity = new_capacity;3346return MZ_TRUE;3347}
3348
3349static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing)3350{
3351if (new_capacity > pArray->m_capacity)3352{3353if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))3354return MZ_FALSE;3355}3356return MZ_TRUE;3357}
3358
3359static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)3360{
3361if (new_size > pArray->m_capacity)3362{3363if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))3364return MZ_FALSE;3365}3366pArray->m_size = new_size;3367return MZ_TRUE;3368}
3369
3370static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n)3371{
3372return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);3373}
3374
3375static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n)3376{
3377size_t orig_size = pArray->m_size;3378if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE))3379return MZ_FALSE;3380if (n > 0)3381memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size);3382return MZ_TRUE;3383}
3384
3385#ifndef MINIZ_NO_TIME3386static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date)3387{
3388struct tm tm;3389memset(&tm, 0, sizeof(tm));3390tm.tm_isdst = -1;3391tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900;3392tm.tm_mon = ((dos_date >> 5) & 15) - 1;3393tm.tm_mday = dos_date & 31;3394tm.tm_hour = (dos_time >> 11) & 31;3395tm.tm_min = (dos_time >> 5) & 63;3396tm.tm_sec = (dos_time << 1) & 62;3397return mktime(&tm);3398}
3399
3400#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS3401static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)3402{
3403#ifdef _MSC_VER3404struct tm tm_struct;3405struct tm *tm = &tm_struct;3406errno_t err = localtime_s(tm, &time);3407if (err)3408{3409*pDOS_date = 0;3410*pDOS_time = 0;3411return;3412}3413#else3414struct tm *tm = localtime(&time);3415#endif /* #ifdef _MSC_VER */3416
3417*pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1));3418*pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday);3419}
3420#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */3421
3422#ifndef MINIZ_NO_STDIO3423#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS3424static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime)3425{
3426struct MZ_FILE_STAT_STRUCT file_stat;3427
3428/* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */3429if (MZ_FILE_STAT(pFilename, &file_stat) != 0)3430return MZ_FALSE;3431
3432*pTime = file_stat.st_mtime;3433
3434return MZ_TRUE;3435}
3436#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/3437
3438static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time)3439{
3440struct utimbuf t;3441
3442memset(&t, 0, sizeof(t));3443t.actime = access_time;3444t.modtime = modified_time;3445
3446return !utime(pFilename, &t);3447}
3448#endif /* #ifndef MINIZ_NO_STDIO */3449#endif /* #ifndef MINIZ_NO_TIME */3450
3451static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num)3452{
3453if (pZip)3454pZip->m_last_error = err_num;3455return MZ_FALSE;3456}
3457
3458static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags)3459{
3460(void)flags;3461if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))3462return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);3463
3464if (!pZip->m_pAlloc)3465pZip->m_pAlloc = miniz_def_alloc_func;3466if (!pZip->m_pFree)3467pZip->m_pFree = miniz_def_free_func;3468if (!pZip->m_pRealloc)3469pZip->m_pRealloc = miniz_def_realloc_func;3470
3471pZip->m_archive_size = 0;3472pZip->m_central_directory_file_ofs = 0;3473pZip->m_total_files = 0;3474pZip->m_last_error = MZ_ZIP_NO_ERROR;3475
3476if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))3477return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);3478
3479memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));3480MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));3481MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));3482MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));3483pZip->m_pState->m_init_flags = flags;3484pZip->m_pState->m_zip64 = MZ_FALSE;3485pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE;3486
3487pZip->m_zip_mode = MZ_ZIP_MODE_READING;3488
3489return MZ_TRUE;3490}
3491
3492static 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)3493{
3494// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3495const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;3496const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));3497mz_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);3498mz_uint8 l = 0, r = 0;3499pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;3500pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;3501pE = pL + MZ_MIN(l_len, r_len);3502while (pL < pE)3503{3504if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))3505break;3506pL++;3507pR++;3508}3509return (pL == pE) ? (l_len < r_len) : (l < r);3510}
3511
3512#define MZ_SWAP_UINT32(a, b) \3513do \3514{ \3515mz_uint32 t = a; \3516a = b; \3517b = t; \3518} \3519MZ_MACRO_END3520
3521/* 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.) */
3522static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip)3523{
3524mz_zip_internal_state *pState = pZip->m_pState;3525const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;3526const mz_zip_array *pCentral_dir = &pState->m_central_dir;3527// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3528mz_uint32 *pIndices;3529// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3530mz_uint32 start, end;3531const mz_uint32 size = pZip->m_total_files;3532
3533if (size <= 1U)3534return;3535
3536pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);3537
3538start = (size - 2U) >> 1U;3539for (;;)3540{3541// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3542mz_uint64 child, root = start;3543for (;;)3544{3545if ((child = (root << 1U) + 1U) >= size)3546break;3547child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])));3548if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))3549break;3550MZ_SWAP_UINT32(pIndices[root], pIndices[child]);3551root = child;3552}3553if (!start)3554break;3555start--;3556}3557
3558end = size - 1;3559while (end > 0)3560{3561// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3562mz_uint64 child, root = 0;3563MZ_SWAP_UINT32(pIndices[end], pIndices[0]);3564for (;;)3565{3566if ((child = (root << 1U) + 1U) >= end)3567break;3568child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]));3569if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))3570break;3571MZ_SWAP_UINT32(pIndices[root], pIndices[child]);3572root = child;3573}3574end--;3575}3576}
3577
3578static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs)3579{
3580// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3581mz_int64 cur_file_ofs;3582mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];3583mz_uint8 *pBuf = (mz_uint8 *)buf_u32;3584
3585/* Basic sanity checks - reject files which are too small */3586if (pZip->m_archive_size < record_size)3587return MZ_FALSE;3588
3589/* Find the record by scanning the file from the end towards the beginning. */3590cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);3591for (;;)3592{3593// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3594int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);3595
3596if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)3597return MZ_FALSE;3598
3599for (i = n - 4; i >= 0; --i)3600{3601mz_uint s = MZ_READ_LE32(pBuf + i);3602if (s == record_sig)3603{3604if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)3605break;3606}3607}3608
3609if (i >= 0)3610{3611cur_file_ofs += i;3612break;3613}3614
3615/* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */3616if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size)))3617return MZ_FALSE;3618
3619cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);3620}3621
3622*pOfs = cur_file_ofs;3623return MZ_TRUE;3624}
3625
3626static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags)3627{
3628mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0;3629mz_uint64 cdir_ofs = 0;3630mz_int64 cur_file_ofs = 0;3631// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3632const mz_uint8 *p;3633
3634mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];3635mz_uint8 *pBuf = (mz_uint8 *)buf_u32;3636mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);3637mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];3638mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;3639
3640mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];3641mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32;3642
3643mz_uint64 zip64_end_of_central_dir_ofs = 0;3644
3645/* 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. */3646if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)3647return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);3648
3649if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))3650return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);3651
3652/* Read and verify the end of central directory record. */3653if (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)3654return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);3655
3656if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)3657return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);3658
3659if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))3660{3661if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE)3662{3663if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG)3664{3665zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);3666if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))3667return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);3668
3669if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)3670{3671if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG)3672{3673pZip->m_pState->m_zip64 = MZ_TRUE;3674}3675}3676}3677}3678}3679
3680pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);3681cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);3682num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);3683cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);3684cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);3685cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);3686
3687if (pZip->m_pState->m_zip64)3688{3689// NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)3690mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);3691// NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)3692mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);3693mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);3694mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);3695mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);3696
3697if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))3698return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);3699
3700if (zip64_total_num_of_disks != 1U)3701return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);3702
3703/* Check for miniz's practical limits */3704if (zip64_cdir_total_entries > MZ_UINT32_MAX)3705return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);3706
3707pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;3708
3709if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)3710return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);3711
3712cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk;3713
3714/* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */3715if (zip64_size_of_central_directory > MZ_UINT32_MAX)3716return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);3717
3718cdir_size = (mz_uint32)zip64_size_of_central_directory;3719
3720num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);3721
3722cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);3723
3724cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);3725}3726
3727if (pZip->m_total_files != cdir_entries_on_this_disk)3728return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);3729
3730if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1)))3731return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);3732
3733if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)3734return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);3735
3736if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)3737return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);3738
3739pZip->m_central_directory_file_ofs = cdir_ofs;3740
3741if (pZip->m_total_files)3742{3743// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3744mz_uint i, n;3745/* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */3746if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) ||3747(!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE)))3748return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);3749
3750if (sort_central_dir)3751{3752if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE))3753return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);3754}3755
3756if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size)3757return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);3758
3759/* Now create an index into the central directory file records, do some basic sanity checking on each record */3760p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;3761for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i)3762{3763// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3764mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size;3765// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3766mz_uint64 comp_size, decomp_size, local_header_ofs;3767
3768if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))3769return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);3770
3771MZ_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);3772
3773if (sort_central_dir)3774MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i;3775
3776comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);3777decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);3778local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);3779filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);3780ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);3781
3782if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&3783(ext_data_size) &&3784(MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX))3785{3786/* Attempt to find zip64 extended information field in the entry's extra data */3787mz_uint32 extra_size_remaining = ext_data_size;3788
3789if (extra_size_remaining)3790{3791const mz_uint8 *pExtra_data;3792void* buf = NULL;3793
3794if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n)3795{3796buf = MZ_MALLOC(ext_data_size);3797if(buf==NULL)3798return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);3799
3800if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size)3801{3802MZ_FREE(buf);3803return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);3804}3805
3806pExtra_data = (mz_uint8*)buf;3807}3808else3809{3810pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;3811}3812
3813do3814{3815// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3816mz_uint32 field_id;3817// NOLINTNEXTLINE(cppcoreguidelines-init-variables)3818mz_uint32 field_data_size;3819
3820if (extra_size_remaining < (sizeof(mz_uint16) * 2))3821{3822MZ_FREE(buf);3823return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);3824}3825
3826field_id = MZ_READ_LE16(pExtra_data);3827field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));3828
3829if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)3830{3831MZ_FREE(buf);3832return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);3833}3834
3835if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)3836{3837/* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */3838pZip->m_pState->m_zip64 = MZ_TRUE;3839pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;3840break;3841}3842
3843pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;3844extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;3845} while (extra_size_remaining);3846
3847MZ_FREE(buf);3848}3849}3850
3851/* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */3852if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX))3853{3854if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size))3855return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);3856}3857
3858disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);3859if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1)))3860return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);3861
3862if (comp_size != MZ_UINT32_MAX)3863{3864if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)3865return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);3866}3867
3868bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);3869if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)3870return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);3871
3872if ((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)3873return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);3874
3875n -= total_header_size;3876p += total_header_size;3877}3878}3879
3880if (sort_central_dir)3881mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);3882
3883return MZ_TRUE;3884}
3885
3886void mz_zip_zero_struct(mz_zip_archive *pZip)3887{
3888if (pZip)3889MZ_CLEAR_OBJ(*pZip);3890}
3891
3892static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error)3893{
3894mz_bool status = MZ_TRUE;3895
3896if (!pZip)3897return MZ_FALSE;3898
3899if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))3900{3901if (set_last_error)3902pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER;3903
3904return MZ_FALSE;3905}3906
3907if (pZip->m_pState)3908{3909mz_zip_internal_state *pState = pZip->m_pState;3910pZip->m_pState = NULL;3911
3912mz_zip_array_clear(pZip, &pState->m_central_dir);3913mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);3914mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);3915
3916#ifndef MINIZ_NO_STDIO3917if (pState->m_pFile)3918{3919if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)3920{3921if (MZ_FCLOSE(pState->m_pFile) == EOF)3922{3923if (set_last_error)3924pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED;3925status = MZ_FALSE;3926}3927}3928pState->m_pFile = NULL;3929}3930#endif /* #ifndef MINIZ_NO_STDIO */3931
3932pZip->m_pFree(pZip->m_pAlloc_opaque, pState);3933}3934pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;3935
3936return status;3937}
3938
3939mz_bool mz_zip_reader_end(mz_zip_archive *pZip)3940{
3941return mz_zip_reader_end_internal(pZip, MZ_TRUE);3942}
3943mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags)3944{
3945if ((!pZip) || (!pZip->m_pRead))3946return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);3947
3948if (!mz_zip_reader_init_internal(pZip, flags))3949return MZ_FALSE;3950
3951pZip->m_zip_type = MZ_ZIP_TYPE_USER;3952pZip->m_archive_size = size;3953
3954if (!mz_zip_reader_read_central_dir(pZip, flags))3955{3956mz_zip_reader_end_internal(pZip, MZ_FALSE);3957return MZ_FALSE;3958}3959
3960return MZ_TRUE;3961}
3962
3963static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)3964{
3965mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;3966size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);3967memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);3968return s;3969}
3970
3971mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags)3972{
3973if (!pMem)3974return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);3975
3976if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)3977return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);3978
3979if (!mz_zip_reader_init_internal(pZip, flags))3980return MZ_FALSE;3981
3982pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY;3983pZip->m_archive_size = size;3984pZip->m_pRead = mz_zip_mem_read_func;3985pZip->m_pIO_opaque = pZip;3986pZip->m_pNeeds_keepalive = NULL;3987
3988#ifdef __cplusplus3989pZip->m_pState->m_pMem = const_cast<void *>(pMem);3990#else3991pZip->m_pState->m_pMem = (void *)pMem;3992#endif3993
3994pZip->m_pState->m_mem_size = size;3995
3996if (!mz_zip_reader_read_central_dir(pZip, flags))3997{3998mz_zip_reader_end_internal(pZip, MZ_FALSE);3999return MZ_FALSE;4000}4001
4002return MZ_TRUE;4003}
4004
4005#ifndef MINIZ_NO_STDIO4006static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)4007{
4008mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;4009mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);4010
4011file_ofs += pZip->m_pState->m_file_archive_start_ofs;4012
4013if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))4014return 0;4015
4016return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);4017}
4018
4019mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags)4020{
4021return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0);4022}
4023
4024mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size)4025{
4026mz_uint64 file_size;4027MZ_FILE *pFile;4028
4029if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))4030return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);4031
4032pFile = MZ_FOPEN(pFilename, "rb");4033if (!pFile)4034return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);4035
4036file_size = archive_size;4037if (!file_size)4038{4039if (MZ_FSEEK64(pFile, 0, SEEK_END))4040{4041MZ_FCLOSE(pFile);4042return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);4043}4044
4045file_size = MZ_FTELL64(pFile);4046}4047
4048/* TODO: Better sanity check archive_size and the # of actual remaining bytes */4049
4050if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)4051{4052MZ_FCLOSE(pFile);4053return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);4054}4055
4056if (!mz_zip_reader_init_internal(pZip, flags))4057{4058MZ_FCLOSE(pFile);4059return MZ_FALSE;4060}4061
4062pZip->m_zip_type = MZ_ZIP_TYPE_FILE;4063pZip->m_pRead = mz_zip_file_read_func;4064pZip->m_pIO_opaque = pZip;4065pZip->m_pState->m_pFile = pFile;4066pZip->m_archive_size = file_size;4067pZip->m_pState->m_file_archive_start_ofs = file_start_ofs;4068
4069if (!mz_zip_reader_read_central_dir(pZip, flags))4070{4071mz_zip_reader_end_internal(pZip, MZ_FALSE);4072return MZ_FALSE;4073}4074
4075return MZ_TRUE;4076}
4077
4078mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags)4079{
4080mz_uint64 cur_file_ofs;4081
4082if ((!pZip) || (!pFile))4083return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);4084
4085cur_file_ofs = MZ_FTELL64(pFile);4086
4087if (!archive_size)4088{4089if (MZ_FSEEK64(pFile, 0, SEEK_END))4090return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);4091
4092archive_size = MZ_FTELL64(pFile) - cur_file_ofs;4093
4094if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)4095return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);4096}4097
4098if (!mz_zip_reader_init_internal(pZip, flags))4099return MZ_FALSE;4100
4101pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;4102pZip->m_pRead = mz_zip_file_read_func;4103
4104pZip->m_pIO_opaque = pZip;4105pZip->m_pState->m_pFile = pFile;4106pZip->m_archive_size = archive_size;4107pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs;4108
4109if (!mz_zip_reader_read_central_dir(pZip, flags))4110{4111mz_zip_reader_end_internal(pZip, MZ_FALSE);4112return MZ_FALSE;4113}4114
4115return MZ_TRUE;4116}
4117
4118#endif /* #ifndef MINIZ_NO_STDIO */4119
4120static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index)4121{
4122if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files))4123return NULL;4124return &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));4125}
4126
4127mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index)4128{
4129// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4130mz_uint m_bit_flag;4131const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);4132if (!p)4133{4134mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);4135return MZ_FALSE;4136}4137
4138m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);4139return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0;4140}
4141
4142mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index)4143{
4144// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4145mz_uint bit_flag;4146// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4147mz_uint method;4148
4149const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);4150if (!p)4151{4152mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);4153return MZ_FALSE;4154}4155
4156method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);4157bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);4158
4159if ((method != 0) && (method != MZ_DEFLATED))4160{4161mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);4162return MZ_FALSE;4163}4164
4165if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION))4166{4167mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);4168return MZ_FALSE;4169}4170
4171if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)4172{4173mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);4174return MZ_FALSE;4175}4176
4177return MZ_TRUE;4178}
4179
4180mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index)4181{
4182// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4183mz_uint filename_len, attribute_mapping_id, external_attr;4184const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);4185if (!p)4186{4187mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);4188return MZ_FALSE;4189}4190
4191filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);4192if (filename_len)4193{4194if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')4195return MZ_TRUE;4196}4197
4198/* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */4199/* 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. */4200/* FIXME: Remove this check? Is it necessary - we already check the filename. */4201attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8;4202(void)attribute_mapping_id;4203
4204external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);4205if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0)4206{4207return MZ_TRUE;4208}4209
4210return MZ_FALSE;4211}
4212
4213static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data)4214{
4215// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4216mz_uint n;4217const mz_uint8 *p = pCentral_dir_header;4218
4219if (pFound_zip64_extra_data)4220*pFound_zip64_extra_data = MZ_FALSE;4221
4222if ((!p) || (!pStat))4223return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);4224
4225/* Extract fields from the central directory record. */4226pStat->m_file_index = file_index;4227pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);4228pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);4229pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);4230pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);4231pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);4232#ifndef MINIZ_NO_TIME4233pStat->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));4234#endif4235pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);4236pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);4237pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);4238pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);4239pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);4240pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);4241
4242/* Copy as much of the filename and comment as possible. */4243n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);4244n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);4245memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);4246pStat->m_filename[n] = '\0';4247
4248n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);4249n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);4250pStat->m_comment_size = n;4251memcpy(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);4252pStat->m_comment[n] = '\0';4253
4254/* Set some flags for convienance */4255pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index);4256pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index);4257pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index);4258
4259/* See if we need to read any zip64 extended information fields. */4260/* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */4261if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX)4262{4263/* Attempt to find zip64 extended information field in the entry's extra data */4264mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);4265
4266if (extra_size_remaining)4267{4268const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);4269
4270do4271{4272// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4273mz_uint32 field_id;4274// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4275mz_uint32 field_data_size;4276
4277if (extra_size_remaining < (sizeof(mz_uint16) * 2))4278return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);4279
4280field_id = MZ_READ_LE16(pExtra_data);4281field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));4282
4283if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)4284return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);4285
4286if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)4287{4288const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2;4289mz_uint32 field_data_remaining = field_data_size;4290
4291if (pFound_zip64_extra_data)4292*pFound_zip64_extra_data = MZ_TRUE;4293
4294if (pStat->m_uncomp_size == MZ_UINT32_MAX)4295{4296if (field_data_remaining < sizeof(mz_uint64))4297return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);4298
4299pStat->m_uncomp_size = MZ_READ_LE64(pField_data);4300pField_data += sizeof(mz_uint64);4301field_data_remaining -= sizeof(mz_uint64);4302}4303
4304if (pStat->m_comp_size == MZ_UINT32_MAX)4305{4306if (field_data_remaining < sizeof(mz_uint64))4307return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);4308
4309pStat->m_comp_size = MZ_READ_LE64(pField_data);4310pField_data += sizeof(mz_uint64);4311field_data_remaining -= sizeof(mz_uint64);4312}4313
4314if (pStat->m_local_header_ofs == MZ_UINT32_MAX)4315{4316if (field_data_remaining < sizeof(mz_uint64))4317return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);4318
4319pStat->m_local_header_ofs = MZ_READ_LE64(pField_data);4320// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)4321pField_data += sizeof(mz_uint64);4322// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)4323field_data_remaining -= sizeof(mz_uint64);4324}4325
4326break;4327}4328
4329pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;4330extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;4331} while (extra_size_remaining);4332}4333}4334
4335return MZ_TRUE;4336}
4337
4338static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags)4339{
4340// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4341mz_uint i;4342if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE)4343return 0 == memcmp(pA, pB, len);4344for (i = 0; i < len; ++i)4345if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i]))4346return MZ_FALSE;4347return MZ_TRUE;4348}
4349
4350static MZ_FORCEINLINE int mz_zip_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)4351{
4352// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4353const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;4354mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);4355mz_uint8 l = 0, r = 0;4356pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;4357pE = pL + MZ_MIN(l_len, r_len);4358while (pL < pE)4359{4360if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))4361break;4362pL++;4363pR++;4364}4365return (pL == pE) ? (int)(l_len - r_len) : (l - r);4366}
4367
4368static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex)4369{
4370mz_zip_internal_state *pState = pZip->m_pState;4371const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;4372const mz_zip_array *pCentral_dir = &pState->m_central_dir;4373mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);4374const uint32_t size = pZip->m_total_files;4375const mz_uint filename_len = (mz_uint)strlen(pFilename);4376
4377if (pIndex)4378*pIndex = 0;4379
4380if (size)4381{4382/* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */4383/* honestly the major expense here on 32-bit CPU's will still be the filename compare */4384mz_int64 l = 0, h = (mz_int64)size - 1;4385
4386while (l <= h)4387{4388mz_int64 m = l + ((h - l) >> 1);4389uint32_t file_index = pIndices[(uint32_t)m];4390
4391int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len);4392if (!comp)4393{4394if (pIndex)4395*pIndex = file_index;4396return MZ_TRUE;4397}4398else if (comp < 0)4399l = m + 1;4400else4401h = m - 1;4402}4403}4404
4405return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);4406}
4407
4408int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags)4409{
4410// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4411mz_uint32 index;4412if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index))4413return -1;4414else4415return (int)index;4416}
4417
4418mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex)4419{
4420// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4421mz_uint file_index;4422// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4423size_t name_len, comment_len;4424
4425if (pIndex)4426*pIndex = 0;4427
4428if ((!pZip) || (!pZip->m_pState) || (!pName))4429return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);4430
4431/* See if we can use a binary search */4432if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) &&4433(pZip->m_zip_mode == MZ_ZIP_MODE_READING) &&4434((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))4435{4436return mz_zip_locate_file_binary_search(pZip, pName, pIndex);4437}4438
4439/* Locate the entry by scanning the entire central directory */4440name_len = strlen(pName);4441if (name_len > MZ_UINT16_MAX)4442return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);4443
4444comment_len = pComment ? strlen(pComment) : 0;4445if (comment_len > MZ_UINT16_MAX)4446return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);4447
4448for (file_index = 0; file_index < pZip->m_total_files; file_index++)4449{4450const 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));4451mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);4452const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;4453if (filename_len < name_len)4454continue;4455if (comment_len)4456{4457mz_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);4458const char *pFile_comment = pFilename + filename_len + file_extra_len;4459if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags)))4460continue;4461}4462if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len))4463{4464// NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)4465int ofs = filename_len - 1;4466do4467{4468if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':'))4469break;4470} while (--ofs >= 0);4471ofs++;4472pFilename += ofs;4473filename_len -= ofs;4474}4475if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags)))4476{4477if (pIndex)4478*pIndex = file_index;4479return MZ_TRUE;4480}4481}4482
4483return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);4484}
4485
4486mz_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)4487{
4488int status = TINFL_STATUS_DONE;4489// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4490mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;4491mz_zip_archive_file_stat file_stat;4492// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4493void *pRead_buf;4494mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];4495mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;4496tinfl_decompressor inflator;4497
4498if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead))4499return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);4500
4501if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))4502return MZ_FALSE;4503
4504/* A directory or zero length file */4505if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))4506return MZ_TRUE;4507
4508/* Encryption and patch files are not supported. */4509if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))4510return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);4511
4512/* This function only supports decompressing stored and deflate. */4513if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))4514return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);4515
4516/* Ensure supplied output buffer is large enough. */4517needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size;4518if (buf_size < needed_size)4519return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL);4520
4521/* Read and parse the local directory entry. */4522cur_file_ofs = file_stat.m_local_header_ofs;4523if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)4524return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);4525
4526if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)4527return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);4528
4529cur_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);4530if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)4531return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);4532
4533if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))4534{4535/* The file is stored or the caller has requested the compressed data. */4536if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size)4537return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);4538
4539#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS4540if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0)4541{4542if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)4543return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);4544}4545#endif4546
4547return MZ_TRUE;4548}4549
4550/* Decompress the file either directly from memory or from a file input buffer. */4551tinfl_init(&inflator);4552
4553if (pZip->m_pState->m_pMem)4554{4555/* Read directly from the archive in memory. */4556pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;4557read_buf_size = read_buf_avail = file_stat.m_comp_size;4558comp_remaining = 0;4559}4560else if (pUser_read_buf)4561{4562/* Use a user provided read buffer. */4563if (!user_read_buf_size)4564return MZ_FALSE;4565pRead_buf = (mz_uint8 *)pUser_read_buf;4566read_buf_size = user_read_buf_size;4567read_buf_avail = 0;4568comp_remaining = file_stat.m_comp_size;4569}4570else4571{4572/* Temporarily allocate a read buffer. */4573read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);4574if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))4575return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);4576
4577if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))4578return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);4579
4580read_buf_avail = 0;4581comp_remaining = file_stat.m_comp_size;4582}4583
4584do4585{4586/* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */4587// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4588size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);4589if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))4590{4591read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);4592if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)4593{4594status = TINFL_STATUS_FAILED;4595mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);4596break;4597}4598cur_file_ofs += read_buf_avail;4599comp_remaining -= read_buf_avail;4600read_buf_ofs = 0;4601}4602in_buf_size = (size_t)read_buf_avail;4603status = 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));4604read_buf_avail -= in_buf_size;4605read_buf_ofs += in_buf_size;4606out_buf_ofs += out_buf_size;4607} while (status == TINFL_STATUS_NEEDS_MORE_INPUT);4608
4609if (status == TINFL_STATUS_DONE)4610{4611/* Make sure the entire file was decompressed, and check its CRC. */4612if (out_buf_ofs != file_stat.m_uncomp_size)4613{4614mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);4615status = TINFL_STATUS_FAILED;4616}4617#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS4618else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)4619{4620mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);4621status = TINFL_STATUS_FAILED;4622}4623#endif4624}4625
4626if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))4627pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);4628
4629return status == TINFL_STATUS_DONE;4630}
4631
4632mz_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)4633{
4634// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4635mz_uint32 file_index;4636if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))4637return MZ_FALSE;4638return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size);4639}
4640
4641mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags)4642{
4643return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0);4644}
4645
4646mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags)4647{
4648return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0);4649}
4650
4651void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags)4652{
4653// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4654mz_uint64 comp_size, uncomp_size, alloc_size;4655const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);4656// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4657void *pBuf;4658
4659if (pSize)4660*pSize = 0;4661
4662if (!p)4663{4664mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);4665return NULL;4666}4667
4668comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);4669uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);4670
4671alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;4672if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))4673{4674mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);4675return NULL;4676}4677
4678if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))4679{4680mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);4681return NULL;4682}4683
4684if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags))4685{4686pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);4687return NULL;4688}4689
4690if (pSize)4691*pSize = (size_t)alloc_size;4692return pBuf;4693}
4694
4695void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags)4696{
4697// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4698mz_uint32 file_index;4699if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))4700{4701if (pSize)4702*pSize = 0;4703return MZ_FALSE;4704}4705return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);4706}
4707
4708mz_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)4709{
4710int status = TINFL_STATUS_DONE;4711#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS4712mz_uint file_crc32 = MZ_CRC32_INIT;4713#endif4714// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4715mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs;4716mz_zip_archive_file_stat file_stat;4717void *pRead_buf = NULL;4718void *pWrite_buf = NULL;4719mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];4720mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;4721
4722if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead))4723return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);4724
4725if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))4726return MZ_FALSE;4727
4728/* A directory or zero length file */4729if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))4730return MZ_TRUE;4731
4732/* Encryption and patch files are not supported. */4733if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))4734return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);4735
4736/* This function only supports decompressing stored and deflate. */4737if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))4738return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);4739
4740/* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */4741cur_file_ofs = file_stat.m_local_header_ofs;4742if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)4743return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);4744
4745if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)4746return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);4747
4748cur_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);4749if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)4750return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);4751
4752/* Decompress the file either directly from memory or from a file input buffer. */4753if (pZip->m_pState->m_pMem)4754{4755pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;4756read_buf_size = read_buf_avail = file_stat.m_comp_size;4757comp_remaining = 0;4758}4759else4760{4761read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);4762if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))4763return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);4764
4765read_buf_avail = 0;4766comp_remaining = file_stat.m_comp_size;4767}4768
4769if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))4770{4771/* The file is stored or the caller has requested the compressed data. */4772if (pZip->m_pState->m_pMem)4773{4774if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX))4775return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);4776
4777if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)4778{4779mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);4780status = TINFL_STATUS_FAILED;4781}4782else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))4783{4784#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS4785file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size);4786#endif4787}4788
4789// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)4790cur_file_ofs += file_stat.m_comp_size;4791out_buf_ofs += file_stat.m_comp_size;4792// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)4793comp_remaining = 0;4794}4795else4796{4797while (comp_remaining)4798{4799read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);4800if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)4801{4802mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);4803status = TINFL_STATUS_FAILED;4804break;4805}4806
4807#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS4808if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))4809{4810file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);4811}4812#endif4813
4814if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)4815{4816mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);4817status = TINFL_STATUS_FAILED;4818break;4819}4820
4821cur_file_ofs += read_buf_avail;4822out_buf_ofs += read_buf_avail;4823comp_remaining -= read_buf_avail;4824}4825}4826}4827else4828{4829tinfl_decompressor inflator;4830tinfl_init(&inflator);4831
4832if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE)))4833{4834mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);4835status = TINFL_STATUS_FAILED;4836}4837else4838{4839do4840{4841mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));4842// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4843size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));4844if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))4845{4846read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);4847if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)4848{4849mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);4850status = TINFL_STATUS_FAILED;4851break;4852}4853cur_file_ofs += read_buf_avail;4854comp_remaining -= read_buf_avail;4855read_buf_ofs = 0;4856}4857
4858in_buf_size = (size_t)read_buf_avail;4859status = 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);4860read_buf_avail -= in_buf_size;4861read_buf_ofs += in_buf_size;4862
4863if (out_buf_size)4864{4865if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size)4866{4867mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);4868status = TINFL_STATUS_FAILED;4869break;4870}4871
4872#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS4873file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);4874#endif4875if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size)4876{4877mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);4878status = TINFL_STATUS_FAILED;4879break;4880}4881}4882} while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT));4883}4884}4885
4886if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))4887{4888/* Make sure the entire file was decompressed, and check its CRC. */4889if (out_buf_ofs != file_stat.m_uncomp_size)4890{4891mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);4892status = TINFL_STATUS_FAILED;4893}4894#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS4895else if (file_crc32 != file_stat.m_crc32)4896{4897mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);4898status = TINFL_STATUS_FAILED;4899}4900#endif4901}4902
4903if (!pZip->m_pState->m_pMem)4904pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);4905
4906if (pWrite_buf)4907pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);4908
4909return status == TINFL_STATUS_DONE;4910}
4911
4912mz_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)4913{
4914// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4915mz_uint32 file_index;4916if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))4917return MZ_FALSE;4918
4919return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags);4920}
4921
4922mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags)4923{
4924// NOLINTNEXTLINE(cppcoreguidelines-init-variables)4925mz_zip_reader_extract_iter_state *pState;4926mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];4927mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;4928
4929/* Argument sanity check */4930if ((!pZip) || (!pZip->m_pState))4931return NULL;4932
4933/* Allocate an iterator status structure */4934pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state));4935if (!pState)4936{4937mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);4938return NULL;4939}4940
4941/* Fetch file details */4942if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat))4943{4944pZip->m_pFree(pZip->m_pAlloc_opaque, pState);4945return NULL;4946}4947
4948/* Encryption and patch files are not supported. */4949if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))4950{4951mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);4952pZip->m_pFree(pZip->m_pAlloc_opaque, pState);4953return NULL;4954}4955
4956/* This function only supports decompressing stored and deflate. */4957if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED))4958{4959mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);4960pZip->m_pFree(pZip->m_pAlloc_opaque, pState);4961return NULL;4962}4963
4964/* Init state - save args */4965pState->pZip = pZip;4966pState->flags = flags;4967
4968/* Init state - reset variables to defaults */4969pState->status = TINFL_STATUS_DONE;4970#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS4971pState->file_crc32 = MZ_CRC32_INIT;4972#endif4973pState->read_buf_ofs = 0;4974pState->out_buf_ofs = 0;4975pState->pRead_buf = NULL;4976pState->pWrite_buf = NULL;4977pState->out_blk_remain = 0;4978
4979/* Read and parse the local directory entry. */4980pState->cur_file_ofs = pState->file_stat.m_local_header_ofs;4981if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)4982{4983mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);4984pZip->m_pFree(pZip->m_pAlloc_opaque, pState);4985return NULL;4986}4987
4988if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)4989{4990mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);4991pZip->m_pFree(pZip->m_pAlloc_opaque, pState);4992return NULL;4993}4994
4995pState->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);4996if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size)4997{4998mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);4999pZip->m_pFree(pZip->m_pAlloc_opaque, pState);5000return NULL;5001}5002
5003/* Decompress the file either directly from memory or from a file input buffer. */5004if (pZip->m_pState->m_pMem)5005{5006pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs;5007pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size;5008pState->comp_remaining = pState->file_stat.m_comp_size;5009}5010else5011{5012if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)))5013{5014/* Decompression required, therefore intermediate read buffer required */5015pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);5016if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size)))5017{5018mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);5019pZip->m_pFree(pZip->m_pAlloc_opaque, pState);5020return NULL;5021}5022}5023else5024{5025/* Decompression not required - we will be reading directly into user buffer, no temp buf required */5026pState->read_buf_size = 0;5027}5028pState->read_buf_avail = 0;5029pState->comp_remaining = pState->file_stat.m_comp_size;5030}5031
5032if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)))5033{5034/* Decompression required, init decompressor */5035tinfl_init( &pState->inflator );5036
5037/* Allocate write buffer */5038if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE)))5039{5040mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);5041if (pState->pRead_buf)5042pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf);5043pZip->m_pFree(pZip->m_pAlloc_opaque, pState);5044return NULL;5045}5046}5047
5048return pState;5049}
5050
5051mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags)5052{
5053// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5054mz_uint32 file_index;5055
5056/* Locate file index by name */5057if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))5058return NULL;5059
5060/* Construct iterator */5061return mz_zip_reader_extract_iter_new(pZip, file_index, flags);5062}
5063
5064size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size)5065{
5066size_t copied_to_caller = 0;5067
5068/* Argument sanity check */5069if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf))5070return 0;5071
5072if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))5073{5074/* The file is stored or the caller has requested the compressed data, calc amount to return. */5075copied_to_caller = (size_t)MZ_MIN( buf_size, pState->comp_remaining );5076
5077/* Zip is in memory....or requires reading from a file? */5078if (pState->pZip->m_pState->m_pMem)5079{5080/* Copy data to caller's buffer */5081memcpy( pvBuf, pState->pRead_buf, copied_to_caller );5082pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller;5083}5084else5085{5086/* Read directly into caller's buffer */5087if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller)5088{5089/* Failed to read all that was asked for, flag failure and alert user */5090mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED);5091pState->status = TINFL_STATUS_FAILED;5092copied_to_caller = 0;5093}5094}5095
5096#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS5097/* Compute CRC if not returning compressed data only */5098if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))5099pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller);5100#endif5101
5102/* Advance offsets, dec counters */5103pState->cur_file_ofs += copied_to_caller;5104pState->out_buf_ofs += copied_to_caller;5105pState->comp_remaining -= copied_to_caller;5106}5107else5108{5109do5110{5111/* Calc ptr to write buffer - given current output pos and block size */5112mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));5113
5114/* Calc max output size - given current output pos and block size */5115// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5116size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));5117
5118if (!pState->out_blk_remain)5119{5120/* Read more data from file if none available (and reading from file) */5121if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem))5122{5123/* Calc read size */5124pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining);5125if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail)5126{5127mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED);5128pState->status = TINFL_STATUS_FAILED;5129break;5130}5131
5132/* Advance offsets, dec counters */5133pState->cur_file_ofs += pState->read_buf_avail;5134pState->comp_remaining -= pState->read_buf_avail;5135pState->read_buf_ofs = 0;5136}5137
5138/* Perform decompression */5139in_buf_size = (size_t)pState->read_buf_avail;5140pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);5141pState->read_buf_avail -= in_buf_size;5142pState->read_buf_ofs += in_buf_size;5143
5144/* Update current output block size remaining */5145pState->out_blk_remain = out_buf_size;5146}5147
5148if (pState->out_blk_remain)5149{5150/* Calc amount to return. */5151size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain );5152
5153/* Copy data to caller's buffer */5154memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy );5155
5156#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS5157/* Perform CRC */5158pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy);5159#endif5160
5161/* Decrement data consumed from block */5162pState->out_blk_remain -= to_copy;5163
5164/* Inc output offset, while performing sanity check */5165if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size)5166{5167mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED);5168pState->status = TINFL_STATUS_FAILED;5169break;5170}5171
5172/* Increment counter of data copied to caller */5173copied_to_caller += to_copy;5174}5175} while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) );5176}5177
5178/* Return how many bytes were copied into user buffer */5179return copied_to_caller;5180}
5181
5182mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState)5183{
5184// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5185int status;5186
5187/* Argument sanity check */5188if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState))5189return MZ_FALSE;5190
5191/* Was decompression completed and requested? */5192if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))5193{5194/* Make sure the entire file was decompressed, and check its CRC. */5195if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size)5196{5197mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);5198pState->status = TINFL_STATUS_FAILED;5199}5200#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS5201else if (pState->file_crc32 != pState->file_stat.m_crc32)5202{5203mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED);5204pState->status = TINFL_STATUS_FAILED;5205}5206#endif5207}5208
5209/* Free buffers */5210if (!pState->pZip->m_pState->m_pMem)5211pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf);5212if (pState->pWrite_buf)5213pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf);5214
5215/* Save status */5216status = pState->status;5217
5218/* Free context */5219pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState);5220
5221return status == TINFL_STATUS_DONE;5222}
5223
5224#ifndef MINIZ_NO_STDIO5225static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n)5226{
5227(void)ofs;5228
5229return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque);5230}
5231
5232mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags)5233{
5234mz_bool status;5235mz_zip_archive_file_stat file_stat;5236MZ_FILE *pFile;5237
5238if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))5239return MZ_FALSE;5240
5241if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))5242return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);5243
5244pFile = MZ_FOPEN(pDst_filename, "wb");5245if (!pFile)5246return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);5247
5248status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);5249
5250if (MZ_FCLOSE(pFile) == EOF)5251{5252if (status)5253mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);5254
5255status = MZ_FALSE;5256}5257
5258#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)5259if (status)5260mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);5261#endif5262
5263return status;5264}
5265
5266mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags)5267{
5268mz_uint32 file_index;5269if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index))5270return MZ_FALSE;5271
5272return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);5273}
5274
5275mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags)5276{
5277mz_zip_archive_file_stat file_stat;5278
5279if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))5280return MZ_FALSE;5281
5282if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))5283return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);5284
5285return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);5286}
5287
5288mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags)5289{
5290mz_uint32 file_index;5291if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index))5292return MZ_FALSE;5293
5294return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags);5295}
5296#endif /* #ifndef MINIZ_NO_STDIO */5297
5298static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)5299{
5300mz_uint32 *p = (mz_uint32 *)pOpaque;5301(void)file_ofs;5302*p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n);5303return n;5304}
5305
5306mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags)5307{
5308mz_zip_archive_file_stat file_stat;5309// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5310mz_zip_internal_state *pState;5311// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5312const mz_uint8 *pCentral_dir_header;5313mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE;5314mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;5315mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];5316mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;5317mz_uint64 local_header_ofs = 0;5318// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5319mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32;5320// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5321mz_uint64 local_header_comp_size, local_header_uncomp_size;5322mz_uint32 uncomp_crc32 = MZ_CRC32_INIT;5323// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5324mz_bool has_data_descriptor;5325// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5326mz_uint32 local_header_bit_flags;5327
5328mz_zip_array file_data_array;5329mz_zip_array_init(&file_data_array, 1);5330
5331if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead))5332return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5333
5334if (file_index > pZip->m_total_files)5335return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5336
5337pState = pZip->m_pState;5338
5339pCentral_dir_header = mz_zip_get_cdh(pZip, file_index);5340
5341if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir))5342return MZ_FALSE;5343
5344/* A directory or zero length file */5345if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size))5346return MZ_TRUE;5347
5348/* Encryption and patch files are not supported. */5349if (file_stat.m_is_encrypted)5350return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);5351
5352/* This function only supports stored and deflate. */5353if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))5354return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);5355
5356if (!file_stat.m_is_supported)5357return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);5358
5359/* Read and parse the local directory entry. */5360local_header_ofs = file_stat.m_local_header_ofs;5361if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)5362return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);5363
5364if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)5365return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);5366
5367local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);5368local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);5369local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);5370local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);5371local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS);5372local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);5373has_data_descriptor = (local_header_bit_flags & 8) != 0;5374
5375if (local_header_filename_len != strlen(file_stat.m_filename))5376return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);5377
5378if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size)5379return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);5380
5381if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE))5382return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);5383
5384if (local_header_filename_len)5385{5386if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len)5387{5388mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);5389goto handle_failure;5390}5391
5392/* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */5393// NOLINTNEXTLINE(clang-analyzer-unix.cstring.NullArg)5394if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0)5395{5396mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);5397goto handle_failure;5398}5399}5400
5401if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX)))5402{5403mz_uint32 extra_size_remaining = local_header_extra_len;5404const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p;5405
5406if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len)5407{5408mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);5409goto handle_failure;5410}5411
5412do5413{5414// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5415mz_uint32 field_id, field_data_size, field_total_size;5416
5417if (extra_size_remaining < (sizeof(mz_uint16) * 2))5418return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);5419
5420// NOLINTNEXTLINE(clang-analyzer-core.NullDereference)5421field_id = MZ_READ_LE16(pExtra_data);5422field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));5423field_total_size = field_data_size + sizeof(mz_uint16) * 2;5424
5425if (field_total_size > extra_size_remaining)5426return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);5427
5428if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)5429{5430const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);5431
5432if (field_data_size < sizeof(mz_uint64) * 2)5433{5434mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);5435goto handle_failure;5436}5437
5438local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);5439local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64));5440
5441found_zip64_ext_data_in_ldir = MZ_TRUE;5442break;5443}5444
5445pExtra_data += field_total_size;5446extra_size_remaining -= field_total_size;5447} while (extra_size_remaining);5448}5449
5450/* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */5451/* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */5452if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32))5453{5454mz_uint8 descriptor_buf[32];5455// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5456mz_bool has_id;5457// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5458const mz_uint8 *pSrc;5459// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5460mz_uint32 file_crc32;5461mz_uint64 comp_size = 0, uncomp_size = 0;5462
5463mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4;5464
5465if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s))5466{5467mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);5468goto handle_failure;5469}5470
5471has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID);5472pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf;5473
5474file_crc32 = MZ_READ_LE32(pSrc);5475
5476if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir))5477{5478comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32));5479uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64));5480}5481else5482{5483comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32));5484uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32));5485}5486
5487if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size))5488{5489mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);5490goto handle_failure;5491}5492}5493else5494{5495if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size))5496{5497mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);5498goto handle_failure;5499}5500}5501
5502mz_zip_array_clear(pZip, &file_data_array);5503
5504if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0)5505{5506if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0))5507return MZ_FALSE;5508
5509/* 1 more check to be sure, although the extract checks too. */5510if (uncomp_crc32 != file_stat.m_crc32)5511{5512mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);5513return MZ_FALSE;5514}5515}5516
5517return MZ_TRUE;5518
5519handle_failure:5520mz_zip_array_clear(pZip, &file_data_array);5521return MZ_FALSE;5522}
5523
5524mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags)5525{
5526// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5527mz_zip_internal_state *pState;5528// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5529uint32_t i;5530
5531if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead))5532return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5533
5534pState = pZip->m_pState;5535
5536/* Basic sanity checks */5537if (!pState->m_zip64)5538{5539if (pZip->m_total_files > MZ_UINT16_MAX)5540return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);5541
5542if (pZip->m_archive_size > MZ_UINT32_MAX)5543return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);5544}5545else5546{5547if (pZip->m_total_files >= MZ_UINT32_MAX)5548return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);5549
5550if (pState->m_central_dir.m_size >= MZ_UINT32_MAX)5551return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);5552}5553
5554for (i = 0; i < pZip->m_total_files; i++)5555{5556if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags)5557{5558// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5559mz_uint32 found_index;5560mz_zip_archive_file_stat stat;5561
5562if (!mz_zip_reader_file_stat(pZip, i, &stat))5563return MZ_FALSE;5564
5565if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index))5566return MZ_FALSE;5567
5568/* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */5569if (found_index != i)5570return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);5571}5572
5573if (!mz_zip_validate_file(pZip, i, flags))5574return MZ_FALSE;5575}5576
5577return MZ_TRUE;5578}
5579
5580mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr)5581{
5582mz_bool success = MZ_TRUE;5583mz_zip_archive zip;5584mz_zip_error actual_err = MZ_ZIP_NO_ERROR;5585
5586if ((!pMem) || (!size))5587{5588if (pErr)5589*pErr = MZ_ZIP_INVALID_PARAMETER;5590return MZ_FALSE;5591}5592
5593mz_zip_zero_struct(&zip);5594
5595if (!mz_zip_reader_init_mem(&zip, pMem, size, flags))5596{5597if (pErr)5598*pErr = zip.m_last_error;5599return MZ_FALSE;5600}5601
5602if (!mz_zip_validate_archive(&zip, flags))5603{5604actual_err = zip.m_last_error;5605success = MZ_FALSE;5606}5607
5608if (!mz_zip_reader_end_internal(&zip, success))5609{5610if (!actual_err)5611actual_err = zip.m_last_error;5612success = MZ_FALSE;5613}5614
5615if (pErr)5616*pErr = actual_err;5617
5618return success;5619}
5620
5621#ifndef MINIZ_NO_STDIO5622mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr)5623{
5624mz_bool success = MZ_TRUE;5625mz_zip_archive zip;5626mz_zip_error actual_err = MZ_ZIP_NO_ERROR;5627
5628if (!pFilename)5629{5630if (pErr)5631*pErr = MZ_ZIP_INVALID_PARAMETER;5632return MZ_FALSE;5633}5634
5635mz_zip_zero_struct(&zip);5636
5637if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0))5638{5639if (pErr)5640*pErr = zip.m_last_error;5641return MZ_FALSE;5642}5643
5644if (!mz_zip_validate_archive(&zip, flags))5645{5646actual_err = zip.m_last_error;5647success = MZ_FALSE;5648}5649
5650if (!mz_zip_reader_end_internal(&zip, success))5651{5652if (!actual_err)5653actual_err = zip.m_last_error;5654success = MZ_FALSE;5655}5656
5657if (pErr)5658*pErr = actual_err;5659
5660return success;5661}
5662#endif /* #ifndef MINIZ_NO_STDIO */5663
5664/* ------------------- .ZIP archive writing */
5665
5666#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS5667
5668static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v)5669{
5670p[0] = (mz_uint8)v;5671p[1] = (mz_uint8)(v >> 8);5672}
5673static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v)5674{
5675p[0] = (mz_uint8)v;5676p[1] = (mz_uint8)(v >> 8);5677p[2] = (mz_uint8)(v >> 16);5678p[3] = (mz_uint8)(v >> 24);5679}
5680static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v)5681{
5682mz_write_le32(p, (mz_uint32)v);5683mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32));5684}
5685
5686#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))5687#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))5688#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v))5689
5690static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)5691{
5692mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;5693mz_zip_internal_state *pState = pZip->m_pState;5694mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);5695
5696if (!n)5697return 0;5698
5699/* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */5700if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))5701{5702mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);5703return 0;5704}5705
5706if (new_size > pState->m_mem_capacity)5707{5708// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5709void *pNew_block;5710size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity);5711
5712while (new_capacity < new_size)5713new_capacity *= 2;5714
5715if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))5716{5717mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);5718return 0;5719}5720
5721pState->m_pMem = pNew_block;5722pState->m_mem_capacity = new_capacity;5723}5724memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);5725pState->m_mem_size = (size_t)new_size;5726return n;5727}
5728
5729static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error)5730{
5731// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5732mz_zip_internal_state *pState;5733mz_bool status = MZ_TRUE;5734
5735if ((!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)))5736{5737if (set_last_error)5738mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5739return MZ_FALSE;5740}5741
5742pState = pZip->m_pState;5743pZip->m_pState = NULL;5744mz_zip_array_clear(pZip, &pState->m_central_dir);5745mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);5746mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);5747
5748#ifndef MINIZ_NO_STDIO5749if (pState->m_pFile)5750{5751if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)5752{5753if (MZ_FCLOSE(pState->m_pFile) == EOF)5754{5755if (set_last_error)5756mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);5757status = MZ_FALSE;5758}5759}5760
5761pState->m_pFile = NULL;5762}5763#endif /* #ifndef MINIZ_NO_STDIO */5764
5765if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem))5766{5767pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);5768pState->m_pMem = NULL;5769}5770
5771pZip->m_pFree(pZip->m_pAlloc_opaque, pState);5772pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;5773return status;5774}
5775
5776mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags)5777{
5778mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0;5779
5780if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))5781return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5782
5783if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)5784{5785if (!pZip->m_pRead)5786return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5787}5788
5789if (pZip->m_file_offset_alignment)5790{5791/* Ensure user specified file offset alignment is a power of 2. */5792if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))5793return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5794}5795
5796if (!pZip->m_pAlloc)5797pZip->m_pAlloc = miniz_def_alloc_func;5798if (!pZip->m_pFree)5799pZip->m_pFree = miniz_def_free_func;5800if (!pZip->m_pRealloc)5801pZip->m_pRealloc = miniz_def_realloc_func;5802
5803pZip->m_archive_size = existing_size;5804pZip->m_central_directory_file_ofs = 0;5805pZip->m_total_files = 0;5806
5807if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))5808return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);5809
5810memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));5811
5812MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));5813MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));5814MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));5815
5816pZip->m_pState->m_zip64 = zip64;5817pZip->m_pState->m_zip64_has_extended_info_fields = zip64;5818
5819pZip->m_zip_type = MZ_ZIP_TYPE_USER;5820pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;5821
5822return MZ_TRUE;5823}
5824
5825mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size)5826{
5827return mz_zip_writer_init_v2(pZip, existing_size, 0);5828}
5829
5830mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags)5831{
5832pZip->m_pWrite = mz_zip_heap_write_func;5833pZip->m_pNeeds_keepalive = NULL;5834
5835if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)5836pZip->m_pRead = mz_zip_mem_read_func;5837
5838pZip->m_pIO_opaque = pZip;5839
5840if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))5841return MZ_FALSE;5842
5843pZip->m_zip_type = MZ_ZIP_TYPE_HEAP;5844
5845if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning)))5846{5847if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size)))5848{5849mz_zip_writer_end_internal(pZip, MZ_FALSE);5850return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);5851}5852pZip->m_pState->m_mem_capacity = initial_allocation_size;5853}5854
5855return MZ_TRUE;5856}
5857
5858mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size)5859{
5860return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0);5861}
5862
5863#ifndef MINIZ_NO_STDIO5864static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)5865{
5866mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;5867mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);5868
5869file_ofs += pZip->m_pState->m_file_archive_start_ofs;5870
5871if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))5872{5873mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);5874return 0;5875}5876
5877return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);5878}
5879
5880mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning)5881{
5882return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0);5883}
5884
5885mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags)5886{
5887MZ_FILE *pFile;5888
5889pZip->m_pWrite = mz_zip_file_write_func;5890pZip->m_pNeeds_keepalive = NULL;5891
5892if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)5893pZip->m_pRead = mz_zip_file_read_func;5894
5895pZip->m_pIO_opaque = pZip;5896
5897if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))5898return MZ_FALSE;5899
5900if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb")))5901{5902mz_zip_writer_end(pZip);5903return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);5904}5905
5906pZip->m_pState->m_pFile = pFile;5907pZip->m_zip_type = MZ_ZIP_TYPE_FILE;5908
5909if (size_to_reserve_at_beginning)5910{5911mz_uint64 cur_ofs = 0;5912char buf[4096];5913
5914MZ_CLEAR_OBJ(buf);5915
5916do5917{5918size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);5919if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n)5920{5921mz_zip_writer_end(pZip);5922return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);5923}5924cur_ofs += n;5925size_to_reserve_at_beginning -= n;5926} while (size_to_reserve_at_beginning);5927}5928
5929return MZ_TRUE;5930}
5931
5932mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags)5933{
5934pZip->m_pWrite = mz_zip_file_write_func;5935pZip->m_pNeeds_keepalive = NULL;5936
5937if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)5938pZip->m_pRead = mz_zip_file_read_func;5939
5940pZip->m_pIO_opaque = pZip;5941
5942if (!mz_zip_writer_init_v2(pZip, 0, flags))5943return MZ_FALSE;5944
5945pZip->m_pState->m_pFile = pFile;5946pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);5947pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;5948
5949return MZ_TRUE;5950}
5951#endif /* #ifndef MINIZ_NO_STDIO */5952
5953mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags)5954{
5955// NOLINTNEXTLINE(cppcoreguidelines-init-variables)5956mz_zip_internal_state *pState;5957
5958if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))5959return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5960
5961if (flags & MZ_ZIP_FLAG_WRITE_ZIP64)5962{5963/* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */5964if (!pZip->m_pState->m_zip64)5965return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5966}5967
5968/* No sense in trying to write to an archive that's already at the support max size */5969if (pZip->m_pState->m_zip64)5970{5971if (pZip->m_total_files == MZ_UINT32_MAX)5972return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);5973}5974else5975{5976if (pZip->m_total_files == MZ_UINT16_MAX)5977return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);5978
5979if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)5980return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);5981}5982
5983pState = pZip->m_pState;5984
5985if (pState->m_pFile)5986{5987#ifdef MINIZ_NO_STDIO5988(void)pFilename;5989return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5990#else5991if (pZip->m_pIO_opaque != pZip)5992return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5993
5994if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)5995{5996if (!pFilename)5997return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);5998
5999/* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */6000if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile)))6001{6002/* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */6003mz_zip_reader_end_internal(pZip, MZ_FALSE);6004return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);6005}6006}6007
6008pZip->m_pWrite = mz_zip_file_write_func;6009pZip->m_pNeeds_keepalive = NULL;6010#endif /* #ifdef MINIZ_NO_STDIO */6011}6012else if (pState->m_pMem)6013{6014/* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */6015if (pZip->m_pIO_opaque != pZip)6016return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);6017
6018pState->m_mem_capacity = pState->m_mem_size;6019pZip->m_pWrite = mz_zip_heap_write_func;6020pZip->m_pNeeds_keepalive = NULL;6021}6022/* Archive is being read via a user provided read function - make sure the user has specified a write function too. */6023else if (!pZip->m_pWrite)6024return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);6025
6026/* Start writing new files at the archive's current central directory location. */6027/* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */6028pZip->m_archive_size = pZip->m_central_directory_file_ofs;6029pZip->m_central_directory_file_ofs = 0;6030
6031/* Clear the sorted central dir offsets, they aren't useful or maintained now. */6032/* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */6033/* TODO: We could easily maintain the sorted central directory offsets. */6034mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets);6035
6036pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;6037
6038return MZ_TRUE;6039}
6040
6041mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename)6042{
6043return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0);6044}
6045
6046/* TODO: pArchive_name is a terrible name here! */
6047mz_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)6048{
6049return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0);6050}
6051
6052typedef struct6053{
6054mz_zip_archive *m_pZip;6055mz_uint64 m_cur_archive_file_ofs;6056mz_uint64 m_comp_size;6057} mz_zip_writer_add_state;6058
6059static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser)6060{
6061mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;6062if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len)6063return MZ_FALSE;6064
6065pState->m_cur_archive_file_ofs += len;6066pState->m_comp_size += len;6067return MZ_TRUE;6068}
6069
6070#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2)6071#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3)6072static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs)6073{
6074mz_uint8 *pDst = pBuf;6075mz_uint32 field_size = 0;6076
6077MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);6078MZ_WRITE_LE16(pDst + 2, 0);6079pDst += sizeof(mz_uint16) * 2;6080
6081if (pUncomp_size)6082{6083MZ_WRITE_LE64(pDst, *pUncomp_size);6084pDst += sizeof(mz_uint64);6085field_size += sizeof(mz_uint64);6086}6087
6088if (pComp_size)6089{6090MZ_WRITE_LE64(pDst, *pComp_size);6091pDst += sizeof(mz_uint64);6092field_size += sizeof(mz_uint64);6093}6094
6095if (pLocal_header_ofs)6096{6097MZ_WRITE_LE64(pDst, *pLocal_header_ofs);6098pDst += sizeof(mz_uint64);6099field_size += sizeof(mz_uint64);6100}6101
6102MZ_WRITE_LE16(pBuf + 2, field_size);6103
6104return (mz_uint32)(pDst - pBuf);6105}
6106
6107static 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)6108{
6109(void)pZip;6110memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);6111MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);6112MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);6113MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);6114MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);6115MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);6116MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);6117MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);6118MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX));6119MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX));6120MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);6121MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);6122return MZ_TRUE;6123}
6124
6125static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst,6126mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size,6127mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32,6128mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,6129mz_uint64 local_header_ofs, mz_uint32 ext_attributes)6130{
6131(void)pZip;6132memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);6133MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);6134MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);6135MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);6136MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);6137MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);6138MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);6139MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);6140MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX));6141MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX));6142MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);6143MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);6144MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);6145MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);6146MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX));6147return MZ_TRUE;6148}
6149
6150static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size,6151const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size,6152mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32,6153mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,6154mz_uint64 local_header_ofs, mz_uint32 ext_attributes,6155const char *user_extra_data, mz_uint user_extra_data_len)6156{
6157mz_zip_internal_state *pState = pZip->m_pState;6158mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;6159size_t orig_central_dir_size = pState->m_central_dir.m_size;6160mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];6161
6162if (!pZip->m_pState->m_zip64)6163{6164if (local_header_ofs > 0xFFFFFFFF)6165return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);6166}6167
6168/* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */6169if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX)6170return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);6171
6172if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, (mz_uint16)(extra_size + user_extra_data_len), comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes))6173return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);6174
6175if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||6176(!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) ||6177(!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) ||6178(!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) ||6179(!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) ||6180(!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1)))6181{6182/* Try to resize the central directory array back into its original state. */6183mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);6184return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);6185}6186
6187return MZ_TRUE;6188}
6189
6190static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name)6191{
6192/* 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. */6193if (*pArchive_name == '/')6194return MZ_FALSE;6195
6196/* Making sure the name does not contain drive letters or DOS style backward slashes is the responsibility of the program using miniz*/6197
6198return MZ_TRUE;6199}
6200
6201static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip)6202{
6203// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6204mz_uint32 n;6205if (!pZip->m_file_offset_alignment)6206return 0;6207n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));6208return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1));6209}
6210
6211static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n)6212{
6213char buf[4096];6214memset(buf, 0, MZ_MIN(sizeof(buf), n));6215while (n)6216{6217mz_uint32 s = MZ_MIN(sizeof(buf), n);6218if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)6219return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6220
6221cur_file_ofs += s;6222n -= s;6223}6224return MZ_TRUE;6225}
6226
6227mz_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,6228mz_uint64 uncomp_size, mz_uint32 uncomp_crc32)6229{
6230return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0);6231}
6232
6233mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size,6234mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified,6235const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)6236{
6237mz_uint16 method = 0, dos_time = 0, dos_date = 0;6238// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6239mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;6240mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;6241// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6242size_t archive_name_size;6243mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];6244tdefl_compressor *pComp = NULL;6245// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6246mz_bool store_data_uncompressed;6247// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6248mz_zip_internal_state *pState;6249mz_uint8 *pExtra_data = NULL;6250mz_uint32 extra_size = 0;6251mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];6252mz_uint16 bit_flags = 0;6253mz_bool write_metadata_only = buf_size && !pBuf;6254
6255if ((int)level_and_flags < 0)6256level_and_flags = MZ_DEFAULT_LEVEL;6257
6258if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))6259bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;6260
6261if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))6262bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;6263
6264level = level_and_flags & 0xF;6265store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));6266
6267if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))6268return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);6269
6270pState = pZip->m_pState;6271
6272if (pState->m_zip64)6273{6274if (pZip->m_total_files == MZ_UINT32_MAX)6275return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);6276}6277else6278{6279if (pZip->m_total_files == MZ_UINT16_MAX)6280{6281pState->m_zip64 = MZ_TRUE;6282/*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */6283}6284if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF))6285{6286pState->m_zip64 = MZ_TRUE;6287/*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */6288}6289}6290
6291if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))6292return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);6293
6294if (!mz_zip_writer_validate_archive_name(pArchive_name))6295return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);6296
6297#ifndef MINIZ_NO_TIME6298if (last_modified != NULL)6299{6300mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date);6301}6302else6303{6304MZ_TIME_T cur_time;6305time(&cur_time);6306mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date);6307}6308#endif /* #ifndef MINIZ_NO_TIME */6309
6310if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))6311{6312if (!write_metadata_only) {6313uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);6314}6315uncomp_size = buf_size;6316if (uncomp_size <= 3)6317{6318level = 0;6319store_data_uncompressed = MZ_TRUE;6320}6321}6322
6323archive_name_size = strlen(pArchive_name);6324if (archive_name_size > MZ_UINT16_MAX)6325return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);6326
6327num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);6328
6329/* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */6330if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX)6331return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);6332
6333if (!pState->m_zip64)6334{6335/* Bail early if the archive would obviously become too large */6336if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size6337+ MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len +6338pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len6339+ MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF)6340{6341pState->m_zip64 = MZ_TRUE;6342/*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */6343}6344}6345
6346if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/'))6347{6348/* Set DOS Subdirectory attribute bit. */6349ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG;6350
6351/* Subdirectories cannot contain data. */6352if ((buf_size) || (uncomp_size))6353return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);6354}6355
6356/* 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.) */6357if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))6358return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);6359
6360if ((!store_data_uncompressed) && (buf_size))6361{6362if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))6363return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);6364}6365
6366if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes))6367{6368pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);6369return MZ_FALSE;6370}6371
6372local_dir_header_ofs += num_alignment_padding_bytes;6373if (pZip->m_file_offset_alignment)6374{6375MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0);6376}6377cur_archive_file_ofs += num_alignment_padding_bytes;6378
6379MZ_CLEAR_OBJ(local_dir_header);6380
6381if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))6382{6383method = MZ_DEFLATED;6384}6385
6386if (pState->m_zip64)6387{6388if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX)6389{6390pExtra_data = extra_data;6391extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,6392(uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);6393}6394
6395if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, bit_flags, dos_time, dos_date))6396return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);6397
6398if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))6399return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6400
6401cur_archive_file_ofs += sizeof(local_dir_header);6402
6403if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)6404{6405pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);6406return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6407}6408cur_archive_file_ofs += archive_name_size;6409
6410if (pExtra_data != NULL)6411{6412if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size)6413return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6414
6415cur_archive_file_ofs += extra_size;6416}6417}6418else6419{6420if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))6421return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);6422if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date))6423return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);6424
6425if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))6426return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6427
6428cur_archive_file_ofs += sizeof(local_dir_header);6429
6430if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)6431{6432pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);6433return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6434}6435cur_archive_file_ofs += archive_name_size;6436}6437
6438if (user_extra_data_len > 0)6439{6440if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)6441return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6442
6443cur_archive_file_ofs += user_extra_data_len;6444}6445
6446if (store_data_uncompressed)6447{6448if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size)6449{6450pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);6451return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6452}6453
6454cur_archive_file_ofs += buf_size;6455comp_size = buf_size;6456}6457else if (buf_size)6458{6459mz_zip_writer_add_state state;6460
6461state.m_pZip = pZip;6462state.m_cur_archive_file_ofs = cur_archive_file_ofs;6463state.m_comp_size = 0;6464
6465if ((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) ||6466(tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE))6467{6468pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);6469return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);6470}6471
6472comp_size = state.m_comp_size;6473cur_archive_file_ofs = state.m_cur_archive_file_ofs;6474}6475
6476pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);6477pComp = NULL;6478
6479if (uncomp_size)6480{6481mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];6482mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;6483
6484MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR);6485
6486MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);6487MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);6488if (pExtra_data == NULL)6489{6490if (comp_size > MZ_UINT32_MAX)6491return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);6492
6493MZ_WRITE_LE32(local_dir_footer + 8, comp_size);6494MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);6495}6496else6497{6498MZ_WRITE_LE64(local_dir_footer + 8, comp_size);6499MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);6500local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;6501}6502
6503if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size)6504return MZ_FALSE;6505
6506cur_archive_file_ofs += local_dir_footer_size;6507}6508
6509if (pExtra_data != NULL)6510{6511extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,6512(uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);6513}6514
6515if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment,6516comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes,6517user_extra_data_central, user_extra_data_central_len))6518return MZ_FALSE;6519
6520pZip->m_total_files++;6521pZip->m_archive_size = cur_archive_file_ofs;6522
6523return MZ_TRUE;6524}
6525
6526mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,6527const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)6528{
6529mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;6530mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;6531mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;6532mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0;6533size_t archive_name_size;6534mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];6535mz_uint8 *pExtra_data = NULL;6536mz_uint32 extra_size = 0;6537mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];6538mz_zip_internal_state *pState;6539mz_uint64 file_ofs = 0;6540
6541if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))6542gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;6543
6544if ((int)level_and_flags < 0)6545level_and_flags = MZ_DEFAULT_LEVEL;6546level = level_and_flags & 0xF;6547
6548/* Sanity checks */6549if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))6550return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);6551
6552pState = pZip->m_pState;6553
6554if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX))6555{6556/* Source file is too large for non-zip64 */6557/*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */6558pState->m_zip64 = MZ_TRUE;6559}6560
6561/* We could support this, but why? */6562if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)6563return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);6564
6565if (!mz_zip_writer_validate_archive_name(pArchive_name))6566return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);6567
6568if (pState->m_zip64)6569{6570if (pZip->m_total_files == MZ_UINT32_MAX)6571return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);6572}6573else6574{6575if (pZip->m_total_files == MZ_UINT16_MAX)6576{6577pState->m_zip64 = MZ_TRUE;6578/*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */6579}6580}6581
6582archive_name_size = strlen(pArchive_name);6583if (archive_name_size > MZ_UINT16_MAX)6584return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);6585
6586num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);6587
6588/* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */6589if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX)6590return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);6591
6592if (!pState->m_zip64)6593{6594/* Bail early if the archive would obviously become too large */6595if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE6596+ archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 10246597+ MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF)6598{6599pState->m_zip64 = MZ_TRUE;6600/*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */6601}6602}6603
6604#ifndef MINIZ_NO_TIME6605if (pFile_time)6606{6607mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date);6608}6609#endif6610
6611if (uncomp_size <= 3)6612level = 0;6613
6614if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes))6615{6616return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6617}6618
6619cur_archive_file_ofs += num_alignment_padding_bytes;6620local_dir_header_ofs = cur_archive_file_ofs;6621
6622if (pZip->m_file_offset_alignment)6623{6624MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0);6625}6626
6627if (uncomp_size && level)6628{6629method = MZ_DEFLATED;6630}6631
6632MZ_CLEAR_OBJ(local_dir_header);6633if (pState->m_zip64)6634{6635if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX)6636{6637pExtra_data = extra_data;6638extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,6639(uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);6640}6641
6642if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, gen_flags, dos_time, dos_date))6643return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);6644
6645if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))6646return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6647
6648cur_archive_file_ofs += sizeof(local_dir_header);6649
6650if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)6651{6652return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6653}6654
6655cur_archive_file_ofs += archive_name_size;6656
6657if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size)6658return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6659
6660cur_archive_file_ofs += extra_size;6661}6662else6663{6664if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))6665return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);6666if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date))6667return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);6668
6669if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))6670return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6671
6672cur_archive_file_ofs += sizeof(local_dir_header);6673
6674if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)6675{6676return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6677}6678
6679cur_archive_file_ofs += archive_name_size;6680}6681
6682if (user_extra_data_len > 0)6683{6684if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)6685return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);6686
6687cur_archive_file_ofs += user_extra_data_len;6688}6689
6690if (uncomp_size)6691{6692mz_uint64 uncomp_remaining = uncomp_size;6693void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);6694if (!pRead_buf)6695{6696return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);6697}6698
6699if (!level)6700{6701while (uncomp_remaining)6702{6703mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);6704if ((read_callback(callback_opaque, file_ofs, pRead_buf, n) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n))6705{6706pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);6707return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);6708}6709file_ofs += n;6710uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);6711uncomp_remaining -= n;6712cur_archive_file_ofs += n;6713}6714comp_size = uncomp_size;6715}6716else6717{6718mz_bool result = MZ_FALSE;6719mz_zip_writer_add_state state;6720tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));6721if (!pComp)6722{6723pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);6724return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);6725}6726
6727state.m_pZip = pZip;6728state.m_cur_archive_file_ofs = cur_archive_file_ofs;6729state.m_comp_size = 0;6730
6731if (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)6732{6733pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);6734pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);6735return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);6736}6737
6738for (;;)6739{6740size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);6741tdefl_status status;6742tdefl_flush flush = TDEFL_NO_FLUSH;6743
6744if (read_callback(callback_opaque, file_ofs, pRead_buf, in_buf_size)!= in_buf_size)6745{6746mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);6747break;6748}6749
6750file_ofs += in_buf_size;6751uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);6752uncomp_remaining -= in_buf_size;6753
6754if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque))6755flush = TDEFL_FULL_FLUSH;6756
6757status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH);6758if (status == TDEFL_STATUS_DONE)6759{6760result = MZ_TRUE;6761break;6762}6763else if (status != TDEFL_STATUS_OKAY)6764{6765mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);6766break;6767}6768}6769
6770pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);6771
6772if (!result)6773{6774pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);6775return MZ_FALSE;6776}6777
6778comp_size = state.m_comp_size;6779cur_archive_file_ofs = state.m_cur_archive_file_ofs;6780}6781
6782pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);6783}6784
6785{6786mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];6787mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;6788
6789MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);6790MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);6791if (pExtra_data == NULL)6792{6793if (comp_size > MZ_UINT32_MAX)6794return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);6795
6796MZ_WRITE_LE32(local_dir_footer + 8, comp_size);6797MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);6798}6799else6800{6801MZ_WRITE_LE64(local_dir_footer + 8, comp_size);6802MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);6803local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;6804}6805
6806if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size)6807return MZ_FALSE;6808
6809cur_archive_file_ofs += local_dir_footer_size;6810}6811
6812if (pExtra_data != NULL)6813{6814extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,6815(uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);6816}6817
6818if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, comment_size,6819uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes,6820user_extra_data_central, user_extra_data_central_len))6821return MZ_FALSE;6822
6823pZip->m_total_files++;6824pZip->m_archive_size = cur_archive_file_ofs;6825
6826return MZ_TRUE;6827}
6828
6829#ifndef MINIZ_NO_STDIO6830
6831static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)6832{
6833MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque;6834mz_int64 cur_ofs = MZ_FTELL64(pSrc_file);6835
6836if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET))))6837return 0;6838
6839return MZ_FREAD(pBuf, 1, n, pSrc_file);6840}
6841
6842mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,6843const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)6844{
6845return mz_zip_writer_add_read_buf_callback(pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, size_to_add, pFile_time, pComment, comment_size, level_and_flags,6846user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len);6847}
6848
6849mz_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)6850{
6851MZ_FILE *pSrc_file = NULL;6852mz_uint64 uncomp_size = 0;6853MZ_TIME_T file_modified_time;6854MZ_TIME_T *pFile_time = NULL;6855mz_bool status;6856
6857memset(&file_modified_time, 0, sizeof(file_modified_time));6858
6859#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)6860pFile_time = &file_modified_time;6861if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time))6862return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED);6863#endif6864
6865pSrc_file = MZ_FOPEN(pSrc_filename, "rb");6866if (!pSrc_file)6867return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);6868
6869MZ_FSEEK64(pSrc_file, 0, SEEK_END);6870uncomp_size = MZ_FTELL64(pSrc_file);6871MZ_FSEEK64(pSrc_file, 0, SEEK_SET);6872
6873status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0);6874
6875MZ_FCLOSE(pSrc_file);6876
6877return status;6878}
6879#endif /* #ifndef MINIZ_NO_STDIO */6880
6881static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start)6882{
6883/* + 64 should be enough for any new zip64 data */6884if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE))6885return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);6886
6887mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE);6888
6889if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start))6890{6891mz_uint8 new_ext_block[64];6892mz_uint8 *pDst = new_ext_block;6893mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);6894mz_write_le16(pDst + sizeof(mz_uint16), 0);6895pDst += sizeof(mz_uint16) * 2;6896
6897if (pUncomp_size)6898{6899mz_write_le64(pDst, *pUncomp_size);6900pDst += sizeof(mz_uint64);6901}6902
6903if (pComp_size)6904{6905mz_write_le64(pDst, *pComp_size);6906pDst += sizeof(mz_uint64);6907}6908
6909if (pLocal_header_ofs)6910{6911mz_write_le64(pDst, *pLocal_header_ofs);6912pDst += sizeof(mz_uint64);6913}6914
6915if (pDisk_start)6916{6917mz_write_le32(pDst, *pDisk_start);6918pDst += sizeof(mz_uint32);6919}6920
6921mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2));6922
6923if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block))6924return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);6925}6926
6927if ((pExt) && (ext_len))6928{6929mz_uint32 extra_size_remaining = ext_len;6930const mz_uint8 *pExtra_data = pExt;6931
6932do6933{6934// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6935mz_uint32 field_id, field_data_size, field_total_size;6936
6937if (extra_size_remaining < (sizeof(mz_uint16) * 2))6938return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);6939
6940field_id = MZ_READ_LE16(pExtra_data);6941field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));6942field_total_size = field_data_size + sizeof(mz_uint16) * 2;6943
6944if (field_total_size > extra_size_remaining)6945return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);6946
6947if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)6948{6949if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size))6950return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);6951}6952
6953pExtra_data += field_total_size;6954extra_size_remaining -= field_total_size;6955} while (extra_size_remaining);6956}6957
6958return MZ_TRUE;6959}
6960
6961/* TODO: This func is now pretty freakin complex due to zip64, split it up? */
6962mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index)6963{
6964// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6965mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size;6966// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6967mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs;6968// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6969mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;6970mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];6971mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;6972mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];6973// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6974size_t orig_central_dir_size;6975// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6976mz_zip_internal_state *pState;6977// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6978void *pBuf;6979// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6980const mz_uint8 *pSrc_central_header;6981mz_zip_archive_file_stat src_file_stat;6982// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6983mz_uint32 src_filename_len, src_comment_len, src_ext_len;6984// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6985mz_uint32 local_header_filename_size, local_header_extra_len;6986// NOLINTNEXTLINE(cppcoreguidelines-init-variables)6987mz_uint64 local_header_comp_size, local_header_uncomp_size;6988mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;6989
6990/* Sanity checks */6991if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead))6992return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);6993
6994pState = pZip->m_pState;6995
6996/* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */6997if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64))6998return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);6999
7000/* Get pointer to the source central dir header and crack it */7001if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index)))7002return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);7003
7004if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)7005return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);7006
7007src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS);7008src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);7009src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS);7010src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len;7011
7012/* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */7013if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX)7014return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);7015
7016num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);7017
7018if (!pState->m_zip64)7019{7020if (pZip->m_total_files == MZ_UINT16_MAX)7021return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);7022}7023else7024{7025/* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */7026if (pZip->m_total_files == MZ_UINT32_MAX)7027return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);7028}7029
7030if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL))7031return MZ_FALSE;7032
7033cur_src_file_ofs = src_file_stat.m_local_header_ofs;7034cur_dst_file_ofs = pZip->m_archive_size;7035
7036/* Read the source archive's local dir header */7037if (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)7038return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);7039
7040if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)7041return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);7042
7043cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;7044
7045/* Compute the total size we need to copy (filename+extra data+compressed data) */7046local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);7047local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);7048local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);7049local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);7050src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size;7051
7052/* Try to find a zip64 extended information field */7053if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX)))7054{7055mz_zip_array file_data_array;7056const mz_uint8 *pExtra_data;7057mz_uint32 extra_size_remaining = local_header_extra_len;7058
7059mz_zip_array_init(&file_data_array, 1);7060if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE))7061{7062return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);7063}7064
7065if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len)7066{7067mz_zip_array_clear(pZip, &file_data_array);7068return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);7069}7070
7071pExtra_data = (const mz_uint8 *)file_data_array.m_p;7072
7073do7074{7075// NOLINTNEXTLINE(cppcoreguidelines-init-variables)7076mz_uint32 field_id, field_data_size, field_total_size;7077
7078if (extra_size_remaining < (sizeof(mz_uint16) * 2))7079{7080mz_zip_array_clear(pZip, &file_data_array);7081return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);7082}7083
7084field_id = MZ_READ_LE16(pExtra_data);7085field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));7086field_total_size = field_data_size + sizeof(mz_uint16) * 2;7087
7088if (field_total_size > extra_size_remaining)7089{7090mz_zip_array_clear(pZip, &file_data_array);7091return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);7092}7093
7094if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)7095{7096const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);7097
7098if (field_data_size < sizeof(mz_uint64) * 2)7099{7100mz_zip_array_clear(pZip, &file_data_array);7101return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);7102}7103
7104// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)7105local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);7106// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)7107local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */7108
7109found_zip64_ext_data_in_ldir = MZ_TRUE;7110break;7111}7112
7113pExtra_data += field_total_size;7114extra_size_remaining -= field_total_size;7115} while (extra_size_remaining);7116
7117mz_zip_array_clear(pZip, &file_data_array);7118}7119
7120if (!pState->m_zip64)7121{7122/* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */7123/* We also check when the archive is finalized so this doesn't need to be perfect. */7124mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) +7125pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64;7126
7127if (approx_new_archive_size >= MZ_UINT32_MAX)7128return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);7129}7130
7131/* Write dest archive padding */7132if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes))7133return MZ_FALSE;7134
7135cur_dst_file_ofs += num_alignment_padding_bytes;7136
7137local_dir_header_ofs = cur_dst_file_ofs;7138if (pZip->m_file_offset_alignment)7139{7140MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0);7141}7142
7143/* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */7144if (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)7145return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);7146
7147cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;7148
7149/* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */7150if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining)))))7151return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);7152
7153while (src_archive_bytes_remaining)7154{7155n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining);7156if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n)7157{7158pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);7159return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);7160}7161cur_src_file_ofs += n;7162
7163if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)7164{7165pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);7166return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);7167}7168cur_dst_file_ofs += n;7169
7170src_archive_bytes_remaining -= n;7171}7172
7173/* Now deal with the optional data descriptor */7174bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);7175if (bit_flags & 8)7176{7177/* Copy data descriptor */7178if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir))7179{7180/* src is zip64, dest must be zip64 */7181
7182/* name uint32_t's */7183/* id 1 (optional in zip64?) */7184/* crc 1 */7185/* comp_size 2 */7186/* uncomp_size 2 */7187if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6))7188{7189pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);7190return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);7191}7192
7193n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5);7194}7195else7196{7197/* src is NOT zip64 */7198// NOLINTNEXTLINE(cppcoreguidelines-init-variables)7199mz_bool has_id;7200
7201if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4)7202{7203pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);7204return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);7205}7206
7207has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID);7208
7209if (pZip->m_pState->m_zip64)7210{7211/* dest is zip64, so upgrade the data descriptor */7212const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0));7213const mz_uint32 src_crc32 = pSrc_descriptor[0];7214const mz_uint64 src_comp_size = pSrc_descriptor[1];7215const mz_uint64 src_uncomp_size = pSrc_descriptor[2];7216
7217mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID);7218mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32);7219mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size);7220mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size);7221
7222n = sizeof(mz_uint32) * 6;7223}7224else7225{7226/* dest is NOT zip64, just copy it as-is */7227n = sizeof(mz_uint32) * (has_id ? 4 : 3);7228}7229}7230
7231if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)7232{7233pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);7234return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);7235}7236
7237// NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)7238cur_src_file_ofs += n;7239cur_dst_file_ofs += n;7240}7241pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);7242
7243/* Finally, add the new central dir header */7244orig_central_dir_size = pState->m_central_dir.m_size;7245
7246memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);7247
7248if (pState->m_zip64)7249{7250/* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */7251const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len;7252mz_zip_array new_ext_block;7253
7254mz_zip_array_init(&new_ext_block, sizeof(mz_uint8));7255
7256MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX);7257MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX);7258MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX);7259
7260if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL))7261{7262mz_zip_array_clear(pZip, &new_ext_block);7263return MZ_FALSE;7264}7265
7266MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size);7267
7268if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))7269{7270mz_zip_array_clear(pZip, &new_ext_block);7271return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);7272}7273
7274if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len))7275{7276mz_zip_array_clear(pZip, &new_ext_block);7277mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);7278return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);7279}7280
7281if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size))7282{7283mz_zip_array_clear(pZip, &new_ext_block);7284mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);7285return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);7286}7287
7288if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len))7289{7290mz_zip_array_clear(pZip, &new_ext_block);7291mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);7292return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);7293}7294
7295mz_zip_array_clear(pZip, &new_ext_block);7296}7297else7298{7299/* sanity checks */7300if (cur_dst_file_ofs > MZ_UINT32_MAX)7301return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);7302
7303if (local_dir_header_ofs >= MZ_UINT32_MAX)7304return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);7305
7306MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs);7307
7308if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))7309return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);7310
7311if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size))7312{7313mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);7314return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);7315}7316}7317
7318/* This shouldn't trigger unless we screwed up during the initial sanity checks */7319if (pState->m_central_dir.m_size >= MZ_UINT32_MAX)7320{7321/* TODO: Support central dirs >= 32-bits in size */7322mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);7323return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);7324}7325
7326n = (mz_uint32)orig_central_dir_size;7327if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1))7328{7329mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);7330return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);7331}7332
7333pZip->m_total_files++;7334pZip->m_archive_size = cur_dst_file_ofs;7335
7336return MZ_TRUE;7337}
7338
7339mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip)7340{
7341// NOLINTNEXTLINE(cppcoreguidelines-init-variables)7342mz_zip_internal_state *pState;7343// NOLINTNEXTLINE(cppcoreguidelines-init-variables)7344mz_uint64 central_dir_ofs, central_dir_size;7345mz_uint8 hdr[256];7346
7347if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))7348return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);7349
7350pState = pZip->m_pState;7351
7352if (pState->m_zip64)7353{7354if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX))7355return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);7356}7357else7358{7359if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX))7360return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);7361}7362
7363central_dir_ofs = 0;7364central_dir_size = 0;7365if (pZip->m_total_files)7366{7367/* Write central directory */7368central_dir_ofs = pZip->m_archive_size;7369central_dir_size = pState->m_central_dir.m_size;7370pZip->m_central_directory_file_ofs = central_dir_ofs;7371if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size)7372return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);7373
7374pZip->m_archive_size += central_dir_size;7375}7376
7377if (pState->m_zip64)7378{7379/* Write zip64 end of central directory header */7380mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size;7381
7382MZ_CLEAR_OBJ(hdr);7383MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG);7384MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64));7385MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */7386MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D);7387MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files);7388MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);7389MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size);7390MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs);7391if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)7392return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);7393
7394pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE;7395
7396/* Write zip64 end of central directory locator */7397MZ_CLEAR_OBJ(hdr);7398MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG);7399MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr);7400MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1);7401if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE)7402return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);7403
7404pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE;7405}7406
7407/* Write end of central directory record */7408MZ_CLEAR_OBJ(hdr);7409MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);7410MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));7411MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));7412MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size));7413MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs));7414
7415if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)7416return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);7417
7418#ifndef MINIZ_NO_STDIO7419if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))7420return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);7421#endif /* #ifndef MINIZ_NO_STDIO */7422
7423pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE;7424
7425pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;7426return MZ_TRUE;7427}
7428
7429mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize)7430{
7431if ((!ppBuf) || (!pSize))7432return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);7433
7434*ppBuf = NULL;7435*pSize = 0;7436
7437if ((!pZip) || (!pZip->m_pState))7438return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);7439
7440if (pZip->m_pWrite != mz_zip_heap_write_func)7441return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);7442
7443if (!mz_zip_writer_finalize_archive(pZip))7444return MZ_FALSE;7445
7446*ppBuf = pZip->m_pState->m_pMem;7447*pSize = pZip->m_pState->m_mem_size;7448pZip->m_pState->m_pMem = NULL;7449pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;7450
7451return MZ_TRUE;7452}
7453
7454mz_bool mz_zip_writer_end(mz_zip_archive *pZip)7455{
7456return mz_zip_writer_end_internal(pZip, MZ_TRUE);7457}
7458
7459#ifndef MINIZ_NO_STDIO7460mz_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)7461{
7462return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL);7463}
7464
7465mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(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, mz_zip_error *pErr)7466{
7467mz_bool status, created_new_archive = MZ_FALSE;7468mz_zip_archive zip_archive;7469struct MZ_FILE_STAT_STRUCT file_stat;7470mz_zip_error actual_err = MZ_ZIP_NO_ERROR;7471
7472mz_zip_zero_struct(&zip_archive);7473if ((int)level_and_flags < 0)7474level_and_flags = MZ_DEFAULT_LEVEL;7475
7476if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))7477{7478if (pErr)7479*pErr = MZ_ZIP_INVALID_PARAMETER;7480return MZ_FALSE;7481}7482
7483if (!mz_zip_writer_validate_archive_name(pArchive_name))7484{7485if (pErr)7486*pErr = MZ_ZIP_INVALID_FILENAME;7487return MZ_FALSE;7488}7489
7490/* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */7491/* So be sure to compile with _LARGEFILE64_SOURCE 1 */7492if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0)7493{7494/* Create a new archive. */7495if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags))7496{7497if (pErr)7498*pErr = zip_archive.m_last_error;7499return MZ_FALSE;7500}7501
7502created_new_archive = MZ_TRUE;7503}7504else7505{7506/* Append to an existing archive. */7507if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0))7508{7509if (pErr)7510*pErr = zip_archive.m_last_error;7511return MZ_FALSE;7512}7513
7514if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags))7515{7516if (pErr)7517*pErr = zip_archive.m_last_error;7518
7519mz_zip_reader_end_internal(&zip_archive, MZ_FALSE);7520
7521return MZ_FALSE;7522}7523}7524
7525status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0);7526actual_err = zip_archive.m_last_error;7527
7528/* 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.) */7529if (!mz_zip_writer_finalize_archive(&zip_archive))7530{7531if (!actual_err)7532actual_err = zip_archive.m_last_error;7533
7534status = MZ_FALSE;7535}7536
7537if (!mz_zip_writer_end_internal(&zip_archive, status))7538{7539if (!actual_err)7540actual_err = zip_archive.m_last_error;7541
7542status = MZ_FALSE;7543}7544
7545if ((!status) && (created_new_archive))7546{7547/* It's a new archive and something went wrong, so just delete it. */7548int ignoredStatus = MZ_DELETE_FILE(pZip_filename);7549(void)ignoredStatus;7550}7551
7552if (pErr)7553*pErr = actual_err;7554
7555return status;7556}
7557
7558void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr)7559{
7560mz_uint32 file_index;7561mz_zip_archive zip_archive;7562void *p = NULL;7563
7564if (pSize)7565*pSize = 0;7566
7567if ((!pZip_filename) || (!pArchive_name))7568{7569if (pErr)7570*pErr = MZ_ZIP_INVALID_PARAMETER;7571
7572return NULL;7573}7574
7575mz_zip_zero_struct(&zip_archive);7576if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0))7577{7578if (pErr)7579*pErr = zip_archive.m_last_error;7580
7581return NULL;7582}7583
7584if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index))7585{7586p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);7587}7588
7589mz_zip_reader_end_internal(&zip_archive, p != NULL);7590
7591if (pErr)7592*pErr = zip_archive.m_last_error;7593
7594return p;7595}
7596
7597void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags)7598{
7599return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL);7600}
7601
7602#endif /* #ifndef MINIZ_NO_STDIO */7603
7604#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */7605
7606/* ------------------- Misc utils */
7607
7608mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip)7609{
7610return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID;7611}
7612
7613mz_zip_type mz_zip_get_type(mz_zip_archive *pZip)7614{
7615return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID;7616}
7617
7618mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num)7619{
7620// NOLINTNEXTLINE(cppcoreguidelines-init-variables)7621mz_zip_error prev_err;7622
7623if (!pZip)7624return MZ_ZIP_INVALID_PARAMETER;7625
7626prev_err = pZip->m_last_error;7627
7628pZip->m_last_error = err_num;7629return prev_err;7630}
7631
7632mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip)7633{
7634if (!pZip)7635return MZ_ZIP_INVALID_PARAMETER;7636
7637return pZip->m_last_error;7638}
7639
7640mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip)7641{
7642return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR);7643}
7644
7645mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip)7646{
7647// NOLINTNEXTLINE(cppcoreguidelines-init-variables)7648mz_zip_error prev_err;7649
7650if (!pZip)7651return MZ_ZIP_INVALID_PARAMETER;7652
7653prev_err = pZip->m_last_error;7654
7655pZip->m_last_error = MZ_ZIP_NO_ERROR;7656return prev_err;7657}
7658
7659const char *mz_zip_get_error_string(mz_zip_error mz_err)7660{
7661switch (mz_err)7662{7663case MZ_ZIP_NO_ERROR:7664return "no error";7665case MZ_ZIP_UNDEFINED_ERROR:7666return "undefined error";7667case MZ_ZIP_TOO_MANY_FILES:7668return "too many files";7669case MZ_ZIP_FILE_TOO_LARGE:7670return "file too large";7671case MZ_ZIP_UNSUPPORTED_METHOD:7672return "unsupported method";7673case MZ_ZIP_UNSUPPORTED_ENCRYPTION:7674return "unsupported encryption";7675case MZ_ZIP_UNSUPPORTED_FEATURE:7676return "unsupported feature";7677case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:7678return "failed finding central directory";7679case MZ_ZIP_NOT_AN_ARCHIVE:7680return "not a ZIP archive";7681case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:7682return "invalid header or archive is corrupted";7683case MZ_ZIP_UNSUPPORTED_MULTIDISK:7684return "unsupported multidisk archive";7685case MZ_ZIP_DECOMPRESSION_FAILED:7686return "decompression failed or archive is corrupted";7687case MZ_ZIP_COMPRESSION_FAILED:7688return "compression failed";7689case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:7690return "unexpected decompressed size";7691case MZ_ZIP_CRC_CHECK_FAILED:7692return "CRC-32 check failed";7693case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:7694return "unsupported central directory size";7695case MZ_ZIP_ALLOC_FAILED:7696return "allocation failed";7697case MZ_ZIP_FILE_OPEN_FAILED:7698return "file open failed";7699case MZ_ZIP_FILE_CREATE_FAILED:7700return "file create failed";7701case MZ_ZIP_FILE_WRITE_FAILED:7702return "file write failed";7703case MZ_ZIP_FILE_READ_FAILED:7704return "file read failed";7705case MZ_ZIP_FILE_CLOSE_FAILED:7706return "file close failed";7707case MZ_ZIP_FILE_SEEK_FAILED:7708return "file seek failed";7709case MZ_ZIP_FILE_STAT_FAILED:7710return "file stat failed";7711case MZ_ZIP_INVALID_PARAMETER:7712return "invalid parameter";7713case MZ_ZIP_INVALID_FILENAME:7714return "invalid filename";7715case MZ_ZIP_BUF_TOO_SMALL:7716return "buffer too small";7717case MZ_ZIP_INTERNAL_ERROR:7718return "internal error";7719case MZ_ZIP_FILE_NOT_FOUND:7720return "file not found";7721case MZ_ZIP_ARCHIVE_TOO_LARGE:7722return "archive is too large";7723case MZ_ZIP_VALIDATION_FAILED:7724return "validation failed";7725case MZ_ZIP_WRITE_CALLBACK_FAILED:7726return "write calledback failed";7727default:7728break;7729}7730
7731return "unknown error";7732}
7733
7734/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */
7735mz_bool mz_zip_is_zip64(mz_zip_archive *pZip)7736{
7737if ((!pZip) || (!pZip->m_pState))7738return MZ_FALSE;7739
7740return pZip->m_pState->m_zip64;7741}
7742
7743size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip)7744{
7745if ((!pZip) || (!pZip->m_pState))7746return 0;7747
7748return pZip->m_pState->m_central_dir.m_size;7749}
7750
7751mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip)7752{
7753return pZip ? pZip->m_total_files : 0;7754}
7755
7756mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip)7757{
7758if (!pZip)7759return 0;7760return pZip->m_archive_size;7761}
7762
7763mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip)7764{
7765if ((!pZip) || (!pZip->m_pState))7766return 0;7767return pZip->m_pState->m_file_archive_start_ofs;7768}
7769
7770MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip)7771{
7772if ((!pZip) || (!pZip->m_pState))7773return 0;7774return pZip->m_pState->m_pFile;7775}
7776
7777size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n)7778{
7779if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead))7780return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);7781
7782return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n);7783}
7784
7785mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size)7786{
7787// NOLINTNEXTLINE(cppcoreguidelines-init-variables)7788mz_uint n;7789const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);7790if (!p)7791{7792if (filename_buf_size)7793pFilename[0] = '\0';7794mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);7795return 0;7796}7797n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);7798if (filename_buf_size)7799{7800n = MZ_MIN(n, filename_buf_size - 1);7801memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);7802pFilename[n] = '\0';7803}7804return n + 1;7805}
7806
7807mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat)7808{
7809return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL);7810}
7811
7812mz_bool mz_zip_end(mz_zip_archive *pZip)7813{
7814if (!pZip)7815return MZ_FALSE;7816
7817if (pZip->m_zip_mode == MZ_ZIP_MODE_READING)7818return mz_zip_reader_end(pZip);7819#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS7820else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))7821return mz_zip_writer_end(pZip);7822#endif7823
7824return MZ_FALSE;7825}
7826
7827#ifdef __cplusplus7828}
7829#endif7830
7831#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/7832