1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5  * Copyright 2016 Martin Raiber
6  * All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  *
26  **************************************************************************/
27 #include "miniz_zip.h"
28 
29 #ifndef MINIZ_NO_ARCHIVE_APIS
30 
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34 
35 /* ------------------- .ZIP archive reading */
36 
37 #ifdef MINIZ_NO_STDIO
38 #define MZ_FILE void *
39 #else
40 #include <sys/stat.h>
41 
42 #if defined(_MSC_VER) || defined(__MINGW64__)
43 static FILE *mz_fopen(const char *pFilename, const char *pMode)
44 {
45     FILE *pFile = NULL;
46     fopen_s(&pFile, pFilename, pMode);
47     return pFile;
48 }
49 static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream)
50 {
51     FILE *pFile = NULL;
52     if (freopen_s(&pFile, pPath, pMode, pStream))
53         return NULL;
54     return pFile;
55 }
56 #ifndef MINIZ_NO_TIME
57 #include <sys/utime.h>
58 #endif
59 #define MZ_FOPEN mz_fopen
60 #define MZ_FCLOSE fclose
61 #define MZ_FREAD fread
62 #define MZ_FWRITE fwrite
63 #define MZ_FTELL64 _ftelli64
64 #define MZ_FSEEK64 _fseeki64
65 #define MZ_FILE_STAT_STRUCT _stat
66 #define MZ_FILE_STAT _stat
67 #define MZ_FFLUSH fflush
68 #define MZ_FREOPEN mz_freopen
69 #define MZ_DELETE_FILE remove
70 #elif defined(__MINGW32__)
71 #ifndef MINIZ_NO_TIME
72 #include <sys/utime.h>
73 #endif
74 #define MZ_FOPEN(f, m) fopen(f, m)
75 #define MZ_FCLOSE fclose
76 #define MZ_FREAD fread
77 #define MZ_FWRITE fwrite
78 #define MZ_FTELL64 ftello64
79 #define MZ_FSEEK64 fseeko64
80 #define MZ_FILE_STAT_STRUCT _stat
81 #define MZ_FILE_STAT _stat
82 #define MZ_FFLUSH fflush
83 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
84 #define MZ_DELETE_FILE remove
85 #elif defined(__TINYC__)
86 #ifndef MINIZ_NO_TIME
87 #include <sys/utime.h>
88 #endif
89 #define MZ_FOPEN(f, m) fopen(f, m)
90 #define MZ_FCLOSE fclose
91 #define MZ_FREAD fread
92 #define MZ_FWRITE fwrite
93 #define MZ_FTELL64 ftell
94 #define MZ_FSEEK64 fseek
95 #define MZ_FILE_STAT_STRUCT stat
96 #define MZ_FILE_STAT stat
97 #define MZ_FFLUSH fflush
98 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
99 #define MZ_DELETE_FILE remove
100 #elif defined(__GNUC__) && _LARGEFILE64_SOURCE
101 #ifndef MINIZ_NO_TIME
102 #include <utime.h>
103 #endif
104 #define MZ_FOPEN(f, m) fopen64(f, m)
105 #define MZ_FCLOSE fclose
106 #define MZ_FREAD fread
107 #define MZ_FWRITE fwrite
108 #define MZ_FTELL64 ftello64
109 #define MZ_FSEEK64 fseeko64
110 #define MZ_FILE_STAT_STRUCT stat64
111 #define MZ_FILE_STAT stat64
112 #define MZ_FFLUSH fflush
113 #define MZ_FREOPEN(p, m, s) freopen64(p, m, s)
114 #define MZ_DELETE_FILE remove
115 #elif defined(__APPLE__) && _LARGEFILE64_SOURCE
116 #ifndef MINIZ_NO_TIME
117 #include <utime.h>
118 #endif
119 #define MZ_FOPEN(f, m) fopen(f, m)
120 #define MZ_FCLOSE fclose
121 #define MZ_FREAD fread
122 #define MZ_FWRITE fwrite
123 #define MZ_FTELL64 ftello
124 #define MZ_FSEEK64 fseeko
125 #define MZ_FILE_STAT_STRUCT stat
126 #define MZ_FILE_STAT stat
127 #define MZ_FFLUSH fflush
128 #define MZ_FREOPEN(p, m, s) freopen(p, m, s)
129 #define MZ_DELETE_FILE remove
130 
131 #else
132 #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.")
133 #ifndef MINIZ_NO_TIME
134 #include <utime.h>
135 #endif
136 #define MZ_FOPEN(f, m) fopen(f, m)
137 #define MZ_FCLOSE fclose
138 #define MZ_FREAD fread
139 #define MZ_FWRITE fwrite
140 #ifdef __STRICT_ANSI__
141 #define MZ_FTELL64 ftell
142 #define MZ_FSEEK64 fseek
143 #else
144 #define MZ_FTELL64 ftello
145 #define MZ_FSEEK64 fseeko
146 #endif
147 #define MZ_FILE_STAT_STRUCT stat
148 #define MZ_FILE_STAT stat
149 #define MZ_FFLUSH fflush
150 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
151 #define MZ_DELETE_FILE remove
152 #endif /* #ifdef _MSC_VER */
153 #endif /* #ifdef MINIZ_NO_STDIO */
154 
155 #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
156 
157 /* 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. */
158 enum
159 {
160     /* ZIP archive identifiers and record sizes */
161     MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50,
162     MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50,
163     MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
164     MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
165     MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
166     MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
167 
168     /* ZIP64 archive identifier and record sizes */
169     MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,
170     MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,
171     MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,
172     MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,
173     MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,
174     MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,
175     MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,
176     MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,
177 
178     /* Central directory header record offsets */
179     MZ_ZIP_CDH_SIG_OFS = 0,
180     MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
181     MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6,
182     MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
183     MZ_ZIP_CDH_METHOD_OFS = 10,
184     MZ_ZIP_CDH_FILE_TIME_OFS = 12,
185     MZ_ZIP_CDH_FILE_DATE_OFS = 14,
186     MZ_ZIP_CDH_CRC32_OFS = 16,
187     MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20,
188     MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24,
189     MZ_ZIP_CDH_FILENAME_LEN_OFS = 28,
190     MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
191     MZ_ZIP_CDH_COMMENT_LEN_OFS = 32,
192     MZ_ZIP_CDH_DISK_START_OFS = 34,
193     MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36,
194     MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38,
195     MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
196 
197     /* Local directory header offsets */
198     MZ_ZIP_LDH_SIG_OFS = 0,
199     MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4,
200     MZ_ZIP_LDH_BIT_FLAG_OFS = 6,
201     MZ_ZIP_LDH_METHOD_OFS = 8,
202     MZ_ZIP_LDH_FILE_TIME_OFS = 10,
203     MZ_ZIP_LDH_FILE_DATE_OFS = 12,
204     MZ_ZIP_LDH_CRC32_OFS = 14,
205     MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18,
206     MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
207     MZ_ZIP_LDH_FILENAME_LEN_OFS = 26,
208     MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
209     MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3,
210 
211     /* End of central directory offsets */
212     MZ_ZIP_ECDH_SIG_OFS = 0,
213     MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4,
214     MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6,
215     MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
216     MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10,
217     MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
218     MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
219     MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
220 
221     /* ZIP64 End of central directory locator offsets */
222     MZ_ZIP64_ECDL_SIG_OFS = 0,                    /* 4 bytes */
223     MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4,          /* 4 bytes */
224     MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8,  /* 8 bytes */
225     MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */
226 
227     /* ZIP64 End of central directory header offsets */
228     MZ_ZIP64_ECDH_SIG_OFS = 0,                       /* 4 bytes */
229     MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4,            /* 8 bytes */
230     MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12,          /* 2 bytes */
231     MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14,           /* 2 bytes */
232     MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16,            /* 4 bytes */
233     MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20,            /* 4 bytes */
234     MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */
235     MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32,       /* 8 bytes */
236     MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40,                /* 8 bytes */
237     MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48,                 /* 8 bytes */
238     MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,
239     MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,
240     MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,
241     MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,
242     MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,
243     MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,
244     MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11
245 };
246 
247 typedef struct
248 {
249     void *m_p;
250     size_t m_size, m_capacity;
251     mz_uint m_element_size;
252 } mz_zip_array;
253 
254 struct mz_zip_internal_state_tag
255 {
256     mz_zip_array m_central_dir;
257     mz_zip_array m_central_dir_offsets;
258     mz_zip_array m_sorted_central_dir_offsets;
259 
260     /* The flags passed in when the archive is initially opened. */
261     uint32_t m_init_flags;
262 
263     /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */
264     mz_bool m_zip64;
265 
266     /* 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.) */
267     mz_bool m_zip64_has_extended_info_fields;
268 
269     /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */
270     MZ_FILE *m_pFile;
271     mz_uint64 m_file_archive_start_ofs;
272 
273     void *m_pMem;
274     size_t m_mem_size;
275     size_t m_mem_capacity;
276 };
277 
278 #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size
279 
280 #if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG)
mz_zip_array_range_check(const mz_zip_array * pArray,mz_uint index)281 static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index)
282 {
283     MZ_ASSERT(index < pArray->m_size);
284     return index;
285 }
286 #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)]
287 #else
288 #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index]
289 #endif
290 
mz_zip_array_init(mz_zip_array * pArray,mz_uint32 element_size)291 static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size)
292 {
293     memset(pArray, 0, sizeof(mz_zip_array));
294     pArray->m_element_size = element_size;
295 }
296 
mz_zip_array_clear(mz_zip_archive * pZip,mz_zip_array * pArray)297 static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)
298 {
299     pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
300     memset(pArray, 0, sizeof(mz_zip_array));
301 }
302 
mz_zip_array_ensure_capacity(mz_zip_archive * pZip,mz_zip_array * pArray,size_t min_new_capacity,mz_uint growing)303 static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing)
304 {
305     void *pNew_p;
306     size_t new_capacity = min_new_capacity;
307     MZ_ASSERT(pArray->m_element_size);
308     if (pArray->m_capacity >= min_new_capacity)
309         return MZ_TRUE;
310     if (growing)
311     {
312         new_capacity = MZ_MAX(1, pArray->m_capacity);
313         while (new_capacity < min_new_capacity)
314             new_capacity *= 2;
315     }
316     if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity)))
317         return MZ_FALSE;
318     pArray->m_p = pNew_p;
319     pArray->m_capacity = new_capacity;
320     return MZ_TRUE;
321 }
322 
mz_zip_array_reserve(mz_zip_archive * pZip,mz_zip_array * pArray,size_t new_capacity,mz_uint growing)323 static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing)
324 {
325     if (new_capacity > pArray->m_capacity)
326     {
327         if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))
328             return MZ_FALSE;
329     }
330     return MZ_TRUE;
331 }
332 
mz_zip_array_resize(mz_zip_archive * pZip,mz_zip_array * pArray,size_t new_size,mz_uint growing)333 static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)
334 {
335     if (new_size > pArray->m_capacity)
336     {
337         if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))
338             return MZ_FALSE;
339     }
340     pArray->m_size = new_size;
341     return MZ_TRUE;
342 }
343 
mz_zip_array_ensure_room(mz_zip_archive * pZip,mz_zip_array * pArray,size_t n)344 static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n)
345 {
346     return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
347 }
348 
mz_zip_array_push_back(mz_zip_archive * pZip,mz_zip_array * pArray,const void * pElements,size_t n)349 static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n)
350 {
351     size_t orig_size = pArray->m_size;
352     if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE))
353         return MZ_FALSE;
354     memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size);
355     return MZ_TRUE;
356 }
357 
358 #ifndef MINIZ_NO_TIME
mz_zip_dos_to_time_t(int dos_time,int dos_date)359 static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date)
360 {
361     struct tm tm;
362     memset(&tm, 0, sizeof(tm));
363     tm.tm_isdst = -1;
364     tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900;
365     tm.tm_mon = ((dos_date >> 5) & 15) - 1;
366     tm.tm_mday = dos_date & 31;
367     tm.tm_hour = (dos_time >> 11) & 31;
368     tm.tm_min = (dos_time >> 5) & 63;
369     tm.tm_sec = (dos_time << 1) & 62;
370     return mktime(&tm);
371 }
372 
373 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
mz_zip_time_t_to_dos_time(MZ_TIME_T time,mz_uint16 * pDOS_time,mz_uint16 * pDOS_date)374 static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)
375 {
376 #ifdef _MSC_VER
377     struct tm tm_struct;
378     struct tm *tm = &tm_struct;
379     errno_t err = localtime_s(tm, &time);
380     if (err)
381     {
382         *pDOS_date = 0;
383         *pDOS_time = 0;
384         return;
385     }
386 #else
387     struct tm *tm = localtime(&time);
388 #endif /* #ifdef _MSC_VER */
389 
390     *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1));
391     *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday);
392 }
393 #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */
394 
395 #ifndef MINIZ_NO_STDIO
396 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
mz_zip_get_file_modified_time(const char * pFilename,MZ_TIME_T * pTime)397 static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime)
398 {
399     struct MZ_FILE_STAT_STRUCT file_stat;
400 
401     /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */
402     if (MZ_FILE_STAT(pFilename, &file_stat) != 0)
403         return MZ_FALSE;
404 
405     *pTime = file_stat.st_mtime;
406 
407     return MZ_TRUE;
408 }
409 #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/
410 
mz_zip_set_file_times(const char * pFilename,MZ_TIME_T access_time,MZ_TIME_T modified_time)411 static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time)
412 {
413     struct utimbuf t;
414 
415     memset(&t, 0, sizeof(t));
416     t.actime = access_time;
417     t.modtime = modified_time;
418 
419     return !utime(pFilename, &t);
420 }
421 #endif /* #ifndef MINIZ_NO_STDIO */
422 #endif /* #ifndef MINIZ_NO_TIME */
423 
mz_zip_set_error(mz_zip_archive * pZip,mz_zip_error err_num)424 static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num)
425 {
426     if (pZip)
427         pZip->m_last_error = err_num;
428     return MZ_FALSE;
429 }
430 
mz_zip_reader_init_internal(mz_zip_archive * pZip,mz_uint flags)431 static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags)
432 {
433     (void)flags;
434     if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
435         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
436 
437     if (!pZip->m_pAlloc)
438         pZip->m_pAlloc = miniz_def_alloc_func;
439     if (!pZip->m_pFree)
440         pZip->m_pFree = miniz_def_free_func;
441     if (!pZip->m_pRealloc)
442         pZip->m_pRealloc = miniz_def_realloc_func;
443 
444     pZip->m_archive_size = 0;
445     pZip->m_central_directory_file_ofs = 0;
446     pZip->m_total_files = 0;
447     pZip->m_last_error = MZ_ZIP_NO_ERROR;
448 
449     if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
450         return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
451 
452     memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
453     MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
454     MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
455     MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
456     pZip->m_pState->m_init_flags = flags;
457     pZip->m_pState->m_zip64 = MZ_FALSE;
458     pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE;
459 
460     pZip->m_zip_mode = MZ_ZIP_MODE_READING;
461 
462     return MZ_TRUE;
463 }
464 
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)465 static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index)
466 {
467     const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;
468     const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
469     mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);
470     mz_uint8 l = 0, r = 0;
471     pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
472     pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
473     pE = pL + MZ_MIN(l_len, r_len);
474     while (pL < pE)
475     {
476         if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
477             break;
478         pL++;
479         pR++;
480     }
481     return (pL == pE) ? (l_len < r_len) : (l < r);
482 }
483 
484 #define MZ_SWAP_UINT32(a, b) \
485     do                       \
486     {                        \
487         mz_uint32 t = a;     \
488         a = b;               \
489         b = t;               \
490     }                        \
491     MZ_MACRO_END
492 
493 /* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */
mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive * pZip)494 static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip)
495 {
496     mz_zip_internal_state *pState = pZip->m_pState;
497     const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
498     const mz_zip_array *pCentral_dir = &pState->m_central_dir;
499     mz_uint32 *pIndices;
500     mz_uint32 start, end;
501     const mz_uint32 size = pZip->m_total_files;
502 
503     if (size <= 1U)
504         return;
505 
506     pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
507 
508     start = (size - 2U) >> 1U;
509     for (;;)
510     {
511         mz_uint64 child, root = start;
512         for (;;)
513         {
514             if ((child = (root << 1U) + 1U) >= size)
515                 break;
516             child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])));
517             if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
518                 break;
519             MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
520             root = child;
521         }
522         if (!start)
523             break;
524         start--;
525     }
526 
527     end = size - 1;
528     while (end > 0)
529     {
530         mz_uint64 child, root = 0;
531         MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
532         for (;;)
533         {
534             if ((child = (root << 1U) + 1U) >= end)
535                 break;
536             child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]));
537             if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
538                 break;
539             MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
540             root = child;
541         }
542         end--;
543     }
544 }
545 
mz_zip_reader_locate_header_sig(mz_zip_archive * pZip,mz_uint32 record_sig,mz_uint32 record_size,mz_int64 * pOfs)546 static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs)
547 {
548     mz_int64 cur_file_ofs;
549     mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
550     mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
551 
552     /* Basic sanity checks - reject files which are too small */
553     if (pZip->m_archive_size < record_size)
554         return MZ_FALSE;
555 
556     /* Find the record by scanning the file from the end towards the beginning. */
557     cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
558     for (;;)
559     {
560         int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
561 
562         if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
563             return MZ_FALSE;
564 
565         for (i = n - 4; i >= 0; --i)
566         {
567             mz_uint s = MZ_READ_LE32(pBuf + i);
568             if (s == record_sig)
569             {
570                 if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)
571                     break;
572             }
573         }
574 
575         if (i >= 0)
576         {
577             cur_file_ofs += i;
578             break;
579         }
580 
581         /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */
582         if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size)))
583             return MZ_FALSE;
584 
585         cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
586     }
587 
588     *pOfs = cur_file_ofs;
589     return MZ_TRUE;
590 }
591 
mz_zip_reader_read_central_dir(mz_zip_archive * pZip,mz_uint flags)592 static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags)
593 {
594     mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0;
595     mz_uint64 cdir_ofs = 0;
596     mz_int64 cur_file_ofs = 0;
597     const mz_uint8 *p;
598 
599     mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
600     mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
601     mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
602     mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
603     mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;
604 
605     mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
606     mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32;
607 
608     mz_uint64 zip64_end_of_central_dir_ofs = 0;
609 
610     /* 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. */
611     if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
612         return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
613 
614     if (!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))
615         return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);
616 
617     /* Read and verify the end of central directory record. */
618     if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
619         return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
620 
621     if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
622         return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
623 
624     if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
625     {
626         if (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)
627         {
628             if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG)
629             {
630                 zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);
631                 if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
632                     return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
633 
634                 if (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)
635                 {
636                     if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG)
637                     {
638                         pZip->m_pState->m_zip64 = MZ_TRUE;
639                     }
640                 }
641             }
642         }
643     }
644 
645     pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);
646     cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
647     num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
648     cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
649     cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);
650     cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
651 
652     if (pZip->m_pState->m_zip64)
653     {
654         mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);
655         mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);
656         mz_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);
657         mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);
658         mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);
659 
660         if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))
661             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
662 
663         if (zip64_total_num_of_disks != 1U)
664             return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
665 
666         /* Check for miniz's practical limits */
667         if (zip64_cdir_total_entries > MZ_UINT32_MAX)
668             return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
669 
670         pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;
671 
672         if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)
673             return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
674 
675         cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk;
676 
677         /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */
678         if (zip64_size_of_central_directory > MZ_UINT32_MAX)
679             return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
680 
681         cdir_size = (mz_uint32)zip64_size_of_central_directory;
682 
683         num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);
684 
685         cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);
686 
687         cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);
688     }
689 
690     if (pZip->m_total_files != cdir_entries_on_this_disk)
691         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
692 
693     if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1)))
694         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
695 
696     if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
697         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
698 
699     if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
700         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
701 
702     pZip->m_central_directory_file_ofs = cdir_ofs;
703 
704     if (pZip->m_total_files)
705     {
706         mz_uint i, n;
707         /* 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. */
708         if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) ||
709             (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE)))
710             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
711 
712         if (sort_central_dir)
713         {
714             if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE))
715                 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
716         }
717 
718         if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size)
719             return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
720 
721         /* Now create an index into the central directory file records, do some basic sanity checking on each record */
722         p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
723         for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i)
724         {
725             mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size;
726             mz_uint64 comp_size, decomp_size, local_header_ofs;
727 
728             if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
729                 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
730 
731             MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
732 
733             if (sort_central_dir)
734                 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i;
735 
736             comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
737             decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
738             local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
739             filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
740             ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
741 
742             if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&
743                 (ext_data_size) &&
744                 (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX))
745             {
746                 /* Attempt to find zip64 extended information field in the entry's extra data */
747                 mz_uint32 extra_size_remaining = ext_data_size;
748 
749                 if (extra_size_remaining)
750                 {
751                     const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
752 
753                     do
754                     {
755                         mz_uint32 field_id;
756                         mz_uint32 field_data_size;
757 
758                         if (extra_size_remaining < (sizeof(mz_uint16) * 2))
759                             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
760 
761                         field_id = MZ_READ_LE16(pExtra_data);
762                         field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
763 
764                         if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)
765                             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
766 
767                         if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
768                         {
769                             /* 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). */
770                             pZip->m_pState->m_zip64 = MZ_TRUE;
771                             pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;
772                             break;
773                         }
774 
775                         pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
776                         extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
777                     } while (extra_size_remaining);
778                 }
779             }
780 
781             /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */
782             if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX))
783             {
784                 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size))
785                     return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
786             }
787 
788             disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
789             if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1)))
790                 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
791 
792             if (comp_size != MZ_UINT32_MAX)
793             {
794                 if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
795                     return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
796             }
797 
798             bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
799             if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)
800                 return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
801 
802             if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n)
803                 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
804 
805             n -= total_header_size;
806             p += total_header_size;
807         }
808     }
809 
810     if (sort_central_dir)
811         mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
812 
813     return MZ_TRUE;
814 }
815 
mz_zip_zero_struct(mz_zip_archive * pZip)816 void mz_zip_zero_struct(mz_zip_archive *pZip)
817 {
818     if (pZip)
819         MZ_CLEAR_OBJ(*pZip);
820 }
821 
mz_zip_reader_end_internal(mz_zip_archive * pZip,mz_bool set_last_error)822 static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error)
823 {
824     mz_bool status = MZ_TRUE;
825 
826     if (!pZip)
827         return MZ_FALSE;
828 
829     if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
830     {
831         if (set_last_error)
832             pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER;
833 
834         return MZ_FALSE;
835     }
836 
837     if (pZip->m_pState)
838     {
839         mz_zip_internal_state *pState = pZip->m_pState;
840         pZip->m_pState = NULL;
841 
842         mz_zip_array_clear(pZip, &pState->m_central_dir);
843         mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
844         mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
845 
846 #ifndef MINIZ_NO_STDIO
847         if (pState->m_pFile)
848         {
849             if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)
850             {
851                 if (MZ_FCLOSE(pState->m_pFile) == EOF)
852                 {
853                     if (set_last_error)
854                         pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED;
855                     status = MZ_FALSE;
856                 }
857             }
858             pState->m_pFile = NULL;
859         }
860 #endif /* #ifndef MINIZ_NO_STDIO */
861 
862         pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
863     }
864     pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
865 
866     return status;
867 }
868 
mz_zip_reader_end(mz_zip_archive * pZip)869 mz_bool mz_zip_reader_end(mz_zip_archive *pZip)
870 {
871     return mz_zip_reader_end_internal(pZip, MZ_TRUE);
872 }
mz_zip_reader_init(mz_zip_archive * pZip,mz_uint64 size,mz_uint flags)873 mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags)
874 {
875     if ((!pZip) || (!pZip->m_pRead))
876         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
877 
878     if (!mz_zip_reader_init_internal(pZip, flags))
879         return MZ_FALSE;
880 
881     pZip->m_zip_type = MZ_ZIP_TYPE_USER;
882     pZip->m_archive_size = size;
883 
884     if (!mz_zip_reader_read_central_dir(pZip, flags))
885     {
886         mz_zip_reader_end_internal(pZip, MZ_FALSE);
887         return MZ_FALSE;
888     }
889 
890     return MZ_TRUE;
891 }
892 
mz_zip_mem_read_func(void * pOpaque,mz_uint64 file_ofs,void * pBuf,size_t n)893 static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
894 {
895     mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
896     size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
897     memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
898     return s;
899 }
900 
mz_zip_reader_init_mem(mz_zip_archive * pZip,const void * pMem,size_t size,mz_uint flags)901 mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags)
902 {
903     if (!pMem)
904         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
905 
906     if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
907         return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
908 
909     if (!mz_zip_reader_init_internal(pZip, flags))
910         return MZ_FALSE;
911 
912     pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY;
913     pZip->m_archive_size = size;
914     pZip->m_pRead = mz_zip_mem_read_func;
915     pZip->m_pIO_opaque = pZip;
916     pZip->m_pNeeds_keepalive = NULL;
917 
918 #ifdef __cplusplus
919     pZip->m_pState->m_pMem = const_cast<void *>(pMem);
920 #else
921     pZip->m_pState->m_pMem = (void *)pMem;
922 #endif
923 
924     pZip->m_pState->m_mem_size = size;
925 
926     if (!mz_zip_reader_read_central_dir(pZip, flags))
927     {
928         mz_zip_reader_end_internal(pZip, MZ_FALSE);
929         return MZ_FALSE;
930     }
931 
932     return MZ_TRUE;
933 }
934 
935 #ifndef MINIZ_NO_STDIO
mz_zip_file_read_func(void * pOpaque,mz_uint64 file_ofs,void * pBuf,size_t n)936 static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
937 {
938     mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
939     mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
940 
941     file_ofs += pZip->m_pState->m_file_archive_start_ofs;
942 
943     if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
944         return 0;
945 
946     return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
947 }
948 
mz_zip_reader_init_file(mz_zip_archive * pZip,const char * pFilename,mz_uint32 flags)949 mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags)
950 {
951     return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0);
952 }
953 
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)954 mz_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)
955 {
956     mz_uint64 file_size;
957     MZ_FILE *pFile;
958 
959     if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
960         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
961 
962     pFile = MZ_FOPEN(pFilename, "rb");
963     if (!pFile)
964         return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
965 
966     file_size = archive_size;
967     if (!file_size)
968     {
969         if (MZ_FSEEK64(pFile, 0, SEEK_END))
970         {
971             MZ_FCLOSE(pFile);
972             return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
973         }
974 
975         file_size = MZ_FTELL64(pFile);
976     }
977 
978     /* TODO: Better sanity check archive_size and the # of actual remaining bytes */
979 
980     if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
981     {
982 	MZ_FCLOSE(pFile);
983         return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
984     }
985 
986     if (!mz_zip_reader_init_internal(pZip, flags))
987     {
988         MZ_FCLOSE(pFile);
989         return MZ_FALSE;
990     }
991 
992     pZip->m_zip_type = MZ_ZIP_TYPE_FILE;
993     pZip->m_pRead = mz_zip_file_read_func;
994     pZip->m_pIO_opaque = pZip;
995     pZip->m_pState->m_pFile = pFile;
996     pZip->m_archive_size = file_size;
997     pZip->m_pState->m_file_archive_start_ofs = file_start_ofs;
998 
999     if (!mz_zip_reader_read_central_dir(pZip, flags))
1000     {
1001         mz_zip_reader_end_internal(pZip, MZ_FALSE);
1002         return MZ_FALSE;
1003     }
1004 
1005     return MZ_TRUE;
1006 }
1007 
mz_zip_reader_init_cfile(mz_zip_archive * pZip,MZ_FILE * pFile,mz_uint64 archive_size,mz_uint flags)1008 mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags)
1009 {
1010     mz_uint64 cur_file_ofs;
1011 
1012     if ((!pZip) || (!pFile))
1013         return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
1014 
1015     cur_file_ofs = MZ_FTELL64(pFile);
1016 
1017     if (!archive_size)
1018     {
1019         if (MZ_FSEEK64(pFile, 0, SEEK_END))
1020             return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
1021 
1022         archive_size = MZ_FTELL64(pFile) - cur_file_ofs;
1023 
1024         if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
1025             return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
1026     }
1027 
1028     if (!mz_zip_reader_init_internal(pZip, flags))
1029         return MZ_FALSE;
1030 
1031     pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;
1032     pZip->m_pRead = mz_zip_file_read_func;
1033 
1034     pZip->m_pIO_opaque = pZip;
1035     pZip->m_pState->m_pFile = pFile;
1036     pZip->m_archive_size = archive_size;
1037     pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs;
1038 
1039     if (!mz_zip_reader_read_central_dir(pZip, flags))
1040     {
1041         mz_zip_reader_end_internal(pZip, MZ_FALSE);
1042         return MZ_FALSE;
1043     }
1044 
1045     return MZ_TRUE;
1046 }
1047 
1048 #endif /* #ifndef MINIZ_NO_STDIO */
1049 
mz_zip_get_cdh(mz_zip_archive * pZip,mz_uint file_index)1050 static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index)
1051 {
1052     if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files))
1053         return NULL;
1054     return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index));
1055 }
1056 
mz_zip_reader_is_file_encrypted(mz_zip_archive * pZip,mz_uint file_index)1057 mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index)
1058 {
1059     mz_uint m_bit_flag;
1060     const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
1061     if (!p)
1062     {
1063         mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
1064         return MZ_FALSE;
1065     }
1066 
1067     m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
1068     return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0;
1069 }
1070 
mz_zip_reader_is_file_supported(mz_zip_archive * pZip,mz_uint file_index)1071 mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index)
1072 {
1073     mz_uint bit_flag;
1074     mz_uint method;
1075 
1076     const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
1077     if (!p)
1078     {
1079         mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
1080         return MZ_FALSE;
1081     }
1082 
1083     method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
1084     bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
1085 
1086     if ((method != 0) && (method != MZ_DEFLATED))
1087     {
1088         mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
1089         return MZ_FALSE;
1090     }
1091 
1092     if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION))
1093     {
1094         mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
1095         return MZ_FALSE;
1096     }
1097 
1098     if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)
1099     {
1100         mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
1101         return MZ_FALSE;
1102     }
1103 
1104     return MZ_TRUE;
1105 }
1106 
mz_zip_reader_is_file_a_directory(mz_zip_archive * pZip,mz_uint file_index)1107 mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index)
1108 {
1109     mz_uint filename_len, attribute_mapping_id, external_attr;
1110     const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
1111     if (!p)
1112     {
1113         mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
1114         return MZ_FALSE;
1115     }
1116 
1117     filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
1118     if (filename_len)
1119     {
1120         if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
1121             return MZ_TRUE;
1122     }
1123 
1124     /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */
1125     /* 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. */
1126     /* FIXME: Remove this check? Is it necessary - we already check the filename. */
1127     attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8;
1128     (void)attribute_mapping_id;
1129 
1130     external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
1131     if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0)
1132     {
1133         return MZ_TRUE;
1134     }
1135 
1136     return MZ_FALSE;
1137 }
1138 
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)1139 static 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)
1140 {
1141     mz_uint n;
1142     const mz_uint8 *p = pCentral_dir_header;
1143 
1144     if (pFound_zip64_extra_data)
1145         *pFound_zip64_extra_data = MZ_FALSE;
1146 
1147     if ((!p) || (!pStat))
1148         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
1149 
1150     /* Extract fields from the central directory record. */
1151     pStat->m_file_index = file_index;
1152     pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
1153     pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
1154     pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
1155     pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
1156     pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
1157 #ifndef MINIZ_NO_TIME
1158     pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));
1159 #endif
1160     pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
1161     pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
1162     pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
1163     pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
1164     pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
1165     pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
1166 
1167     /* Copy as much of the filename and comment as possible. */
1168     n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
1169     n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
1170     memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
1171     pStat->m_filename[n] = '\0';
1172 
1173     n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
1174     n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
1175     pStat->m_comment_size = n;
1176     memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n);
1177     pStat->m_comment[n] = '\0';
1178 
1179     /* Set some flags for convienance */
1180     pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index);
1181     pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index);
1182     pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index);
1183 
1184     /* See if we need to read any zip64 extended information fields. */
1185     /* 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). */
1186     if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX)
1187     {
1188         /* Attempt to find zip64 extended information field in the entry's extra data */
1189         mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
1190 
1191         if (extra_size_remaining)
1192         {
1193             const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
1194 
1195             do
1196             {
1197                 mz_uint32 field_id;
1198                 mz_uint32 field_data_size;
1199 
1200                 if (extra_size_remaining < (sizeof(mz_uint16) * 2))
1201                     return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
1202 
1203                 field_id = MZ_READ_LE16(pExtra_data);
1204                 field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
1205 
1206                 if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)
1207                     return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
1208 
1209                 if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
1210                 {
1211                     const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2;
1212                     mz_uint32 field_data_remaining = field_data_size;
1213 
1214                     if (pFound_zip64_extra_data)
1215                         *pFound_zip64_extra_data = MZ_TRUE;
1216 
1217                     if (pStat->m_uncomp_size == MZ_UINT32_MAX)
1218                     {
1219                         if (field_data_remaining < sizeof(mz_uint64))
1220                             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
1221 
1222                         pStat->m_uncomp_size = MZ_READ_LE64(pField_data);
1223                         pField_data += sizeof(mz_uint64);
1224                         field_data_remaining -= sizeof(mz_uint64);
1225                     }
1226 
1227                     if (pStat->m_comp_size == MZ_UINT32_MAX)
1228                     {
1229                         if (field_data_remaining < sizeof(mz_uint64))
1230                             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
1231 
1232                         pStat->m_comp_size = MZ_READ_LE64(pField_data);
1233                         pField_data += sizeof(mz_uint64);
1234                         field_data_remaining -= sizeof(mz_uint64);
1235                     }
1236 
1237                     if (pStat->m_local_header_ofs == MZ_UINT32_MAX)
1238                     {
1239                         if (field_data_remaining < sizeof(mz_uint64))
1240                             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
1241 
1242                         pStat->m_local_header_ofs = MZ_READ_LE64(pField_data);
1243                         pField_data += sizeof(mz_uint64);
1244                         field_data_remaining -= sizeof(mz_uint64);
1245                     }
1246 
1247                     break;
1248                 }
1249 
1250                 pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
1251                 extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
1252             } while (extra_size_remaining);
1253         }
1254     }
1255 
1256     return MZ_TRUE;
1257 }
1258 
mz_zip_string_equal(const char * pA,const char * pB,mz_uint len,mz_uint flags)1259 static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags)
1260 {
1261     mz_uint i;
1262     if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE)
1263         return 0 == memcmp(pA, pB, len);
1264     for (i = 0; i < len; ++i)
1265         if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i]))
1266             return MZ_FALSE;
1267     return MZ_TRUE;
1268 }
1269 
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)1270 static 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)
1271 {
1272     const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;
1273     mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
1274     mz_uint8 l = 0, r = 0;
1275     pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
1276     pE = pL + MZ_MIN(l_len, r_len);
1277     while (pL < pE)
1278     {
1279         if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
1280             break;
1281         pL++;
1282         pR++;
1283     }
1284     return (pL == pE) ? (int)(l_len - r_len) : (l - r);
1285 }
1286 
mz_zip_locate_file_binary_search(mz_zip_archive * pZip,const char * pFilename,mz_uint32 * pIndex)1287 static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex)
1288 {
1289     mz_zip_internal_state *pState = pZip->m_pState;
1290     const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
1291     const mz_zip_array *pCentral_dir = &pState->m_central_dir;
1292     mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
1293     const uint32_t size = pZip->m_total_files;
1294     const mz_uint filename_len = (mz_uint)strlen(pFilename);
1295 
1296     if (pIndex)
1297         *pIndex = 0;
1298 
1299     if (size)
1300     {
1301         /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */
1302         /* honestly the major expense here on 32-bit CPU's will still be the filename compare */
1303         mz_int64 l = 0, h = (mz_int64)size - 1;
1304 
1305         while (l <= h)
1306         {
1307             mz_int64 m = l + ((h - l) >> 1);
1308             uint32_t file_index = pIndices[(uint32_t)m];
1309 
1310             int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len);
1311             if (!comp)
1312             {
1313                 if (pIndex)
1314                     *pIndex = file_index;
1315                 return MZ_TRUE;
1316             }
1317             else if (comp < 0)
1318                 l = m + 1;
1319             else
1320                 h = m - 1;
1321         }
1322     }
1323 
1324     return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);
1325 }
1326 
mz_zip_reader_locate_file(mz_zip_archive * pZip,const char * pName,const char * pComment,mz_uint flags)1327 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags)
1328 {
1329     mz_uint32 index;
1330     if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index))
1331         return -1;
1332     else
1333         return (int)index;
1334 }
1335 
mz_zip_reader_locate_file_v2(mz_zip_archive * pZip,const char * pName,const char * pComment,mz_uint flags,mz_uint32 * pIndex)1336 mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex)
1337 {
1338     mz_uint file_index;
1339     size_t name_len, comment_len;
1340 
1341     if (pIndex)
1342         *pIndex = 0;
1343 
1344     if ((!pZip) || (!pZip->m_pState) || (!pName))
1345         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
1346 
1347     /* See if we can use a binary search */
1348     if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) &&
1349         (pZip->m_zip_mode == MZ_ZIP_MODE_READING) &&
1350         ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))
1351     {
1352         return mz_zip_locate_file_binary_search(pZip, pName, pIndex);
1353     }
1354 
1355     /* Locate the entry by scanning the entire central directory */
1356     name_len = strlen(pName);
1357     if (name_len > MZ_UINT16_MAX)
1358         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
1359 
1360     comment_len = pComment ? strlen(pComment) : 0;
1361     if (comment_len > MZ_UINT16_MAX)
1362         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
1363 
1364     for (file_index = 0; file_index < pZip->m_total_files; file_index++)
1365     {
1366         const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index));
1367         mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
1368         const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
1369         if (filename_len < name_len)
1370             continue;
1371         if (comment_len)
1372         {
1373             mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);
1374             const char *pFile_comment = pFilename + filename_len + file_extra_len;
1375             if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags)))
1376                 continue;
1377         }
1378         if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len))
1379         {
1380             int ofs = filename_len - 1;
1381             do
1382             {
1383                 if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':'))
1384                     break;
1385             } while (--ofs >= 0);
1386             ofs++;
1387             pFilename += ofs;
1388             filename_len -= ofs;
1389         }
1390         if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags)))
1391         {
1392             if (pIndex)
1393                 *pIndex = file_index;
1394             return MZ_TRUE;
1395         }
1396     }
1397 
1398     return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);
1399 }
1400 
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)1401 mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)
1402 {
1403     int status = TINFL_STATUS_DONE;
1404     mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
1405     mz_zip_archive_file_stat file_stat;
1406     void *pRead_buf;
1407     mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
1408     mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
1409     tinfl_decompressor inflator;
1410 
1411     if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead))
1412         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
1413 
1414     if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
1415         return MZ_FALSE;
1416 
1417     /* A directory or zero length file */
1418     if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))
1419         return MZ_TRUE;
1420 
1421     /* Encryption and patch files are not supported. */
1422     if (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))
1423         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
1424 
1425     /* This function only supports decompressing stored and deflate. */
1426     if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
1427         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
1428 
1429     /* Ensure supplied output buffer is large enough. */
1430     needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size;
1431     if (buf_size < needed_size)
1432         return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL);
1433 
1434     /* Read and parse the local directory entry. */
1435     cur_file_ofs = file_stat.m_local_header_ofs;
1436     if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
1437         return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
1438 
1439     if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
1440         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
1441 
1442     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);
1443     if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
1444         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
1445 
1446     if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
1447     {
1448         /* The file is stored or the caller has requested the compressed data. */
1449         if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size)
1450             return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
1451 
1452 #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
1453         if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0)
1454         {
1455             if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)
1456                 return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);
1457         }
1458 #endif
1459 
1460         return MZ_TRUE;
1461     }
1462 
1463     /* Decompress the file either directly from memory or from a file input buffer. */
1464     tinfl_init(&inflator);
1465 
1466     if (pZip->m_pState->m_pMem)
1467     {
1468         /* Read directly from the archive in memory. */
1469         pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
1470         read_buf_size = read_buf_avail = file_stat.m_comp_size;
1471         comp_remaining = 0;
1472     }
1473     else if (pUser_read_buf)
1474     {
1475         /* Use a user provided read buffer. */
1476         if (!user_read_buf_size)
1477             return MZ_FALSE;
1478         pRead_buf = (mz_uint8 *)pUser_read_buf;
1479         read_buf_size = user_read_buf_size;
1480         read_buf_avail = 0;
1481         comp_remaining = file_stat.m_comp_size;
1482     }
1483     else
1484     {
1485         /* Temporarily allocate a read buffer. */
1486         read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
1487         if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
1488             return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
1489 
1490         if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
1491             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
1492 
1493         read_buf_avail = 0;
1494         comp_remaining = file_stat.m_comp_size;
1495     }
1496 
1497     do
1498     {
1499         /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */
1500         size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
1501         if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
1502         {
1503             read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
1504             if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
1505             {
1506                 status = TINFL_STATUS_FAILED;
1507                 mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
1508                 break;
1509             }
1510             cur_file_ofs += read_buf_avail;
1511             comp_remaining -= read_buf_avail;
1512             read_buf_ofs = 0;
1513         }
1514         in_buf_size = (size_t)read_buf_avail;
1515         status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));
1516         read_buf_avail -= in_buf_size;
1517         read_buf_ofs += in_buf_size;
1518         out_buf_ofs += out_buf_size;
1519     } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
1520 
1521     if (status == TINFL_STATUS_DONE)
1522     {
1523         /* Make sure the entire file was decompressed, and check its CRC. */
1524         if (out_buf_ofs != file_stat.m_uncomp_size)
1525         {
1526             mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);
1527             status = TINFL_STATUS_FAILED;
1528         }
1529 #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
1530         else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)
1531         {
1532             mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);
1533             status = TINFL_STATUS_FAILED;
1534         }
1535 #endif
1536     }
1537 
1538     if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
1539         pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
1540 
1541     return status == TINFL_STATUS_DONE;
1542 }
1543 
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)1544 mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)
1545 {
1546     mz_uint32 file_index;
1547     if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
1548         return MZ_FALSE;
1549     return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size);
1550 }
1551 
mz_zip_reader_extract_to_mem(mz_zip_archive * pZip,mz_uint file_index,void * pBuf,size_t buf_size,mz_uint flags)1552 mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags)
1553 {
1554     return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0);
1555 }
1556 
mz_zip_reader_extract_file_to_mem(mz_zip_archive * pZip,const char * pFilename,void * pBuf,size_t buf_size,mz_uint flags)1557 mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags)
1558 {
1559     return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0);
1560 }
1561 
mz_zip_reader_extract_to_heap(mz_zip_archive * pZip,mz_uint file_index,size_t * pSize,mz_uint flags)1562 void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags)
1563 {
1564     mz_uint64 comp_size, uncomp_size, alloc_size;
1565     const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
1566     void *pBuf;
1567 
1568     if (pSize)
1569         *pSize = 0;
1570 
1571     if (!p)
1572     {
1573         mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
1574         return NULL;
1575     }
1576 
1577     comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
1578     uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
1579 
1580     alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
1581     if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
1582     {
1583         mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
1584         return NULL;
1585     }
1586 
1587     if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))
1588     {
1589         mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
1590         return NULL;
1591     }
1592 
1593     if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags))
1594     {
1595         pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
1596         return NULL;
1597     }
1598 
1599     if (pSize)
1600         *pSize = (size_t)alloc_size;
1601     return pBuf;
1602 }
1603 
mz_zip_reader_extract_file_to_heap(mz_zip_archive * pZip,const char * pFilename,size_t * pSize,mz_uint flags)1604 void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags)
1605 {
1606     mz_uint32 file_index;
1607     if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
1608     {
1609         if (pSize)
1610             *pSize = 0;
1611         return MZ_FALSE;
1612     }
1613     return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
1614 }
1615 
mz_zip_reader_extract_to_callback(mz_zip_archive * pZip,mz_uint file_index,mz_file_write_func pCallback,void * pOpaque,mz_uint flags)1616 mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)
1617 {
1618     int status = TINFL_STATUS_DONE;
1619     mz_uint file_crc32 = MZ_CRC32_INIT;
1620     mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs;
1621     mz_zip_archive_file_stat file_stat;
1622     void *pRead_buf = NULL;
1623     void *pWrite_buf = NULL;
1624     mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
1625     mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
1626 
1627     if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead))
1628         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
1629 
1630     if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
1631         return MZ_FALSE;
1632 
1633     /* A directory or zero length file */
1634     if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))
1635         return MZ_TRUE;
1636 
1637     /* Encryption and patch files are not supported. */
1638     if (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))
1639         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
1640 
1641     /* This function only supports decompressing stored and deflate. */
1642     if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
1643         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
1644 
1645     /* 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) */
1646     cur_file_ofs = file_stat.m_local_header_ofs;
1647     if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
1648         return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
1649 
1650     if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
1651         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
1652 
1653     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);
1654     if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
1655         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
1656 
1657     /* Decompress the file either directly from memory or from a file input buffer. */
1658     if (pZip->m_pState->m_pMem)
1659     {
1660         pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
1661         read_buf_size = read_buf_avail = file_stat.m_comp_size;
1662         comp_remaining = 0;
1663     }
1664     else
1665     {
1666         read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
1667         if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
1668             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
1669 
1670         read_buf_avail = 0;
1671         comp_remaining = file_stat.m_comp_size;
1672     }
1673 
1674     if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
1675     {
1676         /* The file is stored or the caller has requested the compressed data. */
1677         if (pZip->m_pState->m_pMem)
1678         {
1679             if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX))
1680                 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
1681 
1682             if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)
1683             {
1684                 mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
1685                 status = TINFL_STATUS_FAILED;
1686             }
1687             else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
1688             {
1689 #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
1690                 file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size);
1691 #endif
1692             }
1693 
1694             cur_file_ofs += file_stat.m_comp_size;
1695             out_buf_ofs += file_stat.m_comp_size;
1696             comp_remaining = 0;
1697         }
1698         else
1699         {
1700             while (comp_remaining)
1701             {
1702                 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
1703                 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
1704                 {
1705                     mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
1706                     status = TINFL_STATUS_FAILED;
1707                     break;
1708                 }
1709 
1710 #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
1711                 if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
1712                 {
1713                     file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
1714                 }
1715 #endif
1716 
1717                 if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
1718                 {
1719                     mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
1720                     status = TINFL_STATUS_FAILED;
1721                     break;
1722                 }
1723 
1724                 cur_file_ofs += read_buf_avail;
1725                 out_buf_ofs += read_buf_avail;
1726                 comp_remaining -= read_buf_avail;
1727             }
1728         }
1729     }
1730     else
1731     {
1732         tinfl_decompressor inflator;
1733         tinfl_init(&inflator);
1734 
1735         if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE)))
1736         {
1737             mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
1738             status = TINFL_STATUS_FAILED;
1739         }
1740         else
1741         {
1742             do
1743             {
1744                 mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
1745                 size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
1746                 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
1747                 {
1748                     read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
1749                     if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
1750                     {
1751                         mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
1752                         status = TINFL_STATUS_FAILED;
1753                         break;
1754                     }
1755                     cur_file_ofs += read_buf_avail;
1756                     comp_remaining -= read_buf_avail;
1757                     read_buf_ofs = 0;
1758                 }
1759 
1760                 in_buf_size = (size_t)read_buf_avail;
1761                 status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
1762                 read_buf_avail -= in_buf_size;
1763                 read_buf_ofs += in_buf_size;
1764 
1765                 if (out_buf_size)
1766                 {
1767                     if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size)
1768                     {
1769                         mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
1770                         status = TINFL_STATUS_FAILED;
1771                         break;
1772                     }
1773 
1774 #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
1775                     file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
1776 #endif
1777                     if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size)
1778                     {
1779                         mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
1780                         status = TINFL_STATUS_FAILED;
1781                         break;
1782                     }
1783                 }
1784             } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT));
1785         }
1786     }
1787 
1788     if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
1789     {
1790         /* Make sure the entire file was decompressed, and check its CRC. */
1791         if (out_buf_ofs != file_stat.m_uncomp_size)
1792         {
1793             mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);
1794             status = TINFL_STATUS_FAILED;
1795         }
1796 #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
1797         else if (file_crc32 != file_stat.m_crc32)
1798         {
1799             mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
1800             status = TINFL_STATUS_FAILED;
1801         }
1802 #endif
1803     }
1804 
1805     if (!pZip->m_pState->m_pMem)
1806         pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
1807 
1808     if (pWrite_buf)
1809         pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
1810 
1811     return status == TINFL_STATUS_DONE;
1812 }
1813 
mz_zip_reader_extract_file_to_callback(mz_zip_archive * pZip,const char * pFilename,mz_file_write_func pCallback,void * pOpaque,mz_uint flags)1814 mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)
1815 {
1816     mz_uint32 file_index;
1817     if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
1818         return MZ_FALSE;
1819 
1820     return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags);
1821 }
1822 
mz_zip_reader_extract_iter_new(mz_zip_archive * pZip,mz_uint file_index,mz_uint flags)1823 mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags)
1824 {
1825     mz_zip_reader_extract_iter_state *pState;
1826     mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
1827     mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
1828 
1829     /* Argument sanity check */
1830     if ((!pZip) || (!pZip->m_pState))
1831         return NULL;
1832 
1833     /* Allocate an iterator status structure */
1834     pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state));
1835     if (!pState)
1836     {
1837         mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
1838         return NULL;
1839     }
1840 
1841     /* Fetch file details */
1842     if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat))
1843     {
1844         pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
1845         return NULL;
1846     }
1847 
1848     /* Encryption and patch files are not supported. */
1849     if (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))
1850     {
1851         mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
1852         pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
1853         return NULL;
1854     }
1855 
1856     /* This function only supports decompressing stored and deflate. */
1857     if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED))
1858     {
1859         mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
1860         pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
1861         return NULL;
1862     }
1863 
1864     /* Init state - save args */
1865     pState->pZip = pZip;
1866     pState->flags = flags;
1867 
1868     /* Init state - reset variables to defaults */
1869     pState->status = TINFL_STATUS_DONE;
1870 #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
1871     pState->file_crc32 = MZ_CRC32_INIT;
1872 #endif
1873     pState->read_buf_ofs = 0;
1874     pState->out_buf_ofs = 0;
1875     pState->pRead_buf = NULL;
1876     pState->pWrite_buf = NULL;
1877     pState->out_blk_remain = 0;
1878 
1879     /* Read and parse the local directory entry. */
1880     pState->cur_file_ofs = pState->file_stat.m_local_header_ofs;
1881     if (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)
1882     {
1883         mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
1884         pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
1885         return NULL;
1886     }
1887 
1888     if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
1889     {
1890         mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
1891         pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
1892         return NULL;
1893     }
1894 
1895     pState->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);
1896     if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size)
1897     {
1898         mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
1899         pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
1900         return NULL;
1901     }
1902 
1903     /* Decompress the file either directly from memory or from a file input buffer. */
1904     if (pZip->m_pState->m_pMem)
1905     {
1906         pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs;
1907         pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size;
1908         pState->comp_remaining = pState->file_stat.m_comp_size;
1909     }
1910     else
1911     {
1912         if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)))
1913         {
1914             /* Decompression required, therefore intermediate read buffer required */
1915             pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);
1916             if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size)))
1917             {
1918                 mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
1919                 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
1920                 return NULL;
1921             }
1922         }
1923         else
1924         {
1925             /* Decompression not required - we will be reading directly into user buffer, no temp buf required */
1926             pState->read_buf_size = 0;
1927         }
1928         pState->read_buf_avail = 0;
1929         pState->comp_remaining = pState->file_stat.m_comp_size;
1930     }
1931 
1932     if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)))
1933     {
1934         /* Decompression required, init decompressor */
1935         tinfl_init( &pState->inflator );
1936 
1937         /* Allocate write buffer */
1938         if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE)))
1939         {
1940             mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
1941             if (pState->pRead_buf)
1942                 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf);
1943             pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
1944             return NULL;
1945         }
1946     }
1947 
1948     return pState;
1949 }
1950 
mz_zip_reader_extract_file_iter_new(mz_zip_archive * pZip,const char * pFilename,mz_uint flags)1951 mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags)
1952 {
1953     mz_uint32 file_index;
1954 
1955     /* Locate file index by name */
1956     if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
1957         return NULL;
1958 
1959     /* Construct iterator */
1960     return mz_zip_reader_extract_iter_new(pZip, file_index, flags);
1961 }
1962 
mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state * pState,void * pvBuf,size_t buf_size)1963 size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size)
1964 {
1965     size_t copied_to_caller = 0;
1966 
1967     /* Argument sanity check */
1968     if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf))
1969         return 0;
1970 
1971     if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))
1972     {
1973         /* The file is stored or the caller has requested the compressed data, calc amount to return. */
1974         copied_to_caller = MZ_MIN( buf_size, pState->comp_remaining );
1975 
1976         /* Zip is in memory....or requires reading from a file? */
1977         if (pState->pZip->m_pState->m_pMem)
1978         {
1979             /* Copy data to caller's buffer */
1980             memcpy( pvBuf, pState->pRead_buf, copied_to_caller );
1981             pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller;
1982         }
1983         else
1984         {
1985             /* Read directly into caller's buffer */
1986             if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller)
1987             {
1988                 /* Failed to read all that was asked for, flag failure and alert user */
1989                 mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED);
1990                 pState->status = TINFL_STATUS_FAILED;
1991                 copied_to_caller = 0;
1992             }
1993         }
1994 
1995 #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
1996         /* Compute CRC if not returning compressed data only */
1997         if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
1998             pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller);
1999 #endif
2000 
2001         /* Advance offsets, dec counters */
2002         pState->cur_file_ofs += copied_to_caller;
2003         pState->out_buf_ofs += copied_to_caller;
2004         pState->comp_remaining -= copied_to_caller;
2005     }
2006     else
2007     {
2008         do
2009         {
2010             /* Calc ptr to write buffer - given current output pos and block size */
2011             mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
2012 
2013             /* Calc max output size - given current output pos and block size */
2014             size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
2015 
2016             if (!pState->out_blk_remain)
2017             {
2018                 /* Read more data from file if none available (and reading from file) */
2019                 if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem))
2020                 {
2021                     /* Calc read size */
2022                     pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining);
2023                     if (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)
2024                     {
2025                         mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED);
2026                         pState->status = TINFL_STATUS_FAILED;
2027                         break;
2028                     }
2029 
2030                     /* Advance offsets, dec counters */
2031                     pState->cur_file_ofs += pState->read_buf_avail;
2032                     pState->comp_remaining -= pState->read_buf_avail;
2033                     pState->read_buf_ofs = 0;
2034                 }
2035 
2036                 /* Perform decompression */
2037                 in_buf_size = (size_t)pState->read_buf_avail;
2038                 pState->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);
2039                 pState->read_buf_avail -= in_buf_size;
2040                 pState->read_buf_ofs += in_buf_size;
2041 
2042                 /* Update current output block size remaining */
2043                 pState->out_blk_remain = out_buf_size;
2044             }
2045 
2046             if (pState->out_blk_remain)
2047             {
2048                 /* Calc amount to return. */
2049                 size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain );
2050 
2051                 /* Copy data to caller's buffer */
2052                 memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy );
2053 
2054 #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
2055                 /* Perform CRC */
2056                 pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy);
2057 #endif
2058 
2059                 /* Decrement data consumed from block */
2060                 pState->out_blk_remain -= to_copy;
2061 
2062                 /* Inc output offset, while performing sanity check */
2063                 if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size)
2064                 {
2065                     mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED);
2066                     pState->status = TINFL_STATUS_FAILED;
2067                     break;
2068                 }
2069 
2070                 /* Increment counter of data copied to caller */
2071                 copied_to_caller += to_copy;
2072             }
2073         } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) );
2074     }
2075 
2076     /* Return how many bytes were copied into user buffer */
2077     return copied_to_caller;
2078 }
2079 
mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state * pState)2080 mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState)
2081 {
2082     int status;
2083 
2084     /* Argument sanity check */
2085     if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState))
2086         return MZ_FALSE;
2087 
2088     /* Was decompression completed and requested? */
2089     if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
2090     {
2091         /* Make sure the entire file was decompressed, and check its CRC. */
2092         if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size)
2093         {
2094             mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);
2095             pState->status = TINFL_STATUS_FAILED;
2096         }
2097 #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
2098         else if (pState->file_crc32 != pState->file_stat.m_crc32)
2099         {
2100             mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED);
2101             pState->status = TINFL_STATUS_FAILED;
2102         }
2103 #endif
2104     }
2105 
2106     /* Free buffers */
2107     if (!pState->pZip->m_pState->m_pMem)
2108         pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf);
2109     if (pState->pWrite_buf)
2110         pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf);
2111 
2112     /* Save status */
2113     status = pState->status;
2114 
2115     /* Free context */
2116     pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState);
2117 
2118     return status == TINFL_STATUS_DONE;
2119 }
2120 
2121 #ifndef MINIZ_NO_STDIO
mz_zip_file_write_callback(void * pOpaque,mz_uint64 ofs,const void * pBuf,size_t n)2122 static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n)
2123 {
2124     (void)ofs;
2125 
2126     return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque);
2127 }
2128 
mz_zip_reader_extract_to_file(mz_zip_archive * pZip,mz_uint file_index,const char * pDst_filename,mz_uint flags)2129 mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags)
2130 {
2131     mz_bool status;
2132     mz_zip_archive_file_stat file_stat;
2133     MZ_FILE *pFile;
2134 
2135     if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
2136         return MZ_FALSE;
2137 
2138     if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))
2139         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
2140 
2141     pFile = MZ_FOPEN(pDst_filename, "wb");
2142     if (!pFile)
2143         return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
2144 
2145     status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);
2146 
2147     if (MZ_FCLOSE(pFile) == EOF)
2148     {
2149         if (status)
2150             mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
2151 
2152         status = MZ_FALSE;
2153     }
2154 
2155 #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)
2156     if (status)
2157         mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
2158 #endif
2159 
2160     return status;
2161 }
2162 
mz_zip_reader_extract_file_to_file(mz_zip_archive * pZip,const char * pArchive_filename,const char * pDst_filename,mz_uint flags)2163 mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags)
2164 {
2165     mz_uint32 file_index;
2166     if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index))
2167         return MZ_FALSE;
2168 
2169     return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
2170 }
2171 
mz_zip_reader_extract_to_cfile(mz_zip_archive * pZip,mz_uint file_index,MZ_FILE * pFile,mz_uint flags)2172 mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags)
2173 {
2174     mz_zip_archive_file_stat file_stat;
2175 
2176     if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
2177         return MZ_FALSE;
2178 
2179     if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))
2180         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
2181 
2182     return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);
2183 }
2184 
mz_zip_reader_extract_file_to_cfile(mz_zip_archive * pZip,const char * pArchive_filename,MZ_FILE * pFile,mz_uint flags)2185 mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags)
2186 {
2187     mz_uint32 file_index;
2188     if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index))
2189         return MZ_FALSE;
2190 
2191     return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags);
2192 }
2193 #endif /* #ifndef MINIZ_NO_STDIO */
2194 
mz_zip_compute_crc32_callback(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)2195 static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
2196 {
2197     mz_uint32 *p = (mz_uint32 *)pOpaque;
2198     (void)file_ofs;
2199     *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n);
2200     return n;
2201 }
2202 
mz_zip_validate_file(mz_zip_archive * pZip,mz_uint file_index,mz_uint flags)2203 mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags)
2204 {
2205     mz_zip_archive_file_stat file_stat;
2206     mz_zip_internal_state *pState;
2207     const mz_uint8 *pCentral_dir_header;
2208     mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE;
2209     mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;
2210     mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
2211     mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
2212     mz_uint64 local_header_ofs = 0;
2213     mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32;
2214     mz_uint64 local_header_comp_size, local_header_uncomp_size;
2215     mz_uint32 uncomp_crc32 = MZ_CRC32_INIT;
2216     mz_bool has_data_descriptor;
2217     mz_uint32 local_header_bit_flags;
2218 
2219     mz_zip_array file_data_array;
2220     mz_zip_array_init(&file_data_array, 1);
2221 
2222     if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead))
2223         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2224 
2225     if (file_index > pZip->m_total_files)
2226         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2227 
2228     pState = pZip->m_pState;
2229 
2230     pCentral_dir_header = mz_zip_get_cdh(pZip, file_index);
2231 
2232     if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir))
2233         return MZ_FALSE;
2234 
2235     /* A directory or zero length file */
2236     if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size))
2237         return MZ_TRUE;
2238 
2239     /* Encryption and patch files are not supported. */
2240     if (file_stat.m_is_encrypted)
2241         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
2242 
2243     /* This function only supports stored and deflate. */
2244     if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
2245         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
2246 
2247     if (!file_stat.m_is_supported)
2248         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
2249 
2250     /* Read and parse the local directory entry. */
2251     local_header_ofs = file_stat.m_local_header_ofs;
2252     if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
2253         return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
2254 
2255     if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
2256         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
2257 
2258     local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);
2259     local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
2260     local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);
2261     local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);
2262     local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS);
2263     local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
2264     has_data_descriptor = (local_header_bit_flags & 8) != 0;
2265 
2266     if (local_header_filename_len != strlen(file_stat.m_filename))
2267         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
2268 
2269     if ((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)
2270         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
2271 
2272     if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE))
2273         return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
2274 
2275     if (local_header_filename_len)
2276     {
2277         if (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)
2278         {
2279             mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
2280             goto handle_failure;
2281         }
2282 
2283         /* 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. */
2284         if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0)
2285         {
2286             mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
2287             goto handle_failure;
2288         }
2289     }
2290 
2291     if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX)))
2292     {
2293         mz_uint32 extra_size_remaining = local_header_extra_len;
2294         const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p;
2295 
2296         if (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)
2297         {
2298             mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
2299             goto handle_failure;
2300         }
2301 
2302         do
2303         {
2304             mz_uint32 field_id, field_data_size, field_total_size;
2305 
2306             if (extra_size_remaining < (sizeof(mz_uint16) * 2))
2307                 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
2308 
2309             field_id = MZ_READ_LE16(pExtra_data);
2310             field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
2311             field_total_size = field_data_size + sizeof(mz_uint16) * 2;
2312 
2313             if (field_total_size > extra_size_remaining)
2314                 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
2315 
2316             if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
2317             {
2318                 const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);
2319 
2320                 if (field_data_size < sizeof(mz_uint64) * 2)
2321                 {
2322                     mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
2323                     goto handle_failure;
2324                 }
2325 
2326                 local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);
2327                 local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64));
2328 
2329                 found_zip64_ext_data_in_ldir = MZ_TRUE;
2330                 break;
2331             }
2332 
2333             pExtra_data += field_total_size;
2334             extra_size_remaining -= field_total_size;
2335         } while (extra_size_remaining);
2336     }
2337 
2338     /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */
2339     /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */
2340     if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32))
2341     {
2342         mz_uint8 descriptor_buf[32];
2343         mz_bool has_id;
2344         const mz_uint8 *pSrc;
2345         mz_uint32 file_crc32;
2346         mz_uint64 comp_size = 0, uncomp_size = 0;
2347 
2348         mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4;
2349 
2350         if (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))
2351         {
2352             mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
2353             goto handle_failure;
2354         }
2355 
2356         has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID);
2357         pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf;
2358 
2359         file_crc32 = MZ_READ_LE32(pSrc);
2360 
2361         if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir))
2362         {
2363             comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32));
2364             uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64));
2365         }
2366         else
2367         {
2368             comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32));
2369             uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32));
2370         }
2371 
2372         if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size))
2373         {
2374             mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
2375             goto handle_failure;
2376         }
2377     }
2378     else
2379     {
2380         if ((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))
2381         {
2382             mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
2383             goto handle_failure;
2384         }
2385     }
2386 
2387     mz_zip_array_clear(pZip, &file_data_array);
2388 
2389     if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0)
2390     {
2391         if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0))
2392             return MZ_FALSE;
2393 
2394         /* 1 more check to be sure, although the extract checks too. */
2395         if (uncomp_crc32 != file_stat.m_crc32)
2396         {
2397             mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
2398             return MZ_FALSE;
2399         }
2400     }
2401 
2402     return MZ_TRUE;
2403 
2404 handle_failure:
2405     mz_zip_array_clear(pZip, &file_data_array);
2406     return MZ_FALSE;
2407 }
2408 
mz_zip_validate_archive(mz_zip_archive * pZip,mz_uint flags)2409 mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags)
2410 {
2411     mz_zip_internal_state *pState;
2412     uint32_t i;
2413 
2414     if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead))
2415         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2416 
2417     pState = pZip->m_pState;
2418 
2419     /* Basic sanity checks */
2420     if (!pState->m_zip64)
2421     {
2422         if (pZip->m_total_files > MZ_UINT16_MAX)
2423             return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
2424 
2425         if (pZip->m_archive_size > MZ_UINT32_MAX)
2426             return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
2427     }
2428     else
2429     {
2430         if (pZip->m_total_files >= MZ_UINT32_MAX)
2431             return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
2432 
2433         if (pState->m_central_dir.m_size >= MZ_UINT32_MAX)
2434             return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
2435     }
2436 
2437     for (i = 0; i < pZip->m_total_files; i++)
2438     {
2439         if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags)
2440         {
2441             mz_uint32 found_index;
2442             mz_zip_archive_file_stat stat;
2443 
2444             if (!mz_zip_reader_file_stat(pZip, i, &stat))
2445                 return MZ_FALSE;
2446 
2447             if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index))
2448                 return MZ_FALSE;
2449 
2450             /* 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) */
2451             if (found_index != i)
2452                 return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
2453         }
2454 
2455         if (!mz_zip_validate_file(pZip, i, flags))
2456             return MZ_FALSE;
2457     }
2458 
2459     return MZ_TRUE;
2460 }
2461 
mz_zip_validate_mem_archive(const void * pMem,size_t size,mz_uint flags,mz_zip_error * pErr)2462 mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr)
2463 {
2464     mz_bool success = MZ_TRUE;
2465     mz_zip_archive zip;
2466     mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
2467 
2468     if ((!pMem) || (!size))
2469     {
2470         if (pErr)
2471             *pErr = MZ_ZIP_INVALID_PARAMETER;
2472         return MZ_FALSE;
2473     }
2474 
2475     mz_zip_zero_struct(&zip);
2476 
2477     if (!mz_zip_reader_init_mem(&zip, pMem, size, flags))
2478     {
2479         if (pErr)
2480             *pErr = zip.m_last_error;
2481         return MZ_FALSE;
2482     }
2483 
2484     if (!mz_zip_validate_archive(&zip, flags))
2485     {
2486         actual_err = zip.m_last_error;
2487         success = MZ_FALSE;
2488     }
2489 
2490     if (!mz_zip_reader_end_internal(&zip, success))
2491     {
2492         if (!actual_err)
2493             actual_err = zip.m_last_error;
2494         success = MZ_FALSE;
2495     }
2496 
2497     if (pErr)
2498         *pErr = actual_err;
2499 
2500     return success;
2501 }
2502 
2503 #ifndef MINIZ_NO_STDIO
mz_zip_validate_file_archive(const char * pFilename,mz_uint flags,mz_zip_error * pErr)2504 mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr)
2505 {
2506     mz_bool success = MZ_TRUE;
2507     mz_zip_archive zip;
2508     mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
2509 
2510     if (!pFilename)
2511     {
2512         if (pErr)
2513             *pErr = MZ_ZIP_INVALID_PARAMETER;
2514         return MZ_FALSE;
2515     }
2516 
2517     mz_zip_zero_struct(&zip);
2518 
2519     if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0))
2520     {
2521         if (pErr)
2522             *pErr = zip.m_last_error;
2523         return MZ_FALSE;
2524     }
2525 
2526     if (!mz_zip_validate_archive(&zip, flags))
2527     {
2528         actual_err = zip.m_last_error;
2529         success = MZ_FALSE;
2530     }
2531 
2532     if (!mz_zip_reader_end_internal(&zip, success))
2533     {
2534         if (!actual_err)
2535             actual_err = zip.m_last_error;
2536         success = MZ_FALSE;
2537     }
2538 
2539     if (pErr)
2540         *pErr = actual_err;
2541 
2542     return success;
2543 }
2544 #endif /* #ifndef MINIZ_NO_STDIO */
2545 
2546 /* ------------------- .ZIP archive writing */
2547 
2548 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
2549 
mz_write_le16(mz_uint8 * p,mz_uint16 v)2550 static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v)
2551 {
2552     p[0] = (mz_uint8)v;
2553     p[1] = (mz_uint8)(v >> 8);
2554 }
mz_write_le32(mz_uint8 * p,mz_uint32 v)2555 static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v)
2556 {
2557     p[0] = (mz_uint8)v;
2558     p[1] = (mz_uint8)(v >> 8);
2559     p[2] = (mz_uint8)(v >> 16);
2560     p[3] = (mz_uint8)(v >> 24);
2561 }
mz_write_le64(mz_uint8 * p,mz_uint64 v)2562 static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v)
2563 {
2564     mz_write_le32(p, (mz_uint32)v);
2565     mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32));
2566 }
2567 
2568 #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
2569 #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
2570 #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v))
2571 
mz_zip_heap_write_func(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)2572 static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
2573 {
2574     mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
2575     mz_zip_internal_state *pState = pZip->m_pState;
2576     mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
2577 
2578     if (!n)
2579         return 0;
2580 
2581     /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */
2582     if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))
2583     {
2584         mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
2585         return 0;
2586     }
2587 
2588     if (new_size > pState->m_mem_capacity)
2589     {
2590         void *pNew_block;
2591         size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity);
2592 
2593         while (new_capacity < new_size)
2594             new_capacity *= 2;
2595 
2596         if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))
2597         {
2598             mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
2599             return 0;
2600         }
2601 
2602         pState->m_pMem = pNew_block;
2603         pState->m_mem_capacity = new_capacity;
2604     }
2605     memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
2606     pState->m_mem_size = (size_t)new_size;
2607     return n;
2608 }
2609 
mz_zip_writer_end_internal(mz_zip_archive * pZip,mz_bool set_last_error)2610 static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error)
2611 {
2612     mz_zip_internal_state *pState;
2613     mz_bool status = MZ_TRUE;
2614 
2615     if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)))
2616     {
2617         if (set_last_error)
2618             mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2619         return MZ_FALSE;
2620     }
2621 
2622     pState = pZip->m_pState;
2623     pZip->m_pState = NULL;
2624     mz_zip_array_clear(pZip, &pState->m_central_dir);
2625     mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
2626     mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
2627 
2628 #ifndef MINIZ_NO_STDIO
2629     if (pState->m_pFile)
2630     {
2631         if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)
2632         {
2633             if (MZ_FCLOSE(pState->m_pFile) == EOF)
2634             {
2635                 if (set_last_error)
2636                     mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
2637                 status = MZ_FALSE;
2638             }
2639         }
2640 
2641         pState->m_pFile = NULL;
2642     }
2643 #endif /* #ifndef MINIZ_NO_STDIO */
2644 
2645     if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem))
2646     {
2647         pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
2648         pState->m_pMem = NULL;
2649     }
2650 
2651     pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
2652     pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
2653     return status;
2654 }
2655 
mz_zip_writer_init_v2(mz_zip_archive * pZip,mz_uint64 existing_size,mz_uint flags)2656 mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags)
2657 {
2658     mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0;
2659 
2660     if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
2661         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2662 
2663     if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
2664     {
2665         if (!pZip->m_pRead)
2666             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2667     }
2668 
2669     if (pZip->m_file_offset_alignment)
2670     {
2671         /* Ensure user specified file offset alignment is a power of 2. */
2672         if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
2673             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2674     }
2675 
2676     if (!pZip->m_pAlloc)
2677         pZip->m_pAlloc = miniz_def_alloc_func;
2678     if (!pZip->m_pFree)
2679         pZip->m_pFree = miniz_def_free_func;
2680     if (!pZip->m_pRealloc)
2681         pZip->m_pRealloc = miniz_def_realloc_func;
2682 
2683     pZip->m_archive_size = existing_size;
2684     pZip->m_central_directory_file_ofs = 0;
2685     pZip->m_total_files = 0;
2686 
2687     if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
2688         return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
2689 
2690     memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
2691 
2692     MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
2693     MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
2694     MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
2695 
2696     pZip->m_pState->m_zip64 = zip64;
2697     pZip->m_pState->m_zip64_has_extended_info_fields = zip64;
2698 
2699     pZip->m_zip_type = MZ_ZIP_TYPE_USER;
2700     pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
2701 
2702     return MZ_TRUE;
2703 }
2704 
mz_zip_writer_init(mz_zip_archive * pZip,mz_uint64 existing_size)2705 mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size)
2706 {
2707     return mz_zip_writer_init_v2(pZip, existing_size, 0);
2708 }
2709 
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)2710 mz_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)
2711 {
2712     pZip->m_pWrite = mz_zip_heap_write_func;
2713     pZip->m_pNeeds_keepalive = NULL;
2714 
2715     if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
2716         pZip->m_pRead = mz_zip_mem_read_func;
2717 
2718     pZip->m_pIO_opaque = pZip;
2719 
2720     if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))
2721         return MZ_FALSE;
2722 
2723     pZip->m_zip_type = MZ_ZIP_TYPE_HEAP;
2724 
2725     if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning)))
2726     {
2727         if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size)))
2728         {
2729             mz_zip_writer_end_internal(pZip, MZ_FALSE);
2730             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
2731         }
2732         pZip->m_pState->m_mem_capacity = initial_allocation_size;
2733     }
2734 
2735     return MZ_TRUE;
2736 }
2737 
mz_zip_writer_init_heap(mz_zip_archive * pZip,size_t size_to_reserve_at_beginning,size_t initial_allocation_size)2738 mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size)
2739 {
2740     return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0);
2741 }
2742 
2743 #ifndef MINIZ_NO_STDIO
mz_zip_file_write_func(void * pOpaque,mz_uint64 file_ofs,const void * pBuf,size_t n)2744 static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
2745 {
2746     mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
2747     mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
2748 
2749     file_ofs += pZip->m_pState->m_file_archive_start_ofs;
2750 
2751     if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
2752     {
2753         mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
2754         return 0;
2755     }
2756 
2757     return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
2758 }
2759 
mz_zip_writer_init_file(mz_zip_archive * pZip,const char * pFilename,mz_uint64 size_to_reserve_at_beginning)2760 mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning)
2761 {
2762     return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0);
2763 }
2764 
mz_zip_writer_init_file_v2(mz_zip_archive * pZip,const char * pFilename,mz_uint64 size_to_reserve_at_beginning,mz_uint flags)2765 mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags)
2766 {
2767     MZ_FILE *pFile;
2768 
2769     pZip->m_pWrite = mz_zip_file_write_func;
2770     pZip->m_pNeeds_keepalive = NULL;
2771 
2772     if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
2773         pZip->m_pRead = mz_zip_file_read_func;
2774 
2775     pZip->m_pIO_opaque = pZip;
2776 
2777     if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))
2778         return MZ_FALSE;
2779 
2780     if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb")))
2781     {
2782         mz_zip_writer_end(pZip);
2783         return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
2784     }
2785 
2786     pZip->m_pState->m_pFile = pFile;
2787     pZip->m_zip_type = MZ_ZIP_TYPE_FILE;
2788 
2789     if (size_to_reserve_at_beginning)
2790     {
2791         mz_uint64 cur_ofs = 0;
2792         char buf[4096];
2793 
2794         MZ_CLEAR_OBJ(buf);
2795 
2796         do
2797         {
2798             size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
2799             if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n)
2800             {
2801                 mz_zip_writer_end(pZip);
2802                 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
2803             }
2804             cur_ofs += n;
2805             size_to_reserve_at_beginning -= n;
2806         } while (size_to_reserve_at_beginning);
2807     }
2808 
2809     return MZ_TRUE;
2810 }
2811 
mz_zip_writer_init_cfile(mz_zip_archive * pZip,MZ_FILE * pFile,mz_uint flags)2812 mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags)
2813 {
2814     pZip->m_pWrite = mz_zip_file_write_func;
2815     pZip->m_pNeeds_keepalive = NULL;
2816 
2817     if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
2818         pZip->m_pRead = mz_zip_file_read_func;
2819 
2820     pZip->m_pIO_opaque = pZip;
2821 
2822     if (!mz_zip_writer_init_v2(pZip, 0, flags))
2823         return MZ_FALSE;
2824 
2825     pZip->m_pState->m_pFile = pFile;
2826     pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
2827     pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;
2828 
2829     return MZ_TRUE;
2830 }
2831 #endif /* #ifndef MINIZ_NO_STDIO */
2832 
mz_zip_writer_init_from_reader_v2(mz_zip_archive * pZip,const char * pFilename,mz_uint flags)2833 mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags)
2834 {
2835     mz_zip_internal_state *pState;
2836 
2837     if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
2838         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2839 
2840     if (flags & MZ_ZIP_FLAG_WRITE_ZIP64)
2841     {
2842         /* 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?) */
2843         if (!pZip->m_pState->m_zip64)
2844             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2845     }
2846 
2847     /* No sense in trying to write to an archive that's already at the support max size */
2848     if (pZip->m_pState->m_zip64)
2849     {
2850         if (pZip->m_total_files == MZ_UINT32_MAX)
2851             return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
2852     }
2853     else
2854     {
2855         if (pZip->m_total_files == MZ_UINT16_MAX)
2856             return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
2857 
2858         if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)
2859             return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
2860     }
2861 
2862     pState = pZip->m_pState;
2863 
2864     if (pState->m_pFile)
2865     {
2866 #ifdef MINIZ_NO_STDIO
2867         (void)pFilename;
2868         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2869 #else
2870         if (pZip->m_pIO_opaque != pZip)
2871             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2872 
2873         if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)
2874         {
2875             if (!pFilename)
2876                 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2877 
2878             /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */
2879             if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile)))
2880             {
2881                 /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */
2882                 mz_zip_reader_end_internal(pZip, MZ_FALSE);
2883                 return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
2884             }
2885         }
2886 
2887         pZip->m_pWrite = mz_zip_file_write_func;
2888         pZip->m_pNeeds_keepalive = NULL;
2889 #endif /* #ifdef MINIZ_NO_STDIO */
2890     }
2891     else if (pState->m_pMem)
2892     {
2893         /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */
2894         if (pZip->m_pIO_opaque != pZip)
2895             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2896 
2897         pState->m_mem_capacity = pState->m_mem_size;
2898         pZip->m_pWrite = mz_zip_heap_write_func;
2899         pZip->m_pNeeds_keepalive = NULL;
2900     }
2901     /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */
2902     else if (!pZip->m_pWrite)
2903         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
2904 
2905     /* Start writing new files at the archive's current central directory location. */
2906     /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */
2907     pZip->m_archive_size = pZip->m_central_directory_file_ofs;
2908     pZip->m_central_directory_file_ofs = 0;
2909 
2910     /* Clear the sorted central dir offsets, they aren't useful or maintained now. */
2911     /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */
2912     /* TODO: We could easily maintain the sorted central directory offsets. */
2913     mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets);
2914 
2915     pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
2916 
2917     return MZ_TRUE;
2918 }
2919 
mz_zip_writer_init_from_reader(mz_zip_archive * pZip,const char * pFilename)2920 mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename)
2921 {
2922     return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0);
2923 }
2924 
2925 /* TODO: pArchive_name is a terrible name here! */
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)2926 mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags)
2927 {
2928     return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0);
2929 }
2930 
2931 typedef struct
2932 {
2933     mz_zip_archive *m_pZip;
2934     mz_uint64 m_cur_archive_file_ofs;
2935     mz_uint64 m_comp_size;
2936 } mz_zip_writer_add_state;
2937 
mz_zip_writer_add_put_buf_callback(const void * pBuf,int len,void * pUser)2938 static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser)
2939 {
2940     mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
2941     if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len)
2942         return MZ_FALSE;
2943 
2944     pState->m_cur_archive_file_ofs += len;
2945     pState->m_comp_size += len;
2946     return MZ_TRUE;
2947 }
2948 
2949 #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2)
2950 #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3)
mz_zip_writer_create_zip64_extra_data(mz_uint8 * pBuf,mz_uint64 * pUncomp_size,mz_uint64 * pComp_size,mz_uint64 * pLocal_header_ofs)2951 static 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)
2952 {
2953     mz_uint8 *pDst = pBuf;
2954     mz_uint32 field_size = 0;
2955 
2956     MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);
2957     MZ_WRITE_LE16(pDst + 2, 0);
2958     pDst += sizeof(mz_uint16) * 2;
2959 
2960     if (pUncomp_size)
2961     {
2962         MZ_WRITE_LE64(pDst, *pUncomp_size);
2963         pDst += sizeof(mz_uint64);
2964         field_size += sizeof(mz_uint64);
2965     }
2966 
2967     if (pComp_size)
2968     {
2969         MZ_WRITE_LE64(pDst, *pComp_size);
2970         pDst += sizeof(mz_uint64);
2971         field_size += sizeof(mz_uint64);
2972     }
2973 
2974     if (pLocal_header_ofs)
2975     {
2976         MZ_WRITE_LE64(pDst, *pLocal_header_ofs);
2977         pDst += sizeof(mz_uint64);
2978         field_size += sizeof(mz_uint64);
2979     }
2980 
2981     MZ_WRITE_LE16(pBuf + 2, field_size);
2982 
2983     return (mz_uint32)(pDst - pBuf);
2984 }
2985 
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)2986 static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date)
2987 {
2988     (void)pZip;
2989     memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
2990     MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
2991     MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
2992     MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
2993     MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
2994     MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
2995     MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
2996     MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
2997     MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX));
2998     MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX));
2999     MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
3000     MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
3001     return MZ_TRUE;
3002 }
3003 
mz_zip_writer_create_central_dir_header(mz_zip_archive * pZip,mz_uint8 * pDst,mz_uint16 filename_size,mz_uint16 extra_size,mz_uint16 comment_size,mz_uint64 uncomp_size,mz_uint64 comp_size,mz_uint32 uncomp_crc32,mz_uint16 method,mz_uint16 bit_flags,mz_uint16 dos_time,mz_uint16 dos_date,mz_uint64 local_header_ofs,mz_uint32 ext_attributes)3004 static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst,
3005                                                        mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size,
3006                                                        mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32,
3007                                                        mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,
3008                                                        mz_uint64 local_header_ofs, mz_uint32 ext_attributes)
3009 {
3010     (void)pZip;
3011     memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
3012     MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
3013     MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
3014     MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
3015     MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
3016     MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
3017     MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
3018     MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
3019     MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX));
3020     MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX));
3021     MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
3022     MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
3023     MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
3024     MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
3025     MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX));
3026     return MZ_TRUE;
3027 }
3028 
mz_zip_writer_add_to_central_dir(mz_zip_archive * pZip,const char * pFilename,mz_uint16 filename_size,const void * pExtra,mz_uint16 extra_size,const void * pComment,mz_uint16 comment_size,mz_uint64 uncomp_size,mz_uint64 comp_size,mz_uint32 uncomp_crc32,mz_uint16 method,mz_uint16 bit_flags,mz_uint16 dos_time,mz_uint16 dos_date,mz_uint64 local_header_ofs,mz_uint32 ext_attributes,const char * user_extra_data,mz_uint user_extra_data_len)3029 static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size,
3030                                                 const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size,
3031                                                 mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32,
3032                                                 mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,
3033                                                 mz_uint64 local_header_ofs, mz_uint32 ext_attributes,
3034                                                 const char *user_extra_data, mz_uint user_extra_data_len)
3035 {
3036     mz_zip_internal_state *pState = pZip->m_pState;
3037     mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
3038     size_t orig_central_dir_size = pState->m_central_dir.m_size;
3039     mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
3040 
3041     if (!pZip->m_pState->m_zip64)
3042     {
3043         if (local_header_ofs > 0xFFFFFFFF)
3044             return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
3045     }
3046 
3047     /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
3048     if (((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)
3049         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
3050 
3051     if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, 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))
3052         return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
3053 
3054     if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
3055         (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) ||
3056         (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) ||
3057         (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) ||
3058         (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) ||
3059         (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &central_dir_ofs, 1)))
3060     {
3061         /* Try to resize the central directory array back into its original state. */
3062         mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
3063         return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3064     }
3065 
3066     return MZ_TRUE;
3067 }
3068 
mz_zip_writer_validate_archive_name(const char * pArchive_name)3069 static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name)
3070 {
3071     /* 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. */
3072     if (*pArchive_name == '/')
3073         return MZ_FALSE;
3074 
3075     while (*pArchive_name)
3076     {
3077         if ((*pArchive_name == '\\') || (*pArchive_name == ':'))
3078             return MZ_FALSE;
3079 
3080         pArchive_name++;
3081     }
3082 
3083     return MZ_TRUE;
3084 }
3085 
mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive * pZip)3086 static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip)
3087 {
3088     mz_uint32 n;
3089     if (!pZip->m_file_offset_alignment)
3090         return 0;
3091     n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
3092     return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1));
3093 }
3094 
mz_zip_writer_write_zeros(mz_zip_archive * pZip,mz_uint64 cur_file_ofs,mz_uint32 n)3095 static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n)
3096 {
3097     char buf[4096];
3098     memset(buf, 0, MZ_MIN(sizeof(buf), n));
3099     while (n)
3100     {
3101         mz_uint32 s = MZ_MIN(sizeof(buf), n);
3102         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
3103             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3104 
3105         cur_file_ofs += s;
3106         n -= s;
3107     }
3108     return MZ_TRUE;
3109 }
3110 
mz_zip_writer_add_mem_ex(mz_zip_archive * pZip,const char * pArchive_name,const void * pBuf,size_t buf_size,const void * pComment,mz_uint16 comment_size,mz_uint level_and_flags,mz_uint64 uncomp_size,mz_uint32 uncomp_crc32)3111 mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
3112                                  mz_uint64 uncomp_size, mz_uint32 uncomp_crc32)
3113 {
3114     return 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);
3115 }
3116 
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,mz_uint level_and_flags,mz_uint64 uncomp_size,mz_uint32 uncomp_crc32,MZ_TIME_T * last_modified,const char * user_extra_data,mz_uint user_extra_data_len,const char * user_extra_data_central,mz_uint user_extra_data_central_len)3117 mz_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,
3118                                     mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified,
3119                                     const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)
3120 {
3121     mz_uint16 method = 0, dos_time = 0, dos_date = 0;
3122     mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
3123     mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
3124     size_t archive_name_size;
3125     mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
3126     tdefl_compressor *pComp = NULL;
3127     mz_bool store_data_uncompressed;
3128     mz_zip_internal_state *pState;
3129     mz_uint8 *pExtra_data = NULL;
3130     mz_uint32 extra_size = 0;
3131     mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];
3132     mz_uint16 bit_flags = 0;
3133 
3134     if ((int)level_and_flags < 0)
3135         level_and_flags = MZ_DEFAULT_LEVEL;
3136 
3137     if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
3138         bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;
3139 
3140     if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))
3141         bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;
3142 
3143     level = level_and_flags & 0xF;
3144     store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
3145 
3146     if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
3147         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
3148 
3149     pState = pZip->m_pState;
3150 
3151     if (pState->m_zip64)
3152     {
3153         if (pZip->m_total_files == MZ_UINT32_MAX)
3154             return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
3155     }
3156     else
3157     {
3158         if (pZip->m_total_files == MZ_UINT16_MAX)
3159         {
3160             pState->m_zip64 = MZ_TRUE;
3161             /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */
3162         }
3163         if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF))
3164         {
3165             pState->m_zip64 = MZ_TRUE;
3166             /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
3167         }
3168     }
3169 
3170     if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
3171         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
3172 
3173     if (!mz_zip_writer_validate_archive_name(pArchive_name))
3174         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
3175 
3176 #ifndef MINIZ_NO_TIME
3177     if (last_modified != NULL)
3178     {
3179         mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date);
3180     }
3181     else
3182     {
3183         MZ_TIME_T cur_time;
3184         time(&cur_time);
3185         mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date);
3186     }
3187 #endif /* #ifndef MINIZ_NO_TIME */
3188 
3189     archive_name_size = strlen(pArchive_name);
3190     if (archive_name_size > MZ_UINT16_MAX)
3191         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
3192 
3193     num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
3194 
3195     /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
3196     if (((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)
3197         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
3198 
3199     if (!pState->m_zip64)
3200     {
3201         /* Bail early if the archive would obviously become too large */
3202         if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size
3203 			+ MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len +
3204 			pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len
3205 			+ MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF)
3206         {
3207             pState->m_zip64 = MZ_TRUE;
3208             /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
3209         }
3210     }
3211 
3212     if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/'))
3213     {
3214         /* Set DOS Subdirectory attribute bit. */
3215         ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG;
3216 
3217         /* Subdirectories cannot contain data. */
3218         if ((buf_size) || (uncomp_size))
3219             return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
3220     }
3221 
3222     /* 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.) */
3223     if ((!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)))
3224         return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3225 
3226     if ((!store_data_uncompressed) && (buf_size))
3227     {
3228         if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
3229             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3230     }
3231 
3232     if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes))
3233     {
3234         pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3235         return MZ_FALSE;
3236     }
3237 
3238     local_dir_header_ofs += num_alignment_padding_bytes;
3239     if (pZip->m_file_offset_alignment)
3240     {
3241         MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0);
3242     }
3243     cur_archive_file_ofs += num_alignment_padding_bytes;
3244 
3245     MZ_CLEAR_OBJ(local_dir_header);
3246 
3247     if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
3248     {
3249         method = MZ_DEFLATED;
3250     }
3251 
3252     if (pState->m_zip64)
3253     {
3254         if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX)
3255         {
3256             pExtra_data = extra_data;
3257             extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
3258                                                                (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
3259         }
3260 
3261         if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date))
3262             return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
3263 
3264         if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
3265             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3266 
3267         cur_archive_file_ofs += sizeof(local_dir_header);
3268 
3269         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
3270         {
3271             pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3272             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3273         }
3274         cur_archive_file_ofs += archive_name_size;
3275 
3276         if (pExtra_data != NULL)
3277         {
3278             if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size)
3279                 return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3280 
3281             cur_archive_file_ofs += extra_size;
3282         }
3283     }
3284     else
3285     {
3286         if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))
3287             return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
3288         if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date))
3289             return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
3290 
3291         if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
3292             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3293 
3294         cur_archive_file_ofs += sizeof(local_dir_header);
3295 
3296         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
3297         {
3298             pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3299             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3300         }
3301         cur_archive_file_ofs += archive_name_size;
3302     }
3303 
3304     if (user_extra_data_len > 0)
3305     {
3306         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
3307             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3308 
3309         cur_archive_file_ofs += user_extra_data_len;
3310     }
3311 
3312     if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
3313     {
3314         uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
3315         uncomp_size = buf_size;
3316         if (uncomp_size <= 3)
3317         {
3318             level = 0;
3319             store_data_uncompressed = MZ_TRUE;
3320         }
3321     }
3322 
3323     if (store_data_uncompressed)
3324     {
3325         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size)
3326         {
3327             pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3328             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3329         }
3330 
3331         cur_archive_file_ofs += buf_size;
3332         comp_size = buf_size;
3333     }
3334     else if (buf_size)
3335     {
3336         mz_zip_writer_add_state state;
3337 
3338         state.m_pZip = pZip;
3339         state.m_cur_archive_file_ofs = cur_archive_file_ofs;
3340         state.m_comp_size = 0;
3341 
3342         if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) ||
3343             (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE))
3344         {
3345             pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3346             return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);
3347         }
3348 
3349         comp_size = state.m_comp_size;
3350         cur_archive_file_ofs = state.m_cur_archive_file_ofs;
3351     }
3352 
3353     pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3354     pComp = NULL;
3355 
3356     if (uncomp_size)
3357     {
3358         mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];
3359         mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;
3360 
3361         MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR);
3362 
3363         MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);
3364         MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);
3365         if (pExtra_data == NULL)
3366         {
3367             if (comp_size > MZ_UINT32_MAX)
3368                 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
3369 
3370             MZ_WRITE_LE32(local_dir_footer + 8, comp_size);
3371             MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);
3372         }
3373         else
3374         {
3375             MZ_WRITE_LE64(local_dir_footer + 8, comp_size);
3376             MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);
3377             local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;
3378         }
3379 
3380         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size)
3381             return MZ_FALSE;
3382 
3383         cur_archive_file_ofs += local_dir_footer_size;
3384     }
3385 
3386     if (pExtra_data != NULL)
3387     {
3388         extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
3389                                                            (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
3390     }
3391 
3392     if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment,
3393                                           comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes,
3394                                           user_extra_data_central, user_extra_data_central_len))
3395         return MZ_FALSE;
3396 
3397     pZip->m_total_files++;
3398     pZip->m_archive_size = cur_archive_file_ofs;
3399 
3400     return MZ_TRUE;
3401 }
3402 
3403 #ifndef MINIZ_NO_STDIO
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,const char * user_extra_data,mz_uint user_extra_data_len,const char * user_extra_data_central,mz_uint user_extra_data_central_len)3404 mz_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,
3405                                 const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)
3406 {
3407     mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;
3408     mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
3409     mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
3410     mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0;
3411     size_t archive_name_size;
3412     mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
3413     mz_uint8 *pExtra_data = NULL;
3414     mz_uint32 extra_size = 0;
3415     mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];
3416     mz_zip_internal_state *pState;
3417 
3418     if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))
3419         gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;
3420 
3421     if ((int)level_and_flags < 0)
3422         level_and_flags = MZ_DEFAULT_LEVEL;
3423     level = level_and_flags & 0xF;
3424 
3425     /* Sanity checks */
3426     if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
3427         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
3428 
3429     pState = pZip->m_pState;
3430 
3431     if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX))
3432     {
3433         /* Source file is too large for non-zip64 */
3434         /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
3435         pState->m_zip64 = MZ_TRUE;
3436     }
3437 
3438     /* We could support this, but why? */
3439     if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
3440         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
3441 
3442     if (!mz_zip_writer_validate_archive_name(pArchive_name))
3443         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
3444 
3445     if (pState->m_zip64)
3446     {
3447         if (pZip->m_total_files == MZ_UINT32_MAX)
3448             return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
3449     }
3450     else
3451     {
3452         if (pZip->m_total_files == MZ_UINT16_MAX)
3453         {
3454             pState->m_zip64 = MZ_TRUE;
3455             /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */
3456         }
3457     }
3458 
3459     archive_name_size = strlen(pArchive_name);
3460     if (archive_name_size > MZ_UINT16_MAX)
3461         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
3462 
3463     num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
3464 
3465     /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
3466     if (((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)
3467         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
3468 
3469     if (!pState->m_zip64)
3470     {
3471         /* Bail early if the archive would obviously become too large */
3472         if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE
3473 			+ archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024
3474 			+ MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF)
3475         {
3476             pState->m_zip64 = MZ_TRUE;
3477             /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
3478         }
3479     }
3480 
3481 #ifndef MINIZ_NO_TIME
3482     if (pFile_time)
3483     {
3484         mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date);
3485     }
3486 #endif
3487 
3488     if (uncomp_size <= 3)
3489         level = 0;
3490 
3491     if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes))
3492     {
3493         return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3494     }
3495 
3496     cur_archive_file_ofs += num_alignment_padding_bytes;
3497     local_dir_header_ofs = cur_archive_file_ofs;
3498 
3499     if (pZip->m_file_offset_alignment)
3500     {
3501         MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0);
3502     }
3503 
3504     if (uncomp_size && level)
3505     {
3506         method = MZ_DEFLATED;
3507     }
3508 
3509     MZ_CLEAR_OBJ(local_dir_header);
3510     if (pState->m_zip64)
3511     {
3512         if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX)
3513         {
3514             pExtra_data = extra_data;
3515             extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
3516                                                                (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
3517         }
3518 
3519         if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date))
3520             return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
3521 
3522         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
3523             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3524 
3525         cur_archive_file_ofs += sizeof(local_dir_header);
3526 
3527         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
3528         {
3529             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3530         }
3531 
3532         cur_archive_file_ofs += archive_name_size;
3533 
3534         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size)
3535             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3536 
3537         cur_archive_file_ofs += extra_size;
3538     }
3539     else
3540     {
3541         if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))
3542             return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
3543         if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date))
3544             return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
3545 
3546         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
3547             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3548 
3549         cur_archive_file_ofs += sizeof(local_dir_header);
3550 
3551         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
3552         {
3553             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3554         }
3555 
3556         cur_archive_file_ofs += archive_name_size;
3557     }
3558 
3559     if (user_extra_data_len > 0)
3560     {
3561         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
3562             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3563 
3564         cur_archive_file_ofs += user_extra_data_len;
3565     }
3566 
3567     if (uncomp_size)
3568     {
3569         mz_uint64 uncomp_remaining = uncomp_size;
3570         void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
3571         if (!pRead_buf)
3572         {
3573             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3574         }
3575 
3576         if (!level)
3577         {
3578             while (uncomp_remaining)
3579             {
3580                 mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
3581                 if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n))
3582                 {
3583                     pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3584                     return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
3585                 }
3586                 uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
3587                 uncomp_remaining -= n;
3588                 cur_archive_file_ofs += n;
3589             }
3590             comp_size = uncomp_size;
3591         }
3592         else
3593         {
3594             mz_bool result = MZ_FALSE;
3595             mz_zip_writer_add_state state;
3596             tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
3597             if (!pComp)
3598             {
3599                 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3600                 return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3601             }
3602 
3603             state.m_pZip = pZip;
3604             state.m_cur_archive_file_ofs = cur_archive_file_ofs;
3605             state.m_comp_size = 0;
3606 
3607             if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY)
3608             {
3609                 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3610                 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3611                 return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
3612             }
3613 
3614             for (;;)
3615             {
3616                 size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
3617                 tdefl_status status;
3618                 tdefl_flush flush = TDEFL_NO_FLUSH;
3619 
3620                 if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size)
3621                 {
3622                     mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
3623                     break;
3624                 }
3625 
3626                 uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
3627                 uncomp_remaining -= in_buf_size;
3628 
3629                 if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque))
3630                     flush = TDEFL_FULL_FLUSH;
3631 
3632                 status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH);
3633                 if (status == TDEFL_STATUS_DONE)
3634                 {
3635                     result = MZ_TRUE;
3636                     break;
3637                 }
3638                 else if (status != TDEFL_STATUS_OKAY)
3639                 {
3640                     mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);
3641                     break;
3642                 }
3643             }
3644 
3645             pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
3646 
3647             if (!result)
3648             {
3649                 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3650                 return MZ_FALSE;
3651             }
3652 
3653             comp_size = state.m_comp_size;
3654             cur_archive_file_ofs = state.m_cur_archive_file_ofs;
3655         }
3656 
3657         pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3658     }
3659 
3660     {
3661         mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];
3662         mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;
3663 
3664         MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);
3665         MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);
3666         if (pExtra_data == NULL)
3667         {
3668             if (comp_size > MZ_UINT32_MAX)
3669                 return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
3670 
3671             MZ_WRITE_LE32(local_dir_footer + 8, comp_size);
3672             MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);
3673         }
3674         else
3675         {
3676             MZ_WRITE_LE64(local_dir_footer + 8, comp_size);
3677             MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);
3678             local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;
3679         }
3680 
3681         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size)
3682             return MZ_FALSE;
3683 
3684         cur_archive_file_ofs += local_dir_footer_size;
3685     }
3686 
3687     if (pExtra_data != NULL)
3688     {
3689         extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
3690                                                            (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
3691     }
3692 
3693     if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size,
3694                                           uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes,
3695                                           user_extra_data_central, user_extra_data_central_len))
3696         return MZ_FALSE;
3697 
3698     pZip->m_total_files++;
3699     pZip->m_archive_size = cur_archive_file_ofs;
3700 
3701     return MZ_TRUE;
3702 }
3703 
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)3704 mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
3705 {
3706     MZ_FILE *pSrc_file = NULL;
3707     mz_uint64 uncomp_size = 0;
3708     MZ_TIME_T file_modified_time;
3709     MZ_TIME_T *pFile_time = NULL;
3710     mz_bool status;
3711 
3712     memset(&file_modified_time, 0, sizeof(file_modified_time));
3713 
3714 #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)
3715     pFile_time = &file_modified_time;
3716     if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time))
3717         return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED);
3718 #endif
3719 
3720     pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
3721     if (!pSrc_file)
3722         return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
3723 
3724     MZ_FSEEK64(pSrc_file, 0, SEEK_END);
3725     uncomp_size = MZ_FTELL64(pSrc_file);
3726     MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
3727 
3728     status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0);
3729 
3730     MZ_FCLOSE(pSrc_file);
3731 
3732     return status;
3733 }
3734 #endif /* #ifndef MINIZ_NO_STDIO */
3735 
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)3736 static 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)
3737 {
3738     /* + 64 should be enough for any new zip64 data */
3739     if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE))
3740         return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3741 
3742     mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE);
3743 
3744     if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start))
3745     {
3746         mz_uint8 new_ext_block[64];
3747         mz_uint8 *pDst = new_ext_block;
3748         mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);
3749         mz_write_le16(pDst + sizeof(mz_uint16), 0);
3750         pDst += sizeof(mz_uint16) * 2;
3751 
3752         if (pUncomp_size)
3753         {
3754             mz_write_le64(pDst, *pUncomp_size);
3755             pDst += sizeof(mz_uint64);
3756         }
3757 
3758         if (pComp_size)
3759         {
3760             mz_write_le64(pDst, *pComp_size);
3761             pDst += sizeof(mz_uint64);
3762         }
3763 
3764         if (pLocal_header_ofs)
3765         {
3766             mz_write_le64(pDst, *pLocal_header_ofs);
3767             pDst += sizeof(mz_uint64);
3768         }
3769 
3770         if (pDisk_start)
3771         {
3772             mz_write_le32(pDst, *pDisk_start);
3773             pDst += sizeof(mz_uint32);
3774         }
3775 
3776         mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2));
3777 
3778         if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block))
3779             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3780     }
3781 
3782     if ((pExt) && (ext_len))
3783     {
3784         mz_uint32 extra_size_remaining = ext_len;
3785         const mz_uint8 *pExtra_data = pExt;
3786 
3787         do
3788         {
3789             mz_uint32 field_id, field_data_size, field_total_size;
3790 
3791             if (extra_size_remaining < (sizeof(mz_uint16) * 2))
3792                 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
3793 
3794             field_id = MZ_READ_LE16(pExtra_data);
3795             field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
3796             field_total_size = field_data_size + sizeof(mz_uint16) * 2;
3797 
3798             if (field_total_size > extra_size_remaining)
3799                 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
3800 
3801             if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
3802             {
3803                 if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size))
3804                     return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3805             }
3806 
3807             pExtra_data += field_total_size;
3808             extra_size_remaining -= field_total_size;
3809         } while (extra_size_remaining);
3810     }
3811 
3812     return MZ_TRUE;
3813 }
3814 
3815 /* TODO: This func is now pretty freakin complex due to zip64, split it up? */
mz_zip_writer_add_from_zip_reader(mz_zip_archive * pZip,mz_zip_archive * pSource_zip,mz_uint src_file_index)3816 mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index)
3817 {
3818     mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size;
3819     mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs;
3820     mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
3821     mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
3822     mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
3823     mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
3824     size_t orig_central_dir_size;
3825     mz_zip_internal_state *pState;
3826     void *pBuf;
3827     const mz_uint8 *pSrc_central_header;
3828     mz_zip_archive_file_stat src_file_stat;
3829     mz_uint32 src_filename_len, src_comment_len, src_ext_len;
3830     mz_uint32 local_header_filename_size, local_header_extra_len;
3831     mz_uint64 local_header_comp_size, local_header_uncomp_size;
3832     mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;
3833 
3834     /* Sanity checks */
3835     if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead))
3836         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
3837 
3838     pState = pZip->m_pState;
3839 
3840     /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */
3841     if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64))
3842         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
3843 
3844     /* Get pointer to the source central dir header and crack it */
3845     if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index)))
3846         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
3847 
3848     if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)
3849         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
3850 
3851     src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS);
3852     src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
3853     src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS);
3854     src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len;
3855 
3856     /* 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) */
3857     if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX)
3858         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
3859 
3860     num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
3861 
3862     if (!pState->m_zip64)
3863     {
3864         if (pZip->m_total_files == MZ_UINT16_MAX)
3865             return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
3866     }
3867     else
3868     {
3869         /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */
3870         if (pZip->m_total_files == MZ_UINT32_MAX)
3871             return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
3872     }
3873 
3874     if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL))
3875         return MZ_FALSE;
3876 
3877     cur_src_file_ofs = src_file_stat.m_local_header_ofs;
3878     cur_dst_file_ofs = pZip->m_archive_size;
3879 
3880     /* Read the source archive's local dir header */
3881     if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
3882         return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
3883 
3884     if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
3885         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
3886 
3887     cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
3888 
3889     /* Compute the total size we need to copy (filename+extra data+compressed data) */
3890     local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);
3891     local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
3892     local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);
3893     local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);
3894     src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size;
3895 
3896     /* Try to find a zip64 extended information field */
3897     if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX)))
3898     {
3899         mz_zip_array file_data_array;
3900         const mz_uint8 *pExtra_data;
3901         mz_uint32 extra_size_remaining = local_header_extra_len;
3902 
3903         mz_zip_array_init(&file_data_array, 1);
3904         if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE))
3905         {
3906             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3907         }
3908 
3909         if (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)
3910         {
3911             mz_zip_array_clear(pZip, &file_data_array);
3912             return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
3913         }
3914 
3915         pExtra_data = (const mz_uint8 *)file_data_array.m_p;
3916 
3917         do
3918         {
3919             mz_uint32 field_id, field_data_size, field_total_size;
3920 
3921             if (extra_size_remaining < (sizeof(mz_uint16) * 2))
3922             {
3923                 mz_zip_array_clear(pZip, &file_data_array);
3924                 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
3925             }
3926 
3927             field_id = MZ_READ_LE16(pExtra_data);
3928             field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
3929             field_total_size = field_data_size + sizeof(mz_uint16) * 2;
3930 
3931             if (field_total_size > extra_size_remaining)
3932             {
3933                 mz_zip_array_clear(pZip, &file_data_array);
3934                 return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
3935             }
3936 
3937             if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
3938             {
3939                 const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);
3940 
3941                 if (field_data_size < sizeof(mz_uint64) * 2)
3942                 {
3943                     mz_zip_array_clear(pZip, &file_data_array);
3944                     return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
3945                 }
3946 
3947                 local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);
3948                 local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */
3949 
3950                 found_zip64_ext_data_in_ldir = MZ_TRUE;
3951                 break;
3952             }
3953 
3954             pExtra_data += field_total_size;
3955             extra_size_remaining -= field_total_size;
3956         } while (extra_size_remaining);
3957 
3958         mz_zip_array_clear(pZip, &file_data_array);
3959     }
3960 
3961     if (!pState->m_zip64)
3962     {
3963         /* 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). */
3964         /* We also check when the archive is finalized so this doesn't need to be perfect. */
3965         mz_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) +
3966                                             pState->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;
3967 
3968         if (approx_new_archive_size >= MZ_UINT32_MAX)
3969             return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
3970     }
3971 
3972     /* Write dest archive padding */
3973     if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes))
3974         return MZ_FALSE;
3975 
3976     cur_dst_file_ofs += num_alignment_padding_bytes;
3977 
3978     local_dir_header_ofs = cur_dst_file_ofs;
3979     if (pZip->m_file_offset_alignment)
3980     {
3981         MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0);
3982     }
3983 
3984     /* 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 */
3985     if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
3986         return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
3987 
3988     cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
3989 
3990     /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */
3991     if (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)))))
3992         return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
3993 
3994     while (src_archive_bytes_remaining)
3995     {
3996         n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining);
3997         if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n)
3998         {
3999             pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4000             return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
4001         }
4002         cur_src_file_ofs += n;
4003 
4004         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
4005         {
4006             pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4007             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
4008         }
4009         cur_dst_file_ofs += n;
4010 
4011         src_archive_bytes_remaining -= n;
4012     }
4013 
4014     /* Now deal with the optional data descriptor */
4015     bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
4016     if (bit_flags & 8)
4017     {
4018         /* Copy data descriptor */
4019         if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir))
4020         {
4021             /* src is zip64, dest must be zip64 */
4022 
4023             /* name			uint32_t's */
4024             /* id				1 (optional in zip64?) */
4025             /* crc			1 */
4026             /* comp_size	2 */
4027             /* uncomp_size 2 */
4028             if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6))
4029             {
4030                 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4031                 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
4032             }
4033 
4034             n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5);
4035         }
4036         else
4037         {
4038             /* src is NOT zip64 */
4039             mz_bool has_id;
4040 
4041             if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4)
4042             {
4043                 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4044                 return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
4045             }
4046 
4047             has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID);
4048 
4049             if (pZip->m_pState->m_zip64)
4050             {
4051                 /* dest is zip64, so upgrade the data descriptor */
4052                 const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0));
4053                 const mz_uint32 src_crc32 = pSrc_descriptor[0];
4054                 const mz_uint64 src_comp_size = pSrc_descriptor[1];
4055                 const mz_uint64 src_uncomp_size = pSrc_descriptor[2];
4056 
4057                 mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID);
4058                 mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32);
4059                 mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size);
4060                 mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size);
4061 
4062                 n = sizeof(mz_uint32) * 6;
4063             }
4064             else
4065             {
4066                 /* dest is NOT zip64, just copy it as-is */
4067                 n = sizeof(mz_uint32) * (has_id ? 4 : 3);
4068             }
4069         }
4070 
4071         if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
4072         {
4073             pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4074             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
4075         }
4076 
4077         cur_src_file_ofs += n;
4078         cur_dst_file_ofs += n;
4079     }
4080     pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4081 
4082     /* Finally, add the new central dir header */
4083     orig_central_dir_size = pState->m_central_dir.m_size;
4084 
4085     memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
4086 
4087     if (pState->m_zip64)
4088     {
4089         /* 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. */
4090         const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len;
4091         mz_zip_array new_ext_block;
4092 
4093         mz_zip_array_init(&new_ext_block, sizeof(mz_uint8));
4094 
4095         MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX);
4096         MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX);
4097         MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX);
4098 
4099         if (!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))
4100         {
4101             mz_zip_array_clear(pZip, &new_ext_block);
4102             return MZ_FALSE;
4103         }
4104 
4105         MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size);
4106 
4107         if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
4108         {
4109             mz_zip_array_clear(pZip, &new_ext_block);
4110             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4111         }
4112 
4113         if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len))
4114         {
4115             mz_zip_array_clear(pZip, &new_ext_block);
4116             mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
4117             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4118         }
4119 
4120         if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size))
4121         {
4122             mz_zip_array_clear(pZip, &new_ext_block);
4123             mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
4124             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4125         }
4126 
4127         if (!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))
4128         {
4129             mz_zip_array_clear(pZip, &new_ext_block);
4130             mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
4131             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4132         }
4133 
4134         mz_zip_array_clear(pZip, &new_ext_block);
4135     }
4136     else
4137     {
4138         /* sanity checks */
4139         if (cur_dst_file_ofs > MZ_UINT32_MAX)
4140             return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
4141 
4142         if (local_dir_header_ofs >= MZ_UINT32_MAX)
4143             return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
4144 
4145         MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs);
4146 
4147         if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
4148             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4149 
4150         if (!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))
4151         {
4152             mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
4153             return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4154         }
4155     }
4156 
4157     /* This shouldn't trigger unless we screwed up during the initial sanity checks */
4158     if (pState->m_central_dir.m_size >= MZ_UINT32_MAX)
4159     {
4160         /* TODO: Support central dirs >= 32-bits in size */
4161         mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
4162         return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
4163     }
4164 
4165     n = (mz_uint32)orig_central_dir_size;
4166     if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1))
4167     {
4168         mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
4169         return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
4170     }
4171 
4172     pZip->m_total_files++;
4173     pZip->m_archive_size = cur_dst_file_ofs;
4174 
4175     return MZ_TRUE;
4176 }
4177 
mz_zip_writer_finalize_archive(mz_zip_archive * pZip)4178 mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip)
4179 {
4180     mz_zip_internal_state *pState;
4181     mz_uint64 central_dir_ofs, central_dir_size;
4182     mz_uint8 hdr[256];
4183 
4184     if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
4185         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4186 
4187     pState = pZip->m_pState;
4188 
4189     if (pState->m_zip64)
4190     {
4191         if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX))
4192             return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
4193     }
4194     else
4195     {
4196         if ((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))
4197             return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
4198     }
4199 
4200     central_dir_ofs = 0;
4201     central_dir_size = 0;
4202     if (pZip->m_total_files)
4203     {
4204         /* Write central directory */
4205         central_dir_ofs = pZip->m_archive_size;
4206         central_dir_size = pState->m_central_dir.m_size;
4207         pZip->m_central_directory_file_ofs = central_dir_ofs;
4208         if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size)
4209             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
4210 
4211         pZip->m_archive_size += central_dir_size;
4212     }
4213 
4214     if (pState->m_zip64)
4215     {
4216         /* Write zip64 end of central directory header */
4217         mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size;
4218 
4219         MZ_CLEAR_OBJ(hdr);
4220         MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG);
4221         MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64));
4222         MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */
4223         MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D);
4224         MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files);
4225         MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
4226         MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size);
4227         MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs);
4228         if (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)
4229             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
4230 
4231         pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE;
4232 
4233         /* Write zip64 end of central directory locator */
4234         MZ_CLEAR_OBJ(hdr);
4235         MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG);
4236         MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr);
4237         MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1);
4238         if (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)
4239             return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
4240 
4241         pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE;
4242     }
4243 
4244     /* Write end of central directory record */
4245     MZ_CLEAR_OBJ(hdr);
4246     MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
4247     MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));
4248     MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));
4249     MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size));
4250     MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs));
4251 
4252     if (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)
4253         return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
4254 
4255 #ifndef MINIZ_NO_STDIO
4256     if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))
4257         return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
4258 #endif /* #ifndef MINIZ_NO_STDIO */
4259 
4260     pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE;
4261 
4262     pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
4263     return MZ_TRUE;
4264 }
4265 
mz_zip_writer_finalize_heap_archive(mz_zip_archive * pZip,void ** ppBuf,size_t * pSize)4266 mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize)
4267 {
4268     if ((!ppBuf) || (!pSize))
4269         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4270 
4271     *ppBuf = NULL;
4272     *pSize = 0;
4273 
4274     if ((!pZip) || (!pZip->m_pState))
4275         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4276 
4277     if (pZip->m_pWrite != mz_zip_heap_write_func)
4278         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4279 
4280     if (!mz_zip_writer_finalize_archive(pZip))
4281         return MZ_FALSE;
4282 
4283     *ppBuf = pZip->m_pState->m_pMem;
4284     *pSize = pZip->m_pState->m_mem_size;
4285     pZip->m_pState->m_pMem = NULL;
4286     pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
4287 
4288     return MZ_TRUE;
4289 }
4290 
mz_zip_writer_end(mz_zip_archive * pZip)4291 mz_bool mz_zip_writer_end(mz_zip_archive *pZip)
4292 {
4293     return mz_zip_writer_end_internal(pZip, MZ_TRUE);
4294 }
4295 
4296 #ifndef MINIZ_NO_STDIO
mz_zip_add_mem_to_archive_file_in_place(const char * pZip_filename,const char * pArchive_name,const void * pBuf,size_t buf_size,const void * pComment,mz_uint16 comment_size,mz_uint level_and_flags)4297 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
4298 {
4299     return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL);
4300 }
4301 
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)4302 mz_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)
4303 {
4304     mz_bool status, created_new_archive = MZ_FALSE;
4305     mz_zip_archive zip_archive;
4306     struct MZ_FILE_STAT_STRUCT file_stat;
4307     mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
4308 
4309     mz_zip_zero_struct(&zip_archive);
4310     if ((int)level_and_flags < 0)
4311         level_and_flags = MZ_DEFAULT_LEVEL;
4312 
4313     if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
4314     {
4315         if (pErr)
4316             *pErr = MZ_ZIP_INVALID_PARAMETER;
4317         return MZ_FALSE;
4318     }
4319 
4320     if (!mz_zip_writer_validate_archive_name(pArchive_name))
4321     {
4322         if (pErr)
4323             *pErr = MZ_ZIP_INVALID_FILENAME;
4324         return MZ_FALSE;
4325     }
4326 
4327     /* 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. */
4328     /* So be sure to compile with _LARGEFILE64_SOURCE 1 */
4329     if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0)
4330     {
4331         /* Create a new archive. */
4332         if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags))
4333         {
4334             if (pErr)
4335                 *pErr = zip_archive.m_last_error;
4336             return MZ_FALSE;
4337         }
4338 
4339         created_new_archive = MZ_TRUE;
4340     }
4341     else
4342     {
4343         /* Append to an existing archive. */
4344         if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0))
4345         {
4346             if (pErr)
4347                 *pErr = zip_archive.m_last_error;
4348             return MZ_FALSE;
4349         }
4350 
4351         if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags))
4352         {
4353             if (pErr)
4354                 *pErr = zip_archive.m_last_error;
4355 
4356             mz_zip_reader_end_internal(&zip_archive, MZ_FALSE);
4357 
4358             return MZ_FALSE;
4359         }
4360     }
4361 
4362     status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0);
4363     actual_err = zip_archive.m_last_error;
4364 
4365     /* 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.) */
4366     if (!mz_zip_writer_finalize_archive(&zip_archive))
4367     {
4368         if (!actual_err)
4369             actual_err = zip_archive.m_last_error;
4370 
4371         status = MZ_FALSE;
4372     }
4373 
4374     if (!mz_zip_writer_end_internal(&zip_archive, status))
4375     {
4376         if (!actual_err)
4377             actual_err = zip_archive.m_last_error;
4378 
4379         status = MZ_FALSE;
4380     }
4381 
4382     if ((!status) && (created_new_archive))
4383     {
4384         /* It's a new archive and something went wrong, so just delete it. */
4385         int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
4386         (void)ignoredStatus;
4387     }
4388 
4389     if (pErr)
4390         *pErr = actual_err;
4391 
4392     return status;
4393 }
4394 
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)4395 void *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)
4396 {
4397     mz_uint32 file_index;
4398     mz_zip_archive zip_archive;
4399     void *p = NULL;
4400 
4401     if (pSize)
4402         *pSize = 0;
4403 
4404     if ((!pZip_filename) || (!pArchive_name))
4405     {
4406         if (pErr)
4407             *pErr = MZ_ZIP_INVALID_PARAMETER;
4408 
4409         return NULL;
4410     }
4411 
4412     mz_zip_zero_struct(&zip_archive);
4413     if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0))
4414     {
4415         if (pErr)
4416             *pErr = zip_archive.m_last_error;
4417 
4418         return NULL;
4419     }
4420 
4421     if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index))
4422     {
4423         p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
4424     }
4425 
4426     mz_zip_reader_end_internal(&zip_archive, p != NULL);
4427 
4428     if (pErr)
4429         *pErr = zip_archive.m_last_error;
4430 
4431     return p;
4432 }
4433 
mz_zip_extract_archive_file_to_heap(const char * pZip_filename,const char * pArchive_name,size_t * pSize,mz_uint flags)4434 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags)
4435 {
4436     return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL);
4437 }
4438 
4439 #endif /* #ifndef MINIZ_NO_STDIO */
4440 
4441 #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */
4442 
4443 /* ------------------- Misc utils */
4444 
mz_zip_get_mode(mz_zip_archive * pZip)4445 mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip)
4446 {
4447     return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID;
4448 }
4449 
mz_zip_get_type(mz_zip_archive * pZip)4450 mz_zip_type mz_zip_get_type(mz_zip_archive *pZip)
4451 {
4452     return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID;
4453 }
4454 
mz_zip_set_last_error(mz_zip_archive * pZip,mz_zip_error err_num)4455 mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num)
4456 {
4457     mz_zip_error prev_err;
4458 
4459     if (!pZip)
4460         return MZ_ZIP_INVALID_PARAMETER;
4461 
4462     prev_err = pZip->m_last_error;
4463 
4464     pZip->m_last_error = err_num;
4465     return prev_err;
4466 }
4467 
mz_zip_peek_last_error(mz_zip_archive * pZip)4468 mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip)
4469 {
4470     if (!pZip)
4471         return MZ_ZIP_INVALID_PARAMETER;
4472 
4473     return pZip->m_last_error;
4474 }
4475 
mz_zip_clear_last_error(mz_zip_archive * pZip)4476 mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip)
4477 {
4478     return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR);
4479 }
4480 
mz_zip_get_last_error(mz_zip_archive * pZip)4481 mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip)
4482 {
4483     mz_zip_error prev_err;
4484 
4485     if (!pZip)
4486         return MZ_ZIP_INVALID_PARAMETER;
4487 
4488     prev_err = pZip->m_last_error;
4489 
4490     pZip->m_last_error = MZ_ZIP_NO_ERROR;
4491     return prev_err;
4492 }
4493 
mz_zip_get_error_string(mz_zip_error mz_err)4494 const char *mz_zip_get_error_string(mz_zip_error mz_err)
4495 {
4496     switch (mz_err)
4497     {
4498         case MZ_ZIP_NO_ERROR:
4499             return "no error";
4500         case MZ_ZIP_UNDEFINED_ERROR:
4501             return "undefined error";
4502         case MZ_ZIP_TOO_MANY_FILES:
4503             return "too many files";
4504         case MZ_ZIP_FILE_TOO_LARGE:
4505             return "file too large";
4506         case MZ_ZIP_UNSUPPORTED_METHOD:
4507             return "unsupported method";
4508         case MZ_ZIP_UNSUPPORTED_ENCRYPTION:
4509             return "unsupported encryption";
4510         case MZ_ZIP_UNSUPPORTED_FEATURE:
4511             return "unsupported feature";
4512         case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:
4513             return "failed finding central directory";
4514         case MZ_ZIP_NOT_AN_ARCHIVE:
4515             return "not a ZIP archive";
4516         case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:
4517             return "invalid header or archive is corrupted";
4518         case MZ_ZIP_UNSUPPORTED_MULTIDISK:
4519             return "unsupported multidisk archive";
4520         case MZ_ZIP_DECOMPRESSION_FAILED:
4521             return "decompression failed or archive is corrupted";
4522         case MZ_ZIP_COMPRESSION_FAILED:
4523             return "compression failed";
4524         case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:
4525             return "unexpected decompressed size";
4526         case MZ_ZIP_CRC_CHECK_FAILED:
4527             return "CRC-32 check failed";
4528         case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:
4529             return "unsupported central directory size";
4530         case MZ_ZIP_ALLOC_FAILED:
4531             return "allocation failed";
4532         case MZ_ZIP_FILE_OPEN_FAILED:
4533             return "file open failed";
4534         case MZ_ZIP_FILE_CREATE_FAILED:
4535             return "file create failed";
4536         case MZ_ZIP_FILE_WRITE_FAILED:
4537             return "file write failed";
4538         case MZ_ZIP_FILE_READ_FAILED:
4539             return "file read failed";
4540         case MZ_ZIP_FILE_CLOSE_FAILED:
4541             return "file close failed";
4542         case MZ_ZIP_FILE_SEEK_FAILED:
4543             return "file seek failed";
4544         case MZ_ZIP_FILE_STAT_FAILED:
4545             return "file stat failed";
4546         case MZ_ZIP_INVALID_PARAMETER:
4547             return "invalid parameter";
4548         case MZ_ZIP_INVALID_FILENAME:
4549             return "invalid filename";
4550         case MZ_ZIP_BUF_TOO_SMALL:
4551             return "buffer too small";
4552         case MZ_ZIP_INTERNAL_ERROR:
4553             return "internal error";
4554         case MZ_ZIP_FILE_NOT_FOUND:
4555             return "file not found";
4556         case MZ_ZIP_ARCHIVE_TOO_LARGE:
4557             return "archive is too large";
4558         case MZ_ZIP_VALIDATION_FAILED:
4559             return "validation failed";
4560         case MZ_ZIP_WRITE_CALLBACK_FAILED:
4561             return "write calledback failed";
4562         default:
4563             break;
4564     }
4565 
4566     return "unknown error";
4567 }
4568 
4569 /* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */
mz_zip_is_zip64(mz_zip_archive * pZip)4570 mz_bool mz_zip_is_zip64(mz_zip_archive *pZip)
4571 {
4572     if ((!pZip) || (!pZip->m_pState))
4573         return MZ_FALSE;
4574 
4575     return pZip->m_pState->m_zip64;
4576 }
4577 
mz_zip_get_central_dir_size(mz_zip_archive * pZip)4578 size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip)
4579 {
4580     if ((!pZip) || (!pZip->m_pState))
4581         return 0;
4582 
4583     return pZip->m_pState->m_central_dir.m_size;
4584 }
4585 
mz_zip_reader_get_num_files(mz_zip_archive * pZip)4586 mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip)
4587 {
4588     return pZip ? pZip->m_total_files : 0;
4589 }
4590 
mz_zip_get_archive_size(mz_zip_archive * pZip)4591 mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip)
4592 {
4593     if (!pZip)
4594         return 0;
4595     return pZip->m_archive_size;
4596 }
4597 
mz_zip_get_archive_file_start_offset(mz_zip_archive * pZip)4598 mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip)
4599 {
4600     if ((!pZip) || (!pZip->m_pState))
4601         return 0;
4602     return pZip->m_pState->m_file_archive_start_ofs;
4603 }
4604 
mz_zip_get_cfile(mz_zip_archive * pZip)4605 MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip)
4606 {
4607     if ((!pZip) || (!pZip->m_pState))
4608         return 0;
4609     return pZip->m_pState->m_pFile;
4610 }
4611 
mz_zip_read_archive_data(mz_zip_archive * pZip,mz_uint64 file_ofs,void * pBuf,size_t n)4612 size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n)
4613 {
4614     if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead))
4615         return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4616 
4617     return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n);
4618 }
4619 
mz_zip_reader_get_filename(mz_zip_archive * pZip,mz_uint file_index,char * pFilename,mz_uint filename_buf_size)4620 mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size)
4621 {
4622     mz_uint n;
4623     const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
4624     if (!p)
4625     {
4626         if (filename_buf_size)
4627             pFilename[0] = '\0';
4628         mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
4629         return 0;
4630     }
4631     n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
4632     if (filename_buf_size)
4633     {
4634         n = MZ_MIN(n, filename_buf_size - 1);
4635         memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
4636         pFilename[n] = '\0';
4637     }
4638     return n + 1;
4639 }
4640 
mz_zip_reader_file_stat(mz_zip_archive * pZip,mz_uint file_index,mz_zip_archive_file_stat * pStat)4641 mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat)
4642 {
4643     return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL);
4644 }
4645 
mz_zip_end(mz_zip_archive * pZip)4646 mz_bool mz_zip_end(mz_zip_archive *pZip)
4647 {
4648     if (!pZip)
4649         return MZ_FALSE;
4650 
4651     if (pZip->m_zip_mode == MZ_ZIP_MODE_READING)
4652         return mz_zip_reader_end(pZip);
4653 #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
4654     else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))
4655         return mz_zip_writer_end(pZip);
4656 #endif
4657 
4658     return MZ_FALSE;
4659 }
4660 
4661 #ifdef __cplusplus
4662 }
4663 #endif
4664 
4665 #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/
4666