diff mbox series

[v2,3/4] package/assimp: fix build on musl

Message ID 20210128200436.4162618-3-fontaine.fabrice@gmail.com
State Accepted
Headers show
Series [v2,1/4] Revert "package/assimp: fix musl zlib/zip related compile failure" | expand

Commit Message

Fabrice Fontaine Jan. 28, 2021, 8:04 p.m. UTC
Fixes:
 - http://autobuild.buildroot.net/results/7c2db184ee200d1719308f38f42382bb39d8d5c6

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
---
 ...p-to-fix-gcc-build-for-v9-2-0-32-bit.patch | 1638 +++++++++++++++++
 ...oses-2954-upgrade-to-latest-greatest.patch |  243 +++
 2 files changed, 1881 insertions(+)
 create mode 100644 package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch
 create mode 100644 package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch

Comments

Arnout Vandecappelle May 20, 2021, 7:36 p.m. UTC | #1
I was about to apply, but then I noticed this...

On 28/01/2021 21:04, Fabrice Fontaine wrote:
> Fixes:
>  - http://autobuild.buildroot.net/results/7c2db184ee200d1719308f38f42382bb39d8d5c6
> 
> Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
> ---
>  ...p-to-fix-gcc-build-for-v9-2-0-32-bit.patch | 1638 +++++++++++++++++
>  ...oses-2954-upgrade-to-latest-greatest.patch |  243 +++
>  2 files changed, 1881 insertions(+)
>  create mode 100644 package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch
>  create mode 100644 package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch
> 
> diff --git a/package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch b/package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch
> new file mode 100644
> index 0000000000..4b86cc584f
> --- /dev/null
> +++ b/package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch
> @@ -0,0 +1,1638 @@
> +From f78446b14aff46db2ef27d062a275b6a01fd68b1 Mon Sep 17 00:00:00 2001
> +From: Kim Kulling <kim.kulling@googlemail.com>
> +Date: Tue, 19 Nov 2019 20:30:40 +0100
> +Subject: [PATCH] closes https://github.com/assimp/assimp/issues/2733: update
> + of zlip to fix gcc build for v9.2.0 32 bit
> +
> +[Retrieved (and updated to remove .gitignore and appveyor.yml) from:
> +https://github.com/assimp/assimp/commit/f78446b14aff46db2ef27d062a275b6a01fd68b1]
> +Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
> +---
> + contrib/zip/.gitignore          |   2 +
> + contrib/zip/CMakeLists.txt      |  83 +++++-
> + contrib/zip/README.md           |  12 +-
> + contrib/zip/appveyor.yml        |   2 +-
> + contrib/zip/src/miniz.h         | 457 ++++++++++++++++++++++++++++----
> + contrib/zip/src/zip.c           |  62 +++--
> + contrib/zip/src/zip.h           | 457 ++++++++++++++++----------------
> + contrib/zip/test/CMakeLists.txt |  27 +-
> + contrib/zip/test/test.c         |  38 ++-
> + contrib/zip/test/test_miniz.c   |  25 +-

 This patch (and the other one) only affects contrib/zip.

 However, top-level CMakeLists.txt has this:
  IF ( NOT ASSIMP_BUILD_ZLIB )
    FIND_PACKAGE(ZLIB)
  ENDIF( NOT ASSIMP_BUILD_ZLIB )

  IF( NOT ZLIB_FOUND )
    MESSAGE(STATUS "compiling zlib from sources")
    ...
    # compile from sources
    ADD_SUBDIRECTORY(contrib/zlib)
  ELSE(NOT ZLIB_FOUND)
    ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
    SET(ZLIB_LIBRARIES_LINKED -lz)
  ENDIF(NOT ZLIB_FOUND)

Since we have a dependency on zlib, the contrib/zip code should never be used!

So, either there is something wrong somewhere and zlib is not found. Or these
patches don't do anything useful. (Or, of course, I'm missing something.)


 I realize it's months ago, but perhaps you can shed some light?

 Regards,
 Arnout


