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