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