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