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