> + 10 files changed, 821 insertions(+), 344 deletions(-)
> +
> +diff --git a/contrib/zip/CMakeLists.txt b/contrib/zip/CMakeLists.txt
> +index b46dbb1db0..77916d2e14 100644
> +--- a/contrib/zip/CMakeLists.txt
> ++++ b/contrib/zip/CMakeLists.txt
> +@@ -1,10 +1,14 @@
> +-cmake_minimum_required(VERSION 2.8)
> +-project(zip)
> +-enable_language(C)
> ++cmake_minimum_required(VERSION 3.0)
> ++
> ++project(zip
> ++  LANGUAGES C
> ++  VERSION "0.1.15")
> + set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
> + 
> ++option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
> ++
> + if (MSVC)
> +-  # Use secure functions by defaualt and suppress warnings about "deprecated" functions
> ++  # Use secure functions by default and suppress warnings about "deprecated" functions
> +   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1")
> +   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
> +   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
> +@@ -12,28 +16,80 @@ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
> +         "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
> +         "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
> +   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic")
> ++  if(ENABLE_COVERAGE)
> ++    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
> ++    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
> ++  endif()
> + endif (MSVC)
> + 
> + # zip
> + set(SRC src/miniz.h src/zip.h src/zip.c)
> + add_library(${PROJECT_NAME} ${SRC})
> +-target_include_directories(${PROJECT_NAME} INTERFACE src)
> ++target_include_directories(${PROJECT_NAME} PUBLIC
> ++  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
> ++  $<INSTALL_INTERFACE:include>
> ++)
> + 
> + # test
> + if (NOT CMAKE_DISABLE_TESTING)
> +   enable_testing()
> +   add_subdirectory(test)
> +   find_package(Sanitizers)
> +-  add_sanitizers(${PROJECT_NAME} test.exe)
> +-  add_sanitizers(${PROJECT_NAME} test_miniz.exe)
> ++  add_sanitizers(${PROJECT_NAME} ${test_out} ${test_miniz_out})
> + endif()
> + 
> ++####
> ++# Installation (https://github.com/forexample/package-example) {
> ++
> ++set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
> ++set(INCLUDE_INSTALL_DIR "include")
> ++
> ++set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
> ++
> ++# Configuration
> ++set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
> ++set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
> ++set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
> ++set(NAMESPACE "${PROJECT_NAME}::")
> ++
> ++# Include module with fuction 'write_basic_package_version_file'
> ++include(CMakePackageConfigHelpers)
> ++
> ++# Note: PROJECT_VERSION is used as a VERSION
> ++write_basic_package_version_file(
> ++    "${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion
> ++)
> ++
> ++# Use variables:
> ++#   * TARGETS_EXPORT_NAME
> ++#   * PROJECT_NAME
> ++configure_package_config_file(
> ++    "cmake/Config.cmake.in"
> ++    "${PROJECT_CONFIG}"
> ++    INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
> ++)
> ++
> ++install(
> ++    FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
> ++    DESTINATION "${CONFIG_INSTALL_DIR}"
> ++)
> ++
> ++install(
> ++    EXPORT "${TARGETS_EXPORT_NAME}"
> ++    NAMESPACE "${NAMESPACE}"
> ++    DESTINATION "${CONFIG_INSTALL_DIR}"
> ++)
> ++
> ++# }
> ++
> + install(TARGETS ${PROJECT_NAME}
> ++        EXPORT ${TARGETS_EXPORT_NAME}
> +         RUNTIME DESTINATION bin
> +         ARCHIVE DESTINATION lib
> +         LIBRARY DESTINATION lib
> +-        COMPONENT library)
> +-install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION include)
> ++        INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR}
> ++)
> ++install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION ${INCLUDE_INSTALL_DIR}/zip)
> + 
> + # uninstall target (https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake)
> + if(NOT TARGET uninstall)
> +@@ -45,3 +101,12 @@ if(NOT TARGET uninstall)
> +     add_custom_target(uninstall
> +         COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
> + endif()
> ++
> ++find_package(Doxygen)
> ++if(DOXYGEN_FOUND)
> ++    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
> ++    add_custom_target(doc
> ++        ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
> ++        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
> ++        COMMENT "Generating API documentation with Doxygen" VERBATIM)
> ++endif()
> +diff --git a/contrib/zip/README.md b/contrib/zip/README.md
> +index d5fb8cd203..14eb9a34c8 100644
> +--- a/contrib/zip/README.md
> ++++ b/contrib/zip/README.md
> +@@ -71,7 +71,7 @@ int arg = 2;
> + zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
> + ```
> + 
> +-*   Extract a zip entry into memory.
> ++* Extract a zip entry into memory.
> + ```c
> + void *buf = NULL;
> + size_t bufsize;
> +@@ -89,7 +89,7 @@ zip_close(zip);
> + free(buf);
> + ```
> + 
> +-*   Extract a zip entry into memory (no internal allocation).
> ++* Extract a zip entry into memory (no internal allocation).
> + ```c
> + unsigned char *buf;
> + size_t bufsize;
> +@@ -110,7 +110,7 @@ zip_close(zip);
> + free(buf);
> + ```
> + 
> +-*   Extract a zip entry into memory using callback.
> ++* Extract a zip entry into memory using callback.
> + ```c
> + struct buffer_t {
> +     char *data;
> +@@ -144,7 +144,7 @@ free(buf.data);
> + ```
> + 
> + 
> +-*   Extract a zip entry into a file.
> ++* Extract a zip entry into a file.
> + ```c
> + struct zip_t *zip = zip_open("foo.zip", 0, 'r');
> + {
> +@@ -157,7 +157,7 @@ struct zip_t *zip = zip_open("foo.zip", 0, 'r');
> + zip_close(zip);
> + ```
> + 
> +-*   List of all zip entries
> ++* List of all zip entries
> + ```c
> + struct zip_t *zip = zip_open("foo.zip", 0, 'r');
> + int i, n = zip_total_entries(zip);
> +@@ -174,7 +174,7 @@ for (i = 0; i < n; ++i) {
> + zip_close(zip);
> + ```
> + 
> +-## Bindings
> ++# Bindings
> + Compile zip library as a dynamic library.
> + ```shell
> + $ mkdir build
> +diff --git a/contrib/zip/src/miniz.h b/contrib/zip/src/miniz.h
> +index 2c27a94d8d..c4fcfb83e6 100644
> +--- a/contrib/zip/src/miniz.h
> ++++ b/contrib/zip/src/miniz.h
> +@@ -221,6 +221,7 @@
> + #ifndef MINIZ_HEADER_INCLUDED
> + #define MINIZ_HEADER_INCLUDED
> + 
> ++#include <stdint.h>
> + #include <stdlib.h>
> + 
> + // Defines to completely disable specific portions of miniz.c:
> +@@ -284,7 +285,8 @@
> + /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */
> + #if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES)
> + #if MINIZ_X86_OR_X64_CPU
> +-/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */
> ++/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
> ++ * integer loads and stores from unaligned addresses. */
> + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
> + #define MINIZ_UNALIGNED_USE_MEMCPY
> + #else
> +@@ -354,6 +356,44 @@ enum {
> +   MZ_FIXED = 4
> + };
> + 
> ++/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or
> ++ * modify this enum. */
> ++typedef enum {
> ++  MZ_ZIP_NO_ERROR = 0,
> ++  MZ_ZIP_UNDEFINED_ERROR,
> ++  MZ_ZIP_TOO_MANY_FILES,
> ++  MZ_ZIP_FILE_TOO_LARGE,
> ++  MZ_ZIP_UNSUPPORTED_METHOD,
> ++  MZ_ZIP_UNSUPPORTED_ENCRYPTION,
> ++  MZ_ZIP_UNSUPPORTED_FEATURE,
> ++  MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,
> ++  MZ_ZIP_NOT_AN_ARCHIVE,
> ++  MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,
> ++  MZ_ZIP_UNSUPPORTED_MULTIDISK,
> ++  MZ_ZIP_DECOMPRESSION_FAILED,
> ++  MZ_ZIP_COMPRESSION_FAILED,
> ++  MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,
> ++  MZ_ZIP_CRC_CHECK_FAILED,
> ++  MZ_ZIP_UNSUPPORTED_CDIR_SIZE,
> ++  MZ_ZIP_ALLOC_FAILED,
> ++  MZ_ZIP_FILE_OPEN_FAILED,
> ++  MZ_ZIP_FILE_CREATE_FAILED,
> ++  MZ_ZIP_FILE_WRITE_FAILED,
> ++  MZ_ZIP_FILE_READ_FAILED,
> ++  MZ_ZIP_FILE_CLOSE_FAILED,
> ++  MZ_ZIP_FILE_SEEK_FAILED,
> ++  MZ_ZIP_FILE_STAT_FAILED,
> ++  MZ_ZIP_INVALID_PARAMETER,
> ++  MZ_ZIP_INVALID_FILENAME,
> ++  MZ_ZIP_BUF_TOO_SMALL,
> ++  MZ_ZIP_INTERNAL_ERROR,
> ++  MZ_ZIP_FILE_NOT_FOUND,
> ++  MZ_ZIP_ARCHIVE_TOO_LARGE,
> ++  MZ_ZIP_VALIDATION_FAILED,
> ++  MZ_ZIP_WRITE_CALLBACK_FAILED,
> ++  MZ_ZIP_TOTAL_ERRORS
> ++} mz_zip_error;
> ++
> + // Method
> + #define MZ_DEFLATED 8
> + 
> +@@ -696,6 +736,7 @@ typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
> +                                     void *pBuf, size_t n);
> + typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
> +                                      const void *pBuf, size_t n);
> ++typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);
> + 
> + struct mz_zip_internal_state_tag;
> + typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
> +@@ -707,13 +748,27 @@ typedef enum {
> +   MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
> + } mz_zip_mode;
> + 
> +-typedef struct mz_zip_archive_tag {
> ++typedef enum {
> ++  MZ_ZIP_TYPE_INVALID = 0,
> ++  MZ_ZIP_TYPE_USER,
> ++  MZ_ZIP_TYPE_MEMORY,
> ++  MZ_ZIP_TYPE_HEAP,
> ++  MZ_ZIP_TYPE_FILE,
> ++  MZ_ZIP_TYPE_CFILE,
> ++  MZ_ZIP_TOTAL_TYPES
> ++} mz_zip_type;
> ++
> ++typedef struct {
> +   mz_uint64 m_archive_size;
> +   mz_uint64 m_central_directory_file_ofs;
> +-  mz_uint m_total_files;
> ++
> ++  /* We only support up to UINT32_MAX files in zip64 mode. */
> ++  mz_uint32 m_total_files;
> +   mz_zip_mode m_zip_mode;
> ++  mz_zip_type m_zip_type;
> ++  mz_zip_error m_last_error;
> + 
> +-  mz_uint m_file_offset_alignment;
> ++  mz_uint64 m_file_offset_alignment;
> + 
> +   mz_alloc_func m_pAlloc;
> +   mz_free_func m_pFree;
> +@@ -722,6 +777,7 @@ typedef struct mz_zip_archive_tag {
> + 
> +   mz_file_read_func m_pRead;
> +   mz_file_write_func m_pWrite;
> ++  mz_file_needs_keepalive m_pNeeds_keepalive;
> +   void *m_pIO_opaque;
> + 
> +   mz_zip_internal_state *m_pState;
> +@@ -1263,6 +1319,9 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
> +                                                 int strategy);
> + #endif // #ifndef MINIZ_NO_ZLIB_APIS
> + 
> ++#define MZ_UINT16_MAX (0xFFFFU)
> ++#define MZ_UINT32_MAX (0xFFFFFFFFU)
> ++
> + #ifdef __cplusplus
> + }
> + #endif
> +@@ -1311,6 +1370,11 @@ typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
> +    ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
> + #endif
> + 
> ++#define MZ_READ_LE64(p)                                                        \
> ++  (((mz_uint64)MZ_READ_LE32(p)) |                                              \
> ++   (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32)))       \
> ++    << 32U))
> ++
> + #ifdef _MSC_VER
> + #define MZ_FORCEINLINE __forceinline
> + #elif defined(__GNUC__)
> +@@ -4160,6 +4224,17 @@ enum {
> +   MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
> +   MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
> +   MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
> ++
> ++  /* ZIP64 archive identifier and record sizes */
> ++  MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,
> ++  MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,
> ++  MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,
> ++  MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,
> ++  MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,
> ++  MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,
> ++  MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,
> ++  MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,
> ++
> +   // Central directory header record offsets
> +   MZ_ZIP_CDH_SIG_OFS = 0,
> +   MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
> +@@ -4199,6 +4274,31 @@ enum {
> +   MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
> +   MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
> +   MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
> ++
> ++  /* ZIP64 End of central directory locator offsets */
> ++  MZ_ZIP64_ECDL_SIG_OFS = 0,                    /* 4 bytes */
> ++  MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4,          /* 4 bytes */
> ++  MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8,  /* 8 bytes */
> ++  MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */
> ++
> ++  /* ZIP64 End of central directory header offsets */
> ++  MZ_ZIP64_ECDH_SIG_OFS = 0,                       /* 4 bytes */
> ++  MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4,            /* 8 bytes */
> ++  MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12,          /* 2 bytes */
> ++  MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14,           /* 2 bytes */
> ++  MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16,            /* 4 bytes */
> ++  MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20,            /* 4 bytes */
> ++  MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */
> ++  MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32,       /* 8 bytes */
> ++  MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40,                /* 8 bytes */
> ++  MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48,                 /* 8 bytes */
> ++  MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,
> ++  MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,
> ++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,
> ++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,
> ++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,
> ++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,
> ++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11
> + };
> + 
> + typedef struct {
> +@@ -4211,7 +4311,24 @@ struct mz_zip_internal_state_tag {
> +   mz_zip_array m_central_dir;
> +   mz_zip_array m_central_dir_offsets;
> +   mz_zip_array m_sorted_central_dir_offsets;
> ++
> ++  /* The flags passed in when the archive is initially opened. */
> ++  uint32_t m_init_flags;
> ++
> ++  /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc.
> ++   */
> ++  mz_bool m_zip64;
> ++
> ++  /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64
> ++   * will also be slammed to true too, even if we didn't find a zip64 end of
> ++   * central dir header, etc.) */
> ++  mz_bool m_zip64_has_extended_info_fields;
> ++
> ++  /* These fields are used by the file, FILE, memory, and memory/heap read/write
> ++   * helpers. */
> +   MZ_FILE *m_pFile;
> ++  mz_uint64 m_file_archive_start_ofs;
> ++
> +   void *m_pMem;
> +   size_t m_mem_size;
> +   size_t m_mem_capacity;
> +@@ -4363,6 +4480,13 @@ static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time,
> + #endif /* #ifndef MINIZ_NO_STDIO */
> + #endif /* #ifndef MINIZ_NO_TIME */
> + 
> ++static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip,
> ++                                               mz_zip_error err_num) {
> ++  if (pZip)
> ++    pZip->m_last_error = err_num;
> ++  return MZ_FALSE;
> ++}
> ++
> + static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
> +                                            mz_uint32 flags) {
> +   (void)flags;
> +@@ -4480,127 +4604,346 @@ mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) {
> +   }
> + }
> + 
> +-static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
> +-                                              mz_uint32 flags) {
> +-  mz_uint cdir_size, num_this_disk, cdir_disk_index;
> +-  mz_uint64 cdir_ofs;
> ++static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip,
> ++                                               mz_uint32 record_sig,
> ++                                               mz_uint32 record_size,
> ++                                               mz_int64 *pOfs) {
> +   mz_int64 cur_file_ofs;
> +-  const mz_uint8 *p;
> +   mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
> +   mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
> +-  mz_bool sort_central_dir =
> +-      ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
> +-  // Basic sanity checks - reject files which are too small, and check the first
> +-  // 4 bytes of the file to make sure a local header is there.
> +-  if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
> ++
> ++  /* Basic sanity checks - reject files which are too small */
> ++  if (pZip->m_archive_size < record_size)
> +     return MZ_FALSE;
> +-  // Find the end of central directory record by scanning the file from the end
> +-  // towards the beginning.
> ++
> ++  /* Find the record by scanning the file from the end towards the beginning. */
> +   cur_file_ofs =
> +       MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
> +   for (;;) {
> +     int i,
> +         n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
> ++
> +     if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
> +       return MZ_FALSE;
> +-    for (i = n - 4; i >= 0; --i)
> +-      if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
> +-        break;
> ++
> ++    for (i = n - 4; i >= 0; --i) {
> ++      mz_uint s = MZ_READ_LE32(pBuf + i);
> ++      if (s == record_sig) {
> ++        if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)
> ++          break;
> ++      }
> ++    }
> ++
> +     if (i >= 0) {
> +       cur_file_ofs += i;
> +       break;
> +     }
> ++
> ++    /* Give up if we've searched the entire file, or we've gone back "too far"
> ++     * (~64kb) */
> +     if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
> +-                            (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
> ++                            (MZ_UINT16_MAX + record_size)))
> +       return MZ_FALSE;
> ++
> +     cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
> +   }
> +-  // Read and verify the end of central directory record.
> ++
> ++  *pOfs = cur_file_ofs;
> ++  return MZ_TRUE;
> ++}
> ++
> ++static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
> ++                                              mz_uint flags) {
> ++  mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0,
> ++          cdir_disk_index = 0;
> ++  mz_uint64 cdir_ofs = 0;
> ++  mz_int64 cur_file_ofs = 0;
> ++  const mz_uint8 *p;
> ++
> ++  mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
> ++  mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
> ++  mz_bool sort_central_dir =
> ++      ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
> ++  mz_uint32 zip64_end_of_central_dir_locator_u32
> ++      [(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) /
> ++       sizeof(mz_uint32)];
> ++  mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;
> ++
> ++  mz_uint32 zip64_end_of_central_dir_header_u32
> ++      [(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
> ++       sizeof(mz_uint32)];
> ++  mz_uint8 *pZip64_end_of_central_dir =
> ++      (mz_uint8 *)zip64_end_of_central_dir_header_u32;
> ++
> ++  mz_uint64 zip64_end_of_central_dir_ofs = 0;
> ++
> ++  /* Basic sanity checks - reject files which are too small, and check the first
> ++   * 4 bytes of the file to make sure a local header is there. */
> ++  if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
> ++    return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
> ++
> ++  if (!mz_zip_reader_locate_header_sig(
> ++          pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG,
> ++          MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))
> ++    return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);
> ++
> ++  /* Read and verify the end of central directory record. */
> +   if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
> +                     MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
> +       MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
> +-    return MZ_FALSE;
> +-  if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
> +-       MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
> +-      ((pZip->m_total_files =
> +-            MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) !=
> +-       MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
> +-    return MZ_FALSE;
> ++    return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
> ++
> ++  if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
> ++      MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
> ++    return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
> ++
> ++  if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE +
> ++                       MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) {
> ++    if (pZip->m_pRead(pZip->m_pIO_opaque,
> ++                      cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE,
> ++                      pZip64_locator,
> ++                      MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ==
> ++        MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) {
> ++      if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) ==
> ++          MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) {
> ++        zip64_end_of_central_dir_ofs = MZ_READ_LE64(
> ++            pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);
> ++        if (zip64_end_of_central_dir_ofs >
> ++            (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
> ++          return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
> ++
> ++        if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs,
> ++                          pZip64_end_of_central_dir,
> ++                          MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ==
> ++            MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) {
> ++          if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) ==
> ++              MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) {
> ++            pZip->m_pState->m_zip64 = MZ_TRUE;
> ++          }
> ++        }
> ++      }
> ++    }
> ++  }
> + 
> ++  pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);
> ++  cdir_entries_on_this_disk =
> ++      MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
> +   num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
> +   cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
> ++  cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);
> ++  cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
> ++
> ++  if (pZip->m_pState->m_zip64) {
> ++    mz_uint32 zip64_total_num_of_disks =
> ++        MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);
> ++    mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(
> ++        pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);
> ++    mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(
> ++        pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
> ++    mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(
> ++        pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);
> ++    mz_uint64 zip64_size_of_central_directory =
> ++        MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);
> ++
> ++    if (zip64_size_of_end_of_central_dir_record <
> ++        (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))
> ++      return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
> ++
> ++    if (zip64_total_num_of_disks != 1U)
> ++      return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
> ++
> ++    /* Check for miniz's practical limits */
> ++    if (zip64_cdir_total_entries > MZ_UINT32_MAX)
> ++      return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
> ++
> ++    pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;
> ++
> ++    if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)
> ++      return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
> ++
> ++    cdir_entries_on_this_disk =
> ++        (mz_uint32)zip64_cdir_total_entries_on_this_disk;
> ++
> ++    /* Check for miniz's current practical limits (sorry, this should be enough
> ++     * for millions of files) */
> ++    if (zip64_size_of_central_directory > MZ_UINT32_MAX)
> ++      return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
> ++
> ++    cdir_size = (mz_uint32)zip64_size_of_central_directory;
> ++
> ++    num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir +
> ++                                 MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);
> ++
> ++    cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir +
> ++                                   MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);
> ++
> ++    cdir_ofs =
> ++        MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);
> ++  }
> ++
> ++  if (pZip->m_total_files != cdir_entries_on_this_disk)
> ++    return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
> ++
> +   if (((num_this_disk | cdir_disk_index) != 0) &&
> +       ((num_this_disk != 1) || (cdir_disk_index != 1)))
> +-    return MZ_FALSE;
> ++    return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
> + 
> +-  if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) <
> +-      pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
> +-    return MZ_FALSE;
> ++  if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
> ++    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
> + 
> +-  cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
> +   if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
> +-    return MZ_FALSE;
> ++    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
> + 
> +   pZip->m_central_directory_file_ofs = cdir_ofs;
> + 
> +   if (pZip->m_total_files) {
> +     mz_uint i, n;
> +-
> +-    // Read the entire central directory into a heap block, and allocate another
> +-    // heap block to hold the unsorted central dir file record offsets, and
> +-    // another to hold the sorted indices.
> ++    /* Read the entire central directory into a heap block, and allocate another
> ++     * heap block to hold the unsorted central dir file record offsets, and
> ++     * possibly another to hold the sorted indices. */
> +     if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
> +                               MZ_FALSE)) ||
> +         (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
> +                               pZip->m_total_files, MZ_FALSE)))
> +-      return MZ_FALSE;
> ++      return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
> + 
> +     if (sort_central_dir) {
> +       if (!mz_zip_array_resize(pZip,
> +                                &pZip->m_pState->m_sorted_central_dir_offsets,
> +                                pZip->m_total_files, MZ_FALSE))
> +-        return MZ_FALSE;
> ++        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
> +     }
> + 
> +     if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
> +                       pZip->m_pState->m_central_dir.m_p,
> +                       cdir_size) != cdir_size)
> +-      return MZ_FALSE;
> ++      return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
> + 
> +-    // Now create an index into the central directory file records, do some
> +-    // basic sanity checking on each record, and check for zip64 entries (which
> +-    // are not yet supported).
> ++    /* Now create an index into the central directory file records, do some
> ++     * basic sanity checking on each record */
> +     p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
> +     for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
> +-      mz_uint total_header_size, comp_size, decomp_size, disk_index;
> ++      mz_uint total_header_size, disk_index, bit_flags, filename_size,
> ++          ext_data_size;
> ++      mz_uint64 comp_size, decomp_size, local_header_ofs;
> ++
> +       if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
> +           (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
> +-        return MZ_FALSE;
> ++        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
> ++
> +       MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
> +                            i) =
> +           (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
> ++
> +       if (sort_central_dir)
> +         MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
> +                              mz_uint32, i) = i;
> ++
> +       comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
> +       decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
> +-      if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
> +-           (decomp_size != comp_size)) ||
> +-          (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) ||
> +-          (comp_size == 0xFFFFFFFF))
> +-        return MZ_FALSE;
> ++      local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
> ++      filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
> ++      ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
> ++
> ++      if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&
> ++          (ext_data_size) &&
> ++          (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) ==
> ++           MZ_UINT32_MAX)) {
> ++        /* Attempt to find zip64 extended information field in the entry's extra
> ++         * data */
> ++        mz_uint32 extra_size_remaining = ext_data_size;
> ++
> ++        if (extra_size_remaining) {
> ++          const mz_uint8 *pExtra_data;
> ++          void *buf = NULL;
> ++
> ++          if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size >
> ++              n) {
> ++            buf = MZ_MALLOC(ext_data_size);
> ++            if (buf == NULL)
> ++              return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
> ++
> ++            if (pZip->m_pRead(pZip->m_pIO_opaque,
> ++                              cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
> ++                                  filename_size,
> ++                              buf, ext_data_size) != ext_data_size) {
> ++              MZ_FREE(buf);
> ++              return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
> ++            }
> ++
> ++            pExtra_data = (mz_uint8 *)buf;
> ++          } else {
> ++            pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
> ++          }
> ++
> ++          do {
> ++            mz_uint32 field_id;
> ++            mz_uint32 field_data_size;
> ++
> ++            if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
> ++              MZ_FREE(buf);
> ++              return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
> ++            }
> ++
> ++            field_id = MZ_READ_LE16(pExtra_data);
> ++            field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
> ++
> ++            if ((field_data_size + sizeof(mz_uint16) * 2) >
> ++                extra_size_remaining) {
> ++              MZ_FREE(buf);
> ++              return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
> ++            }
> ++
> ++            if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
> ++              /* Ok, the archive didn't have any zip64 headers but it uses a
> ++               * zip64 extended information field so mark it as zip64 anyway
> ++               * (this can occur with infozip's zip util when it reads
> ++               * compresses files from stdin). */
> ++              pZip->m_pState->m_zip64 = MZ_TRUE;
> ++              pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;
> ++              break;
> ++            }
> ++
> ++            pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
> ++            extra_size_remaining =
> ++                extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
> ++          } while (extra_size_remaining);
> ++
> ++          MZ_FREE(buf);
> ++        }
> ++      }
> ++
> ++      /* I've seen archives that aren't marked as zip64 that uses zip64 ext
> ++       * data, argh */
> ++      if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) {
> ++        if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
> ++             (decomp_size != comp_size)) ||
> ++            (decomp_size && !comp_size))
> ++          return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
> ++      }
> ++
> +       disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
> +-      if ((disk_index != num_this_disk) && (disk_index != 1))
> +-        return MZ_FALSE;
> +-      if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
> +-           MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
> +-        return MZ_FALSE;
> ++      if ((disk_index == MZ_UINT16_MAX) ||
> ++          ((disk_index != num_this_disk) && (disk_index != 1)))
> ++        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
> ++
> ++      if (comp_size != MZ_UINT32_MAX) {
> ++        if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
> ++             MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
> ++          return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
> ++      }
> ++
> ++      bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
> ++      if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)
> ++        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
> ++
> +       if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
> +                                MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
> +                                MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
> +                                MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
> +           n)
> +-        return MZ_FALSE;
> ++        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
> ++
> +       n -= total_header_size;
> +       p += total_header_size;
> +     }
> +diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c
> +index ff3a8fe1e6..1abcfd8fd1 100644
> +--- a/contrib/zip/src/zip.c
> ++++ b/contrib/zip/src/zip.c
> +@@ -24,7 +24,6 @@
> +   ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) &&   \
> +    (P)[1] == ':')
> + #define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0)
> +-#define ISSLASH(C) ((C) == '/' || (C) == '\\')
> + 
> + #else
> + 
> +@@ -48,7 +47,7 @@ int symlink(const char *target, const char *linkpath); // needed on Linux
> + #endif
> + 
> + #ifndef ISSLASH
> +-#define ISSLASH(C) ((C) == '/')
> ++#define ISSLASH(C) ((C) == '/' || (C) == '\\')
> + #endif
> + 
> + #define CLEANUP(ptr)                                                           \
> +@@ -78,26 +77,34 @@ static const char *base_name(const char *name) {
> +   return base;
> + }
> + 
> +-static int mkpath(const char *path) {
> +-  char const *p;
> ++static int mkpath(char *path) {
> ++  char *p;
> +   char npath[MAX_PATH + 1];
> +   int len = 0;
> +   int has_device = HAS_DEVICE(path);
> + 
> +   memset(npath, 0, MAX_PATH + 1);
> +-
> +-#ifdef _WIN32
> +-  // only on windows fix the path
> +-  npath[0] = path[0];
> +-  npath[1] = path[1];
> +-  len = 2;
> +-#endif // _WIN32
> +-    
> ++  if (has_device) {
> ++    // only on windows
> ++    npath[0] = path[0];
> ++    npath[1] = path[1];
> ++    len = 2;
> ++  }
> +   for (p = path + len; *p && len < MAX_PATH; p++) {
> +     if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) {
> +-      if (MKDIR(npath) == -1)
> +-        if (errno != EEXIST)
> ++#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) ||              \
> ++    defined(__MINGW32__)
> ++#else
> ++      if ('\\' == *p) {
> ++        *p = '/';
> ++      }
> ++#endif
> ++
> ++      if (MKDIR(npath) == -1) {
> ++        if (errno != EEXIST) {
> +           return -1;
> ++        }
> ++      }
> +     }
> +     npath[len++] = *p;
> +   }
> +@@ -279,7 +286,14 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
> +   zip->entry.header_offset = zip->archive.m_archive_size;
> +   memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
> +   zip->entry.method = 0;
> ++
> ++  // UNIX or APPLE
> ++#if MZ_PLATFORM == 3 || MZ_PLATFORM == 19
> ++  // regular file with rw-r--r-- persmissions
> ++  zip->entry.external_attr = (mz_uint32)(0100644) << 16;
> ++#else
> +   zip->entry.external_attr = 0;
> ++#endif
> + 
> +   num_alignment_padding_bytes =
> +       mz_zip_writer_compute_padding_needed_for_file_alignment(pzip);
> +@@ -660,7 +674,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
> +   }
> + 
> +   if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index,
> +-  buf, bufsize, 0, NULL,  0)) {
> ++                                             buf, bufsize, 0, NULL, 0)) {
> +     return -1;
> +   }
> + 
> +@@ -670,10 +684,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
> + int zip_entry_fread(struct zip_t *zip, const char *filename) {
> +   mz_zip_archive *pzip = NULL;
> +   mz_uint idx;
> +-#if defined(_MSC_VER)
> +-#else
> +   mz_uint32 xattr = 0;
> +-#endif
> +   mz_zip_archive_file_stat info;
> + 
> +   if (!zip) {
> +@@ -875,12 +886,19 @@ int zip_extract(const char *zipname, const char *dir,
> +       goto out;
> +     }
> + 
> +-    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)
> +-        && info.m_external_attr & (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40 is directory)
> ++    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)
> ++        && info.m_external_attr &
> ++               (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40
> ++                               // is directory)
> + #if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) ||              \
> +     defined(__MINGW32__)
> +-#else      
> +-      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)) {
> ++#else
> ++      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)) {
> +         goto out;
> +       }
> +       symlink_to[info.m_uncomp_size] = '\0';
> +diff --git a/contrib/zip/src/zip.h b/contrib/zip/src/zip.h
> +index 5f39df50ad..a48d64d6de 100644
> +--- a/contrib/zip/src/zip.h
> ++++ b/contrib/zip/src/zip.h
> +@@ -20,241 +20,240 @@ extern "C" {
> + #endif
> + 
> + #if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) &&               \
> +-    !defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(__ssize_t_defined)
> +-#define _SSIZE_T
> ++    !defined(__DEFINED_ssize_t) && !defined(__ssize_t_defined) &&              \
> ++    !defined(_SSIZE_T) && !defined(_SSIZE_T_)
> ++
> + // 64-bit Windows is the only mainstream platform
> + // where sizeof(long) != sizeof(void*)
> + #ifdef _WIN64
> +-typedef long long  ssize_t;  /* byte count or error */
> ++typedef long long ssize_t; /* byte count or error */
> + #else
> +-typedef long  ssize_t;  /* byte count or error */
> ++typedef long ssize_t; /* byte count or error */
> + #endif
> ++
> ++#define _SSIZE_T_DEFINED
> ++#define _SSIZE_T_DEFINED_
> ++#define __DEFINED_ssize_t
> ++#define __ssize_t_defined
> ++#define _SSIZE_T
> ++#define _SSIZE_T_
> ++
> + #endif
> + 
> + #ifndef MAX_PATH
> + #define MAX_PATH 32767 /* # chars in a path name including NULL */
> + #endif
> + 
> ++/**
> ++ * @mainpage
> ++ *
> ++ * Documenation for @ref zip.
> ++ */
> ++
> ++/**
> ++ * @addtogroup zip
> ++ * @{
> ++ */
> ++
> ++/**
> ++ * Default zip compression level.
> ++ */
> ++
> + #define ZIP_DEFAULT_COMPRESSION_LEVEL 6
> + 
> +-/*
> +-  This data structure is used throughout the library to represent zip archive
> +-  - forward declaration.
> +-*/
> ++/**
> ++ * @struct zip_t
> ++ *
> ++ * This data structure is used throughout the library to represent zip archive -
> ++ * forward declaration.
> ++ */
> + struct zip_t;
> + 
> +-/*
> +-  Opens zip archive with compression level using the given mode.
> +-
> +-  Args:
> +-    zipname: zip archive file name.
> +-    level: compression level (0-9 are the standard zlib-style levels).
> +-    mode: file access mode.
> +-        'r': opens a file for reading/extracting (the file must exists).
> +-        'w': creates an empty file for writing.
> +-        'a': appends to an existing archive.
> +-
> +-  Returns:
> +-    The zip archive handler or NULL on error
> +-*/
> ++/**
> ++ * Opens zip archive with compression level using the given mode.
> ++ *
> ++ * @param zipname zip archive file name.
> ++ * @param level compression level (0-9 are the standard zlib-style levels).
> ++ * @param mode file access mode.
> ++ *        - 'r': opens a file for reading/extracting (the file must exists).
> ++ *        - 'w': creates an empty file for writing.
> ++ *        - 'a': appends to an existing archive.
> ++ *
> ++ * @return the zip archive handler or NULL on error
> ++ */
> + extern struct zip_t *zip_open(const char *zipname, int level, char mode);
> + 
> +-/*
> +-  Closes the zip archive, releases resources - always finalize.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-*/
> ++/**
> ++ * Closes the zip archive, releases resources - always finalize.
> ++ *
> ++ * @param zip zip archive handler.
> ++ */
> + extern void zip_close(struct zip_t *zip);
> + 
> +-/*
> +-  Opens an entry by name in the zip archive.
> +-  For zip archive opened in 'w' or 'a' mode the function will append
> +-  a new entry. In readonly mode the function tries to locate the entry
> +-  in global dictionary.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-    entryname: an entry name in local dictionary.
> +-
> +-  Returns:
> +-    The return code - 0 on success, negative number (< 0) on error.
> +-*/
> ++/**
> ++ * Opens an entry by name in the zip archive.
> ++ *
> ++ * For zip archive opened in 'w' or 'a' mode the function will append
> ++ * a new entry. In readonly mode the function tries to locate the entry
> ++ * in global dictionary.
> ++ *
> ++ * @param zip zip archive handler.
> ++ * @param entryname an entry name in local dictionary.
> ++ *
> ++ * @return the return code - 0 on success, negative number (< 0) on error.
> ++ */
> + extern int zip_entry_open(struct zip_t *zip, const char *entryname);
> + 
> +-/*
> +-  Opens a new entry by index in the zip archive.
> +-  This function is only valid if zip archive was opened in 'r' (readonly) mode.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-    index: index in local dictionary.
> +-
> +-  Returns:
> +-    The return code - 0 on success, negative number (< 0) on error.
> +-*/
> ++/**
> ++ * Opens a new entry by index in the zip archive.
> ++ *
> ++ * This function is only valid if zip archive was opened in 'r' (readonly) mode.
> ++ *
> ++ * @param zip zip archive handler.
> ++ * @param index index in local dictionary.
> ++ *
> ++ * @return the return code - 0 on success, negative number (< 0) on error.
> ++ */
> + extern int zip_entry_openbyindex(struct zip_t *zip, int index);
> + 
> +-/*
> +-  Closes a zip entry, flushes buffer and releases resources.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-
> +-  Returns:
> +-    The return code - 0 on success, negative number (< 0) on error.
> +-*/
> ++/**
> ++ * Closes a zip entry, flushes buffer and releases resources.
> ++ *
> ++ * @param zip zip archive handler.
> ++ *
> ++ * @return the return code - 0 on success, negative number (< 0) on error.
> ++ */
> + extern int zip_entry_close(struct zip_t *zip);
> + 
> +-/*
> +-  Returns a local name of the current zip entry.
> +-  The main difference between user's entry name and local entry name
> +-  is optional relative path.
> +-  Following .ZIP File Format Specification - the path stored MUST not contain
> +-  a drive or device letter, or a leading slash.
> +-  All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
> +-  for compatibility with Amiga and UNIX file systems etc.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-
> +-  Returns:
> +-    The pointer to the current zip entry name, or NULL on error.
> +-*/
> ++/**
> ++ * Returns a local name of the current zip entry.
> ++ *
> ++ * The main difference between user's entry name and local entry name
> ++ * is optional relative path.
> ++ * Following .ZIP File Format Specification - the path stored MUST not contain
> ++ * a drive or device letter, or a leading slash.
> ++ * All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
> ++ * for compatibility with Amiga and UNIX file systems etc.
> ++ *
> ++ * @param zip: zip archive handler.
> ++ *
> ++ * @return the pointer to the current zip entry name, or NULL on error.
> ++ */
> + extern const char *zip_entry_name(struct zip_t *zip);
> + 
> +-/*
> +-  Returns an index of the current zip entry.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-
> +-  Returns:
> +-    The index on success, negative number (< 0) on error.
> +-*/
> ++/**
> ++ * Returns an index of the current zip entry.
> ++ *
> ++ * @param zip zip archive handler.
> ++ *
> ++ * @return the index on success, negative number (< 0) on error.
> ++ */
> + extern int zip_entry_index(struct zip_t *zip);
> + 
> +-/*
> +-  Determines if the current zip entry is a directory entry.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-
> +-  Returns:
> +-    The return code - 1 (true), 0 (false), negative number (< 0) on error.
> +-*/
> ++/**
> ++ * Determines if the current zip entry is a directory entry.
> ++ *
> ++ * @param zip zip archive handler.
> ++ *
> ++ * @return the return code - 1 (true), 0 (false), negative number (< 0) on
> ++ *         error.
> ++ */
> + extern int zip_entry_isdir(struct zip_t *zip);
> + 
> +-/*
> +-  Returns an uncompressed size of the current zip entry.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-
> +-  Returns:
> +-    The uncompressed size in bytes.
> +-*/
> ++/**
> ++ * Returns an uncompressed size of the current zip entry.
> ++ *
> ++ * @param zip zip archive handler.
> ++ *
> ++ * @return the uncompressed size in bytes.
> ++ */
> + extern unsigned long long zip_entry_size(struct zip_t *zip);
> + 
> +-/*
> +-  Returns CRC-32 checksum of the current zip entry.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-
> +-  Returns:
> +-    The CRC-32 checksum.
> +-*/
> ++/**
> ++ * Returns CRC-32 checksum of the current zip entry.
> ++ *
> ++ * @param zip zip archive handler.
> ++ *
> ++ * @return the CRC-32 checksum.
> ++ */
> + extern unsigned int zip_entry_crc32(struct zip_t *zip);
> + 
> +-/*
> +-  Compresses an input buffer for the current zip entry.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-    buf: input buffer.
> +-    bufsize: input buffer size (in bytes).
> +-
> +-  Returns:
> +-    The return code - 0 on success, negative number (< 0) on error.
> +-*/
> ++/**
> ++ * Compresses an input buffer for the current zip entry.
> ++ *
> ++ * @param zip zip archive handler.
> ++ * @param buf input buffer.
> ++ * @param bufsize input buffer size (in bytes).
> ++ *
> ++ * @return the return code - 0 on success, negative number (< 0) on error.
> ++ */
> + extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
> + 
> +-/*
> +-  Compresses a file for the current zip entry.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-    filename: input file.
> +-
> +-  Returns:
> +-    The return code - 0 on success, negative number (< 0) on error.
> +-*/
> ++/**
> ++ * Compresses a file for the current zip entry.
> ++ *
> ++ * @param zip zip archive handler.
> ++ * @param filename input file.
> ++ *
> ++ * @return the return code - 0 on success, negative number (< 0) on error.
> ++ */
> + extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
> + 
> +-/*
> +-  Extracts the current zip entry into output buffer.
> +-  The function allocates sufficient memory for a output buffer.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-    buf: output buffer.
> +-    bufsize: output buffer size (in bytes).
> +-
> +-  Note:
> +-    - remember to release memory allocated for a output buffer.
> +-    - for large entries, please take a look at zip_entry_extract function.
> +-
> +-  Returns:
> +-    The return code - the number of bytes actually read on success.
> +-    Otherwise a -1 on error.
> +-*/
> ++/**
> ++ * Extracts the current zip entry into output buffer.
> ++ *
> ++ * The function allocates sufficient memory for a output buffer.
> ++ *
> ++ * @param zip zip archive handler.
> ++ * @param buf output buffer.
> ++ * @param bufsize output buffer size (in bytes).
> ++ *
> ++ * @note remember to release memory allocated for a output buffer.
> ++ *       for large entries, please take a look at zip_entry_extract function.
> ++ *
> ++ * @return the return code - the number of bytes actually read on success.
> ++ *         Otherwise a -1 on error.
> ++ */
> + extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
> + 
> +-/*
> +-  Extracts the current zip entry into a memory buffer using no memory
> +-  allocation.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-    buf: preallocated output buffer.
> +-    bufsize: output buffer size (in bytes).
> +-
> +-  Note:
> +-    - ensure supplied output buffer is large enough.
> +-    - zip_entry_size function (returns uncompressed size for the current entry)
> +-      can be handy to estimate how big buffer is needed.
> +-    - for large entries, please take a look at zip_entry_extract function.
> +-
> +-  Returns:
> +-    The return code - the number of bytes actually read on success.
> +-    Otherwise a -1 on error (e.g. bufsize is not large enough).
> +-*/
> +-extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize);
> +-
> +-/*
> +-  Extracts the current zip entry into output file.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-    filename: output file.
> +-
> +-  Returns:
> +-    The return code - 0 on success, negative number (< 0) on error.
> +-*/
> ++/**
> ++ * Extracts the current zip entry into a memory buffer using no memory
> ++ * allocation.
> ++ *
> ++ * @param zip zip archive handler.
> ++ * @param buf preallocated output buffer.
> ++ * @param bufsize output buffer size (in bytes).
> ++ *
> ++ * @note ensure supplied output buffer is large enough.
> ++ *       zip_entry_size function (returns uncompressed size for the current
> ++ *       entry) can be handy to estimate how big buffer is needed. for large
> ++ * entries, please take a look at zip_entry_extract function.
> ++ *
> ++ * @return the return code - the number of bytes actually read on success.
> ++ *         Otherwise a -1 on error (e.g. bufsize is not large enough).
> ++ */
> ++extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
> ++                                     size_t bufsize);
> ++
> ++/**
> ++ * Extracts the current zip entry into output file.
> ++ *
> ++ * @param zip zip archive handler.
> ++ * @param filename output file.
> ++ *
> ++ * @return the return code - 0 on success, negative number (< 0) on error.
> ++ */
> + extern int zip_entry_fread(struct zip_t *zip, const char *filename);
> + 
> +-/*
> +-  Extracts the current zip entry using a callback function (on_extract).
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-    on_extract: callback function.
> +-    arg: opaque pointer (optional argument,
> +-                         which you can pass to the on_extract callback)
> +-
> +-   Returns:
> +-    The return code - 0 on success, negative number (< 0) on error.
> ++/**
> ++ * Extracts the current zip entry using a callback function (on_extract).
> ++ *
> ++ * @param zip zip archive handler.
> ++ * @param on_extract callback function.
> ++ * @param arg opaque pointer (optional argument, which you can pass to the
> ++ *        on_extract callback)
> ++ *
> ++ * @return the return code - 0 on success, negative number (< 0) on error.
> +  */
> + extern int
> + zip_entry_extract(struct zip_t *zip,
> +@@ -262,53 +261,49 @@ zip_entry_extract(struct zip_t *zip,
> +                                        const void *data, size_t size),
> +                   void *arg);
> + 
> +-/*
> +-  Returns the number of all entries (files and directories) in the zip archive.
> +-
> +-  Args:
> +-    zip: zip archive handler.
> +-
> +-  Returns:
> +-    The return code - the number of entries on success,
> +-    negative number (< 0) on error.
> +-*/
> ++/**
> ++ * Returns the number of all entries (files and directories) in the zip archive.
> ++ *
> ++ * @param zip zip archive handler.
> ++ *
> ++ * @return the return code - the number of entries on success, negative number
> ++ *         (< 0) on error.
> ++ */
> + extern int zip_total_entries(struct zip_t *zip);
> + 
> +-/*
> +-  Creates a new archive and puts files into a single zip archive.
> +-
> +-  Args:
> +-    zipname: zip archive file.
> +-    filenames: input files.
> +-    len: number of input files.
> +-
> +-  Returns:
> +-    The return code - 0 on success, negative number (< 0) on error.
> +-*/
> ++/**
> ++ * Creates a new archive and puts files into a single zip archive.
> ++ *
> ++ * @param zipname zip archive file.
> ++ * @param filenames input files.
> ++ * @param len: number of input files.
> ++ *
> ++ * @return the return code - 0 on success, negative number (< 0) on error.
> ++ */
> + extern int zip_create(const char *zipname, const char *filenames[], size_t len);
> + 
> +-/*
> +-  Extracts a zip archive file into directory.
> +-
> +-  If on_extract_entry is not NULL, the callback will be called after
> +-  successfully extracted each zip entry.
> +-  Returning a negative value from the callback will cause abort and return an
> +-  error. The last argument (void *arg) is optional, which you can use to pass
> +-  data to the on_extract_entry callback.
> +-
> +-  Args:
> +-    zipname: zip archive file.
> +-    dir: output directory.
> +-    on_extract_entry: on extract callback.
> +-    arg: opaque pointer.
> +-
> +-  Returns:
> +-    The return code - 0 on success, negative number (< 0) on error.
> +-*/
> ++/**
> ++ * Extracts a zip archive file into directory.
> ++ *
> ++ * If on_extract_entry is not NULL, the callback will be called after
> ++ * successfully extracted each zip entry.
> ++ * Returning a negative value from the callback will cause abort and return an
> ++ * error. The last argument (void *arg) is optional, which you can use to pass
> ++ * data to the on_extract_entry callback.
> ++ *
> ++ * @param zipname zip archive file.
> ++ * @param dir output directory.
> ++ * @param on_extract_entry on extract callback.
> ++ * @param arg opaque pointer.
> ++ *
> ++ * @return the return code - 0 on success, negative number (< 0) on error.
> ++ */
> + extern int zip_extract(const char *zipname, const char *dir,
> +                        int (*on_extract_entry)(const char *filename, void *arg),
> +                        void *arg);
> + 
> ++/** @} */
> ++
> + #ifdef __cplusplus
> + }
> + #endif
> +diff --git a/contrib/zip/test/CMakeLists.txt b/contrib/zip/test/CMakeLists.txt
> +index 9b2a8db106..cc060b00fe 100644
> +--- a/contrib/zip/test/CMakeLists.txt
> ++++ b/contrib/zip/test/CMakeLists.txt
> +@@ -1,19 +1,16 @@
> + cmake_minimum_required(VERSION 2.8)
> + 
> +-if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
> +-  if(ENABLE_COVERAGE)
> +-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g ")
> +-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
> +-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs")
> +-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage")
> +-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
> +-  endif()
> +-endif ()
> +-
> + # test
> +-include_directories(../src)
> +-add_executable(test.exe test.c ../src/zip.c)
> +-add_executable(test_miniz.exe test_miniz.c)
> ++set(test_out test.out)
> ++set(test_miniz_out test_miniz.out)
> ++
> ++add_executable(${test_out} test.c)
> ++target_link_libraries(${test_out} zip)
> ++add_executable(${test_miniz_out} test_miniz.c)
> ++target_link_libraries(${test_miniz_out} zip)
> ++
> ++add_test(NAME ${test_out} COMMAND ${test_out})
> ++add_test(NAME ${test_miniz_out} COMMAND ${test_miniz_out})
> + 
> +-add_test(NAME test COMMAND test.exe)
> +-add_test(NAME test_miniz COMMAND test_miniz.exe)
> ++set(test_out ${test_out} PARENT_SCOPE)
> ++set(test_miniz_out ${test_miniz_out} PARENT_SCOPE)
> +diff --git a/contrib/zip/test/test.c b/contrib/zip/test/test.c
> +index 454430533a..a9b2ddab1e 100644
> +--- a/contrib/zip/test/test.c
> ++++ b/contrib/zip/test/test.c
> +@@ -29,6 +29,8 @@
> + #define XFILE "7.txt\0"
> + #define XMODE 0100777
> + 
> ++#define UNIXMODE 0100644
> ++
> + #define UNUSED(x) (void)x
> + 
> + static int total_entries = 0;
> +@@ -102,7 +104,8 @@ static void test_read(void) {
> +   assert(0 == zip_entry_close(zip));
> +   free(buf);
> +   buf = NULL;
> +-  
> ++  bufsize = 0;
> ++
> +   assert(0 == zip_entry_open(zip, "test/test-2.txt"));
> +   assert(strlen(TESTDATA2) == zip_entry_size(zip));
> +   assert(CRC32DATA2 == zip_entry_crc32(zip));
> +@@ -131,7 +134,8 @@ static void test_read(void) {
> +   assert(0 == zip_entry_close(zip));
> +   free(buf);
> +   buf = NULL;
> +-  
> ++  bufsize = 0;
> ++
> +   buftmp = strlen(TESTDATA1);
> +   buf = calloc(buftmp, sizeof(char));
> +   assert(0 == zip_entry_open(zip, "test/test-1.txt"));
> +@@ -433,6 +437,35 @@ static void test_mtime(void) {
> +   remove(ZIPNAME);
> + }
> + 
> ++static void test_unix_permissions(void) {
> ++#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__)
> ++#else
> ++  // UNIX or APPLE
> ++  struct MZ_FILE_STAT_STRUCT file_stats;
> ++
> ++  remove(ZIPNAME);
> ++
> ++  struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
> ++  assert(zip != NULL);
> ++
> ++  assert(0 == zip_entry_open(zip, RFILE));
> ++  assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
> ++  assert(0 == zip_entry_close(zip));
> ++
> ++  zip_close(zip);
> ++
> ++  remove(RFILE);
> ++
> ++  assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
> ++
> ++  assert(0 == MZ_FILE_STAT(RFILE, &file_stats));
> ++  assert(UNIXMODE == file_stats.st_mode);
> ++
> ++  remove(RFILE);
> ++  remove(ZIPNAME);
> ++#endif
> ++}
> ++
> + int main(int argc, char *argv[]) {
> +   UNUSED(argc);
> +   UNUSED(argv);
> +@@ -453,6 +486,7 @@ int main(int argc, char *argv[]) {
> +   test_write_permissions();
> +   test_exe_permissions();
> +   test_mtime();
> ++  test_unix_permissions();
> + 
> +   remove(ZIPNAME);
> +   return 0;
> +diff --git a/contrib/zip/test/test_miniz.c b/contrib/zip/test/test_miniz.c
> +index ebc0564dc3..babcaecdb6 100644
> +--- a/contrib/zip/test/test_miniz.c
> ++++ b/contrib/zip/test/test_miniz.c
> +@@ -23,16 +23,39 @@ int main(int argc, char *argv[]) {
> +   uint step = 0;
> +   int cmp_status;
> +   uLong src_len = (uLong)strlen(s_pStr);
> +-  uLong cmp_len = compressBound(src_len);
> +   uLong uncomp_len = src_len;
> ++  uLong cmp_len;
> +   uint8 *pCmp, *pUncomp;
> ++  size_t sz;
> +   uint total_succeeded = 0;
> +   (void)argc, (void)argv;
> + 
> +   printf("miniz.c version: %s\n", MZ_VERSION);
> + 
> +   do {
> ++    pCmp = (uint8 *)tdefl_compress_mem_to_heap(s_pStr, src_len, &cmp_len, 0);
> ++    if (!pCmp) {
> ++      printf("tdefl_compress_mem_to_heap failed\n");
> ++      return EXIT_FAILURE;
> ++    }
> ++    if (src_len <= cmp_len) {
> ++      printf("tdefl_compress_mem_to_heap failed: from %u to %u bytes\n",
> ++             (mz_uint32)uncomp_len, (mz_uint32)cmp_len);
> ++      free(pCmp);
> ++      return EXIT_FAILURE;
> ++    }
> ++
> ++    sz = tdefl_compress_mem_to_mem(pCmp, cmp_len, s_pStr, src_len, 0);
> ++    if (sz != cmp_len) {
> ++      printf("tdefl_compress_mem_to_mem failed: expected %u, got %u\n",
> ++             (mz_uint32)cmp_len, (mz_uint32)sz);
> ++      free(pCmp);
> ++      return EXIT_FAILURE;
> ++    }
> ++
> +     // Allocate buffers to hold compressed and uncompressed data.
> ++    free(pCmp);
> ++    cmp_len = compressBound(src_len);
> +     pCmp = (mz_uint8 *)malloc((size_t)cmp_len);
> +     pUncomp = (mz_uint8 *)malloc((size_t)src_len);
> +     if ((!pCmp) || (!pUncomp)) {
> diff --git a/package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch b/package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch
> new file mode 100644
> index 0000000000..9bd24630c5
> --- /dev/null
> +++ b/package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch
> @@ -0,0 +1,243 @@
> +From bb3db0ebaffc6b76de256e597ec1d1e4d2a6663f Mon Sep 17 00:00:00 2001
> +From: kimkulling <kim.kulling@googlemail.com>
> +Date: Mon, 9 Mar 2020 10:51:26 +0100
> +Subject: [PATCH] closes https://github.com/assimp/assimp/issues/2954: upgrade
> + to latest greatest.
> +
> +[Retrieved from:
> +https://github.com/assimp/assimp/commit/bb3db0ebaffc6b76de256e597ec1d1e4d2a6663f]
> +Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
> +---
> + contrib/zip/CMakeLists.txt      |  8 ++----
> + contrib/zip/README.md           | 51 +++++++++++++++++++++++++++++++--
> + contrib/zip/src/zip.c           | 17 ++++++++++-
> + contrib/zip/src/zip.h           | 13 ++++++++-
> + contrib/zip/test/CMakeLists.txt |  5 ----
> + contrib/zip/test/test.c         |  4 ++-
> + 6 files changed, 81 insertions(+), 17 deletions(-)
> +
> +diff --git a/contrib/zip/CMakeLists.txt b/contrib/zip/CMakeLists.txt
> +index 77916d2e14..f194649ede 100644
> +--- a/contrib/zip/CMakeLists.txt
> ++++ b/contrib/zip/CMakeLists.txt
> +@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
> + 
> + project(zip
> +   LANGUAGES C
> +-  VERSION "0.1.15")
> ++  VERSION "0.1.18")
> + set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
> + 
> + option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
> +@@ -16,10 +16,6 @@ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
> +         "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
> +         "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
> +   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic")
> +-  if(ENABLE_COVERAGE)
> +-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
> +-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
> +-  endif()
> + endif (MSVC)
> + 
> + # zip
> +@@ -35,7 +31,7 @@ if (NOT CMAKE_DISABLE_TESTING)
> +   enable_testing()
> +   add_subdirectory(test)
> +   find_package(Sanitizers)
> +-  add_sanitizers(${PROJECT_NAME} ${test_out} ${test_miniz_out})
> ++  add_sanitizers(${PROJECT_NAME} ${test_out})
> + endif()
> + 
> + ####
> +diff --git a/contrib/zip/README.md b/contrib/zip/README.md
> +index 14eb9a34c8..bdd0822b67 100644
> +--- a/contrib/zip/README.md
> ++++ b/contrib/zip/README.md
> +@@ -1,10 +1,8 @@
> + ### A portable (OSX/Linux/Windows), simple zip library written in C
> + This is done by hacking awesome [miniz](https://code.google.com/p/miniz) library and layering functions on top of the miniz v1.15 API.
> + 
> +-[![Windows](https://ci.appveyor.com/api/projects/status/bph8dr3jacgmjv32/branch/master?svg=true&label=windows)](https://ci.appveyor.com/project/kuba--/zip)
> +-[![Linux](https://travis-ci.org/kuba--/zip.svg?branch=master&label=linux%2fosx)](https://travis-ci.org/kuba--/zip)
> ++[![Build](https://github.com/kuba--/zip/workflows/build/badge.svg)](https://github.com/kuba--/zip/actions?query=workflow%3Abuild)
> + [![Version](https://badge.fury.io/gh/kuba--%2Fzip.svg)](https://github.com/kuba--/zip/releases)
> +-[![Codecov](https://codecov.io/gh/kuba--/zip/branch/master/graph/badge.svg)](https://codecov.io/gh/kuba--/zip)
> + 
> + 
> + # The Idea
> +@@ -213,6 +211,53 @@ func main() {
> + }
> + ```
> + 
> ++### Rust (ffi)
> ++```rust
> ++extern crate libc;
> ++use std::ffi::CString;
> ++
> ++#[repr(C)]
> ++pub struct Zip {
> ++    _private: [u8; 0],
> ++}
> ++
> ++#[link(name = "zip")]
> ++extern "C" {
> ++    fn zip_open(path: *const libc::c_char, level: libc::c_int, mode: libc::c_char) -> *mut Zip;
> ++    fn zip_close(zip: *mut Zip) -> libc::c_void;
> ++
> ++    fn zip_entry_open(zip: *mut Zip, entryname: *const libc::c_char) -> libc::c_int;
> ++    fn zip_entry_close(zip: *mut Zip) -> libc::c_int;
> ++    fn zip_entry_write(
> ++        zip: *mut Zip,
> ++        buf: *const libc::c_void,
> ++        bufsize: libc::size_t,
> ++    ) -> libc::c_int;
> ++}
> ++
> ++fn main() {
> ++    let path = CString::new("/tmp/test.zip").unwrap();
> ++    let mode: libc::c_char = 'w' as libc::c_char;
> ++
> ++    let entryname = CString::new("test.txt").unwrap();
> ++    let content = "test content\0";
> ++
> ++    unsafe {
> ++        let zip: *mut Zip = zip_open(path.as_ptr(), 5, mode);
> ++        {
> ++            zip_entry_open(zip, entryname.as_ptr());
> ++            {
> ++                let buf = content.as_ptr() as *const libc::c_void;
> ++                let bufsize = content.len() as libc::size_t;
> ++                zip_entry_write(zip, buf, bufsize);
> ++            }
> ++            zip_entry_close(zip);
> ++        }
> ++        zip_close(zip);
> ++    }
> ++}
> ++```
> ++
> + ### Ruby (ffi)
> + Install _ffi_ gem.
> + ```shell
> +diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c
> +index 1abcfd8fd1..3b2821e6a3 100644
> +--- a/contrib/zip/src/zip.c
> ++++ b/contrib/zip/src/zip.c
> +@@ -222,6 +222,20 @@ void zip_close(struct zip_t *zip) {
> +   }
> + }
> + 
> ++int zip_is64(struct zip_t *zip) {
> ++  if (!zip) {
> ++    // zip_t handler is not initialized
> ++    return -1;
> ++  }
> ++
> ++  if (!zip->archive.m_pState) {
> ++    // zip state is not initialized
> ++    return -1;
> ++  }
> ++
> ++  return (int)zip->archive.m_pState->m_zip64;
> ++}
> ++
> + int zip_entry_open(struct zip_t *zip, const char *entryname) {
> +   size_t entrylen = 0;
> +   mz_zip_archive *pzip = NULL;
> +@@ -794,7 +808,8 @@ int zip_create(const char *zipname, const char *filenames[], size_t len) {
> + 
> +     if (MZ_FILE_STAT(name, &file_stat) != 0) {
> +       // problem getting information - check errno
> +-      return -1;
> ++      status = -1;
> ++      break;
> +     }
> + 
> +     if ((file_stat.st_mode & 0200) == 0) {
> +diff --git a/contrib/zip/src/zip.h b/contrib/zip/src/zip.h
> +index a48d64d6de..cd3ab5cd00 100644
> +--- a/contrib/zip/src/zip.h
> ++++ b/contrib/zip/src/zip.h
> +@@ -21,7 +21,7 @@ extern "C" {
> + 
> + #if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) &&               \
> +     !defined(__DEFINED_ssize_t) && !defined(__ssize_t_defined) &&              \
> +-    !defined(_SSIZE_T) && !defined(_SSIZE_T_)
> ++    !defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(_SSIZE_T_DECLARED)
> + 
> + // 64-bit Windows is the only mainstream platform
> + // where sizeof(long) != sizeof(void*)
> +@@ -37,6 +37,7 @@ typedef long ssize_t; /* byte count or error */
> + #define __ssize_t_defined
> + #define _SSIZE_T
> + #define _SSIZE_T_
> ++#define _SSIZE_T_DECLARED
> + 
> + #endif
> + 
> +@@ -90,6 +91,16 @@ extern struct zip_t *zip_open(const char *zipname, int level, char mode);
> +  */
> + extern void zip_close(struct zip_t *zip);
> + 
> ++/**
> ++ * Determines if the archive has a zip64 end of central directory headers.
> ++ *
> ++ * @param zip zip archive handler.
> ++ *
> ++ * @return the return code - 1 (true), 0 (false), negative number (< 0) on
> ++ *         error.
> ++ */
> ++extern int zip_is64(struct zip_t *zip);
> ++
> + /**
> +  * Opens an entry by name in the zip archive.
> +  *
> +diff --git a/contrib/zip/test/CMakeLists.txt b/contrib/zip/test/CMakeLists.txt
> +index cc060b00fe..1224115858 100644
> +--- a/contrib/zip/test/CMakeLists.txt
> ++++ b/contrib/zip/test/CMakeLists.txt
> +@@ -2,15 +2,10 @@ cmake_minimum_required(VERSION 2.8)
> + 
> + # test
> + set(test_out test.out)
> +-set(test_miniz_out test_miniz.out)
> + 
> + add_executable(${test_out} test.c)
> + target_link_libraries(${test_out} zip)
> +-add_executable(${test_miniz_out} test_miniz.c)
> +-target_link_libraries(${test_miniz_out} zip)
> + 
> + add_test(NAME ${test_out} COMMAND ${test_out})
> +-add_test(NAME ${test_miniz_out} COMMAND ${test_miniz_out})
> + 
> + set(test_out ${test_out} PARENT_SCOPE)
> +-set(test_miniz_out ${test_miniz_out} PARENT_SCOPE)
> +diff --git a/contrib/zip/test/test.c b/contrib/zip/test/test.c
> +index a9b2ddab1e..9cc2248ac0 100644
> +--- a/contrib/zip/test/test.c
> ++++ b/contrib/zip/test/test.c
> +@@ -47,7 +47,7 @@ static void test_write(void) {
> +   assert(CRC32DATA1 == zip_entry_crc32(zip));
> +   ++total_entries;
> +   assert(0 == zip_entry_close(zip));
> +-
> ++  assert(0 == zip_is64(zip));
> +   zip_close(zip);
> + }
> + 
> +@@ -92,6 +92,7 @@ static void test_read(void) {
> +   size_t buftmp;
> +   struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
> +   assert(zip != NULL);
> ++  assert(0 == zip_is64(zip));
> + 
> +   assert(0 == zip_entry_open(zip, "test\\test-1.txt"));
> +   assert(strlen(TESTDATA1) == zip_entry_size(zip));
> +@@ -310,6 +311,7 @@ static void test_fwrite(void) {
> +   assert(0 == zip_entry_open(zip, WFILE));
> +   assert(0 == zip_entry_fwrite(zip, WFILE));
> +   assert(0 == zip_entry_close(zip));
> ++  assert(0 == zip_is64(zip));
> + 
> +   zip_close(zip);
> +   remove(WFILE);
>
Arnout Vandecappelle May 20, 2021, 7:44 p.m. UTC | #2
On 20/05/2021 21:36, Arnout Vandecappelle wrote:
>  I was about to apply, but then I noticed this...
> 
> On 28/01/2021 21:04, Fabrice Fontaine wrote:
>> Fixes:
>>  - http://autobuild.buildroot.net/results/7c2db184ee200d1719308f38f42382bb39d8d5c6
>>
>> Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
>> ---
>>  ...p-to-fix-gcc-build-for-v9-2-0-32-bit.patch | 1638 +++++++++++++++++
>>  ...oses-2954-upgrade-to-latest-greatest.patch |  243 +++
>>  2 files changed, 1881 insertions(+)
>>  create mode 100644 package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch
>>  create mode 100644 package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch
>>
>> diff --git a/package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch b/package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch
>> new file mode 100644
>> index 0000000000..4b86cc584f
>> --- /dev/null
>> +++ b/package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch
>> @@ -0,0 +1,1638 @@
>> +From f78446b14aff46db2ef27d062a275b6a01fd68b1 Mon Sep 17 00:00:00 2001
>> +From: Kim Kulling <kim.kulling@googlemail.com>
>> +Date: Tue, 19 Nov 2019 20:30:40 +0100
>> +Subject: [PATCH] closes https://github.com/assimp/assimp/issues/2733: update
>> + of zlip to fix gcc build for v9.2.0 32 bit
>> +
>> +[Retrieved (and updated to remove .gitignore and appveyor.yml) from:
>> +https://github.com/assimp/assimp/commit/f78446b14aff46db2ef27d062a275b6a01fd68b1]
>> +Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
>> +---
>> + contrib/zip/.gitignore          |   2 +
>> + contrib/zip/CMakeLists.txt      |  83 +++++-
>> + contrib/zip/README.md           |  12 +-
>> + contrib/zip/appveyor.yml        |   2 +-
>> + contrib/zip/src/miniz.h         | 457 ++++++++++++++++++++++++++++----
>> + contrib/zip/src/zip.c           |  62 +++--
>> + contrib/zip/src/zip.h           | 457 ++++++++++++++++----------------
>> + contrib/zip/test/CMakeLists.txt |  27 +-
>> + contrib/zip/test/test.c         |  38 ++-
>> + contrib/zip/test/test_miniz.c   |  25 +-
> 
>  This patch (and the other one) only affects contrib/zip.
> 
>  However, top-level CMakeLists.txt has this:
>   IF ( NOT ASSIMP_BUILD_ZLIB )
>     FIND_PACKAGE(ZLIB)
>   ENDIF( NOT ASSIMP_BUILD_ZLIB )
> 
>   IF( NOT ZLIB_FOUND )
>     MESSAGE(STATUS "compiling zlib from sources")
>     ...
>     # compile from sources
>     ADD_SUBDIRECTORY(contrib/zlib)

 D'oh! zlib is not the same as zip... Sorry for the noise.

 Series applied to master, thanks.

 Regards,
 Arnout

>   ELSE(NOT ZLIB_FOUND)
>     ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
>     SET(ZLIB_LIBRARIES_LINKED -lz)
>   ENDIF(NOT ZLIB_FOUND)
> 
> Since we have a dependency on zlib, the contrib/zip code should never be used!
> 
> So, either there is something wrong somewhere and zlib is not found. Or these
> patches don't do anything useful. (Or, of course, I'm missing something.)
> 
> 
>  I realize it's months ago, but perhaps you can shed some light?
> 
>  Regards,
>  Arnout
> 
> 
>> + 10 files changed, 821 insertions(+), 344 deletions(-)
>> +
>> +diff --git a/contrib/zip/CMakeLists.txt b/contrib/zip/CMakeLists.txt
>> +index b46dbb1db0..77916d2e14 100644
>> +--- a/contrib/zip/CMakeLists.txt
>> ++++ b/contrib/zip/CMakeLists.txt
>> +@@ -1,10 +1,14 @@
>> +-cmake_minimum_required(VERSION 2.8)
>> +-project(zip)
>> +-enable_language(C)
>> ++cmake_minimum_required(VERSION 3.0)
>> ++
>> ++project(zip
>> ++  LANGUAGES C
>> ++  VERSION "0.1.15")
>> + set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
>> + 
>> ++option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
>> ++
>> + if (MSVC)
>> +-  # Use secure functions by defaualt and suppress warnings about "deprecated" functions
>> ++  # Use secure functions by default and suppress warnings about "deprecated" functions
>> +   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1")
>> +   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
>> +   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
>> +@@ -12,28 +16,80 @@ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
>> +         "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
>> +         "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
>> +   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic")
>> ++  if(ENABLE_COVERAGE)
>> ++    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
>> ++    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
>> ++  endif()
>> + endif (MSVC)
>> + 
>> + # zip
>> + set(SRC src/miniz.h src/zip.h src/zip.c)
>> + add_library(${PROJECT_NAME} ${SRC})
>> +-target_include_directories(${PROJECT_NAME} INTERFACE src)
>> ++target_include_directories(${PROJECT_NAME} PUBLIC
>> ++  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
>> ++  $<INSTALL_INTERFACE:include>
>> ++)
>> + 
>> + # test
>> + if (NOT CMAKE_DISABLE_TESTING)
>> +   enable_testing()
>> +   add_subdirectory(test)
>> +   find_package(Sanitizers)
>> +-  add_sanitizers(${PROJECT_NAME} test.exe)
>> +-  add_sanitizers(${PROJECT_NAME} test_miniz.exe)
>> ++  add_sanitizers(${PROJECT_NAME} ${test_out} ${test_miniz_out})
>> + endif()
>> + 
>> ++####
>> ++# Installation (https://github.com/forexample/package-example) {
>> ++
>> ++set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
>> ++set(INCLUDE_INSTALL_DIR "include")
>> ++
>> ++set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
>> ++
>> ++# Configuration
>> ++set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
>> ++set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
>> ++set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
>> ++set(NAMESPACE "${PROJECT_NAME}::")
>> ++
>> ++# Include module with fuction 'write_basic_package_version_file'
>> ++include(CMakePackageConfigHelpers)
>> ++
>> ++# Note: PROJECT_VERSION is used as a VERSION
>> ++write_basic_package_version_file(
>> ++    "${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion
>> ++)
>> ++
>> ++# Use variables:
>> ++#   * TARGETS_EXPORT_NAME
>> ++#   * PROJECT_NAME
>> ++configure_package_config_file(
>> ++    "cmake/Config.cmake.in"
>> ++    "${PROJECT_CONFIG}"
>> ++    INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
>> ++)
>> ++
>> ++install(
>> ++    FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
>> ++    DESTINATION "${CONFIG_INSTALL_DIR}"
>> ++)
>> ++
>> ++install(
>> ++    EXPORT "${TARGETS_EXPORT_NAME}"
>> ++    NAMESPACE "${NAMESPACE}"
>> ++    DESTINATION "${CONFIG_INSTALL_DIR}"
>> ++)
>> ++
>> ++# }
>> ++
>> + install(TARGETS ${PROJECT_NAME}
>> ++        EXPORT ${TARGETS_EXPORT_NAME}
>> +         RUNTIME DESTINATION bin
>> +         ARCHIVE DESTINATION lib
>> +         LIBRARY DESTINATION lib
>> +-        COMPONENT library)
>> +-install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION include)
>> ++        INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR}
>> ++)
>> ++install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION ${INCLUDE_INSTALL_DIR}/zip)
>> + 
>> + # uninstall target (https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake)
>> + if(NOT TARGET uninstall)
>> +@@ -45,3 +101,12 @@ if(NOT TARGET uninstall)
>> +     add_custom_target(uninstall
>> +         COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
>> + endif()
>> ++
>> ++find_package(Doxygen)
>> ++if(DOXYGEN_FOUND)
>> ++    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
>> ++    add_custom_target(doc
>> ++        ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
>> ++        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
>> ++        COMMENT "Generating API documentation with Doxygen" VERBATIM)
>> ++endif()
>> +diff --git a/contrib/zip/README.md b/contrib/zip/README.md
>> +index d5fb8cd203..14eb9a34c8 100644
>> +--- a/contrib/zip/README.md
>> ++++ b/contrib/zip/README.md
>> +@@ -71,7 +71,7 @@ int arg = 2;
>> + zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
>> + ```
>> + 
>> +-*   Extract a zip entry into memory.
>> ++* Extract a zip entry into memory.
>> + ```c
>> + void *buf = NULL;
>> + size_t bufsize;
>> +@@ -89,7 +89,7 @@ zip_close(zip);
>> + free(buf);
>> + ```
>> + 
>> +-*   Extract a zip entry into memory (no internal allocation).
>> ++* Extract a zip entry into memory (no internal allocation).
>> + ```c
>> + unsigned char *buf;
>> + size_t bufsize;
>> +@@ -110,7 +110,7 @@ zip_close(zip);
>> + free(buf);
>> + ```
>> + 
>> +-*   Extract a zip entry into memory using callback.
>> ++* Extract a zip entry into memory using callback.
>> + ```c
>> + struct buffer_t {
>> +     char *data;
>> +@@ -144,7 +144,7 @@ free(buf.data);
>> + ```
>> + 
>> + 
>> +-*   Extract a zip entry into a file.
>> ++* Extract a zip entry into a file.
>> + ```c
>> + struct zip_t *zip = zip_open("foo.zip", 0, 'r');
>> + {
>> +@@ -157,7 +157,7 @@ struct zip_t *zip = zip_open("foo.zip", 0, 'r');
>> + zip_close(zip);
>> + ```
>> + 
>> +-*   List of all zip entries
>> ++* List of all zip entries
>> + ```c
>> + struct zip_t *zip = zip_open("foo.zip", 0, 'r');
>> + int i, n = zip_total_entries(zip);
>> +@@ -174,7 +174,7 @@ for (i = 0; i < n; ++i) {
>> + zip_close(zip);
>> + ```
>> + 
>> +-## Bindings
>> ++# Bindings
>> + Compile zip library as a dynamic library.
>> + ```shell
>> + $ mkdir build
>> +diff --git a/contrib/zip/src/miniz.h b/contrib/zip/src/miniz.h
>> +index 2c27a94d8d..c4fcfb83e6 100644
>> +--- a/contrib/zip/src/miniz.h
>> ++++ b/contrib/zip/src/miniz.h
>> +@@ -221,6 +221,7 @@
>> + #ifndef MINIZ_HEADER_INCLUDED
>> + #define MINIZ_HEADER_INCLUDED
>> + 
>> ++#include <stdint.h>
>> + #include <stdlib.h>
>> + 
>> + // Defines to completely disable specific portions of miniz.c:
>> +@@ -284,7 +285,8 @@
>> + /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */
>> + #if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES)
>> + #if MINIZ_X86_OR_X64_CPU
>> +-/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */
>> ++/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
>> ++ * integer loads and stores from unaligned addresses. */
>> + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
>> + #define MINIZ_UNALIGNED_USE_MEMCPY
>> + #else
>> +@@ -354,6 +356,44 @@ enum {
>> +   MZ_FIXED = 4
>> + };
>> + 
>> ++/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or
>> ++ * modify this enum. */
>> ++typedef enum {
>> ++  MZ_ZIP_NO_ERROR = 0,
>> ++  MZ_ZIP_UNDEFINED_ERROR,
>> ++  MZ_ZIP_TOO_MANY_FILES,
>> ++  MZ_ZIP_FILE_TOO_LARGE,
>> ++  MZ_ZIP_UNSUPPORTED_METHOD,
>> ++  MZ_ZIP_UNSUPPORTED_ENCRYPTION,
>> ++  MZ_ZIP_UNSUPPORTED_FEATURE,
>> ++  MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,
>> ++  MZ_ZIP_NOT_AN_ARCHIVE,
>> ++  MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,
>> ++  MZ_ZIP_UNSUPPORTED_MULTIDISK,
>> ++  MZ_ZIP_DECOMPRESSION_FAILED,
>> ++  MZ_ZIP_COMPRESSION_FAILED,
>> ++  MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,
>> ++  MZ_ZIP_CRC_CHECK_FAILED,
>> ++  MZ_ZIP_UNSUPPORTED_CDIR_SIZE,
>> ++  MZ_ZIP_ALLOC_FAILED,
>> ++  MZ_ZIP_FILE_OPEN_FAILED,
>> ++  MZ_ZIP_FILE_CREATE_FAILED,
>> ++  MZ_ZIP_FILE_WRITE_FAILED,
>> ++  MZ_ZIP_FILE_READ_FAILED,
>> ++  MZ_ZIP_FILE_CLOSE_FAILED,
>> ++  MZ_ZIP_FILE_SEEK_FAILED,
>> ++  MZ_ZIP_FILE_STAT_FAILED,
>> ++  MZ_ZIP_INVALID_PARAMETER,
>> ++  MZ_ZIP_INVALID_FILENAME,
>> ++  MZ_ZIP_BUF_TOO_SMALL,
>> ++  MZ_ZIP_INTERNAL_ERROR,
>> ++  MZ_ZIP_FILE_NOT_FOUND,
>> ++  MZ_ZIP_ARCHIVE_TOO_LARGE,
>> ++  MZ_ZIP_VALIDATION_FAILED,
>> ++  MZ_ZIP_WRITE_CALLBACK_FAILED,
>> ++  MZ_ZIP_TOTAL_ERRORS
>> ++} mz_zip_error;
>> ++
>> + // Method
>> + #define MZ_DEFLATED 8
>> + 
>> +@@ -696,6 +736,7 @@ typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
>> +                                     void *pBuf, size_t n);
>> + typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
>> +                                      const void *pBuf, size_t n);
>> ++typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);
>> + 
>> + struct mz_zip_internal_state_tag;
>> + typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
>> +@@ -707,13 +748,27 @@ typedef enum {
>> +   MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
>> + } mz_zip_mode;
>> + 
>> +-typedef struct mz_zip_archive_tag {
>> ++typedef enum {
>> ++  MZ_ZIP_TYPE_INVALID = 0,
>> ++  MZ_ZIP_TYPE_USER,
>> ++  MZ_ZIP_TYPE_MEMORY,
>> ++  MZ_ZIP_TYPE_HEAP,
>> ++  MZ_ZIP_TYPE_FILE,
>> ++  MZ_ZIP_TYPE_CFILE,
>> ++  MZ_ZIP_TOTAL_TYPES
>> ++} mz_zip_type;
>> ++
>> ++typedef struct {
>> +   mz_uint64 m_archive_size;
>> +   mz_uint64 m_central_directory_file_ofs;
>> +-  mz_uint m_total_files;
>> ++
>> ++  /* We only support up to UINT32_MAX files in zip64 mode. */
>> ++  mz_uint32 m_total_files;
>> +   mz_zip_mode m_zip_mode;
>> ++  mz_zip_type m_zip_type;
>> ++  mz_zip_error m_last_error;
>> + 
>> +-  mz_uint m_file_offset_alignment;
>> ++  mz_uint64 m_file_offset_alignment;
>> + 
>> +   mz_alloc_func m_pAlloc;
>> +   mz_free_func m_pFree;
>> +@@ -722,6 +777,7 @@ typedef struct mz_zip_archive_tag {
>> + 
>> +   mz_file_read_func m_pRead;
>> +   mz_file_write_func m_pWrite;
>> ++  mz_file_needs_keepalive m_pNeeds_keepalive;
>> +   void *m_pIO_opaque;
>> + 
>> +   mz_zip_internal_state *m_pState;
>> +@@ -1263,6 +1319,9 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
>> +                                                 int strategy);
>> + #endif // #ifndef MINIZ_NO_ZLIB_APIS
>> + 
>> ++#define MZ_UINT16_MAX (0xFFFFU)
>> ++#define MZ_UINT32_MAX (0xFFFFFFFFU)
>> ++
>> + #ifdef __cplusplus
>> + }
>> + #endif
>> +@@ -1311,6 +1370,11 @@ typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
>> +    ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
>> + #endif
>> + 
>> ++#define MZ_READ_LE64(p)                                                        \
>> ++  (((mz_uint64)MZ_READ_LE32(p)) |                                              \
>> ++   (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32)))       \
>> ++    << 32U))
>> ++
>> + #ifdef _MSC_VER
>> + #define MZ_FORCEINLINE __forceinline
>> + #elif defined(__GNUC__)
>> +@@ -4160,6 +4224,17 @@ enum {
>> +   MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
>> +   MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
>> +   MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
>> ++
>> ++  /* ZIP64 archive identifier and record sizes */
>> ++  MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,
>> ++  MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,
>> ++  MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,
>> ++  MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,
>> ++  MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,
>> ++  MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,
>> ++  MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,
>> ++  MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,
>> ++
>> +   // Central directory header record offsets
>> +   MZ_ZIP_CDH_SIG_OFS = 0,
>> +   MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
>> +@@ -4199,6 +4274,31 @@ enum {
>> +   MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
>> +   MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
>> +   MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
>> ++
>> ++  /* ZIP64 End of central directory locator offsets */
>> ++  MZ_ZIP64_ECDL_SIG_OFS = 0,                    /* 4 bytes */
>> ++  MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4,          /* 4 bytes */
>> ++  MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8,  /* 8 bytes */
>> ++  MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */
>> ++
>> ++  /* ZIP64 End of central directory header offsets */
>> ++  MZ_ZIP64_ECDH_SIG_OFS = 0,                       /* 4 bytes */
>> ++  MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4,            /* 8 bytes */
>> ++  MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12,          /* 2 bytes */
>> ++  MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14,           /* 2 bytes */
>> ++  MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16,            /* 4 bytes */
>> ++  MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20,            /* 4 bytes */
>> ++  MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */
>> ++  MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32,       /* 8 bytes */
>> ++  MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40,                /* 8 bytes */
>> ++  MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48,                 /* 8 bytes */
>> ++  MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,
>> ++  MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,
>> ++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,
>> ++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,
>> ++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,
>> ++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,
>> ++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11
>> + };
>> + 
>> + typedef struct {
>> +@@ -4211,7 +4311,24 @@ struct mz_zip_internal_state_tag {
>> +   mz_zip_array m_central_dir;
>> +   mz_zip_array m_central_dir_offsets;
>> +   mz_zip_array m_sorted_central_dir_offsets;
>> ++
>> ++  /* The flags passed in when the archive is initially opened. */
>> ++  uint32_t m_init_flags;
>> ++
>> ++  /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc.
>> ++   */
>> ++  mz_bool m_zip64;
>> ++
>> ++  /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64
>> ++   * will also be slammed to true too, even if we didn't find a zip64 end of
>> ++   * central dir header, etc.) */
>> ++  mz_bool m_zip64_has_extended_info_fields;
>> ++
>> ++  /* These fields are used by the file, FILE, memory, and memory/heap read/write
>> ++   * helpers. */
>> +   MZ_FILE *m_pFile;
>> ++  mz_uint64 m_file_archive_start_ofs;
>> ++
>> +   void *m_pMem;
>> +   size_t m_mem_size;
>> +   size_t m_mem_capacity;
>> +@@ -4363,6 +4480,13 @@ static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time,
>> + #endif /* #ifndef MINIZ_NO_STDIO */
>> + #endif /* #ifndef MINIZ_NO_TIME */
>> + 
>> ++static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip,
>> ++                                               mz_zip_error err_num) {
>> ++  if (pZip)
>> ++    pZip->m_last_error = err_num;
>> ++  return MZ_FALSE;
>> ++}
>> ++
>> + static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
>> +                                            mz_uint32 flags) {
>> +   (void)flags;
>> +@@ -4480,127 +4604,346 @@ mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) {
>> +   }
>> + }
>> + 
>> +-static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
>> +-                                              mz_uint32 flags) {
>> +-  mz_uint cdir_size, num_this_disk, cdir_disk_index;
>> +-  mz_uint64 cdir_ofs;
>> ++static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip,
>> ++                                               mz_uint32 record_sig,
>> ++                                               mz_uint32 record_size,
>> ++                                               mz_int64 *pOfs) {
>> +   mz_int64 cur_file_ofs;
>> +-  const mz_uint8 *p;
>> +   mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
>> +   mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
>> +-  mz_bool sort_central_dir =
>> +-      ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
>> +-  // Basic sanity checks - reject files which are too small, and check the first
>> +-  // 4 bytes of the file to make sure a local header is there.
>> +-  if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
>> ++
>> ++  /* Basic sanity checks - reject files which are too small */
>> ++  if (pZip->m_archive_size < record_size)
>> +     return MZ_FALSE;
>> +-  // Find the end of central directory record by scanning the file from the end
>> +-  // towards the beginning.
>> ++
>> ++  /* Find the record by scanning the file from the end towards the beginning. */
>> +   cur_file_ofs =
>> +       MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
>> +   for (;;) {
>> +     int i,
>> +         n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
>> ++
>> +     if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
>> +       return MZ_FALSE;
>> +-    for (i = n - 4; i >= 0; --i)
>> +-      if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
>> +-        break;
>> ++
>> ++    for (i = n - 4; i >= 0; --i) {
>> ++      mz_uint s = MZ_READ_LE32(pBuf + i);
>> ++      if (s == record_sig) {
>> ++        if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)
>> ++          break;
>> ++      }
>> ++    }
>> ++
>> +     if (i >= 0) {
>> +       cur_file_ofs += i;
>> +       break;
>> +     }
>> ++
>> ++    /* Give up if we've searched the entire file, or we've gone back "too far"
>> ++     * (~64kb) */
>> +     if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
>> +-                            (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
>> ++                            (MZ_UINT16_MAX + record_size)))
>> +       return MZ_FALSE;
>> ++
>> +     cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
>> +   }
>> +-  // Read and verify the end of central directory record.
>> ++
>> ++  *pOfs = cur_file_ofs;
>> ++  return MZ_TRUE;
>> ++}
>> ++
>> ++static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
>> ++                                              mz_uint flags) {
>> ++  mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0,
>> ++          cdir_disk_index = 0;
>> ++  mz_uint64 cdir_ofs = 0;
>> ++  mz_int64 cur_file_ofs = 0;
>> ++  const mz_uint8 *p;
>> ++
>> ++  mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
>> ++  mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
>> ++  mz_bool sort_central_dir =
>> ++      ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
>> ++  mz_uint32 zip64_end_of_central_dir_locator_u32
>> ++      [(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) /
>> ++       sizeof(mz_uint32)];
>> ++  mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;
>> ++
>> ++  mz_uint32 zip64_end_of_central_dir_header_u32
>> ++      [(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
>> ++       sizeof(mz_uint32)];
>> ++  mz_uint8 *pZip64_end_of_central_dir =
>> ++      (mz_uint8 *)zip64_end_of_central_dir_header_u32;
>> ++
>> ++  mz_uint64 zip64_end_of_central_dir_ofs = 0;
>> ++
>> ++  /* Basic sanity checks - reject files which are too small, and check the first
>> ++   * 4 bytes of the file to make sure a local header is there. */
>> ++  if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
>> ++    return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
>> ++
>> ++  if (!mz_zip_reader_locate_header_sig(
>> ++          pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG,
>> ++          MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))
>> ++    return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);
>> ++
>> ++  /* Read and verify the end of central directory record. */
>> +   if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
>> +                     MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
>> +       MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
>> +-    return MZ_FALSE;
>> +-  if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
>> +-       MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
>> +-      ((pZip->m_total_files =
>> +-            MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) !=
>> +-       MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
>> +-    return MZ_FALSE;
>> ++    return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
>> ++
>> ++  if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
>> ++      MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
>> ++    return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
>> ++
>> ++  if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE +
>> ++                       MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) {
>> ++    if (pZip->m_pRead(pZip->m_pIO_opaque,
>> ++                      cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE,
>> ++                      pZip64_locator,
>> ++                      MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ==
>> ++        MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) {
>> ++      if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) ==
>> ++          MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) {
>> ++        zip64_end_of_central_dir_ofs = MZ_READ_LE64(
>> ++            pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);
>> ++        if (zip64_end_of_central_dir_ofs >
>> ++            (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
>> ++          return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
>> ++
>> ++        if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs,
>> ++                          pZip64_end_of_central_dir,
>> ++                          MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ==
>> ++            MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) {
>> ++          if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) ==
>> ++              MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) {
>> ++            pZip->m_pState->m_zip64 = MZ_TRUE;
>> ++          }
>> ++        }
>> ++      }
>> ++    }
>> ++  }
>> + 
>> ++  pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);
>> ++  cdir_entries_on_this_disk =
>> ++      MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
>> +   num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
>> +   cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
>> ++  cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);
>> ++  cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
>> ++
>> ++  if (pZip->m_pState->m_zip64) {
>> ++    mz_uint32 zip64_total_num_of_disks =
>> ++        MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);
>> ++    mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(
>> ++        pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);
>> ++    mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(
>> ++        pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
>> ++    mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(
>> ++        pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);
>> ++    mz_uint64 zip64_size_of_central_directory =
>> ++        MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);
>> ++
>> ++    if (zip64_size_of_end_of_central_dir_record <
>> ++        (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))
>> ++      return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
>> ++
>> ++    if (zip64_total_num_of_disks != 1U)
>> ++      return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
>> ++
>> ++    /* Check for miniz's practical limits */
>> ++    if (zip64_cdir_total_entries > MZ_UINT32_MAX)
>> ++      return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
>> ++
>> ++    pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;
>> ++
>> ++    if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)
>> ++      return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
>> ++
>> ++    cdir_entries_on_this_disk =
>> ++        (mz_uint32)zip64_cdir_total_entries_on_this_disk;
>> ++
>> ++    /* Check for miniz's current practical limits (sorry, this should be enough
>> ++     * for millions of files) */
>> ++    if (zip64_size_of_central_directory > MZ_UINT32_MAX)
>> ++      return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
>> ++
>> ++    cdir_size = (mz_uint32)zip64_size_of_central_directory;
>> ++
>> ++    num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir +
>> ++                                 MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);
>> ++
>> ++    cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir +
>> ++                                   MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);
>> ++
>> ++    cdir_ofs =
>> ++        MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);
>> ++  }
>> ++
>> ++  if (pZip->m_total_files != cdir_entries_on_this_disk)
>> ++    return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
>> ++
>> +   if (((num_this_disk | cdir_disk_index) != 0) &&
>> +       ((num_this_disk != 1) || (cdir_disk_index != 1)))
>> +-    return MZ_FALSE;
>> ++    return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
>> + 
>> +-  if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) <
>> +-      pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
>> +-    return MZ_FALSE;
>> ++  if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
>> ++    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
>> + 
>> +-  cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
>> +   if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
>> +-    return MZ_FALSE;
>> ++    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
>> + 
>> +   pZip->m_central_directory_file_ofs = cdir_ofs;
>> + 
>> +   if (pZip->m_total_files) {
>> +     mz_uint i, n;
>> +-
>> +-    // Read the entire central directory into a heap block, and allocate another
>> +-    // heap block to hold the unsorted central dir file record offsets, and
>> +-    // another to hold the sorted indices.
>> ++    /* Read the entire central directory into a heap block, and allocate another
>> ++     * heap block to hold the unsorted central dir file record offsets, and
>> ++     * possibly another to hold the sorted indices. */
>> +     if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
>> +                               MZ_FALSE)) ||
>> +         (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
>> +                               pZip->m_total_files, MZ_FALSE)))
>> +-      return MZ_FALSE;
>> ++      return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
>> + 
>> +     if (sort_central_dir) {
>> +       if (!mz_zip_array_resize(pZip,
>> +                                &pZip->m_pState->m_sorted_central_dir_offsets,
>> +                                pZip->m_total_files, MZ_FALSE))
>> +-        return MZ_FALSE;
>> ++        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
>> +     }
>> + 
>> +     if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
>> +                       pZip->m_pState->m_central_dir.m_p,
>> +                       cdir_size) != cdir_size)
>> +-      return MZ_FALSE;
>> ++      return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
>> + 
>> +-    // Now create an index into the central directory file records, do some
>> +-    // basic sanity checking on each record, and check for zip64 entries (which
>> +-    // are not yet supported).
>> ++    /* Now create an index into the central directory file records, do some
>> ++     * basic sanity checking on each record */
>> +     p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
>> +     for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
>> +-      mz_uint total_header_size, comp_size, decomp_size, disk_index;
>> ++      mz_uint total_header_size, disk_index, bit_flags, filename_size,
>> ++          ext_data_size;
>> ++      mz_uint64 comp_size, decomp_size, local_header_ofs;
>> ++
>> +       if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
>> +           (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
>> +-        return MZ_FALSE;
>> ++        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
>> ++
>> +       MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
>> +                            i) =
>> +           (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
>> ++
>> +       if (sort_central_dir)
>> +         MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
>> +                              mz_uint32, i) = i;
>> ++
>> +       comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
>> +       decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
>> +-      if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
>> +-           (decomp_size != comp_size)) ||
>> +-          (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) ||
>> +-          (comp_size == 0xFFFFFFFF))
>> +-        return MZ_FALSE;
>> ++      local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
>> ++      filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
>> ++      ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
>> ++
>> ++      if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&
>> ++          (ext_data_size) &&
>> ++          (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) ==
>> ++           MZ_UINT32_MAX)) {
>> ++        /* Attempt to find zip64 extended information field in the entry's extra
>> ++         * data */
>> ++        mz_uint32 extra_size_remaining = ext_data_size;
>> ++
>> ++        if (extra_size_remaining) {
>> ++          const mz_uint8 *pExtra_data;
>> ++          void *buf = NULL;
>> ++
>> ++          if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size >
>> ++              n) {
>> ++            buf = MZ_MALLOC(ext_data_size);
>> ++            if (buf == NULL)
>> ++              return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
>> ++
>> ++            if (pZip->m_pRead(pZip->m_pIO_opaque,
>> ++                              cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
>> ++                                  filename_size,
>> ++                              buf, ext_data_size) != ext_data_size) {
>> ++              MZ_FREE(buf);
>> ++              return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
>> ++            }
>> ++
>> ++            pExtra_data = (mz_uint8 *)buf;
>> ++          } else {
>> ++            pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
>> ++          }
>> ++
>> ++          do {
>> ++            mz_uint32 field_id;
>> ++            mz_uint32 field_data_size;
>> ++
>> ++            if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
>> ++              MZ_FREE(buf);
>> ++              return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
>> ++            }
>> ++
>> ++            field_id = MZ_READ_LE16(pExtra_data);
>> ++            field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
>> ++
>> ++            if ((field_data_size + sizeof(mz_uint16) * 2) >
>> ++                extra_size_remaining) {
>> ++              MZ_FREE(buf);
>> ++              return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
>> ++            }
>> ++
>> ++            if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
>> ++              /* Ok, the archive didn't have any zip64 headers but it uses a
>> ++               * zip64 extended information field so mark it as zip64 anyway
>> ++               * (this can occur with infozip's zip util when it reads
>> ++               * compresses files from stdin). */
>> ++              pZip->m_pState->m_zip64 = MZ_TRUE;
>> ++              pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;
>> ++              break;
>> ++            }
>> ++
>> ++            pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
>> ++            extra_size_remaining =
>> ++                extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
>> ++          } while (extra_size_remaining);
>> ++
>> ++          MZ_FREE(buf);
>> ++        }
>> ++      }
>> ++
>> ++      /* I've seen archives that aren't marked as zip64 that uses zip64 ext
>> ++       * data, argh */
>> ++      if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) {
>> ++        if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
>> ++             (decomp_size != comp_size)) ||
>> ++            (decomp_size && !comp_size))
>> ++          return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
>> ++      }
>> ++
>> +       disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
>> +-      if ((disk_index != num_this_disk) && (disk_index != 1))
>> +-        return MZ_FALSE;
>> +-      if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
>> +-           MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
>> +-        return MZ_FALSE;
>> ++      if ((disk_index == MZ_UINT16_MAX) ||
>> ++          ((disk_index != num_this_disk) && (disk_index != 1)))
>> ++        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
>> ++
>> ++      if (comp_size != MZ_UINT32_MAX) {
>> ++        if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
>> ++             MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
>> ++          return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
>> ++      }
>> ++
>> ++      bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
>> ++      if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)
>> ++        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
>> ++
>> +       if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
>> +                                MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
>> +                                MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
>> +                                MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
>> +           n)
>> +-        return MZ_FALSE;
>> ++        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
>> ++
>> +       n -= total_header_size;
>> +       p += total_header_size;
>> +     }
>> +diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c
>> +index ff3a8fe1e6..1abcfd8fd1 100644
>> +--- a/contrib/zip/src/zip.c
>> ++++ b/contrib/zip/src/zip.c
>> +@@ -24,7 +24,6 @@
>> +   ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) &&   \
>> +    (P)[1] == ':')
>> + #define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0)
>> +-#define ISSLASH(C) ((C) == '/' || (C) == '\\')
>> + 
>> + #else
>> + 
>> +@@ -48,7 +47,7 @@ int symlink(const char *target, const char *linkpath); // needed on Linux
>> + #endif
>> + 
>> + #ifndef ISSLASH
>> +-#define ISSLASH(C) ((C) == '/')
>> ++#define ISSLASH(C) ((C) == '/' || (C) == '\\')
>> + #endif
>> + 
>> + #define CLEANUP(ptr)                                                           \
>> +@@ -78,26 +77,34 @@ static const char *base_name(const char *name) {
>> +   return base;
>> + }
>> + 
>> +-static int mkpath(const char *path) {
>> +-  char const *p;
>> ++static int mkpath(char *path) {
>> ++  char *p;
>> +   char npath[MAX_PATH + 1];
>> +   int len = 0;
>> +   int has_device = HAS_DEVICE(path);
>> + 
>> +   memset(npath, 0, MAX_PATH + 1);
>> +-
>> +-#ifdef _WIN32
>> +-  // only on windows fix the path
>> +-  npath[0] = path[0];
>> +-  npath[1] = path[1];
>> +-  len = 2;
>> +-#endif // _WIN32
>> +-    
>> ++  if (has_device) {
>> ++    // only on windows
>> ++    npath[0] = path[0];
>> ++    npath[1] = path[1];
>> ++    len = 2;
>> ++  }
>> +   for (p = path + len; *p && len < MAX_PATH; p++) {
>> +     if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) {
>> +-      if (MKDIR(npath) == -1)
>> +-        if (errno != EEXIST)
>> ++#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) ||              \
>> ++    defined(__MINGW32__)
>> ++#else
>> ++      if ('\\' == *p) {
>> ++        *p = '/';
>> ++      }
>> ++#endif
>> ++
>> ++      if (MKDIR(npath) == -1) {
>> ++        if (errno != EEXIST) {
>> +           return -1;
>> ++        }
>> ++      }
>> +     }
>> +     npath[len++] = *p;
>> +   }
>> +@@ -279,7 +286,14 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
>> +   zip->entry.header_offset = zip->archive.m_archive_size;
>> +   memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
>> +   zip->entry.method = 0;
>> ++
>> ++  // UNIX or APPLE
>> ++#if MZ_PLATFORM == 3 || MZ_PLATFORM == 19
>> ++  // regular file with rw-r--r-- persmissions
>> ++  zip->entry.external_attr = (mz_uint32)(0100644) << 16;
>> ++#else
>> +   zip->entry.external_attr = 0;
>> ++#endif
>> + 
>> +   num_alignment_padding_bytes =
>> +       mz_zip_writer_compute_padding_needed_for_file_alignment(pzip);
>> +@@ -660,7 +674,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
>> +   }
>> + 
>> +   if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index,
>> +-  buf, bufsize, 0, NULL,  0)) {
>> ++                                             buf, bufsize, 0, NULL, 0)) {
>> +     return -1;
>> +   }
>> + 
>> +@@ -670,10 +684,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
>> + int zip_entry_fread(struct zip_t *zip, const char *filename) {
>> +   mz_zip_archive *pzip = NULL;
>> +   mz_uint idx;
>> +-#if defined(_MSC_VER)
>> +-#else
>> +   mz_uint32 xattr = 0;
>> +-#endif
>> +   mz_zip_archive_file_stat info;
>> + 
>> +   if (!zip) {
>> +@@ -875,12 +886,19 @@ int zip_extract(const char *zipname, const char *dir,
>> +       goto out;
>> +     }
>> + 
>> +-    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)
>> +-        && info.m_external_attr & (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40 is directory)
>> ++    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)
>> ++        && info.m_external_attr &
>> ++               (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40
>> ++                               // is directory)
>> + #if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) ||              \
>> +     defined(__MINGW32__)
>> +-#else      
>> +-      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)) {
>> ++#else
>> ++      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)) {
>> +         goto out;
>> +       }
>> +       symlink_to[info.m_uncomp_size] = '\0';
>> +diff --git a/contrib/zip/src/zip.h b/contrib/zip/src/zip.h
>> +index 5f39df50ad..a48d64d6de 100644
>> +--- a/contrib/zip/src/zip.h
>> ++++ b/contrib/zip/src/zip.h
>> +@@ -20,241 +20,240 @@ extern "C" {
>> + #endif
>> + 
>> + #if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) &&               \
>> +-    !defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(__ssize_t_defined)
>> +-#define _SSIZE_T
>> ++    !defined(__DEFINED_ssize_t) && !defined(__ssize_t_defined) &&              \
>> ++    !defined(_SSIZE_T) && !defined(_SSIZE_T_)
>> ++
>> + // 64-bit Windows is the only mainstream platform
>> + // where sizeof(long) != sizeof(void*)
>> + #ifdef _WIN64
>> +-typedef long long  ssize_t;  /* byte count or error */
>> ++typedef long long ssize_t; /* byte count or error */
>> + #else
>> +-typedef long  ssize_t;  /* byte count or error */
>> ++typedef long ssize_t; /* byte count or error */
>> + #endif
>> ++
>> ++#define _SSIZE_T_DEFINED
>> ++#define _SSIZE_T_DEFINED_
>> ++#define __DEFINED_ssize_t
>> ++#define __ssize_t_defined
>> ++#define _SSIZE_T
>> ++#define _SSIZE_T_
>> ++
>> + #endif
>> + 
>> + #ifndef MAX_PATH
>> + #define MAX_PATH 32767 /* # chars in a path name including NULL */
>> + #endif
>> + 
>> ++/**
>> ++ * @mainpage
>> ++ *
>> ++ * Documenation for @ref zip.
>> ++ */
>> ++
>> ++/**
>> ++ * @addtogroup zip
>> ++ * @{
>> ++ */
>> ++
>> ++/**
>> ++ * Default zip compression level.
>> ++ */
>> ++
>> + #define ZIP_DEFAULT_COMPRESSION_LEVEL 6
>> + 
>> +-/*
>> +-  This data structure is used throughout the library to represent zip archive
>> +-  - forward declaration.
>> +-*/
>> ++/**
>> ++ * @struct zip_t
>> ++ *
>> ++ * This data structure is used throughout the library to represent zip archive -
>> ++ * forward declaration.
>> ++ */
>> + struct zip_t;
>> + 
>> +-/*
>> +-  Opens zip archive with compression level using the given mode.
>> +-
>> +-  Args:
>> +-    zipname: zip archive file name.
>> +-    level: compression level (0-9 are the standard zlib-style levels).
>> +-    mode: file access mode.
>> +-        'r': opens a file for reading/extracting (the file must exists).
>> +-        'w': creates an empty file for writing.
>> +-        'a': appends to an existing archive.
>> +-
>> +-  Returns:
>> +-    The zip archive handler or NULL on error
>> +-*/
>> ++/**
>> ++ * Opens zip archive with compression level using the given mode.
>> ++ *
>> ++ * @param zipname zip archive file name.
>> ++ * @param level compression level (0-9 are the standard zlib-style levels).
>> ++ * @param mode file access mode.
>> ++ *        - 'r': opens a file for reading/extracting (the file must exists).
>> ++ *        - 'w': creates an empty file for writing.
>> ++ *        - 'a': appends to an existing archive.
>> ++ *
>> ++ * @return the zip archive handler or NULL on error
>> ++ */
>> + extern struct zip_t *zip_open(const char *zipname, int level, char mode);
>> + 
>> +-/*
>> +-  Closes the zip archive, releases resources - always finalize.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-*/
>> ++/**
>> ++ * Closes the zip archive, releases resources - always finalize.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ */
>> + extern void zip_close(struct zip_t *zip);
>> + 
>> +-/*
>> +-  Opens an entry by name in the zip archive.
>> +-  For zip archive opened in 'w' or 'a' mode the function will append
>> +-  a new entry. In readonly mode the function tries to locate the entry
>> +-  in global dictionary.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-    entryname: an entry name in local dictionary.
>> +-
>> +-  Returns:
>> +-    The return code - 0 on success, negative number (< 0) on error.
>> +-*/
>> ++/**
>> ++ * Opens an entry by name in the zip archive.
>> ++ *
>> ++ * For zip archive opened in 'w' or 'a' mode the function will append
>> ++ * a new entry. In readonly mode the function tries to locate the entry
>> ++ * in global dictionary.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ * @param entryname an entry name in local dictionary.
>> ++ *
>> ++ * @return the return code - 0 on success, negative number (< 0) on error.
>> ++ */
>> + extern int zip_entry_open(struct zip_t *zip, const char *entryname);
>> + 
>> +-/*
>> +-  Opens a new entry by index in the zip archive.
>> +-  This function is only valid if zip archive was opened in 'r' (readonly) mode.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-    index: index in local dictionary.
>> +-
>> +-  Returns:
>> +-    The return code - 0 on success, negative number (< 0) on error.
>> +-*/
>> ++/**
>> ++ * Opens a new entry by index in the zip archive.
>> ++ *
>> ++ * This function is only valid if zip archive was opened in 'r' (readonly) mode.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ * @param index index in local dictionary.
>> ++ *
>> ++ * @return the return code - 0 on success, negative number (< 0) on error.
>> ++ */
>> + extern int zip_entry_openbyindex(struct zip_t *zip, int index);
>> + 
>> +-/*
>> +-  Closes a zip entry, flushes buffer and releases resources.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-
>> +-  Returns:
>> +-    The return code - 0 on success, negative number (< 0) on error.
>> +-*/
>> ++/**
>> ++ * Closes a zip entry, flushes buffer and releases resources.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ *
>> ++ * @return the return code - 0 on success, negative number (< 0) on error.
>> ++ */
>> + extern int zip_entry_close(struct zip_t *zip);
>> + 
>> +-/*
>> +-  Returns a local name of the current zip entry.
>> +-  The main difference between user's entry name and local entry name
>> +-  is optional relative path.
>> +-  Following .ZIP File Format Specification - the path stored MUST not contain
>> +-  a drive or device letter, or a leading slash.
>> +-  All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
>> +-  for compatibility with Amiga and UNIX file systems etc.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-
>> +-  Returns:
>> +-    The pointer to the current zip entry name, or NULL on error.
>> +-*/
>> ++/**
>> ++ * Returns a local name of the current zip entry.
>> ++ *
>> ++ * The main difference between user's entry name and local entry name
>> ++ * is optional relative path.
>> ++ * Following .ZIP File Format Specification - the path stored MUST not contain
>> ++ * a drive or device letter, or a leading slash.
>> ++ * All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
>> ++ * for compatibility with Amiga and UNIX file systems etc.
>> ++ *
>> ++ * @param zip: zip archive handler.
>> ++ *
>> ++ * @return the pointer to the current zip entry name, or NULL on error.
>> ++ */
>> + extern const char *zip_entry_name(struct zip_t *zip);
>> + 
>> +-/*
>> +-  Returns an index of the current zip entry.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-
>> +-  Returns:
>> +-    The index on success, negative number (< 0) on error.
>> +-*/
>> ++/**
>> ++ * Returns an index of the current zip entry.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ *
>> ++ * @return the index on success, negative number (< 0) on error.
>> ++ */
>> + extern int zip_entry_index(struct zip_t *zip);
>> + 
>> +-/*
>> +-  Determines if the current zip entry is a directory entry.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-
>> +-  Returns:
>> +-    The return code - 1 (true), 0 (false), negative number (< 0) on error.
>> +-*/
>> ++/**
>> ++ * Determines if the current zip entry is a directory entry.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ *
>> ++ * @return the return code - 1 (true), 0 (false), negative number (< 0) on
>> ++ *         error.
>> ++ */
>> + extern int zip_entry_isdir(struct zip_t *zip);
>> + 
>> +-/*
>> +-  Returns an uncompressed size of the current zip entry.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-
>> +-  Returns:
>> +-    The uncompressed size in bytes.
>> +-*/
>> ++/**
>> ++ * Returns an uncompressed size of the current zip entry.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ *
>> ++ * @return the uncompressed size in bytes.
>> ++ */
>> + extern unsigned long long zip_entry_size(struct zip_t *zip);
>> + 
>> +-/*
>> +-  Returns CRC-32 checksum of the current zip entry.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-
>> +-  Returns:
>> +-    The CRC-32 checksum.
>> +-*/
>> ++/**
>> ++ * Returns CRC-32 checksum of the current zip entry.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ *
>> ++ * @return the CRC-32 checksum.
>> ++ */
>> + extern unsigned int zip_entry_crc32(struct zip_t *zip);
>> + 
>> +-/*
>> +-  Compresses an input buffer for the current zip entry.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-    buf: input buffer.
>> +-    bufsize: input buffer size (in bytes).
>> +-
>> +-  Returns:
>> +-    The return code - 0 on success, negative number (< 0) on error.
>> +-*/
>> ++/**
>> ++ * Compresses an input buffer for the current zip entry.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ * @param buf input buffer.
>> ++ * @param bufsize input buffer size (in bytes).
>> ++ *
>> ++ * @return the return code - 0 on success, negative number (< 0) on error.
>> ++ */
>> + extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
>> + 
>> +-/*
>> +-  Compresses a file for the current zip entry.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-    filename: input file.
>> +-
>> +-  Returns:
>> +-    The return code - 0 on success, negative number (< 0) on error.
>> +-*/
>> ++/**
>> ++ * Compresses a file for the current zip entry.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ * @param filename input file.
>> ++ *
>> ++ * @return the return code - 0 on success, negative number (< 0) on error.
>> ++ */
>> + extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
>> + 
>> +-/*
>> +-  Extracts the current zip entry into output buffer.
>> +-  The function allocates sufficient memory for a output buffer.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-    buf: output buffer.
>> +-    bufsize: output buffer size (in bytes).
>> +-
>> +-  Note:
>> +-    - remember to release memory allocated for a output buffer.
>> +-    - for large entries, please take a look at zip_entry_extract function.
>> +-
>> +-  Returns:
>> +-    The return code - the number of bytes actually read on success.
>> +-    Otherwise a -1 on error.
>> +-*/
>> ++/**
>> ++ * Extracts the current zip entry into output buffer.
>> ++ *
>> ++ * The function allocates sufficient memory for a output buffer.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ * @param buf output buffer.
>> ++ * @param bufsize output buffer size (in bytes).
>> ++ *
>> ++ * @note remember to release memory allocated for a output buffer.
>> ++ *       for large entries, please take a look at zip_entry_extract function.
>> ++ *
>> ++ * @return the return code - the number of bytes actually read on success.
>> ++ *         Otherwise a -1 on error.
>> ++ */
>> + extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
>> + 
>> +-/*
>> +-  Extracts the current zip entry into a memory buffer using no memory
>> +-  allocation.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-    buf: preallocated output buffer.
>> +-    bufsize: output buffer size (in bytes).
>> +-
>> +-  Note:
>> +-    - ensure supplied output buffer is large enough.
>> +-    - zip_entry_size function (returns uncompressed size for the current entry)
>> +-      can be handy to estimate how big buffer is needed.
>> +-    - for large entries, please take a look at zip_entry_extract function.
>> +-
>> +-  Returns:
>> +-    The return code - the number of bytes actually read on success.
>> +-    Otherwise a -1 on error (e.g. bufsize is not large enough).
>> +-*/
>> +-extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize);
>> +-
>> +-/*
>> +-  Extracts the current zip entry into output file.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-    filename: output file.
>> +-
>> +-  Returns:
>> +-    The return code - 0 on success, negative number (< 0) on error.
>> +-*/
>> ++/**
>> ++ * Extracts the current zip entry into a memory buffer using no memory
>> ++ * allocation.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ * @param buf preallocated output buffer.
>> ++ * @param bufsize output buffer size (in bytes).
>> ++ *
>> ++ * @note ensure supplied output buffer is large enough.
>> ++ *       zip_entry_size function (returns uncompressed size for the current
>> ++ *       entry) can be handy to estimate how big buffer is needed. for large
>> ++ * entries, please take a look at zip_entry_extract function.
>> ++ *
>> ++ * @return the return code - the number of bytes actually read on success.
>> ++ *         Otherwise a -1 on error (e.g. bufsize is not large enough).
>> ++ */
>> ++extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
>> ++                                     size_t bufsize);
>> ++
>> ++/**
>> ++ * Extracts the current zip entry into output file.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ * @param filename output file.
>> ++ *
>> ++ * @return the return code - 0 on success, negative number (< 0) on error.
>> ++ */
>> + extern int zip_entry_fread(struct zip_t *zip, const char *filename);
>> + 
>> +-/*
>> +-  Extracts the current zip entry using a callback function (on_extract).
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-    on_extract: callback function.
>> +-    arg: opaque pointer (optional argument,
>> +-                         which you can pass to the on_extract callback)
>> +-
>> +-   Returns:
>> +-    The return code - 0 on success, negative number (< 0) on error.
>> ++/**
>> ++ * Extracts the current zip entry using a callback function (on_extract).
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ * @param on_extract callback function.
>> ++ * @param arg opaque pointer (optional argument, which you can pass to the
>> ++ *        on_extract callback)
>> ++ *
>> ++ * @return the return code - 0 on success, negative number (< 0) on error.
>> +  */
>> + extern int
>> + zip_entry_extract(struct zip_t *zip,
>> +@@ -262,53 +261,49 @@ zip_entry_extract(struct zip_t *zip,
>> +                                        const void *data, size_t size),
>> +                   void *arg);
>> + 
>> +-/*
>> +-  Returns the number of all entries (files and directories) in the zip archive.
>> +-
>> +-  Args:
>> +-    zip: zip archive handler.
>> +-
>> +-  Returns:
>> +-    The return code - the number of entries on success,
>> +-    negative number (< 0) on error.
>> +-*/
>> ++/**
>> ++ * Returns the number of all entries (files and directories) in the zip archive.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ *
>> ++ * @return the return code - the number of entries on success, negative number
>> ++ *         (< 0) on error.
>> ++ */
>> + extern int zip_total_entries(struct zip_t *zip);
>> + 
>> +-/*
>> +-  Creates a new archive and puts files into a single zip archive.
>> +-
>> +-  Args:
>> +-    zipname: zip archive file.
>> +-    filenames: input files.
>> +-    len: number of input files.
>> +-
>> +-  Returns:
>> +-    The return code - 0 on success, negative number (< 0) on error.
>> +-*/
>> ++/**
>> ++ * Creates a new archive and puts files into a single zip archive.
>> ++ *
>> ++ * @param zipname zip archive file.
>> ++ * @param filenames input files.
>> ++ * @param len: number of input files.
>> ++ *
>> ++ * @return the return code - 0 on success, negative number (< 0) on error.
>> ++ */
>> + extern int zip_create(const char *zipname, const char *filenames[], size_t len);
>> + 
>> +-/*
>> +-  Extracts a zip archive file into directory.
>> +-
>> +-  If on_extract_entry is not NULL, the callback will be called after
>> +-  successfully extracted each zip entry.
>> +-  Returning a negative value from the callback will cause abort and return an
>> +-  error. The last argument (void *arg) is optional, which you can use to pass
>> +-  data to the on_extract_entry callback.
>> +-
>> +-  Args:
>> +-    zipname: zip archive file.
>> +-    dir: output directory.
>> +-    on_extract_entry: on extract callback.
>> +-    arg: opaque pointer.
>> +-
>> +-  Returns:
>> +-    The return code - 0 on success, negative number (< 0) on error.
>> +-*/
>> ++/**
>> ++ * Extracts a zip archive file into directory.
>> ++ *
>> ++ * If on_extract_entry is not NULL, the callback will be called after
>> ++ * successfully extracted each zip entry.
>> ++ * Returning a negative value from the callback will cause abort and return an
>> ++ * error. The last argument (void *arg) is optional, which you can use to pass
>> ++ * data to the on_extract_entry callback.
>> ++ *
>> ++ * @param zipname zip archive file.
>> ++ * @param dir output directory.
>> ++ * @param on_extract_entry on extract callback.
>> ++ * @param arg opaque pointer.
>> ++ *
>> ++ * @return the return code - 0 on success, negative number (< 0) on error.
>> ++ */
>> + extern int zip_extract(const char *zipname, const char *dir,
>> +                        int (*on_extract_entry)(const char *filename, void *arg),
>> +                        void *arg);
>> + 
>> ++/** @} */
>> ++
>> + #ifdef __cplusplus
>> + }
>> + #endif
>> +diff --git a/contrib/zip/test/CMakeLists.txt b/contrib/zip/test/CMakeLists.txt
>> +index 9b2a8db106..cc060b00fe 100644
>> +--- a/contrib/zip/test/CMakeLists.txt
>> ++++ b/contrib/zip/test/CMakeLists.txt
>> +@@ -1,19 +1,16 @@
>> + cmake_minimum_required(VERSION 2.8)
>> + 
>> +-if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
>> +-  if(ENABLE_COVERAGE)
>> +-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g ")
>> +-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
>> +-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs")
>> +-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage")
>> +-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
>> +-  endif()
>> +-endif ()
>> +-
>> + # test
>> +-include_directories(../src)
>> +-add_executable(test.exe test.c ../src/zip.c)
>> +-add_executable(test_miniz.exe test_miniz.c)
>> ++set(test_out test.out)
>> ++set(test_miniz_out test_miniz.out)
>> ++
>> ++add_executable(${test_out} test.c)
>> ++target_link_libraries(${test_out} zip)
>> ++add_executable(${test_miniz_out} test_miniz.c)
>> ++target_link_libraries(${test_miniz_out} zip)
>> ++
>> ++add_test(NAME ${test_out} COMMAND ${test_out})
>> ++add_test(NAME ${test_miniz_out} COMMAND ${test_miniz_out})
>> + 
>> +-add_test(NAME test COMMAND test.exe)
>> +-add_test(NAME test_miniz COMMAND test_miniz.exe)
>> ++set(test_out ${test_out} PARENT_SCOPE)
>> ++set(test_miniz_out ${test_miniz_out} PARENT_SCOPE)
>> +diff --git a/contrib/zip/test/test.c b/contrib/zip/test/test.c
>> +index 454430533a..a9b2ddab1e 100644
>> +--- a/contrib/zip/test/test.c
>> ++++ b/contrib/zip/test/test.c
>> +@@ -29,6 +29,8 @@
>> + #define XFILE "7.txt\0"
>> + #define XMODE 0100777
>> + 
>> ++#define UNIXMODE 0100644
>> ++
>> + #define UNUSED(x) (void)x
>> + 
>> + static int total_entries = 0;
>> +@@ -102,7 +104,8 @@ static void test_read(void) {
>> +   assert(0 == zip_entry_close(zip));
>> +   free(buf);
>> +   buf = NULL;
>> +-  
>> ++  bufsize = 0;
>> ++
>> +   assert(0 == zip_entry_open(zip, "test/test-2.txt"));
>> +   assert(strlen(TESTDATA2) == zip_entry_size(zip));
>> +   assert(CRC32DATA2 == zip_entry_crc32(zip));
>> +@@ -131,7 +134,8 @@ static void test_read(void) {
>> +   assert(0 == zip_entry_close(zip));
>> +   free(buf);
>> +   buf = NULL;
>> +-  
>> ++  bufsize = 0;
>> ++
>> +   buftmp = strlen(TESTDATA1);
>> +   buf = calloc(buftmp, sizeof(char));
>> +   assert(0 == zip_entry_open(zip, "test/test-1.txt"));
>> +@@ -433,6 +437,35 @@ static void test_mtime(void) {
>> +   remove(ZIPNAME);
>> + }
>> + 
>> ++static void test_unix_permissions(void) {
>> ++#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__)
>> ++#else
>> ++  // UNIX or APPLE
>> ++  struct MZ_FILE_STAT_STRUCT file_stats;
>> ++
>> ++  remove(ZIPNAME);
>> ++
>> ++  struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
>> ++  assert(zip != NULL);
>> ++
>> ++  assert(0 == zip_entry_open(zip, RFILE));
>> ++  assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
>> ++  assert(0 == zip_entry_close(zip));
>> ++
>> ++  zip_close(zip);
>> ++
>> ++  remove(RFILE);
>> ++
>> ++  assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
>> ++
>> ++  assert(0 == MZ_FILE_STAT(RFILE, &file_stats));
>> ++  assert(UNIXMODE == file_stats.st_mode);
>> ++
>> ++  remove(RFILE);
>> ++  remove(ZIPNAME);
>> ++#endif
>> ++}
>> ++
>> + int main(int argc, char *argv[]) {
>> +   UNUSED(argc);
>> +   UNUSED(argv);
>> +@@ -453,6 +486,7 @@ int main(int argc, char *argv[]) {
>> +   test_write_permissions();
>> +   test_exe_permissions();
>> +   test_mtime();
>> ++  test_unix_permissions();
>> + 
>> +   remove(ZIPNAME);
>> +   return 0;
>> +diff --git a/contrib/zip/test/test_miniz.c b/contrib/zip/test/test_miniz.c
>> +index ebc0564dc3..babcaecdb6 100644
>> +--- a/contrib/zip/test/test_miniz.c
>> ++++ b/contrib/zip/test/test_miniz.c
>> +@@ -23,16 +23,39 @@ int main(int argc, char *argv[]) {
>> +   uint step = 0;
>> +   int cmp_status;
>> +   uLong src_len = (uLong)strlen(s_pStr);
>> +-  uLong cmp_len = compressBound(src_len);
>> +   uLong uncomp_len = src_len;
>> ++  uLong cmp_len;
>> +   uint8 *pCmp, *pUncomp;
>> ++  size_t sz;
>> +   uint total_succeeded = 0;
>> +   (void)argc, (void)argv;
>> + 
>> +   printf("miniz.c version: %s\n", MZ_VERSION);
>> + 
>> +   do {
>> ++    pCmp = (uint8 *)tdefl_compress_mem_to_heap(s_pStr, src_len, &cmp_len, 0);
>> ++    if (!pCmp) {
>> ++      printf("tdefl_compress_mem_to_heap failed\n");
>> ++      return EXIT_FAILURE;
>> ++    }
>> ++    if (src_len <= cmp_len) {
>> ++      printf("tdefl_compress_mem_to_heap failed: from %u to %u bytes\n",
>> ++             (mz_uint32)uncomp_len, (mz_uint32)cmp_len);
>> ++      free(pCmp);
>> ++      return EXIT_FAILURE;
>> ++    }
>> ++
>> ++    sz = tdefl_compress_mem_to_mem(pCmp, cmp_len, s_pStr, src_len, 0);
>> ++    if (sz != cmp_len) {
>> ++      printf("tdefl_compress_mem_to_mem failed: expected %u, got %u\n",
>> ++             (mz_uint32)cmp_len, (mz_uint32)sz);
>> ++      free(pCmp);
>> ++      return EXIT_FAILURE;
>> ++    }
>> ++
>> +     // Allocate buffers to hold compressed and uncompressed data.
>> ++    free(pCmp);
>> ++    cmp_len = compressBound(src_len);
>> +     pCmp = (mz_uint8 *)malloc((size_t)cmp_len);
>> +     pUncomp = (mz_uint8 *)malloc((size_t)src_len);
>> +     if ((!pCmp) || (!pUncomp)) {
>> diff --git a/package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch b/package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch
>> new file mode 100644
>> index 0000000000..9bd24630c5
>> --- /dev/null
>> +++ b/package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch
>> @@ -0,0 +1,243 @@
>> +From bb3db0ebaffc6b76de256e597ec1d1e4d2a6663f Mon Sep 17 00:00:00 2001
>> +From: kimkulling <kim.kulling@googlemail.com>
>> +Date: Mon, 9 Mar 2020 10:51:26 +0100
>> +Subject: [PATCH] closes https://github.com/assimp/assimp/issues/2954: upgrade
>> + to latest greatest.
>> +
>> +[Retrieved from:
>> +https://github.com/assimp/assimp/commit/bb3db0ebaffc6b76de256e597ec1d1e4d2a6663f]
>> +Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
>> +---
>> + contrib/zip/CMakeLists.txt      |  8 ++----
>> + contrib/zip/README.md           | 51 +++++++++++++++++++++++++++++++--
>> + contrib/zip/src/zip.c           | 17 ++++++++++-
>> + contrib/zip/src/zip.h           | 13 ++++++++-
>> + contrib/zip/test/CMakeLists.txt |  5 ----
>> + contrib/zip/test/test.c         |  4 ++-
>> + 6 files changed, 81 insertions(+), 17 deletions(-)
>> +
>> +diff --git a/contrib/zip/CMakeLists.txt b/contrib/zip/CMakeLists.txt
>> +index 77916d2e14..f194649ede 100644
>> +--- a/contrib/zip/CMakeLists.txt
>> ++++ b/contrib/zip/CMakeLists.txt
>> +@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
>> + 
>> + project(zip
>> +   LANGUAGES C
>> +-  VERSION "0.1.15")
>> ++  VERSION "0.1.18")
>> + set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
>> + 
>> + option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
>> +@@ -16,10 +16,6 @@ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
>> +         "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
>> +         "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
>> +   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic")
>> +-  if(ENABLE_COVERAGE)
>> +-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
>> +-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
>> +-  endif()
>> + endif (MSVC)
>> + 
>> + # zip
>> +@@ -35,7 +31,7 @@ if (NOT CMAKE_DISABLE_TESTING)
>> +   enable_testing()
>> +   add_subdirectory(test)
>> +   find_package(Sanitizers)
>> +-  add_sanitizers(${PROJECT_NAME} ${test_out} ${test_miniz_out})
>> ++  add_sanitizers(${PROJECT_NAME} ${test_out})
>> + endif()
>> + 
>> + ####
>> +diff --git a/contrib/zip/README.md b/contrib/zip/README.md
>> +index 14eb9a34c8..bdd0822b67 100644
>> +--- a/contrib/zip/README.md
>> ++++ b/contrib/zip/README.md
>> +@@ -1,10 +1,8 @@
>> + ### A portable (OSX/Linux/Windows), simple zip library written in C
>> + This is done by hacking awesome [miniz](https://code.google.com/p/miniz) library and layering functions on top of the miniz v1.15 API.
>> + 
>> +-[![Windows](https://ci.appveyor.com/api/projects/status/bph8dr3jacgmjv32/branch/master?svg=true&label=windows)](https://ci.appveyor.com/project/kuba--/zip)
>> +-[![Linux](https://travis-ci.org/kuba--/zip.svg?branch=master&label=linux%2fosx)](https://travis-ci.org/kuba--/zip)
>> ++[![Build](https://github.com/kuba--/zip/workflows/build/badge.svg)](https://github.com/kuba--/zip/actions?query=workflow%3Abuild)
>> + [![Version](https://badge.fury.io/gh/kuba--%2Fzip.svg)](https://github.com/kuba--/zip/releases)
>> +-[![Codecov](https://codecov.io/gh/kuba--/zip/branch/master/graph/badge.svg)](https://codecov.io/gh/kuba--/zip)
>> + 
>> + 
>> + # The Idea
>> +@@ -213,6 +211,53 @@ func main() {
>> + }
>> + ```
>> + 
>> ++### Rust (ffi)
>> ++```rust
>> ++extern crate libc;
>> ++use std::ffi::CString;
>> ++
>> ++#[repr(C)]
>> ++pub struct Zip {
>> ++    _private: [u8; 0],
>> ++}
>> ++
>> ++#[link(name = "zip")]
>> ++extern "C" {
>> ++    fn zip_open(path: *const libc::c_char, level: libc::c_int, mode: libc::c_char) -> *mut Zip;
>> ++    fn zip_close(zip: *mut Zip) -> libc::c_void;
>> ++
>> ++    fn zip_entry_open(zip: *mut Zip, entryname: *const libc::c_char) -> libc::c_int;
>> ++    fn zip_entry_close(zip: *mut Zip) -> libc::c_int;
>> ++    fn zip_entry_write(
>> ++        zip: *mut Zip,
>> ++        buf: *const libc::c_void,
>> ++        bufsize: libc::size_t,
>> ++    ) -> libc::c_int;
>> ++}
>> ++
>> ++fn main() {
>> ++    let path = CString::new("/tmp/test.zip").unwrap();
>> ++    let mode: libc::c_char = 'w' as libc::c_char;
>> ++
>> ++    let entryname = CString::new("test.txt").unwrap();
>> ++    let content = "test content\0";
>> ++
>> ++    unsafe {
>> ++        let zip: *mut Zip = zip_open(path.as_ptr(), 5, mode);
>> ++        {
>> ++            zip_entry_open(zip, entryname.as_ptr());
>> ++            {
>> ++                let buf = content.as_ptr() as *const libc::c_void;
>> ++                let bufsize = content.len() as libc::size_t;
>> ++                zip_entry_write(zip, buf, bufsize);
>> ++            }
>> ++            zip_entry_close(zip);
>> ++        }
>> ++        zip_close(zip);
>> ++    }
>> ++}
>> ++```
>> ++
>> + ### Ruby (ffi)
>> + Install _ffi_ gem.
>> + ```shell
>> +diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c
>> +index 1abcfd8fd1..3b2821e6a3 100644
>> +--- a/contrib/zip/src/zip.c
>> ++++ b/contrib/zip/src/zip.c
>> +@@ -222,6 +222,20 @@ void zip_close(struct zip_t *zip) {
>> +   }
>> + }
>> + 
>> ++int zip_is64(struct zip_t *zip) {
>> ++  if (!zip) {
>> ++    // zip_t handler is not initialized
>> ++    return -1;
>> ++  }
>> ++
>> ++  if (!zip->archive.m_pState) {
>> ++    // zip state is not initialized
>> ++    return -1;
>> ++  }
>> ++
>> ++  return (int)zip->archive.m_pState->m_zip64;
>> ++}
>> ++
>> + int zip_entry_open(struct zip_t *zip, const char *entryname) {
>> +   size_t entrylen = 0;
>> +   mz_zip_archive *pzip = NULL;
>> +@@ -794,7 +808,8 @@ int zip_create(const char *zipname, const char *filenames[], size_t len) {
>> + 
>> +     if (MZ_FILE_STAT(name, &file_stat) != 0) {
>> +       // problem getting information - check errno
>> +-      return -1;
>> ++      status = -1;
>> ++      break;
>> +     }
>> + 
>> +     if ((file_stat.st_mode & 0200) == 0) {
>> +diff --git a/contrib/zip/src/zip.h b/contrib/zip/src/zip.h
>> +index a48d64d6de..cd3ab5cd00 100644
>> +--- a/contrib/zip/src/zip.h
>> ++++ b/contrib/zip/src/zip.h
>> +@@ -21,7 +21,7 @@ extern "C" {
>> + 
>> + #if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) &&               \
>> +     !defined(__DEFINED_ssize_t) && !defined(__ssize_t_defined) &&              \
>> +-    !defined(_SSIZE_T) && !defined(_SSIZE_T_)
>> ++    !defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(_SSIZE_T_DECLARED)
>> + 
>> + // 64-bit Windows is the only mainstream platform
>> + // where sizeof(long) != sizeof(void*)
>> +@@ -37,6 +37,7 @@ typedef long ssize_t; /* byte count or error */
>> + #define __ssize_t_defined
>> + #define _SSIZE_T
>> + #define _SSIZE_T_
>> ++#define _SSIZE_T_DECLARED
>> + 
>> + #endif
>> + 
>> +@@ -90,6 +91,16 @@ extern struct zip_t *zip_open(const char *zipname, int level, char mode);
>> +  */
>> + extern void zip_close(struct zip_t *zip);
>> + 
>> ++/**
>> ++ * Determines if the archive has a zip64 end of central directory headers.
>> ++ *
>> ++ * @param zip zip archive handler.
>> ++ *
>> ++ * @return the return code - 1 (true), 0 (false), negative number (< 0) on
>> ++ *         error.
>> ++ */
>> ++extern int zip_is64(struct zip_t *zip);
>> ++
>> + /**
>> +  * Opens an entry by name in the zip archive.
>> +  *
>> +diff --git a/contrib/zip/test/CMakeLists.txt b/contrib/zip/test/CMakeLists.txt
>> +index cc060b00fe..1224115858 100644
>> +--- a/contrib/zip/test/CMakeLists.txt
>> ++++ b/contrib/zip/test/CMakeLists.txt
>> +@@ -2,15 +2,10 @@ cmake_minimum_required(VERSION 2.8)
>> + 
>> + # test
>> + set(test_out test.out)
>> +-set(test_miniz_out test_miniz.out)
>> + 
>> + add_executable(${test_out} test.c)
>> + target_link_libraries(${test_out} zip)
>> +-add_executable(${test_miniz_out} test_miniz.c)
>> +-target_link_libraries(${test_miniz_out} zip)
>> + 
>> + add_test(NAME ${test_out} COMMAND ${test_out})
>> +-add_test(NAME ${test_miniz_out} COMMAND ${test_miniz_out})
>> + 
>> + set(test_out ${test_out} PARENT_SCOPE)
>> +-set(test_miniz_out ${test_miniz_out} PARENT_SCOPE)
>> +diff --git a/contrib/zip/test/test.c b/contrib/zip/test/test.c
>> +index a9b2ddab1e..9cc2248ac0 100644
>> +--- a/contrib/zip/test/test.c
>> ++++ b/contrib/zip/test/test.c
>> +@@ -47,7 +47,7 @@ static void test_write(void) {
>> +   assert(CRC32DATA1 == zip_entry_crc32(zip));
>> +   ++total_entries;
>> +   assert(0 == zip_entry_close(zip));
>> +-
>> ++  assert(0 == zip_is64(zip));
>> +   zip_close(zip);
>> + }
>> + 
>> +@@ -92,6 +92,7 @@ static void test_read(void) {
>> +   size_t buftmp;
>> +   struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
>> +   assert(zip != NULL);
>> ++  assert(0 == zip_is64(zip));
>> + 
>> +   assert(0 == zip_entry_open(zip, "test\\test-1.txt"));
>> +   assert(strlen(TESTDATA1) == zip_entry_size(zip));
>> +@@ -310,6 +311,7 @@ static void test_fwrite(void) {
>> +   assert(0 == zip_entry_open(zip, WFILE));
>> +   assert(0 == zip_entry_fwrite(zip, WFILE));
>> +   assert(0 == zip_entry_close(zip));
>> ++  assert(0 == zip_is64(zip));
>> + 
>> +   zip_close(zip);
>> +   remove(WFILE);
>>
diff mbox series

Patch

diff --git a/package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch b/package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch
new file mode 100644
index 0000000000..4b86cc584f
--- /dev/null
+++ b/package/assimp/0002-closes-2733-update-of-zlip-to-fix-gcc-build-for-v9-2-0-32-bit.patch
@@ -0,0 +1,1638 @@ 
+From f78446b14aff46db2ef27d062a275b6a01fd68b1 Mon Sep 17 00:00:00 2001
+From: Kim Kulling <kim.kulling@googlemail.com>
+Date: Tue, 19 Nov 2019 20:30:40 +0100
+Subject: [PATCH] closes https://github.com/assimp/assimp/issues/2733: update
+ of zlip to fix gcc build for v9.2.0 32 bit
+
+[Retrieved (and updated to remove .gitignore and appveyor.yml) from:
+https://github.com/assimp/assimp/commit/f78446b14aff46db2ef27d062a275b6a01fd68b1]
+Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
+---
+ contrib/zip/.gitignore          |   2 +
+ contrib/zip/CMakeLists.txt      |  83 +++++-
+ contrib/zip/README.md           |  12 +-
+ contrib/zip/appveyor.yml        |   2 +-
+ contrib/zip/src/miniz.h         | 457 ++++++++++++++++++++++++++++----
+ contrib/zip/src/zip.c           |  62 +++--
+ contrib/zip/src/zip.h           | 457 ++++++++++++++++----------------
+ contrib/zip/test/CMakeLists.txt |  27 +-
+ contrib/zip/test/test.c         |  38 ++-
+ contrib/zip/test/test_miniz.c   |  25 +-
+ 10 files changed, 821 insertions(+), 344 deletions(-)
+
+diff --git a/contrib/zip/CMakeLists.txt b/contrib/zip/CMakeLists.txt
+index b46dbb1db0..77916d2e14 100644
+--- a/contrib/zip/CMakeLists.txt
++++ b/contrib/zip/CMakeLists.txt
+@@ -1,10 +1,14 @@
+-cmake_minimum_required(VERSION 2.8)
+-project(zip)
+-enable_language(C)
++cmake_minimum_required(VERSION 3.0)
++
++project(zip
++  LANGUAGES C
++  VERSION "0.1.15")
+ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
+ 
++option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
++
+ if (MSVC)
+-  # Use secure functions by defaualt and suppress warnings about "deprecated" functions
++  # Use secure functions by default and suppress warnings about "deprecated" functions
+   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1")
+   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
+   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
+@@ -12,28 +16,80 @@ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
+         "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
+         "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
+   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic")
++  if(ENABLE_COVERAGE)
++    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
++    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
++  endif()
+ endif (MSVC)
+ 
+ # zip
+ set(SRC src/miniz.h src/zip.h src/zip.c)
+ add_library(${PROJECT_NAME} ${SRC})
+-target_include_directories(${PROJECT_NAME} INTERFACE src)
++target_include_directories(${PROJECT_NAME} PUBLIC
++  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
++  $<INSTALL_INTERFACE:include>
++)
+ 
+ # test
+ if (NOT CMAKE_DISABLE_TESTING)
+   enable_testing()
+   add_subdirectory(test)
+   find_package(Sanitizers)
+-  add_sanitizers(${PROJECT_NAME} test.exe)
+-  add_sanitizers(${PROJECT_NAME} test_miniz.exe)
++  add_sanitizers(${PROJECT_NAME} ${test_out} ${test_miniz_out})
+ endif()
+ 
++####
++# Installation (https://github.com/forexample/package-example) {
++
++set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
++set(INCLUDE_INSTALL_DIR "include")
++
++set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
++
++# Configuration
++set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
++set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
++set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
++set(NAMESPACE "${PROJECT_NAME}::")
++
++# Include module with fuction 'write_basic_package_version_file'
++include(CMakePackageConfigHelpers)
++
++# Note: PROJECT_VERSION is used as a VERSION
++write_basic_package_version_file(
++    "${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion
++)
++
++# Use variables:
++#   * TARGETS_EXPORT_NAME
++#   * PROJECT_NAME
++configure_package_config_file(
++    "cmake/Config.cmake.in"
++    "${PROJECT_CONFIG}"
++    INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
++)
++
++install(
++    FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
++    DESTINATION "${CONFIG_INSTALL_DIR}"
++)
++
++install(
++    EXPORT "${TARGETS_EXPORT_NAME}"
++    NAMESPACE "${NAMESPACE}"
++    DESTINATION "${CONFIG_INSTALL_DIR}"
++)
++
++# }
++
+ install(TARGETS ${PROJECT_NAME}
++        EXPORT ${TARGETS_EXPORT_NAME}
+         RUNTIME DESTINATION bin
+         ARCHIVE DESTINATION lib
+         LIBRARY DESTINATION lib
+-        COMPONENT library)
+-install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION include)
++        INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR}
++)
++install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION ${INCLUDE_INSTALL_DIR}/zip)
+ 
+ # uninstall target (https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake)
+ if(NOT TARGET uninstall)
+@@ -45,3 +101,12 @@ if(NOT TARGET uninstall)
+     add_custom_target(uninstall
+         COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
+ endif()
++
++find_package(Doxygen)
++if(DOXYGEN_FOUND)
++    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
++    add_custom_target(doc
++        ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
++        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
++        COMMENT "Generating API documentation with Doxygen" VERBATIM)
++endif()
+diff --git a/contrib/zip/README.md b/contrib/zip/README.md
+index d5fb8cd203..14eb9a34c8 100644
+--- a/contrib/zip/README.md
++++ b/contrib/zip/README.md
+@@ -71,7 +71,7 @@ int arg = 2;
+ zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
+ ```
+ 
+-*   Extract a zip entry into memory.
++* Extract a zip entry into memory.
+ ```c
+ void *buf = NULL;
+ size_t bufsize;
+@@ -89,7 +89,7 @@ zip_close(zip);
+ free(buf);
+ ```
+ 
+-*   Extract a zip entry into memory (no internal allocation).
++* Extract a zip entry into memory (no internal allocation).
+ ```c
+ unsigned char *buf;
+ size_t bufsize;
+@@ -110,7 +110,7 @@ zip_close(zip);
+ free(buf);
+ ```
+ 
+-*   Extract a zip entry into memory using callback.
++* Extract a zip entry into memory using callback.
+ ```c
+ struct buffer_t {
+     char *data;
+@@ -144,7 +144,7 @@ free(buf.data);
+ ```
+ 
+ 
+-*   Extract a zip entry into a file.
++* Extract a zip entry into a file.
+ ```c
+ struct zip_t *zip = zip_open("foo.zip", 0, 'r');
+ {
+@@ -157,7 +157,7 @@ struct zip_t *zip = zip_open("foo.zip", 0, 'r');
+ zip_close(zip);
+ ```
+ 
+-*   List of all zip entries
++* List of all zip entries
+ ```c
+ struct zip_t *zip = zip_open("foo.zip", 0, 'r');
+ int i, n = zip_total_entries(zip);
+@@ -174,7 +174,7 @@ for (i = 0; i < n; ++i) {
+ zip_close(zip);
+ ```
+ 
+-## Bindings
++# Bindings
+ Compile zip library as a dynamic library.
+ ```shell
+ $ mkdir build
+diff --git a/contrib/zip/src/miniz.h b/contrib/zip/src/miniz.h
+index 2c27a94d8d..c4fcfb83e6 100644
+--- a/contrib/zip/src/miniz.h
++++ b/contrib/zip/src/miniz.h
+@@ -221,6 +221,7 @@
+ #ifndef MINIZ_HEADER_INCLUDED
+ #define MINIZ_HEADER_INCLUDED
+ 
++#include <stdint.h>
+ #include <stdlib.h>
+ 
+ // Defines to completely disable specific portions of miniz.c:
+@@ -284,7 +285,8 @@
+ /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */
+ #if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES)
+ #if MINIZ_X86_OR_X64_CPU
+-/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */
++/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
++ * integer loads and stores from unaligned addresses. */
+ #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
+ #define MINIZ_UNALIGNED_USE_MEMCPY
+ #else
+@@ -354,6 +356,44 @@ enum {
+   MZ_FIXED = 4
+ };
+ 
++/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or
++ * modify this enum. */
++typedef enum {
++  MZ_ZIP_NO_ERROR = 0,
++  MZ_ZIP_UNDEFINED_ERROR,
++  MZ_ZIP_TOO_MANY_FILES,
++  MZ_ZIP_FILE_TOO_LARGE,
++  MZ_ZIP_UNSUPPORTED_METHOD,
++  MZ_ZIP_UNSUPPORTED_ENCRYPTION,
++  MZ_ZIP_UNSUPPORTED_FEATURE,
++  MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,
++  MZ_ZIP_NOT_AN_ARCHIVE,
++  MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,
++  MZ_ZIP_UNSUPPORTED_MULTIDISK,
++  MZ_ZIP_DECOMPRESSION_FAILED,
++  MZ_ZIP_COMPRESSION_FAILED,
++  MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,
++  MZ_ZIP_CRC_CHECK_FAILED,
++  MZ_ZIP_UNSUPPORTED_CDIR_SIZE,
++  MZ_ZIP_ALLOC_FAILED,
++  MZ_ZIP_FILE_OPEN_FAILED,
++  MZ_ZIP_FILE_CREATE_FAILED,
++  MZ_ZIP_FILE_WRITE_FAILED,
++  MZ_ZIP_FILE_READ_FAILED,
++  MZ_ZIP_FILE_CLOSE_FAILED,
++  MZ_ZIP_FILE_SEEK_FAILED,
++  MZ_ZIP_FILE_STAT_FAILED,
++  MZ_ZIP_INVALID_PARAMETER,
++  MZ_ZIP_INVALID_FILENAME,
++  MZ_ZIP_BUF_TOO_SMALL,
++  MZ_ZIP_INTERNAL_ERROR,
++  MZ_ZIP_FILE_NOT_FOUND,
++  MZ_ZIP_ARCHIVE_TOO_LARGE,
++  MZ_ZIP_VALIDATION_FAILED,
++  MZ_ZIP_WRITE_CALLBACK_FAILED,
++  MZ_ZIP_TOTAL_ERRORS
++} mz_zip_error;
++
+ // Method
+ #define MZ_DEFLATED 8
+ 
+@@ -696,6 +736,7 @@ typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
+                                     void *pBuf, size_t n);
+ typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
+                                      const void *pBuf, size_t n);
++typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);
+ 
+ struct mz_zip_internal_state_tag;
+ typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
+@@ -707,13 +748,27 @@ typedef enum {
+   MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
+ } mz_zip_mode;
+ 
+-typedef struct mz_zip_archive_tag {
++typedef enum {
++  MZ_ZIP_TYPE_INVALID = 0,
++  MZ_ZIP_TYPE_USER,
++  MZ_ZIP_TYPE_MEMORY,
++  MZ_ZIP_TYPE_HEAP,
++  MZ_ZIP_TYPE_FILE,
++  MZ_ZIP_TYPE_CFILE,
++  MZ_ZIP_TOTAL_TYPES
++} mz_zip_type;
++
++typedef struct {
+   mz_uint64 m_archive_size;
+   mz_uint64 m_central_directory_file_ofs;
+-  mz_uint m_total_files;
++
++  /* We only support up to UINT32_MAX files in zip64 mode. */
++  mz_uint32 m_total_files;
+   mz_zip_mode m_zip_mode;
++  mz_zip_type m_zip_type;
++  mz_zip_error m_last_error;
+ 
+-  mz_uint m_file_offset_alignment;
++  mz_uint64 m_file_offset_alignment;
+ 
+   mz_alloc_func m_pAlloc;
+   mz_free_func m_pFree;
+@@ -722,6 +777,7 @@ typedef struct mz_zip_archive_tag {
+ 
+   mz_file_read_func m_pRead;
+   mz_file_write_func m_pWrite;
++  mz_file_needs_keepalive m_pNeeds_keepalive;
+   void *m_pIO_opaque;
+ 
+   mz_zip_internal_state *m_pState;
+@@ -1263,6 +1319,9 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
+                                                 int strategy);
+ #endif // #ifndef MINIZ_NO_ZLIB_APIS
+ 
++#define MZ_UINT16_MAX (0xFFFFU)
++#define MZ_UINT32_MAX (0xFFFFFFFFU)
++
+ #ifdef __cplusplus
+ }
+ #endif
+@@ -1311,6 +1370,11 @@ typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
+    ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
+ #endif
+ 
++#define MZ_READ_LE64(p)                                                        \
++  (((mz_uint64)MZ_READ_LE32(p)) |                                              \
++   (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32)))       \
++    << 32U))
++
+ #ifdef _MSC_VER
+ #define MZ_FORCEINLINE __forceinline
+ #elif defined(__GNUC__)
+@@ -4160,6 +4224,17 @@ enum {
+   MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
+   MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
+   MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
++
++  /* ZIP64 archive identifier and record sizes */
++  MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,
++  MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,
++  MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,
++  MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,
++  MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,
++  MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,
++  MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,
++  MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,
++
+   // Central directory header record offsets
+   MZ_ZIP_CDH_SIG_OFS = 0,
+   MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
+@@ -4199,6 +4274,31 @@ enum {
+   MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
+   MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
+   MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
++
++  /* ZIP64 End of central directory locator offsets */
++  MZ_ZIP64_ECDL_SIG_OFS = 0,                    /* 4 bytes */
++  MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4,          /* 4 bytes */
++  MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8,  /* 8 bytes */
++  MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */
++
++  /* ZIP64 End of central directory header offsets */
++  MZ_ZIP64_ECDH_SIG_OFS = 0,                       /* 4 bytes */
++  MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4,            /* 8 bytes */
++  MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12,          /* 2 bytes */
++  MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14,           /* 2 bytes */
++  MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16,            /* 4 bytes */
++  MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20,            /* 4 bytes */
++  MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */
++  MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32,       /* 8 bytes */
++  MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40,                /* 8 bytes */
++  MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48,                 /* 8 bytes */
++  MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,
++  MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,
++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,
++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,
++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,
++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,
++  MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11
+ };
+ 
+ typedef struct {
+@@ -4211,7 +4311,24 @@ struct mz_zip_internal_state_tag {
+   mz_zip_array m_central_dir;
+   mz_zip_array m_central_dir_offsets;
+   mz_zip_array m_sorted_central_dir_offsets;
++
++  /* The flags passed in when the archive is initially opened. */
++  uint32_t m_init_flags;
++
++  /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc.
++   */
++  mz_bool m_zip64;
++
++  /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64
++   * will also be slammed to true too, even if we didn't find a zip64 end of
++   * central dir header, etc.) */
++  mz_bool m_zip64_has_extended_info_fields;
++
++  /* These fields are used by the file, FILE, memory, and memory/heap read/write
++   * helpers. */
+   MZ_FILE *m_pFile;
++  mz_uint64 m_file_archive_start_ofs;
++
+   void *m_pMem;
+   size_t m_mem_size;
+   size_t m_mem_capacity;
+@@ -4363,6 +4480,13 @@ static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time,
+ #endif /* #ifndef MINIZ_NO_STDIO */
+ #endif /* #ifndef MINIZ_NO_TIME */
+ 
++static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip,
++                                               mz_zip_error err_num) {
++  if (pZip)
++    pZip->m_last_error = err_num;
++  return MZ_FALSE;
++}
++
+ static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
+                                            mz_uint32 flags) {
+   (void)flags;
+@@ -4480,127 +4604,346 @@ mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) {
+   }
+ }
+ 
+-static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
+-                                              mz_uint32 flags) {
+-  mz_uint cdir_size, num_this_disk, cdir_disk_index;
+-  mz_uint64 cdir_ofs;
++static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip,
++                                               mz_uint32 record_sig,
++                                               mz_uint32 record_size,
++                                               mz_int64 *pOfs) {
+   mz_int64 cur_file_ofs;
+-  const mz_uint8 *p;
+   mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
+   mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
+-  mz_bool sort_central_dir =
+-      ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
+-  // Basic sanity checks - reject files which are too small, and check the first
+-  // 4 bytes of the file to make sure a local header is there.
+-  if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
++
++  /* Basic sanity checks - reject files which are too small */
++  if (pZip->m_archive_size < record_size)
+     return MZ_FALSE;
+-  // Find the end of central directory record by scanning the file from the end
+-  // towards the beginning.
++
++  /* Find the record by scanning the file from the end towards the beginning. */
+   cur_file_ofs =
+       MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
+   for (;;) {
+     int i,
+         n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
++
+     if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
+       return MZ_FALSE;
+-    for (i = n - 4; i >= 0; --i)
+-      if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
+-        break;
++
++    for (i = n - 4; i >= 0; --i) {
++      mz_uint s = MZ_READ_LE32(pBuf + i);
++      if (s == record_sig) {
++        if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)
++          break;
++      }
++    }
++
+     if (i >= 0) {
+       cur_file_ofs += i;
+       break;
+     }
++
++    /* Give up if we've searched the entire file, or we've gone back "too far"
++     * (~64kb) */
+     if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
+-                            (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
++                            (MZ_UINT16_MAX + record_size)))
+       return MZ_FALSE;
++
+     cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
+   }
+-  // Read and verify the end of central directory record.
++
++  *pOfs = cur_file_ofs;
++  return MZ_TRUE;
++}
++
++static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
++                                              mz_uint flags) {
++  mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0,
++          cdir_disk_index = 0;
++  mz_uint64 cdir_ofs = 0;
++  mz_int64 cur_file_ofs = 0;
++  const mz_uint8 *p;
++
++  mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
++  mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
++  mz_bool sort_central_dir =
++      ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
++  mz_uint32 zip64_end_of_central_dir_locator_u32
++      [(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) /
++       sizeof(mz_uint32)];
++  mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;
++
++  mz_uint32 zip64_end_of_central_dir_header_u32
++      [(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
++       sizeof(mz_uint32)];
++  mz_uint8 *pZip64_end_of_central_dir =
++      (mz_uint8 *)zip64_end_of_central_dir_header_u32;
++
++  mz_uint64 zip64_end_of_central_dir_ofs = 0;
++
++  /* Basic sanity checks - reject files which are too small, and check the first
++   * 4 bytes of the file to make sure a local header is there. */
++  if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
++    return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
++
++  if (!mz_zip_reader_locate_header_sig(
++          pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG,
++          MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))
++    return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);
++
++  /* Read and verify the end of central directory record. */
+   if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
+                     MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
+       MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
+-    return MZ_FALSE;
+-  if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
+-       MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
+-      ((pZip->m_total_files =
+-            MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) !=
+-       MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
+-    return MZ_FALSE;
++    return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
++
++  if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
++      MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
++    return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
++
++  if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE +
++                       MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) {
++    if (pZip->m_pRead(pZip->m_pIO_opaque,
++                      cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE,
++                      pZip64_locator,
++                      MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ==
++        MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) {
++      if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) ==
++          MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) {
++        zip64_end_of_central_dir_ofs = MZ_READ_LE64(
++            pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);
++        if (zip64_end_of_central_dir_ofs >
++            (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
++          return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
++
++        if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs,
++                          pZip64_end_of_central_dir,
++                          MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ==
++            MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) {
++          if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) ==
++              MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) {
++            pZip->m_pState->m_zip64 = MZ_TRUE;
++          }
++        }
++      }
++    }
++  }
+ 
++  pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);
++  cdir_entries_on_this_disk =
++      MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
+   num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
+   cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
++  cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);
++  cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
++
++  if (pZip->m_pState->m_zip64) {
++    mz_uint32 zip64_total_num_of_disks =
++        MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);
++    mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(
++        pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);
++    mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(
++        pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
++    mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(
++        pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);
++    mz_uint64 zip64_size_of_central_directory =
++        MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);
++
++    if (zip64_size_of_end_of_central_dir_record <
++        (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))
++      return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
++
++    if (zip64_total_num_of_disks != 1U)
++      return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
++
++    /* Check for miniz's practical limits */
++    if (zip64_cdir_total_entries > MZ_UINT32_MAX)
++      return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
++
++    pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;
++
++    if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)
++      return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
++
++    cdir_entries_on_this_disk =
++        (mz_uint32)zip64_cdir_total_entries_on_this_disk;
++
++    /* Check for miniz's current practical limits (sorry, this should be enough
++     * for millions of files) */
++    if (zip64_size_of_central_directory > MZ_UINT32_MAX)
++      return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
++
++    cdir_size = (mz_uint32)zip64_size_of_central_directory;
++
++    num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir +
++                                 MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);
++
++    cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir +
++                                   MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);
++
++    cdir_ofs =
++        MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);
++  }
++
++  if (pZip->m_total_files != cdir_entries_on_this_disk)
++    return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
++
+   if (((num_this_disk | cdir_disk_index) != 0) &&
+       ((num_this_disk != 1) || (cdir_disk_index != 1)))
+-    return MZ_FALSE;
++    return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
+ 
+-  if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) <
+-      pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
+-    return MZ_FALSE;
++  if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
++    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+ 
+-  cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
+   if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
+-    return MZ_FALSE;
++    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+ 
+   pZip->m_central_directory_file_ofs = cdir_ofs;
+ 
+   if (pZip->m_total_files) {
+     mz_uint i, n;
+-
+-    // Read the entire central directory into a heap block, and allocate another
+-    // heap block to hold the unsorted central dir file record offsets, and
+-    // another to hold the sorted indices.
++    /* Read the entire central directory into a heap block, and allocate another
++     * heap block to hold the unsorted central dir file record offsets, and
++     * possibly another to hold the sorted indices. */
+     if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
+                               MZ_FALSE)) ||
+         (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
+                               pZip->m_total_files, MZ_FALSE)))
+-      return MZ_FALSE;
++      return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+ 
+     if (sort_central_dir) {
+       if (!mz_zip_array_resize(pZip,
+                                &pZip->m_pState->m_sorted_central_dir_offsets,
+                                pZip->m_total_files, MZ_FALSE))
+-        return MZ_FALSE;
++        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+     }
+ 
+     if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
+                       pZip->m_pState->m_central_dir.m_p,
+                       cdir_size) != cdir_size)
+-      return MZ_FALSE;
++      return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+ 
+-    // Now create an index into the central directory file records, do some
+-    // basic sanity checking on each record, and check for zip64 entries (which
+-    // are not yet supported).
++    /* Now create an index into the central directory file records, do some
++     * basic sanity checking on each record */
+     p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
+     for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
+-      mz_uint total_header_size, comp_size, decomp_size, disk_index;
++      mz_uint total_header_size, disk_index, bit_flags, filename_size,
++          ext_data_size;
++      mz_uint64 comp_size, decomp_size, local_header_ofs;
++
+       if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
+           (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
+-        return MZ_FALSE;
++        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
++
+       MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
+                            i) =
+           (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
++
+       if (sort_central_dir)
+         MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
+                              mz_uint32, i) = i;
++
+       comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
+       decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
+-      if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
+-           (decomp_size != comp_size)) ||
+-          (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) ||
+-          (comp_size == 0xFFFFFFFF))
+-        return MZ_FALSE;
++      local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
++      filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
++      ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
++
++      if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&
++          (ext_data_size) &&
++          (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) ==
++           MZ_UINT32_MAX)) {
++        /* Attempt to find zip64 extended information field in the entry's extra
++         * data */
++        mz_uint32 extra_size_remaining = ext_data_size;
++
++        if (extra_size_remaining) {
++          const mz_uint8 *pExtra_data;
++          void *buf = NULL;
++
++          if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size >
++              n) {
++            buf = MZ_MALLOC(ext_data_size);
++            if (buf == NULL)
++              return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
++
++            if (pZip->m_pRead(pZip->m_pIO_opaque,
++                              cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
++                                  filename_size,
++                              buf, ext_data_size) != ext_data_size) {
++              MZ_FREE(buf);
++              return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
++            }
++
++            pExtra_data = (mz_uint8 *)buf;
++          } else {
++            pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
++          }
++
++          do {
++            mz_uint32 field_id;
++            mz_uint32 field_data_size;
++
++            if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
++              MZ_FREE(buf);
++              return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
++            }
++
++            field_id = MZ_READ_LE16(pExtra_data);
++            field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
++
++            if ((field_data_size + sizeof(mz_uint16) * 2) >
++                extra_size_remaining) {
++              MZ_FREE(buf);
++              return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
++            }
++
++            if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
++              /* Ok, the archive didn't have any zip64 headers but it uses a
++               * zip64 extended information field so mark it as zip64 anyway
++               * (this can occur with infozip's zip util when it reads
++               * compresses files from stdin). */
++              pZip->m_pState->m_zip64 = MZ_TRUE;
++              pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;
++              break;
++            }
++
++            pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
++            extra_size_remaining =
++                extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
++          } while (extra_size_remaining);
++
++          MZ_FREE(buf);
++        }
++      }
++
++      /* I've seen archives that aren't marked as zip64 that uses zip64 ext
++       * data, argh */
++      if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) {
++        if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
++             (decomp_size != comp_size)) ||
++            (decomp_size && !comp_size))
++          return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
++      }
++
+       disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
+-      if ((disk_index != num_this_disk) && (disk_index != 1))
+-        return MZ_FALSE;
+-      if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
+-           MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
+-        return MZ_FALSE;
++      if ((disk_index == MZ_UINT16_MAX) ||
++          ((disk_index != num_this_disk) && (disk_index != 1)))
++        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
++
++      if (comp_size != MZ_UINT32_MAX) {
++        if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
++             MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
++          return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
++      }
++
++      bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
++      if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)
++        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
++
+       if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
+                                MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
+                                MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
+                                MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
+           n)
+-        return MZ_FALSE;
++        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
++
+       n -= total_header_size;
+       p += total_header_size;
+     }
+diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c
+index ff3a8fe1e6..1abcfd8fd1 100644
+--- a/contrib/zip/src/zip.c
++++ b/contrib/zip/src/zip.c
+@@ -24,7 +24,6 @@
+   ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) &&   \
+    (P)[1] == ':')
+ #define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0)
+-#define ISSLASH(C) ((C) == '/' || (C) == '\\')
+ 
+ #else
+ 
+@@ -48,7 +47,7 @@ int symlink(const char *target, const char *linkpath); // needed on Linux
+ #endif
+ 
+ #ifndef ISSLASH
+-#define ISSLASH(C) ((C) == '/')
++#define ISSLASH(C) ((C) == '/' || (C) == '\\')
+ #endif
+ 
+ #define CLEANUP(ptr)                                                           \
+@@ -78,26 +77,34 @@ static const char *base_name(const char *name) {
+   return base;
+ }
+ 
+-static int mkpath(const char *path) {
+-  char const *p;
++static int mkpath(char *path) {
++  char *p;
+   char npath[MAX_PATH + 1];
+   int len = 0;
+   int has_device = HAS_DEVICE(path);
+ 
+   memset(npath, 0, MAX_PATH + 1);
+-
+-#ifdef _WIN32
+-  // only on windows fix the path
+-  npath[0] = path[0];
+-  npath[1] = path[1];
+-  len = 2;
+-#endif // _WIN32
+-    
++  if (has_device) {
++    // only on windows
++    npath[0] = path[0];
++    npath[1] = path[1];
++    len = 2;
++  }
+   for (p = path + len; *p && len < MAX_PATH; p++) {
+     if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) {
+-      if (MKDIR(npath) == -1)
+-        if (errno != EEXIST)
++#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) ||              \
++    defined(__MINGW32__)
++#else
++      if ('\\' == *p) {
++        *p = '/';
++      }
++#endif
++
++      if (MKDIR(npath) == -1) {
++        if (errno != EEXIST) {
+           return -1;
++        }
++      }
+     }
+     npath[len++] = *p;
+   }
+@@ -279,7 +286,14 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
+   zip->entry.header_offset = zip->archive.m_archive_size;
+   memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
+   zip->entry.method = 0;
++
++  // UNIX or APPLE
++#if MZ_PLATFORM == 3 || MZ_PLATFORM == 19
++  // regular file with rw-r--r-- persmissions
++  zip->entry.external_attr = (mz_uint32)(0100644) << 16;
++#else
+   zip->entry.external_attr = 0;
++#endif
+ 
+   num_alignment_padding_bytes =
+       mz_zip_writer_compute_padding_needed_for_file_alignment(pzip);
+@@ -660,7 +674,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
+   }
+ 
+   if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index,
+-  buf, bufsize, 0, NULL,  0)) {
++                                             buf, bufsize, 0, NULL, 0)) {
+     return -1;
+   }
+ 
+@@ -670,10 +684,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
+ int zip_entry_fread(struct zip_t *zip, const char *filename) {
+   mz_zip_archive *pzip = NULL;
+   mz_uint idx;
+-#if defined(_MSC_VER)
+-#else
+   mz_uint32 xattr = 0;
+-#endif
+   mz_zip_archive_file_stat info;
+ 
+   if (!zip) {
+@@ -875,12 +886,19 @@ int zip_extract(const char *zipname, const char *dir,
+       goto out;
+     }
+ 
+-    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)
+-        && info.m_external_attr & (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40 is directory)
++    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)
++        && info.m_external_attr &
++               (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40
++                               // is directory)
+ #if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) ||              \
+     defined(__MINGW32__)
+-#else      
+-      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)) {
++#else
++      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)) {
+         goto out;
+       }
+       symlink_to[info.m_uncomp_size] = '\0';
+diff --git a/contrib/zip/src/zip.h b/contrib/zip/src/zip.h
+index 5f39df50ad..a48d64d6de 100644
+--- a/contrib/zip/src/zip.h
++++ b/contrib/zip/src/zip.h
+@@ -20,241 +20,240 @@ extern "C" {
+ #endif
+ 
+ #if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) &&               \
+-    !defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(__ssize_t_defined)
+-#define _SSIZE_T
++    !defined(__DEFINED_ssize_t) && !defined(__ssize_t_defined) &&              \
++    !defined(_SSIZE_T) && !defined(_SSIZE_T_)
++
+ // 64-bit Windows is the only mainstream platform
+ // where sizeof(long) != sizeof(void*)
+ #ifdef _WIN64
+-typedef long long  ssize_t;  /* byte count or error */
++typedef long long ssize_t; /* byte count or error */
+ #else
+-typedef long  ssize_t;  /* byte count or error */
++typedef long ssize_t; /* byte count or error */
+ #endif
++
++#define _SSIZE_T_DEFINED
++#define _SSIZE_T_DEFINED_
++#define __DEFINED_ssize_t
++#define __ssize_t_defined
++#define _SSIZE_T
++#define _SSIZE_T_
++
+ #endif
+ 
+ #ifndef MAX_PATH
+ #define MAX_PATH 32767 /* # chars in a path name including NULL */
+ #endif
+ 
++/**
++ * @mainpage
++ *
++ * Documenation for @ref zip.
++ */
++
++/**
++ * @addtogroup zip
++ * @{
++ */
++
++/**
++ * Default zip compression level.
++ */
++
+ #define ZIP_DEFAULT_COMPRESSION_LEVEL 6
+ 
+-/*
+-  This data structure is used throughout the library to represent zip archive
+-  - forward declaration.
+-*/
++/**
++ * @struct zip_t
++ *
++ * This data structure is used throughout the library to represent zip archive -
++ * forward declaration.
++ */
+ struct zip_t;
+ 
+-/*
+-  Opens zip archive with compression level using the given mode.
+-
+-  Args:
+-    zipname: zip archive file name.
+-    level: compression level (0-9 are the standard zlib-style levels).
+-    mode: file access mode.
+-        'r': opens a file for reading/extracting (the file must exists).
+-        'w': creates an empty file for writing.
+-        'a': appends to an existing archive.
+-
+-  Returns:
+-    The zip archive handler or NULL on error
+-*/
++/**
++ * Opens zip archive with compression level using the given mode.
++ *
++ * @param zipname zip archive file name.
++ * @param level compression level (0-9 are the standard zlib-style levels).
++ * @param mode file access mode.
++ *        - 'r': opens a file for reading/extracting (the file must exists).
++ *        - 'w': creates an empty file for writing.
++ *        - 'a': appends to an existing archive.
++ *
++ * @return the zip archive handler or NULL on error
++ */
+ extern struct zip_t *zip_open(const char *zipname, int level, char mode);
+ 
+-/*
+-  Closes the zip archive, releases resources - always finalize.
+-
+-  Args:
+-    zip: zip archive handler.
+-*/
++/**
++ * Closes the zip archive, releases resources - always finalize.
++ *
++ * @param zip zip archive handler.
++ */
+ extern void zip_close(struct zip_t *zip);
+ 
+-/*
+-  Opens an entry by name in the zip archive.
+-  For zip archive opened in 'w' or 'a' mode the function will append
+-  a new entry. In readonly mode the function tries to locate the entry
+-  in global dictionary.
+-
+-  Args:
+-    zip: zip archive handler.
+-    entryname: an entry name in local dictionary.
+-
+-  Returns:
+-    The return code - 0 on success, negative number (< 0) on error.
+-*/
++/**
++ * Opens an entry by name in the zip archive.
++ *
++ * For zip archive opened in 'w' or 'a' mode the function will append
++ * a new entry. In readonly mode the function tries to locate the entry
++ * in global dictionary.
++ *
++ * @param zip zip archive handler.
++ * @param entryname an entry name in local dictionary.
++ *
++ * @return the return code - 0 on success, negative number (< 0) on error.
++ */
+ extern int zip_entry_open(struct zip_t *zip, const char *entryname);
+ 
+-/*
+-  Opens a new entry by index in the zip archive.
+-  This function is only valid if zip archive was opened in 'r' (readonly) mode.
+-
+-  Args:
+-    zip: zip archive handler.
+-    index: index in local dictionary.
+-
+-  Returns:
+-    The return code - 0 on success, negative number (< 0) on error.
+-*/
++/**
++ * Opens a new entry by index in the zip archive.
++ *
++ * This function is only valid if zip archive was opened in 'r' (readonly) mode.
++ *
++ * @param zip zip archive handler.
++ * @param index index in local dictionary.
++ *
++ * @return the return code - 0 on success, negative number (< 0) on error.
++ */
+ extern int zip_entry_openbyindex(struct zip_t *zip, int index);
+ 
+-/*
+-  Closes a zip entry, flushes buffer and releases resources.
+-
+-  Args:
+-    zip: zip archive handler.
+-
+-  Returns:
+-    The return code - 0 on success, negative number (< 0) on error.
+-*/
++/**
++ * Closes a zip entry, flushes buffer and releases resources.
++ *
++ * @param zip zip archive handler.
++ *
++ * @return the return code - 0 on success, negative number (< 0) on error.
++ */
+ extern int zip_entry_close(struct zip_t *zip);
+ 
+-/*
+-  Returns a local name of the current zip entry.
+-  The main difference between user's entry name and local entry name
+-  is optional relative path.
+-  Following .ZIP File Format Specification - the path stored MUST not contain
+-  a drive or device letter, or a leading slash.
+-  All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
+-  for compatibility with Amiga and UNIX file systems etc.
+-
+-  Args:
+-    zip: zip archive handler.
+-
+-  Returns:
+-    The pointer to the current zip entry name, or NULL on error.
+-*/
++/**
++ * Returns a local name of the current zip entry.
++ *
++ * The main difference between user's entry name and local entry name
++ * is optional relative path.
++ * Following .ZIP File Format Specification - the path stored MUST not contain
++ * a drive or device letter, or a leading slash.
++ * All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
++ * for compatibility with Amiga and UNIX file systems etc.
++ *
++ * @param zip: zip archive handler.
++ *
++ * @return the pointer to the current zip entry name, or NULL on error.
++ */
+ extern const char *zip_entry_name(struct zip_t *zip);
+ 
+-/*
+-  Returns an index of the current zip entry.
+-
+-  Args:
+-    zip: zip archive handler.
+-
+-  Returns:
+-    The index on success, negative number (< 0) on error.
+-*/
++/**
++ * Returns an index of the current zip entry.
++ *
++ * @param zip zip archive handler.
++ *
++ * @return the index on success, negative number (< 0) on error.
++ */
+ extern int zip_entry_index(struct zip_t *zip);
+ 
+-/*
+-  Determines if the current zip entry is a directory entry.
+-
+-  Args:
+-    zip: zip archive handler.
+-
+-  Returns:
+-    The return code - 1 (true), 0 (false), negative number (< 0) on error.
+-*/
++/**
++ * Determines if the current zip entry is a directory entry.
++ *
++ * @param zip zip archive handler.
++ *
++ * @return the return code - 1 (true), 0 (false), negative number (< 0) on
++ *         error.
++ */
+ extern int zip_entry_isdir(struct zip_t *zip);
+ 
+-/*
+-  Returns an uncompressed size of the current zip entry.
+-
+-  Args:
+-    zip: zip archive handler.
+-
+-  Returns:
+-    The uncompressed size in bytes.
+-*/
++/**
++ * Returns an uncompressed size of the current zip entry.
++ *
++ * @param zip zip archive handler.
++ *
++ * @return the uncompressed size in bytes.
++ */
+ extern unsigned long long zip_entry_size(struct zip_t *zip);
+ 
+-/*
+-  Returns CRC-32 checksum of the current zip entry.
+-
+-  Args:
+-    zip: zip archive handler.
+-
+-  Returns:
+-    The CRC-32 checksum.
+-*/
++/**
++ * Returns CRC-32 checksum of the current zip entry.
++ *
++ * @param zip zip archive handler.
++ *
++ * @return the CRC-32 checksum.
++ */
+ extern unsigned int zip_entry_crc32(struct zip_t *zip);
+ 
+-/*
+-  Compresses an input buffer for the current zip entry.
+-
+-  Args:
+-    zip: zip archive handler.
+-    buf: input buffer.
+-    bufsize: input buffer size (in bytes).
+-
+-  Returns:
+-    The return code - 0 on success, negative number (< 0) on error.
+-*/
++/**
++ * Compresses an input buffer for the current zip entry.
++ *
++ * @param zip zip archive handler.
++ * @param buf input buffer.
++ * @param bufsize input buffer size (in bytes).
++ *
++ * @return the return code - 0 on success, negative number (< 0) on error.
++ */
+ extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
+ 
+-/*
+-  Compresses a file for the current zip entry.
+-
+-  Args:
+-    zip: zip archive handler.
+-    filename: input file.
+-
+-  Returns:
+-    The return code - 0 on success, negative number (< 0) on error.
+-*/
++/**
++ * Compresses a file for the current zip entry.
++ *
++ * @param zip zip archive handler.
++ * @param filename input file.
++ *
++ * @return the return code - 0 on success, negative number (< 0) on error.
++ */
+ extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
+ 
+-/*
+-  Extracts the current zip entry into output buffer.
+-  The function allocates sufficient memory for a output buffer.
+-
+-  Args:
+-    zip: zip archive handler.
+-    buf: output buffer.
+-    bufsize: output buffer size (in bytes).
+-
+-  Note:
+-    - remember to release memory allocated for a output buffer.
+-    - for large entries, please take a look at zip_entry_extract function.
+-
+-  Returns:
+-    The return code - the number of bytes actually read on success.
+-    Otherwise a -1 on error.
+-*/
++/**
++ * Extracts the current zip entry into output buffer.
++ *
++ * The function allocates sufficient memory for a output buffer.
++ *
++ * @param zip zip archive handler.
++ * @param buf output buffer.
++ * @param bufsize output buffer size (in bytes).
++ *
++ * @note remember to release memory allocated for a output buffer.
++ *       for large entries, please take a look at zip_entry_extract function.
++ *
++ * @return the return code - the number of bytes actually read on success.
++ *         Otherwise a -1 on error.
++ */
+ extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
+ 
+-/*
+-  Extracts the current zip entry into a memory buffer using no memory
+-  allocation.
+-
+-  Args:
+-    zip: zip archive handler.
+-    buf: preallocated output buffer.
+-    bufsize: output buffer size (in bytes).
+-
+-  Note:
+-    - ensure supplied output buffer is large enough.
+-    - zip_entry_size function (returns uncompressed size for the current entry)
+-      can be handy to estimate how big buffer is needed.
+-    - for large entries, please take a look at zip_entry_extract function.
+-
+-  Returns:
+-    The return code - the number of bytes actually read on success.
+-    Otherwise a -1 on error (e.g. bufsize is not large enough).
+-*/
+-extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize);
+-
+-/*
+-  Extracts the current zip entry into output file.
+-
+-  Args:
+-    zip: zip archive handler.
+-    filename: output file.
+-
+-  Returns:
+-    The return code - 0 on success, negative number (< 0) on error.
+-*/
++/**
++ * Extracts the current zip entry into a memory buffer using no memory
++ * allocation.
++ *
++ * @param zip zip archive handler.
++ * @param buf preallocated output buffer.
++ * @param bufsize output buffer size (in bytes).
++ *
++ * @note ensure supplied output buffer is large enough.
++ *       zip_entry_size function (returns uncompressed size for the current
++ *       entry) can be handy to estimate how big buffer is needed. for large
++ * entries, please take a look at zip_entry_extract function.
++ *
++ * @return the return code - the number of bytes actually read on success.
++ *         Otherwise a -1 on error (e.g. bufsize is not large enough).
++ */
++extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
++                                     size_t bufsize);
++
++/**
++ * Extracts the current zip entry into output file.
++ *
++ * @param zip zip archive handler.
++ * @param filename output file.
++ *
++ * @return the return code - 0 on success, negative number (< 0) on error.
++ */
+ extern int zip_entry_fread(struct zip_t *zip, const char *filename);
+ 
+-/*
+-  Extracts the current zip entry using a callback function (on_extract).
+-
+-  Args:
+-    zip: zip archive handler.
+-    on_extract: callback function.
+-    arg: opaque pointer (optional argument,
+-                         which you can pass to the on_extract callback)
+-
+-   Returns:
+-    The return code - 0 on success, negative number (< 0) on error.
++/**
++ * Extracts the current zip entry using a callback function (on_extract).
++ *
++ * @param zip zip archive handler.
++ * @param on_extract callback function.
++ * @param arg opaque pointer (optional argument, which you can pass to the
++ *        on_extract callback)
++ *
++ * @return the return code - 0 on success, negative number (< 0) on error.
+  */
+ extern int
+ zip_entry_extract(struct zip_t *zip,
+@@ -262,53 +261,49 @@ zip_entry_extract(struct zip_t *zip,
+                                        const void *data, size_t size),
+                   void *arg);
+ 
+-/*
+-  Returns the number of all entries (files and directories) in the zip archive.
+-
+-  Args:
+-    zip: zip archive handler.
+-
+-  Returns:
+-    The return code - the number of entries on success,
+-    negative number (< 0) on error.
+-*/
++/**
++ * Returns the number of all entries (files and directories) in the zip archive.
++ *
++ * @param zip zip archive handler.
++ *
++ * @return the return code - the number of entries on success, negative number
++ *         (< 0) on error.
++ */
+ extern int zip_total_entries(struct zip_t *zip);
+ 
+-/*
+-  Creates a new archive and puts files into a single zip archive.
+-
+-  Args:
+-    zipname: zip archive file.
+-    filenames: input files.
+-    len: number of input files.
+-
+-  Returns:
+-    The return code - 0 on success, negative number (< 0) on error.
+-*/
++/**
++ * Creates a new archive and puts files into a single zip archive.
++ *
++ * @param zipname zip archive file.
++ * @param filenames input files.
++ * @param len: number of input files.
++ *
++ * @return the return code - 0 on success, negative number (< 0) on error.
++ */
+ extern int zip_create(const char *zipname, const char *filenames[], size_t len);
+ 
+-/*
+-  Extracts a zip archive file into directory.
+-
+-  If on_extract_entry is not NULL, the callback will be called after
+-  successfully extracted each zip entry.
+-  Returning a negative value from the callback will cause abort and return an
+-  error. The last argument (void *arg) is optional, which you can use to pass
+-  data to the on_extract_entry callback.
+-
+-  Args:
+-    zipname: zip archive file.
+-    dir: output directory.
+-    on_extract_entry: on extract callback.
+-    arg: opaque pointer.
+-
+-  Returns:
+-    The return code - 0 on success, negative number (< 0) on error.
+-*/
++/**
++ * Extracts a zip archive file into directory.
++ *
++ * If on_extract_entry is not NULL, the callback will be called after
++ * successfully extracted each zip entry.
++ * Returning a negative value from the callback will cause abort and return an
++ * error. The last argument (void *arg) is optional, which you can use to pass
++ * data to the on_extract_entry callback.
++ *
++ * @param zipname zip archive file.
++ * @param dir output directory.
++ * @param on_extract_entry on extract callback.
++ * @param arg opaque pointer.
++ *
++ * @return the return code - 0 on success, negative number (< 0) on error.
++ */
+ extern int zip_extract(const char *zipname, const char *dir,
+                        int (*on_extract_entry)(const char *filename, void *arg),
+                        void *arg);
+ 
++/** @} */
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff --git a/contrib/zip/test/CMakeLists.txt b/contrib/zip/test/CMakeLists.txt
+index 9b2a8db106..cc060b00fe 100644
+--- a/contrib/zip/test/CMakeLists.txt
++++ b/contrib/zip/test/CMakeLists.txt
+@@ -1,19 +1,16 @@
+ cmake_minimum_required(VERSION 2.8)
+ 
+-if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
+-  if(ENABLE_COVERAGE)
+-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g ")
+-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
+-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs")
+-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage")
+-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
+-  endif()
+-endif ()
+-
+ # test
+-include_directories(../src)
+-add_executable(test.exe test.c ../src/zip.c)
+-add_executable(test_miniz.exe test_miniz.c)
++set(test_out test.out)
++set(test_miniz_out test_miniz.out)
++
++add_executable(${test_out} test.c)
++target_link_libraries(${test_out} zip)
++add_executable(${test_miniz_out} test_miniz.c)
++target_link_libraries(${test_miniz_out} zip)
++
++add_test(NAME ${test_out} COMMAND ${test_out})
++add_test(NAME ${test_miniz_out} COMMAND ${test_miniz_out})
+ 
+-add_test(NAME test COMMAND test.exe)
+-add_test(NAME test_miniz COMMAND test_miniz.exe)
++set(test_out ${test_out} PARENT_SCOPE)
++set(test_miniz_out ${test_miniz_out} PARENT_SCOPE)
+diff --git a/contrib/zip/test/test.c b/contrib/zip/test/test.c
+index 454430533a..a9b2ddab1e 100644
+--- a/contrib/zip/test/test.c
++++ b/contrib/zip/test/test.c
+@@ -29,6 +29,8 @@
+ #define XFILE "7.txt\0"
+ #define XMODE 0100777
+ 
++#define UNIXMODE 0100644
++
+ #define UNUSED(x) (void)x
+ 
+ static int total_entries = 0;
+@@ -102,7 +104,8 @@ static void test_read(void) {
+   assert(0 == zip_entry_close(zip));
+   free(buf);
+   buf = NULL;
+-  
++  bufsize = 0;
++
+   assert(0 == zip_entry_open(zip, "test/test-2.txt"));
+   assert(strlen(TESTDATA2) == zip_entry_size(zip));
+   assert(CRC32DATA2 == zip_entry_crc32(zip));
+@@ -131,7 +134,8 @@ static void test_read(void) {
+   assert(0 == zip_entry_close(zip));
+   free(buf);
+   buf = NULL;
+-  
++  bufsize = 0;
++
+   buftmp = strlen(TESTDATA1);
+   buf = calloc(buftmp, sizeof(char));
+   assert(0 == zip_entry_open(zip, "test/test-1.txt"));
+@@ -433,6 +437,35 @@ static void test_mtime(void) {
+   remove(ZIPNAME);
+ }
+ 
++static void test_unix_permissions(void) {
++#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__)
++#else
++  // UNIX or APPLE
++  struct MZ_FILE_STAT_STRUCT file_stats;
++
++  remove(ZIPNAME);
++
++  struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
++  assert(zip != NULL);
++
++  assert(0 == zip_entry_open(zip, RFILE));
++  assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
++  assert(0 == zip_entry_close(zip));
++
++  zip_close(zip);
++
++  remove(RFILE);
++
++  assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
++
++  assert(0 == MZ_FILE_STAT(RFILE, &file_stats));
++  assert(UNIXMODE == file_stats.st_mode);
++
++  remove(RFILE);
++  remove(ZIPNAME);
++#endif
++}
++
+ int main(int argc, char *argv[]) {
+   UNUSED(argc);
+   UNUSED(argv);
+@@ -453,6 +486,7 @@ int main(int argc, char *argv[]) {
+   test_write_permissions();
+   test_exe_permissions();
+   test_mtime();
++  test_unix_permissions();
+ 
+   remove(ZIPNAME);
+   return 0;
+diff --git a/contrib/zip/test/test_miniz.c b/contrib/zip/test/test_miniz.c
+index ebc0564dc3..babcaecdb6 100644
+--- a/contrib/zip/test/test_miniz.c
++++ b/contrib/zip/test/test_miniz.c
+@@ -23,16 +23,39 @@ int main(int argc, char *argv[]) {
+   uint step = 0;
+   int cmp_status;
+   uLong src_len = (uLong)strlen(s_pStr);
+-  uLong cmp_len = compressBound(src_len);
+   uLong uncomp_len = src_len;
++  uLong cmp_len;
+   uint8 *pCmp, *pUncomp;
++  size_t sz;
+   uint total_succeeded = 0;
+   (void)argc, (void)argv;
+ 
+   printf("miniz.c version: %s\n", MZ_VERSION);
+ 
+   do {
++    pCmp = (uint8 *)tdefl_compress_mem_to_heap(s_pStr, src_len, &cmp_len, 0);
++    if (!pCmp) {
++      printf("tdefl_compress_mem_to_heap failed\n");
++      return EXIT_FAILURE;
++    }
++    if (src_len <= cmp_len) {
++      printf("tdefl_compress_mem_to_heap failed: from %u to %u bytes\n",
++             (mz_uint32)uncomp_len, (mz_uint32)cmp_len);
++      free(pCmp);
++      return EXIT_FAILURE;
++    }
++
++    sz = tdefl_compress_mem_to_mem(pCmp, cmp_len, s_pStr, src_len, 0);
++    if (sz != cmp_len) {
++      printf("tdefl_compress_mem_to_mem failed: expected %u, got %u\n",
++             (mz_uint32)cmp_len, (mz_uint32)sz);
++      free(pCmp);
++      return EXIT_FAILURE;
++    }
++
+     // Allocate buffers to hold compressed and uncompressed data.
++    free(pCmp);
++    cmp_len = compressBound(src_len);
+     pCmp = (mz_uint8 *)malloc((size_t)cmp_len);
+     pUncomp = (mz_uint8 *)malloc((size_t)src_len);
+     if ((!pCmp) || (!pUncomp)) {
diff --git a/package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch b/package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch
new file mode 100644
index 0000000000..9bd24630c5
--- /dev/null
+++ b/package/assimp/0003-closes-2954-upgrade-to-latest-greatest.patch
@@ -0,0 +1,243 @@ 
+From bb3db0ebaffc6b76de256e597ec1d1e4d2a6663f Mon Sep 17 00:00:00 2001
+From: kimkulling <kim.kulling@googlemail.com>
+Date: Mon, 9 Mar 2020 10:51:26 +0100
+Subject: [PATCH] closes https://github.com/assimp/assimp/issues/2954: upgrade
+ to latest greatest.
+
+[Retrieved from:
+https://github.com/assimp/assimp/commit/bb3db0ebaffc6b76de256e597ec1d1e4d2a6663f]
+Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
+---
+ contrib/zip/CMakeLists.txt      |  8 ++----
+ contrib/zip/README.md           | 51 +++++++++++++++++++++++++++++++--
+ contrib/zip/src/zip.c           | 17 ++++++++++-
+ contrib/zip/src/zip.h           | 13 ++++++++-
+ contrib/zip/test/CMakeLists.txt |  5 ----
+ contrib/zip/test/test.c         |  4 ++-
+ 6 files changed, 81 insertions(+), 17 deletions(-)
+
+diff --git a/contrib/zip/CMakeLists.txt b/contrib/zip/CMakeLists.txt
+index 77916d2e14..f194649ede 100644
+--- a/contrib/zip/CMakeLists.txt
++++ b/contrib/zip/CMakeLists.txt
+@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
+ 
+ project(zip
+   LANGUAGES C
+-  VERSION "0.1.15")
++  VERSION "0.1.18")
+ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
+ 
+ option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
+@@ -16,10 +16,6 @@ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
+         "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
+         "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
+   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic")
+-  if(ENABLE_COVERAGE)
+-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
+-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
+-  endif()
+ endif (MSVC)
+ 
+ # zip
+@@ -35,7 +31,7 @@ if (NOT CMAKE_DISABLE_TESTING)
+   enable_testing()
+   add_subdirectory(test)
+   find_package(Sanitizers)
+-  add_sanitizers(${PROJECT_NAME} ${test_out} ${test_miniz_out})
++  add_sanitizers(${PROJECT_NAME} ${test_out})
+ endif()
+ 
+ ####
+diff --git a/contrib/zip/README.md b/contrib/zip/README.md
+index 14eb9a34c8..bdd0822b67 100644
+--- a/contrib/zip/README.md
++++ b/contrib/zip/README.md
+@@ -1,10 +1,8 @@
+ ### A portable (OSX/Linux/Windows), simple zip library written in C
+ This is done by hacking awesome [miniz](https://code.google.com/p/miniz) library and layering functions on top of the miniz v1.15 API.
+ 
+-[![Windows](https://ci.appveyor.com/api/projects/status/bph8dr3jacgmjv32/branch/master?svg=true&label=windows)](https://ci.appveyor.com/project/kuba--/zip)
+-[![Linux](https://travis-ci.org/kuba--/zip.svg?branch=master&label=linux%2fosx)](https://travis-ci.org/kuba--/zip)
++[![Build](https://github.com/kuba--/zip/workflows/build/badge.svg)](https://github.com/kuba--/zip/actions?query=workflow%3Abuild)
+ [![Version](https://badge.fury.io/gh/kuba--%2Fzip.svg)](https://github.com/kuba--/zip/releases)
+-[![Codecov](https://codecov.io/gh/kuba--/zip/branch/master/graph/badge.svg)](https://codecov.io/gh/kuba--/zip)
+ 
+ 
+ # The Idea
+@@ -213,6 +211,53 @@ func main() {
+ }
+ ```
+ 
++### Rust (ffi)
++```rust
++extern crate libc;
++use std::ffi::CString;
++
++#[repr(C)]
++pub struct Zip {
++    _private: [u8; 0],
++}
++
++#[link(name = "zip")]
++extern "C" {
++    fn zip_open(path: *const libc::c_char, level: libc::c_int, mode: libc::c_char) -> *mut Zip;
++    fn zip_close(zip: *mut Zip) -> libc::c_void;
++
++    fn zip_entry_open(zip: *mut Zip, entryname: *const libc::c_char) -> libc::c_int;
++    fn zip_entry_close(zip: *mut Zip) -> libc::c_int;
++    fn zip_entry_write(
++        zip: *mut Zip,
++        buf: *const libc::c_void,
++        bufsize: libc::size_t,
++    ) -> libc::c_int;
++}
++
++fn main() {
++    let path = CString::new("/tmp/test.zip").unwrap();
++    let mode: libc::c_char = 'w' as libc::c_char;
++
++    let entryname = CString::new("test.txt").unwrap();
++    let content = "test content\0";
++
++    unsafe {
++        let zip: *mut Zip = zip_open(path.as_ptr(), 5, mode);
++        {
++            zip_entry_open(zip, entryname.as_ptr());
++            {
++                let buf = content.as_ptr() as *const libc::c_void;
++                let bufsize = content.len() as libc::size_t;
++                zip_entry_write(zip, buf, bufsize);
++            }
++            zip_entry_close(zip);
++        }
++        zip_close(zip);
++    }
++}
++```
++
+ ### Ruby (ffi)
+ Install _ffi_ gem.
+ ```shell
+diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c
+index 1abcfd8fd1..3b2821e6a3 100644
+--- a/contrib/zip/src/zip.c
++++ b/contrib/zip/src/zip.c
+@@ -222,6 +222,20 @@ void zip_close(struct zip_t *zip) {
+   }
+ }
+ 
++int zip_is64(struct zip_t *zip) {
++  if (!zip) {
++    // zip_t handler is not initialized
++    return -1;
++  }
++
++  if (!zip->archive.m_pState) {
++    // zip state is not initialized
++    return -1;
++  }
++
++  return (int)zip->archive.m_pState->m_zip64;
++}
++
+ int zip_entry_open(struct zip_t *zip, const char *entryname) {
+   size_t entrylen = 0;
+   mz_zip_archive *pzip = NULL;
+@@ -794,7 +808,8 @@ int zip_create(const char *zipname, const char *filenames[], size_t len) {
+ 
+     if (MZ_FILE_STAT(name, &file_stat) != 0) {
+       // problem getting information - check errno
+-      return -1;
++      status = -1;
++      break;
+     }
+ 
+     if ((file_stat.st_mode & 0200) == 0) {
+diff --git a/contrib/zip/src/zip.h b/contrib/zip/src/zip.h
+index a48d64d6de..cd3ab5cd00 100644
+--- a/contrib/zip/src/zip.h
++++ b/contrib/zip/src/zip.h
+@@ -21,7 +21,7 @@ extern "C" {
+ 
+ #if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) &&               \
+     !defined(__DEFINED_ssize_t) && !defined(__ssize_t_defined) &&              \
+-    !defined(_SSIZE_T) && !defined(_SSIZE_T_)
++    !defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(_SSIZE_T_DECLARED)
+ 
+ // 64-bit Windows is the only mainstream platform
+ // where sizeof(long) != sizeof(void*)
+@@ -37,6 +37,7 @@ typedef long ssize_t; /* byte count or error */
+ #define __ssize_t_defined
+ #define _SSIZE_T
+ #define _SSIZE_T_
++#define _SSIZE_T_DECLARED
+ 
+ #endif
+ 
+@@ -90,6 +91,16 @@ extern struct zip_t *zip_open(const char *zipname, int level, char mode);
+  */
+ extern void zip_close(struct zip_t *zip);
+ 
++/**
++ * Determines if the archive has a zip64 end of central directory headers.
++ *
++ * @param zip zip archive handler.
++ *
++ * @return the return code - 1 (true), 0 (false), negative number (< 0) on
++ *         error.
++ */
++extern int zip_is64(struct zip_t *zip);
++
+ /**
+  * Opens an entry by name in the zip archive.
+  *
+diff --git a/contrib/zip/test/CMakeLists.txt b/contrib/zip/test/CMakeLists.txt
+index cc060b00fe..1224115858 100644
+--- a/contrib/zip/test/CMakeLists.txt
++++ b/contrib/zip/test/CMakeLists.txt
+@@ -2,15 +2,10 @@ cmake_minimum_required(VERSION 2.8)
+ 
+ # test
+ set(test_out test.out)
+-set(test_miniz_out test_miniz.out)
+ 
+ add_executable(${test_out} test.c)
+ target_link_libraries(${test_out} zip)
+-add_executable(${test_miniz_out} test_miniz.c)
+-target_link_libraries(${test_miniz_out} zip)
+ 
+ add_test(NAME ${test_out} COMMAND ${test_out})
+-add_test(NAME ${test_miniz_out} COMMAND ${test_miniz_out})
+ 
+ set(test_out ${test_out} PARENT_SCOPE)
+-set(test_miniz_out ${test_miniz_out} PARENT_SCOPE)
+diff --git a/contrib/zip/test/test.c b/contrib/zip/test/test.c
+index a9b2ddab1e..9cc2248ac0 100644
+--- a/contrib/zip/test/test.c
++++ b/contrib/zip/test/test.c
+@@ -47,7 +47,7 @@ static void test_write(void) {
+   assert(CRC32DATA1 == zip_entry_crc32(zip));
+   ++total_entries;
+   assert(0 == zip_entry_close(zip));
+-
++  assert(0 == zip_is64(zip));
+   zip_close(zip);
+ }
+ 
+@@ -92,6 +92,7 @@ static void test_read(void) {
+   size_t buftmp;
+   struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
+   assert(zip != NULL);
++  assert(0 == zip_is64(zip));
+ 
+   assert(0 == zip_entry_open(zip, "test\\test-1.txt"));
+   assert(strlen(TESTDATA1) == zip_entry_size(zip));
+@@ -310,6 +311,7 @@ static void test_fwrite(void) {
+   assert(0 == zip_entry_open(zip, WFILE));
+   assert(0 == zip_entry_fwrite(zip, WFILE));
+   assert(0 == zip_entry_close(zip));
++  assert(0 == zip_is64(zip));
+ 
+   zip_close(zip);
+   remove(WFILE);