blob: 87a16587105b89fcb9feecc204104ea853f90262 [file] [log] [blame]
Andrew Geissler82c905d2020-04-13 13:39:40 -05001From 7fc220b2350d78942fb3935cad0b1564418ebe8f Mon Sep 17 00:00:00 2001
2From: Kim Kulling <kim.kulling@googlemail.com>
3Date: Tue, 19 Nov 2019 20:30:40 +0100
4Subject: [PATCH] closes https://github.com/assimp/assimp/issues/2733: update
5 of zlip to fix gcc build for v9.2.0 32 bit
6
7Upstream-Status: Backport [https://github.com/assimp/assimp/commit/f78446b14aff46db2ef27d062a275b6a01fd68b1]
8Signed-off-by: Alexander Kanavin <alex.kanavin@gmail.com>
9---
10 contrib/zip/.gitignore | 2 +
11 contrib/zip/CMakeLists.txt | 83 +++++-
12 contrib/zip/README.md | 12 +-
13 contrib/zip/appveyor.yml | 2 +-
14 contrib/zip/src/miniz.h | 457 ++++++++++++++++++++++++++++----
15 contrib/zip/src/zip.c | 62 +++--
16 contrib/zip/src/zip.h | 457 ++++++++++++++++----------------
17 contrib/zip/test/CMakeLists.txt | 27 +-
18 contrib/zip/test/test.c | 38 ++-
19 contrib/zip/test/test_miniz.c | 25 +-
20 10 files changed, 821 insertions(+), 344 deletions(-)
21
22diff --git a/contrib/zip/.gitignore b/contrib/zip/.gitignore
23index a7904a1e..49b2cb2f 100644
24--- a/contrib/zip/.gitignore
25+++ b/contrib/zip/.gitignore
26@@ -1,6 +1,7 @@
27 /build/
28 /test/build/
29 /xcodeproj/
30+.vscode/
31
32 # Object files
33 *.o
34@@ -54,3 +55,4 @@ zip.dir/
35 test/test.exe.vcxproj.filters
36 test/test.exe.vcxproj
37 test/test.exe.dir/
38+
39diff --git a/contrib/zip/CMakeLists.txt b/contrib/zip/CMakeLists.txt
40index b46dbb1d..77916d2e 100644
41--- a/contrib/zip/CMakeLists.txt
42+++ b/contrib/zip/CMakeLists.txt
43@@ -1,10 +1,14 @@
44-cmake_minimum_required(VERSION 2.8)
45-project(zip)
46-enable_language(C)
47+cmake_minimum_required(VERSION 3.0)
48+
49+project(zip
50+ LANGUAGES C
51+ VERSION "0.1.15")
52 set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
53
54+option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
55+
56 if (MSVC)
57- # Use secure functions by defaualt and suppress warnings about "deprecated" functions
58+ # Use secure functions by default and suppress warnings about "deprecated" functions
59 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1")
60 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
61 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
62@@ -12,28 +16,80 @@ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
63 "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
64 "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
65 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic")
66+ if(ENABLE_COVERAGE)
67+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
68+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
69+ endif()
70 endif (MSVC)
71
72 # zip
73 set(SRC src/miniz.h src/zip.h src/zip.c)
74 add_library(${PROJECT_NAME} ${SRC})
75-target_include_directories(${PROJECT_NAME} INTERFACE src)
76+target_include_directories(${PROJECT_NAME} PUBLIC
77+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
78+ $<INSTALL_INTERFACE:include>
79+)
80
81 # test
82 if (NOT CMAKE_DISABLE_TESTING)
83 enable_testing()
84 add_subdirectory(test)
85 find_package(Sanitizers)
86- add_sanitizers(${PROJECT_NAME} test.exe)
87- add_sanitizers(${PROJECT_NAME} test_miniz.exe)
88+ add_sanitizers(${PROJECT_NAME} ${test_out} ${test_miniz_out})
89 endif()
90
91+####
92+# Installation (https://github.com/forexample/package-example) {
93+
94+set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
95+set(INCLUDE_INSTALL_DIR "include")
96+
97+set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
98+
99+# Configuration
100+set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
101+set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
102+set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
103+set(NAMESPACE "${PROJECT_NAME}::")
104+
105+# Include module with fuction 'write_basic_package_version_file'
106+include(CMakePackageConfigHelpers)
107+
108+# Note: PROJECT_VERSION is used as a VERSION
109+write_basic_package_version_file(
110+ "${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion
111+)
112+
113+# Use variables:
114+# * TARGETS_EXPORT_NAME
115+# * PROJECT_NAME
116+configure_package_config_file(
117+ "cmake/Config.cmake.in"
118+ "${PROJECT_CONFIG}"
119+ INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
120+)
121+
122+install(
123+ FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
124+ DESTINATION "${CONFIG_INSTALL_DIR}"
125+)
126+
127+install(
128+ EXPORT "${TARGETS_EXPORT_NAME}"
129+ NAMESPACE "${NAMESPACE}"
130+ DESTINATION "${CONFIG_INSTALL_DIR}"
131+)
132+
133+# }
134+
135 install(TARGETS ${PROJECT_NAME}
136+ EXPORT ${TARGETS_EXPORT_NAME}
137 RUNTIME DESTINATION bin
138 ARCHIVE DESTINATION lib
139 LIBRARY DESTINATION lib
140- COMPONENT library)
141-install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION include)
142+ INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR}
143+)
144+install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION ${INCLUDE_INSTALL_DIR}/zip)
145
146 # uninstall target (https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake)
147 if(NOT TARGET uninstall)
148@@ -45,3 +101,12 @@ if(NOT TARGET uninstall)
149 add_custom_target(uninstall
150 COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
151 endif()
152+
153+find_package(Doxygen)
154+if(DOXYGEN_FOUND)
155+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
156+ add_custom_target(doc
157+ ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
158+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
159+ COMMENT "Generating API documentation with Doxygen" VERBATIM)
160+endif()
161diff --git a/contrib/zip/README.md b/contrib/zip/README.md
162index d5fb8cd2..14eb9a34 100644
163--- a/contrib/zip/README.md
164+++ b/contrib/zip/README.md
165@@ -71,7 +71,7 @@ int arg = 2;
166 zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
167 ```
168
169-* Extract a zip entry into memory.
170+* Extract a zip entry into memory.
171 ```c
172 void *buf = NULL;
173 size_t bufsize;
174@@ -89,7 +89,7 @@ zip_close(zip);
175 free(buf);
176 ```
177
178-* Extract a zip entry into memory (no internal allocation).
179+* Extract a zip entry into memory (no internal allocation).
180 ```c
181 unsigned char *buf;
182 size_t bufsize;
183@@ -110,7 +110,7 @@ zip_close(zip);
184 free(buf);
185 ```
186
187-* Extract a zip entry into memory using callback.
188+* Extract a zip entry into memory using callback.
189 ```c
190 struct buffer_t {
191 char *data;
192@@ -144,7 +144,7 @@ free(buf.data);
193 ```
194
195
196-* Extract a zip entry into a file.
197+* Extract a zip entry into a file.
198 ```c
199 struct zip_t *zip = zip_open("foo.zip", 0, 'r');
200 {
201@@ -157,7 +157,7 @@ struct zip_t *zip = zip_open("foo.zip", 0, 'r');
202 zip_close(zip);
203 ```
204
205-* List of all zip entries
206+* List of all zip entries
207 ```c
208 struct zip_t *zip = zip_open("foo.zip", 0, 'r');
209 int i, n = zip_total_entries(zip);
210@@ -174,7 +174,7 @@ for (i = 0; i < n; ++i) {
211 zip_close(zip);
212 ```
213
214-## Bindings
215+# Bindings
216 Compile zip library as a dynamic library.
217 ```shell
218 $ mkdir build
219diff --git a/contrib/zip/appveyor.yml b/contrib/zip/appveyor.yml
220index 0be6373c..ea17f5de 100644
221--- a/contrib/zip/appveyor.yml
222+++ b/contrib/zip/appveyor.yml
223@@ -1,4 +1,4 @@
224-version: zip-0.1.9.{build}
225+version: zip-0.1.15.{build}
226 build_script:
227 - cmd: >-
228 cd c:\projects\zip
229diff --git a/contrib/zip/src/miniz.h b/contrib/zip/src/miniz.h
230index 2c27a94d..c4fcfb83 100644
231--- a/contrib/zip/src/miniz.h
232+++ b/contrib/zip/src/miniz.h
233@@ -221,6 +221,7 @@
234 #ifndef MINIZ_HEADER_INCLUDED
235 #define MINIZ_HEADER_INCLUDED
236
237+#include <stdint.h>
238 #include <stdlib.h>
239
240 // Defines to completely disable specific portions of miniz.c:
241@@ -284,7 +285,8 @@
242 /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */
243 #if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES)
244 #if MINIZ_X86_OR_X64_CPU
245-/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */
246+/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
247+ * integer loads and stores from unaligned addresses. */
248 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
249 #define MINIZ_UNALIGNED_USE_MEMCPY
250 #else
251@@ -354,6 +356,44 @@ enum {
252 MZ_FIXED = 4
253 };
254
255+/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or
256+ * modify this enum. */
257+typedef enum {
258+ MZ_ZIP_NO_ERROR = 0,
259+ MZ_ZIP_UNDEFINED_ERROR,
260+ MZ_ZIP_TOO_MANY_FILES,
261+ MZ_ZIP_FILE_TOO_LARGE,
262+ MZ_ZIP_UNSUPPORTED_METHOD,
263+ MZ_ZIP_UNSUPPORTED_ENCRYPTION,
264+ MZ_ZIP_UNSUPPORTED_FEATURE,
265+ MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,
266+ MZ_ZIP_NOT_AN_ARCHIVE,
267+ MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,
268+ MZ_ZIP_UNSUPPORTED_MULTIDISK,
269+ MZ_ZIP_DECOMPRESSION_FAILED,
270+ MZ_ZIP_COMPRESSION_FAILED,
271+ MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,
272+ MZ_ZIP_CRC_CHECK_FAILED,
273+ MZ_ZIP_UNSUPPORTED_CDIR_SIZE,
274+ MZ_ZIP_ALLOC_FAILED,
275+ MZ_ZIP_FILE_OPEN_FAILED,
276+ MZ_ZIP_FILE_CREATE_FAILED,
277+ MZ_ZIP_FILE_WRITE_FAILED,
278+ MZ_ZIP_FILE_READ_FAILED,
279+ MZ_ZIP_FILE_CLOSE_FAILED,
280+ MZ_ZIP_FILE_SEEK_FAILED,
281+ MZ_ZIP_FILE_STAT_FAILED,
282+ MZ_ZIP_INVALID_PARAMETER,
283+ MZ_ZIP_INVALID_FILENAME,
284+ MZ_ZIP_BUF_TOO_SMALL,
285+ MZ_ZIP_INTERNAL_ERROR,
286+ MZ_ZIP_FILE_NOT_FOUND,
287+ MZ_ZIP_ARCHIVE_TOO_LARGE,
288+ MZ_ZIP_VALIDATION_FAILED,
289+ MZ_ZIP_WRITE_CALLBACK_FAILED,
290+ MZ_ZIP_TOTAL_ERRORS
291+} mz_zip_error;
292+
293 // Method
294 #define MZ_DEFLATED 8
295
296@@ -696,6 +736,7 @@ typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
297 void *pBuf, size_t n);
298 typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
299 const void *pBuf, size_t n);
300+typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);
301
302 struct mz_zip_internal_state_tag;
303 typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
304@@ -707,13 +748,27 @@ typedef enum {
305 MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
306 } mz_zip_mode;
307
308-typedef struct mz_zip_archive_tag {
309+typedef enum {
310+ MZ_ZIP_TYPE_INVALID = 0,
311+ MZ_ZIP_TYPE_USER,
312+ MZ_ZIP_TYPE_MEMORY,
313+ MZ_ZIP_TYPE_HEAP,
314+ MZ_ZIP_TYPE_FILE,
315+ MZ_ZIP_TYPE_CFILE,
316+ MZ_ZIP_TOTAL_TYPES
317+} mz_zip_type;
318+
319+typedef struct {
320 mz_uint64 m_archive_size;
321 mz_uint64 m_central_directory_file_ofs;
322- mz_uint m_total_files;
323+
324+ /* We only support up to UINT32_MAX files in zip64 mode. */
325+ mz_uint32 m_total_files;
326 mz_zip_mode m_zip_mode;
327+ mz_zip_type m_zip_type;
328+ mz_zip_error m_last_error;
329
330- mz_uint m_file_offset_alignment;
331+ mz_uint64 m_file_offset_alignment;
332
333 mz_alloc_func m_pAlloc;
334 mz_free_func m_pFree;
335@@ -722,6 +777,7 @@ typedef struct mz_zip_archive_tag {
336
337 mz_file_read_func m_pRead;
338 mz_file_write_func m_pWrite;
339+ mz_file_needs_keepalive m_pNeeds_keepalive;
340 void *m_pIO_opaque;
341
342 mz_zip_internal_state *m_pState;
343@@ -1263,6 +1319,9 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
344 int strategy);
345 #endif // #ifndef MINIZ_NO_ZLIB_APIS
346
347+#define MZ_UINT16_MAX (0xFFFFU)
348+#define MZ_UINT32_MAX (0xFFFFFFFFU)
349+
350 #ifdef __cplusplus
351 }
352 #endif
353@@ -1311,6 +1370,11 @@ typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
354 ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
355 #endif
356
357+#define MZ_READ_LE64(p) \
358+ (((mz_uint64)MZ_READ_LE32(p)) | \
359+ (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) \
360+ << 32U))
361+
362 #ifdef _MSC_VER
363 #define MZ_FORCEINLINE __forceinline
364 #elif defined(__GNUC__)
365@@ -4160,6 +4224,17 @@ enum {
366 MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
367 MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
368 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
369+
370+ /* ZIP64 archive identifier and record sizes */
371+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,
372+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,
373+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,
374+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,
375+ MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,
376+ MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,
377+ MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,
378+ MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,
379+
380 // Central directory header record offsets
381 MZ_ZIP_CDH_SIG_OFS = 0,
382 MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
383@@ -4199,6 +4274,31 @@ enum {
384 MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
385 MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
386 MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
387+
388+ /* ZIP64 End of central directory locator offsets */
389+ MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */
390+ MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */
391+ MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */
392+ MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */
393+
394+ /* ZIP64 End of central directory header offsets */
395+ MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */
396+ MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */
397+ MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */
398+ MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */
399+ MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */
400+ MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */
401+ MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */
402+ MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */
403+ MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */
404+ MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */
405+ MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,
406+ MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,
407+ MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,
408+ MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,
409+ MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,
410+ MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,
411+ MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11
412 };
413
414 typedef struct {
415@@ -4211,7 +4311,24 @@ struct mz_zip_internal_state_tag {
416 mz_zip_array m_central_dir;
417 mz_zip_array m_central_dir_offsets;
418 mz_zip_array m_sorted_central_dir_offsets;
419+
420+ /* The flags passed in when the archive is initially opened. */
421+ uint32_t m_init_flags;
422+
423+ /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc.
424+ */
425+ mz_bool m_zip64;
426+
427+ /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64
428+ * will also be slammed to true too, even if we didn't find a zip64 end of
429+ * central dir header, etc.) */
430+ mz_bool m_zip64_has_extended_info_fields;
431+
432+ /* These fields are used by the file, FILE, memory, and memory/heap read/write
433+ * helpers. */
434 MZ_FILE *m_pFile;
435+ mz_uint64 m_file_archive_start_ofs;
436+
437 void *m_pMem;
438 size_t m_mem_size;
439 size_t m_mem_capacity;
440@@ -4363,6 +4480,13 @@ static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time,
441 #endif /* #ifndef MINIZ_NO_STDIO */
442 #endif /* #ifndef MINIZ_NO_TIME */
443
444+static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip,
445+ mz_zip_error err_num) {
446+ if (pZip)
447+ pZip->m_last_error = err_num;
448+ return MZ_FALSE;
449+}
450+
451 static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
452 mz_uint32 flags) {
453 (void)flags;
454@@ -4480,127 +4604,346 @@ mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) {
455 }
456 }
457
458-static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
459- mz_uint32 flags) {
460- mz_uint cdir_size, num_this_disk, cdir_disk_index;
461- mz_uint64 cdir_ofs;
462+static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip,
463+ mz_uint32 record_sig,
464+ mz_uint32 record_size,
465+ mz_int64 *pOfs) {
466 mz_int64 cur_file_ofs;
467- const mz_uint8 *p;
468 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
469 mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
470- mz_bool sort_central_dir =
471- ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
472- // Basic sanity checks - reject files which are too small, and check the first
473- // 4 bytes of the file to make sure a local header is there.
474- if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
475+
476+ /* Basic sanity checks - reject files which are too small */
477+ if (pZip->m_archive_size < record_size)
478 return MZ_FALSE;
479- // Find the end of central directory record by scanning the file from the end
480- // towards the beginning.
481+
482+ /* Find the record by scanning the file from the end towards the beginning. */
483 cur_file_ofs =
484 MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
485 for (;;) {
486 int i,
487 n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
488+
489 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
490 return MZ_FALSE;
491- for (i = n - 4; i >= 0; --i)
492- if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
493- break;
494+
495+ for (i = n - 4; i >= 0; --i) {
496+ mz_uint s = MZ_READ_LE32(pBuf + i);
497+ if (s == record_sig) {
498+ if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)
499+ break;
500+ }
501+ }
502+
503 if (i >= 0) {
504 cur_file_ofs += i;
505 break;
506 }
507+
508+ /* Give up if we've searched the entire file, or we've gone back "too far"
509+ * (~64kb) */
510 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
511- (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
512+ (MZ_UINT16_MAX + record_size)))
513 return MZ_FALSE;
514+
515 cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
516 }
517- // Read and verify the end of central directory record.
518+
519+ *pOfs = cur_file_ofs;
520+ return MZ_TRUE;
521+}
522+
523+static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
524+ mz_uint flags) {
525+ mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0,
526+ cdir_disk_index = 0;
527+ mz_uint64 cdir_ofs = 0;
528+ mz_int64 cur_file_ofs = 0;
529+ const mz_uint8 *p;
530+
531+ mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
532+ mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
533+ mz_bool sort_central_dir =
534+ ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
535+ mz_uint32 zip64_end_of_central_dir_locator_u32
536+ [(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) /
537+ sizeof(mz_uint32)];
538+ mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;
539+
540+ mz_uint32 zip64_end_of_central_dir_header_u32
541+ [(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
542+ sizeof(mz_uint32)];
543+ mz_uint8 *pZip64_end_of_central_dir =
544+ (mz_uint8 *)zip64_end_of_central_dir_header_u32;
545+
546+ mz_uint64 zip64_end_of_central_dir_ofs = 0;
547+
548+ /* Basic sanity checks - reject files which are too small, and check the first
549+ * 4 bytes of the file to make sure a local header is there. */
550+ if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
551+ return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
552+
553+ if (!mz_zip_reader_locate_header_sig(
554+ pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG,
555+ MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))
556+ return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);
557+
558+ /* Read and verify the end of central directory record. */
559 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
560 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
561 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
562- return MZ_FALSE;
563- if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
564- MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
565- ((pZip->m_total_files =
566- MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) !=
567- MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
568- return MZ_FALSE;
569+ return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
570+
571+ if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
572+ MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
573+ return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
574+
575+ if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE +
576+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) {
577+ if (pZip->m_pRead(pZip->m_pIO_opaque,
578+ cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE,
579+ pZip64_locator,
580+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ==
581+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) {
582+ if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) ==
583+ MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) {
584+ zip64_end_of_central_dir_ofs = MZ_READ_LE64(
585+ pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);
586+ if (zip64_end_of_central_dir_ofs >
587+ (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
588+ return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
589+
590+ if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs,
591+ pZip64_end_of_central_dir,
592+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ==
593+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) {
594+ if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) ==
595+ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) {
596+ pZip->m_pState->m_zip64 = MZ_TRUE;
597+ }
598+ }
599+ }
600+ }
601+ }
602
603+ pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);
604+ cdir_entries_on_this_disk =
605+ MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
606 num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
607 cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
608+ cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);
609+ cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
610+
611+ if (pZip->m_pState->m_zip64) {
612+ mz_uint32 zip64_total_num_of_disks =
613+ MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);
614+ mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(
615+ pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);
616+ mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(
617+ pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
618+ mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(
619+ pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);
620+ mz_uint64 zip64_size_of_central_directory =
621+ MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);
622+
623+ if (zip64_size_of_end_of_central_dir_record <
624+ (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))
625+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
626+
627+ if (zip64_total_num_of_disks != 1U)
628+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
629+
630+ /* Check for miniz's practical limits */
631+ if (zip64_cdir_total_entries > MZ_UINT32_MAX)
632+ return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
633+
634+ pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;
635+
636+ if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)
637+ return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
638+
639+ cdir_entries_on_this_disk =
640+ (mz_uint32)zip64_cdir_total_entries_on_this_disk;
641+
642+ /* Check for miniz's current practical limits (sorry, this should be enough
643+ * for millions of files) */
644+ if (zip64_size_of_central_directory > MZ_UINT32_MAX)
645+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
646+
647+ cdir_size = (mz_uint32)zip64_size_of_central_directory;
648+
649+ num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir +
650+ MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);
651+
652+ cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir +
653+ MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);
654+
655+ cdir_ofs =
656+ MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);
657+ }
658+
659+ if (pZip->m_total_files != cdir_entries_on_this_disk)
660+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
661+
662 if (((num_this_disk | cdir_disk_index) != 0) &&
663 ((num_this_disk != 1) || (cdir_disk_index != 1)))
664- return MZ_FALSE;
665+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
666
667- if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) <
668- pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
669- return MZ_FALSE;
670+ if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
671+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
672
673- cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
674 if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
675- return MZ_FALSE;
676+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
677
678 pZip->m_central_directory_file_ofs = cdir_ofs;
679
680 if (pZip->m_total_files) {
681 mz_uint i, n;
682-
683- // Read the entire central directory into a heap block, and allocate another
684- // heap block to hold the unsorted central dir file record offsets, and
685- // another to hold the sorted indices.
686+ /* Read the entire central directory into a heap block, and allocate another
687+ * heap block to hold the unsorted central dir file record offsets, and
688+ * possibly another to hold the sorted indices. */
689 if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
690 MZ_FALSE)) ||
691 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
692 pZip->m_total_files, MZ_FALSE)))
693- return MZ_FALSE;
694+ return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
695
696 if (sort_central_dir) {
697 if (!mz_zip_array_resize(pZip,
698 &pZip->m_pState->m_sorted_central_dir_offsets,
699 pZip->m_total_files, MZ_FALSE))
700- return MZ_FALSE;
701+ return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
702 }
703
704 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
705 pZip->m_pState->m_central_dir.m_p,
706 cdir_size) != cdir_size)
707- return MZ_FALSE;
708+ return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
709
710- // Now create an index into the central directory file records, do some
711- // basic sanity checking on each record, and check for zip64 entries (which
712- // are not yet supported).
713+ /* Now create an index into the central directory file records, do some
714+ * basic sanity checking on each record */
715 p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
716 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
717- mz_uint total_header_size, comp_size, decomp_size, disk_index;
718+ mz_uint total_header_size, disk_index, bit_flags, filename_size,
719+ ext_data_size;
720+ mz_uint64 comp_size, decomp_size, local_header_ofs;
721+
722 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
723 (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
724- return MZ_FALSE;
725+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
726+
727 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
728 i) =
729 (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
730+
731 if (sort_central_dir)
732 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
733 mz_uint32, i) = i;
734+
735 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
736 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
737- if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
738- (decomp_size != comp_size)) ||
739- (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) ||
740- (comp_size == 0xFFFFFFFF))
741- return MZ_FALSE;
742+ local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
743+ filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
744+ ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
745+
746+ if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&
747+ (ext_data_size) &&
748+ (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) ==
749+ MZ_UINT32_MAX)) {
750+ /* Attempt to find zip64 extended information field in the entry's extra
751+ * data */
752+ mz_uint32 extra_size_remaining = ext_data_size;
753+
754+ if (extra_size_remaining) {
755+ const mz_uint8 *pExtra_data;
756+ void *buf = NULL;
757+
758+ if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size >
759+ n) {
760+ buf = MZ_MALLOC(ext_data_size);
761+ if (buf == NULL)
762+ return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
763+
764+ if (pZip->m_pRead(pZip->m_pIO_opaque,
765+ cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
766+ filename_size,
767+ buf, ext_data_size) != ext_data_size) {
768+ MZ_FREE(buf);
769+ return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
770+ }
771+
772+ pExtra_data = (mz_uint8 *)buf;
773+ } else {
774+ pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
775+ }
776+
777+ do {
778+ mz_uint32 field_id;
779+ mz_uint32 field_data_size;
780+
781+ if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
782+ MZ_FREE(buf);
783+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
784+ }
785+
786+ field_id = MZ_READ_LE16(pExtra_data);
787+ field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
788+
789+ if ((field_data_size + sizeof(mz_uint16) * 2) >
790+ extra_size_remaining) {
791+ MZ_FREE(buf);
792+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
793+ }
794+
795+ if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
796+ /* Ok, the archive didn't have any zip64 headers but it uses a
797+ * zip64 extended information field so mark it as zip64 anyway
798+ * (this can occur with infozip's zip util when it reads
799+ * compresses files from stdin). */
800+ pZip->m_pState->m_zip64 = MZ_TRUE;
801+ pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;
802+ break;
803+ }
804+
805+ pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
806+ extra_size_remaining =
807+ extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
808+ } while (extra_size_remaining);
809+
810+ MZ_FREE(buf);
811+ }
812+ }
813+
814+ /* I've seen archives that aren't marked as zip64 that uses zip64 ext
815+ * data, argh */
816+ if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) {
817+ if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
818+ (decomp_size != comp_size)) ||
819+ (decomp_size && !comp_size))
820+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
821+ }
822+
823 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
824- if ((disk_index != num_this_disk) && (disk_index != 1))
825- return MZ_FALSE;
826- if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
827- MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
828- return MZ_FALSE;
829+ if ((disk_index == MZ_UINT16_MAX) ||
830+ ((disk_index != num_this_disk) && (disk_index != 1)))
831+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
832+
833+ if (comp_size != MZ_UINT32_MAX) {
834+ if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
835+ MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
836+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
837+ }
838+
839+ bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
840+ if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)
841+ return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
842+
843 if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
844 MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
845 MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
846 MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
847 n)
848- return MZ_FALSE;
849+ return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
850+
851 n -= total_header_size;
852 p += total_header_size;
853 }
854diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c
855index ff3a8fe1..1abcfd8f 100644
856--- a/contrib/zip/src/zip.c
857+++ b/contrib/zip/src/zip.c
858@@ -24,7 +24,6 @@
859 ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \
860 (P)[1] == ':')
861 #define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0)
862-#define ISSLASH(C) ((C) == '/' || (C) == '\\')
863
864 #else
865
866@@ -48,7 +47,7 @@ int symlink(const char *target, const char *linkpath); // needed on Linux
867 #endif
868
869 #ifndef ISSLASH
870-#define ISSLASH(C) ((C) == '/')
871+#define ISSLASH(C) ((C) == '/' || (C) == '\\')
872 #endif
873
874 #define CLEANUP(ptr) \
875@@ -78,26 +77,34 @@ static const char *base_name(const char *name) {
876 return base;
877 }
878
879-static int mkpath(const char *path) {
880- char const *p;
881+static int mkpath(char *path) {
882+ char *p;
883 char npath[MAX_PATH + 1];
884 int len = 0;
885 int has_device = HAS_DEVICE(path);
886
887 memset(npath, 0, MAX_PATH + 1);
888-
889-#ifdef _WIN32
890- // only on windows fix the path
891- npath[0] = path[0];
892- npath[1] = path[1];
893- len = 2;
894-#endif // _WIN32
895-
896+ if (has_device) {
897+ // only on windows
898+ npath[0] = path[0];
899+ npath[1] = path[1];
900+ len = 2;
901+ }
902 for (p = path + len; *p && len < MAX_PATH; p++) {
903 if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) {
904- if (MKDIR(npath) == -1)
905- if (errno != EEXIST)
906+#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
907+ defined(__MINGW32__)
908+#else
909+ if ('\\' == *p) {
910+ *p = '/';
911+ }
912+#endif
913+
914+ if (MKDIR(npath) == -1) {
915+ if (errno != EEXIST) {
916 return -1;
917+ }
918+ }
919 }
920 npath[len++] = *p;
921 }
922@@ -279,7 +286,14 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
923 zip->entry.header_offset = zip->archive.m_archive_size;
924 memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
925 zip->entry.method = 0;
926+
927+ // UNIX or APPLE
928+#if MZ_PLATFORM == 3 || MZ_PLATFORM == 19
929+ // regular file with rw-r--r-- persmissions
930+ zip->entry.external_attr = (mz_uint32)(0100644) << 16;
931+#else
932 zip->entry.external_attr = 0;
933+#endif
934
935 num_alignment_padding_bytes =
936 mz_zip_writer_compute_padding_needed_for_file_alignment(pzip);
937@@ -660,7 +674,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
938 }
939
940 if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index,
941- buf, bufsize, 0, NULL, 0)) {
942+ buf, bufsize, 0, NULL, 0)) {
943 return -1;
944 }
945
946@@ -670,10 +684,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
947 int zip_entry_fread(struct zip_t *zip, const char *filename) {
948 mz_zip_archive *pzip = NULL;
949 mz_uint idx;
950-#if defined(_MSC_VER)
951-#else
952 mz_uint32 xattr = 0;
953-#endif
954 mz_zip_archive_file_stat info;
955
956 if (!zip) {
957@@ -875,12 +886,19 @@ int zip_extract(const char *zipname, const char *dir,
958 goto out;
959 }
960
961- if ((((info.m_version_made_by >> 8) == 3) || ((info.m_version_made_by >> 8) == 19)) // if zip is produced on Unix or macOS (3 and 19 from section 4.4.2.2 of zip standard)
962- && info.m_external_attr & (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40 is directory)
963+ if ((((info.m_version_made_by >> 8) == 3) ||
964+ ((info.m_version_made_by >> 8) ==
965+ 19)) // if zip is produced on Unix or macOS (3 and 19 from
966+ // section 4.4.2.2 of zip standard)
967+ && info.m_external_attr &
968+ (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40
969+ // is directory)
970 #if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
971 defined(__MINGW32__)
972-#else
973- if (info.m_uncomp_size > MAX_PATH || !mz_zip_reader_extract_to_mem_no_alloc(&zip_archive, i, symlink_to, MAX_PATH, 0, NULL, 0)) {
974+#else
975+ if (info.m_uncomp_size > MAX_PATH ||
976+ !mz_zip_reader_extract_to_mem_no_alloc(&zip_archive, i, symlink_to,
977+ MAX_PATH, 0, NULL, 0)) {
978 goto out;
979 }
980 symlink_to[info.m_uncomp_size] = '\0';
981diff --git a/contrib/zip/src/zip.h b/contrib/zip/src/zip.h
982index 5f39df50..a48d64d6 100644
983--- a/contrib/zip/src/zip.h
984+++ b/contrib/zip/src/zip.h
985@@ -20,241 +20,240 @@ extern "C" {
986 #endif
987
988 #if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) && \
989- !defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(__ssize_t_defined)
990-#define _SSIZE_T
991+ !defined(__DEFINED_ssize_t) && !defined(__ssize_t_defined) && \
992+ !defined(_SSIZE_T) && !defined(_SSIZE_T_)
993+
994 // 64-bit Windows is the only mainstream platform
995 // where sizeof(long) != sizeof(void*)
996 #ifdef _WIN64
997-typedef long long ssize_t; /* byte count or error */
998+typedef long long ssize_t; /* byte count or error */
999 #else
1000-typedef long ssize_t; /* byte count or error */
1001+typedef long ssize_t; /* byte count or error */
1002 #endif
1003+
1004+#define _SSIZE_T_DEFINED
1005+#define _SSIZE_T_DEFINED_
1006+#define __DEFINED_ssize_t
1007+#define __ssize_t_defined
1008+#define _SSIZE_T
1009+#define _SSIZE_T_
1010+
1011 #endif
1012
1013 #ifndef MAX_PATH
1014 #define MAX_PATH 32767 /* # chars in a path name including NULL */
1015 #endif
1016
1017+/**
1018+ * @mainpage
1019+ *
1020+ * Documenation for @ref zip.
1021+ */
1022+
1023+/**
1024+ * @addtogroup zip
1025+ * @{
1026+ */
1027+
1028+/**
1029+ * Default zip compression level.
1030+ */
1031+
1032 #define ZIP_DEFAULT_COMPRESSION_LEVEL 6
1033
1034-/*
1035- This data structure is used throughout the library to represent zip archive
1036- - forward declaration.
1037-*/
1038+/**
1039+ * @struct zip_t
1040+ *
1041+ * This data structure is used throughout the library to represent zip archive -
1042+ * forward declaration.
1043+ */
1044 struct zip_t;
1045
1046-/*
1047- Opens zip archive with compression level using the given mode.
1048-
1049- Args:
1050- zipname: zip archive file name.
1051- level: compression level (0-9 are the standard zlib-style levels).
1052- mode: file access mode.
1053- 'r': opens a file for reading/extracting (the file must exists).
1054- 'w': creates an empty file for writing.
1055- 'a': appends to an existing archive.
1056-
1057- Returns:
1058- The zip archive handler or NULL on error
1059-*/
1060+/**
1061+ * Opens zip archive with compression level using the given mode.
1062+ *
1063+ * @param zipname zip archive file name.
1064+ * @param level compression level (0-9 are the standard zlib-style levels).
1065+ * @param mode file access mode.
1066+ * - 'r': opens a file for reading/extracting (the file must exists).
1067+ * - 'w': creates an empty file for writing.
1068+ * - 'a': appends to an existing archive.
1069+ *
1070+ * @return the zip archive handler or NULL on error
1071+ */
1072 extern struct zip_t *zip_open(const char *zipname, int level, char mode);
1073
1074-/*
1075- Closes the zip archive, releases resources - always finalize.
1076-
1077- Args:
1078- zip: zip archive handler.
1079-*/
1080+/**
1081+ * Closes the zip archive, releases resources - always finalize.
1082+ *
1083+ * @param zip zip archive handler.
1084+ */
1085 extern void zip_close(struct zip_t *zip);
1086
1087-/*
1088- Opens an entry by name in the zip archive.
1089- For zip archive opened in 'w' or 'a' mode the function will append
1090- a new entry. In readonly mode the function tries to locate the entry
1091- in global dictionary.
1092-
1093- Args:
1094- zip: zip archive handler.
1095- entryname: an entry name in local dictionary.
1096-
1097- Returns:
1098- The return code - 0 on success, negative number (< 0) on error.
1099-*/
1100+/**
1101+ * Opens an entry by name in the zip archive.
1102+ *
1103+ * For zip archive opened in 'w' or 'a' mode the function will append
1104+ * a new entry. In readonly mode the function tries to locate the entry
1105+ * in global dictionary.
1106+ *
1107+ * @param zip zip archive handler.
1108+ * @param entryname an entry name in local dictionary.
1109+ *
1110+ * @return the return code - 0 on success, negative number (< 0) on error.
1111+ */
1112 extern int zip_entry_open(struct zip_t *zip, const char *entryname);
1113
1114-/*
1115- Opens a new entry by index in the zip archive.
1116- This function is only valid if zip archive was opened in 'r' (readonly) mode.
1117-
1118- Args:
1119- zip: zip archive handler.
1120- index: index in local dictionary.
1121-
1122- Returns:
1123- The return code - 0 on success, negative number (< 0) on error.
1124-*/
1125+/**
1126+ * Opens a new entry by index in the zip archive.
1127+ *
1128+ * This function is only valid if zip archive was opened in 'r' (readonly) mode.
1129+ *
1130+ * @param zip zip archive handler.
1131+ * @param index index in local dictionary.
1132+ *
1133+ * @return the return code - 0 on success, negative number (< 0) on error.
1134+ */
1135 extern int zip_entry_openbyindex(struct zip_t *zip, int index);
1136
1137-/*
1138- Closes a zip entry, flushes buffer and releases resources.
1139-
1140- Args:
1141- zip: zip archive handler.
1142-
1143- Returns:
1144- The return code - 0 on success, negative number (< 0) on error.
1145-*/
1146+/**
1147+ * Closes a zip entry, flushes buffer and releases resources.
1148+ *
1149+ * @param zip zip archive handler.
1150+ *
1151+ * @return the return code - 0 on success, negative number (< 0) on error.
1152+ */
1153 extern int zip_entry_close(struct zip_t *zip);
1154
1155-/*
1156- Returns a local name of the current zip entry.
1157- The main difference between user's entry name and local entry name
1158- is optional relative path.
1159- Following .ZIP File Format Specification - the path stored MUST not contain
1160- a drive or device letter, or a leading slash.
1161- All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
1162- for compatibility with Amiga and UNIX file systems etc.
1163-
1164- Args:
1165- zip: zip archive handler.
1166-
1167- Returns:
1168- The pointer to the current zip entry name, or NULL on error.
1169-*/
1170+/**
1171+ * Returns a local name of the current zip entry.
1172+ *
1173+ * The main difference between user's entry name and local entry name
1174+ * is optional relative path.
1175+ * Following .ZIP File Format Specification - the path stored MUST not contain
1176+ * a drive or device letter, or a leading slash.
1177+ * All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
1178+ * for compatibility with Amiga and UNIX file systems etc.
1179+ *
1180+ * @param zip: zip archive handler.
1181+ *
1182+ * @return the pointer to the current zip entry name, or NULL on error.
1183+ */
1184 extern const char *zip_entry_name(struct zip_t *zip);
1185
1186-/*
1187- Returns an index of the current zip entry.
1188-
1189- Args:
1190- zip: zip archive handler.
1191-
1192- Returns:
1193- The index on success, negative number (< 0) on error.
1194-*/
1195+/**
1196+ * Returns an index of the current zip entry.
1197+ *
1198+ * @param zip zip archive handler.
1199+ *
1200+ * @return the index on success, negative number (< 0) on error.
1201+ */
1202 extern int zip_entry_index(struct zip_t *zip);
1203
1204-/*
1205- Determines if the current zip entry is a directory entry.
1206-
1207- Args:
1208- zip: zip archive handler.
1209-
1210- Returns:
1211- The return code - 1 (true), 0 (false), negative number (< 0) on error.
1212-*/
1213+/**
1214+ * Determines if the current zip entry is a directory entry.
1215+ *
1216+ * @param zip zip archive handler.
1217+ *
1218+ * @return the return code - 1 (true), 0 (false), negative number (< 0) on
1219+ * error.
1220+ */
1221 extern int zip_entry_isdir(struct zip_t *zip);
1222
1223-/*
1224- Returns an uncompressed size of the current zip entry.
1225-
1226- Args:
1227- zip: zip archive handler.
1228-
1229- Returns:
1230- The uncompressed size in bytes.
1231-*/
1232+/**
1233+ * Returns an uncompressed size of the current zip entry.
1234+ *
1235+ * @param zip zip archive handler.
1236+ *
1237+ * @return the uncompressed size in bytes.
1238+ */
1239 extern unsigned long long zip_entry_size(struct zip_t *zip);
1240
1241-/*
1242- Returns CRC-32 checksum of the current zip entry.
1243-
1244- Args:
1245- zip: zip archive handler.
1246-
1247- Returns:
1248- The CRC-32 checksum.
1249-*/
1250+/**
1251+ * Returns CRC-32 checksum of the current zip entry.
1252+ *
1253+ * @param zip zip archive handler.
1254+ *
1255+ * @return the CRC-32 checksum.
1256+ */
1257 extern unsigned int zip_entry_crc32(struct zip_t *zip);
1258
1259-/*
1260- Compresses an input buffer for the current zip entry.
1261-
1262- Args:
1263- zip: zip archive handler.
1264- buf: input buffer.
1265- bufsize: input buffer size (in bytes).
1266-
1267- Returns:
1268- The return code - 0 on success, negative number (< 0) on error.
1269-*/
1270+/**
1271+ * Compresses an input buffer for the current zip entry.
1272+ *
1273+ * @param zip zip archive handler.
1274+ * @param buf input buffer.
1275+ * @param bufsize input buffer size (in bytes).
1276+ *
1277+ * @return the return code - 0 on success, negative number (< 0) on error.
1278+ */
1279 extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
1280
1281-/*
1282- Compresses a file for the current zip entry.
1283-
1284- Args:
1285- zip: zip archive handler.
1286- filename: input file.
1287-
1288- Returns:
1289- The return code - 0 on success, negative number (< 0) on error.
1290-*/
1291+/**
1292+ * Compresses a file for the current zip entry.
1293+ *
1294+ * @param zip zip archive handler.
1295+ * @param filename input file.
1296+ *
1297+ * @return the return code - 0 on success, negative number (< 0) on error.
1298+ */
1299 extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
1300
1301-/*
1302- Extracts the current zip entry into output buffer.
1303- The function allocates sufficient memory for a output buffer.
1304-
1305- Args:
1306- zip: zip archive handler.
1307- buf: output buffer.
1308- bufsize: output buffer size (in bytes).
1309-
1310- Note:
1311- - remember to release memory allocated for a output buffer.
1312- - for large entries, please take a look at zip_entry_extract function.
1313-
1314- Returns:
1315- The return code - the number of bytes actually read on success.
1316- Otherwise a -1 on error.
1317-*/
1318+/**
1319+ * Extracts the current zip entry into output buffer.
1320+ *
1321+ * The function allocates sufficient memory for a output buffer.
1322+ *
1323+ * @param zip zip archive handler.
1324+ * @param buf output buffer.
1325+ * @param bufsize output buffer size (in bytes).
1326+ *
1327+ * @note remember to release memory allocated for a output buffer.
1328+ * for large entries, please take a look at zip_entry_extract function.
1329+ *
1330+ * @return the return code - the number of bytes actually read on success.
1331+ * Otherwise a -1 on error.
1332+ */
1333 extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
1334
1335-/*
1336- Extracts the current zip entry into a memory buffer using no memory
1337- allocation.
1338-
1339- Args:
1340- zip: zip archive handler.
1341- buf: preallocated output buffer.
1342- bufsize: output buffer size (in bytes).
1343-
1344- Note:
1345- - ensure supplied output buffer is large enough.
1346- - zip_entry_size function (returns uncompressed size for the current entry)
1347- can be handy to estimate how big buffer is needed.
1348- - for large entries, please take a look at zip_entry_extract function.
1349-
1350- Returns:
1351- The return code - the number of bytes actually read on success.
1352- Otherwise a -1 on error (e.g. bufsize is not large enough).
1353-*/
1354-extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize);
1355-
1356-/*
1357- Extracts the current zip entry into output file.
1358-
1359- Args:
1360- zip: zip archive handler.
1361- filename: output file.
1362-
1363- Returns:
1364- The return code - 0 on success, negative number (< 0) on error.
1365-*/
1366+/**
1367+ * Extracts the current zip entry into a memory buffer using no memory
1368+ * allocation.
1369+ *
1370+ * @param zip zip archive handler.
1371+ * @param buf preallocated output buffer.
1372+ * @param bufsize output buffer size (in bytes).
1373+ *
1374+ * @note ensure supplied output buffer is large enough.
1375+ * zip_entry_size function (returns uncompressed size for the current
1376+ * entry) can be handy to estimate how big buffer is needed. for large
1377+ * entries, please take a look at zip_entry_extract function.
1378+ *
1379+ * @return the return code - the number of bytes actually read on success.
1380+ * Otherwise a -1 on error (e.g. bufsize is not large enough).
1381+ */
1382+extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
1383+ size_t bufsize);
1384+
1385+/**
1386+ * Extracts the current zip entry into output file.
1387+ *
1388+ * @param zip zip archive handler.
1389+ * @param filename output file.
1390+ *
1391+ * @return the return code - 0 on success, negative number (< 0) on error.
1392+ */
1393 extern int zip_entry_fread(struct zip_t *zip, const char *filename);
1394
1395-/*
1396- Extracts the current zip entry using a callback function (on_extract).
1397-
1398- Args:
1399- zip: zip archive handler.
1400- on_extract: callback function.
1401- arg: opaque pointer (optional argument,
1402- which you can pass to the on_extract callback)
1403-
1404- Returns:
1405- The return code - 0 on success, negative number (< 0) on error.
1406+/**
1407+ * Extracts the current zip entry using a callback function (on_extract).
1408+ *
1409+ * @param zip zip archive handler.
1410+ * @param on_extract callback function.
1411+ * @param arg opaque pointer (optional argument, which you can pass to the
1412+ * on_extract callback)
1413+ *
1414+ * @return the return code - 0 on success, negative number (< 0) on error.
1415 */
1416 extern int
1417 zip_entry_extract(struct zip_t *zip,
1418@@ -262,53 +261,49 @@ zip_entry_extract(struct zip_t *zip,
1419 const void *data, size_t size),
1420 void *arg);
1421
1422-/*
1423- Returns the number of all entries (files and directories) in the zip archive.
1424-
1425- Args:
1426- zip: zip archive handler.
1427-
1428- Returns:
1429- The return code - the number of entries on success,
1430- negative number (< 0) on error.
1431-*/
1432+/**
1433+ * Returns the number of all entries (files and directories) in the zip archive.
1434+ *
1435+ * @param zip zip archive handler.
1436+ *
1437+ * @return the return code - the number of entries on success, negative number
1438+ * (< 0) on error.
1439+ */
1440 extern int zip_total_entries(struct zip_t *zip);
1441
1442-/*
1443- Creates a new archive and puts files into a single zip archive.
1444-
1445- Args:
1446- zipname: zip archive file.
1447- filenames: input files.
1448- len: number of input files.
1449-
1450- Returns:
1451- The return code - 0 on success, negative number (< 0) on error.
1452-*/
1453+/**
1454+ * Creates a new archive and puts files into a single zip archive.
1455+ *
1456+ * @param zipname zip archive file.
1457+ * @param filenames input files.
1458+ * @param len: number of input files.
1459+ *
1460+ * @return the return code - 0 on success, negative number (< 0) on error.
1461+ */
1462 extern int zip_create(const char *zipname, const char *filenames[], size_t len);
1463
1464-/*
1465- Extracts a zip archive file into directory.
1466-
1467- If on_extract_entry is not NULL, the callback will be called after
1468- successfully extracted each zip entry.
1469- Returning a negative value from the callback will cause abort and return an
1470- error. The last argument (void *arg) is optional, which you can use to pass
1471- data to the on_extract_entry callback.
1472-
1473- Args:
1474- zipname: zip archive file.
1475- dir: output directory.
1476- on_extract_entry: on extract callback.
1477- arg: opaque pointer.
1478-
1479- Returns:
1480- The return code - 0 on success, negative number (< 0) on error.
1481-*/
1482+/**
1483+ * Extracts a zip archive file into directory.
1484+ *
1485+ * If on_extract_entry is not NULL, the callback will be called after
1486+ * successfully extracted each zip entry.
1487+ * Returning a negative value from the callback will cause abort and return an
1488+ * error. The last argument (void *arg) is optional, which you can use to pass
1489+ * data to the on_extract_entry callback.
1490+ *
1491+ * @param zipname zip archive file.
1492+ * @param dir output directory.
1493+ * @param on_extract_entry on extract callback.
1494+ * @param arg opaque pointer.
1495+ *
1496+ * @return the return code - 0 on success, negative number (< 0) on error.
1497+ */
1498 extern int zip_extract(const char *zipname, const char *dir,
1499 int (*on_extract_entry)(const char *filename, void *arg),
1500 void *arg);
1501
1502+/** @} */
1503+
1504 #ifdef __cplusplus
1505 }
1506 #endif
1507diff --git a/contrib/zip/test/CMakeLists.txt b/contrib/zip/test/CMakeLists.txt
1508index 9b2a8db1..cc060b00 100644
1509--- a/contrib/zip/test/CMakeLists.txt
1510+++ b/contrib/zip/test/CMakeLists.txt
1511@@ -1,19 +1,16 @@
1512 cmake_minimum_required(VERSION 2.8)
1513
1514-if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
1515- if(ENABLE_COVERAGE)
1516- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g ")
1517- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
1518- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs")
1519- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage")
1520- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
1521- endif()
1522-endif ()
1523-
1524 # test
1525-include_directories(../src)
1526-add_executable(test.exe test.c ../src/zip.c)
1527-add_executable(test_miniz.exe test_miniz.c)
1528+set(test_out test.out)
1529+set(test_miniz_out test_miniz.out)
1530+
1531+add_executable(${test_out} test.c)
1532+target_link_libraries(${test_out} zip)
1533+add_executable(${test_miniz_out} test_miniz.c)
1534+target_link_libraries(${test_miniz_out} zip)
1535+
1536+add_test(NAME ${test_out} COMMAND ${test_out})
1537+add_test(NAME ${test_miniz_out} COMMAND ${test_miniz_out})
1538
1539-add_test(NAME test COMMAND test.exe)
1540-add_test(NAME test_miniz COMMAND test_miniz.exe)
1541+set(test_out ${test_out} PARENT_SCOPE)
1542+set(test_miniz_out ${test_miniz_out} PARENT_SCOPE)
1543diff --git a/contrib/zip/test/test.c b/contrib/zip/test/test.c
1544index 45443053..a9b2ddab 100644
1545--- a/contrib/zip/test/test.c
1546+++ b/contrib/zip/test/test.c
1547@@ -29,6 +29,8 @@
1548 #define XFILE "7.txt\0"
1549 #define XMODE 0100777
1550
1551+#define UNIXMODE 0100644
1552+
1553 #define UNUSED(x) (void)x
1554
1555 static int total_entries = 0;
1556@@ -102,7 +104,8 @@ static void test_read(void) {
1557 assert(0 == zip_entry_close(zip));
1558 free(buf);
1559 buf = NULL;
1560-
1561+ bufsize = 0;
1562+
1563 assert(0 == zip_entry_open(zip, "test/test-2.txt"));
1564 assert(strlen(TESTDATA2) == zip_entry_size(zip));
1565 assert(CRC32DATA2 == zip_entry_crc32(zip));
1566@@ -131,7 +134,8 @@ static void test_read(void) {
1567 assert(0 == zip_entry_close(zip));
1568 free(buf);
1569 buf = NULL;
1570-
1571+ bufsize = 0;
1572+
1573 buftmp = strlen(TESTDATA1);
1574 buf = calloc(buftmp, sizeof(char));
1575 assert(0 == zip_entry_open(zip, "test/test-1.txt"));
1576@@ -433,6 +437,35 @@ static void test_mtime(void) {
1577 remove(ZIPNAME);
1578 }
1579
1580+static void test_unix_permissions(void) {
1581+#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__)
1582+#else
1583+ // UNIX or APPLE
1584+ struct MZ_FILE_STAT_STRUCT file_stats;
1585+
1586+ remove(ZIPNAME);
1587+
1588+ struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
1589+ assert(zip != NULL);
1590+
1591+ assert(0 == zip_entry_open(zip, RFILE));
1592+ assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
1593+ assert(0 == zip_entry_close(zip));
1594+
1595+ zip_close(zip);
1596+
1597+ remove(RFILE);
1598+
1599+ assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
1600+
1601+ assert(0 == MZ_FILE_STAT(RFILE, &file_stats));
1602+ assert(UNIXMODE == file_stats.st_mode);
1603+
1604+ remove(RFILE);
1605+ remove(ZIPNAME);
1606+#endif
1607+}
1608+
1609 int main(int argc, char *argv[]) {
1610 UNUSED(argc);
1611 UNUSED(argv);
1612@@ -453,6 +486,7 @@ int main(int argc, char *argv[]) {
1613 test_write_permissions();
1614 test_exe_permissions();
1615 test_mtime();
1616+ test_unix_permissions();
1617
1618 remove(ZIPNAME);
1619 return 0;
1620diff --git a/contrib/zip/test/test_miniz.c b/contrib/zip/test/test_miniz.c
1621index ebc0564d..babcaecd 100644
1622--- a/contrib/zip/test/test_miniz.c
1623+++ b/contrib/zip/test/test_miniz.c
1624@@ -23,16 +23,39 @@ int main(int argc, char *argv[]) {
1625 uint step = 0;
1626 int cmp_status;
1627 uLong src_len = (uLong)strlen(s_pStr);
1628- uLong cmp_len = compressBound(src_len);
1629 uLong uncomp_len = src_len;
1630+ uLong cmp_len;
1631 uint8 *pCmp, *pUncomp;
1632+ size_t sz;
1633 uint total_succeeded = 0;
1634 (void)argc, (void)argv;
1635
1636 printf("miniz.c version: %s\n", MZ_VERSION);
1637
1638 do {
1639+ pCmp = (uint8 *)tdefl_compress_mem_to_heap(s_pStr, src_len, &cmp_len, 0);
1640+ if (!pCmp) {
1641+ printf("tdefl_compress_mem_to_heap failed\n");
1642+ return EXIT_FAILURE;
1643+ }
1644+ if (src_len <= cmp_len) {
1645+ printf("tdefl_compress_mem_to_heap failed: from %u to %u bytes\n",
1646+ (mz_uint32)uncomp_len, (mz_uint32)cmp_len);
1647+ free(pCmp);
1648+ return EXIT_FAILURE;
1649+ }
1650+
1651+ sz = tdefl_compress_mem_to_mem(pCmp, cmp_len, s_pStr, src_len, 0);
1652+ if (sz != cmp_len) {
1653+ printf("tdefl_compress_mem_to_mem failed: expected %u, got %u\n",
1654+ (mz_uint32)cmp_len, (mz_uint32)sz);
1655+ free(pCmp);
1656+ return EXIT_FAILURE;
1657+ }
1658+
1659 // Allocate buffers to hold compressed and uncompressed data.
1660+ free(pCmp);
1661+ cmp_len = compressBound(src_len);
1662 pCmp = (mz_uint8 *)malloc((size_t)cmp_len);
1663 pUncomp = (mz_uint8 *)malloc((size_t)src_len);
1664 if ((!pCmp) || (!pUncomp)) {