[Buildroot] [PATCH 3/3] package/assimp: fix build on musl

Peter Seiderer ps.report at gmx.net
Tue Dec 29 20:54:43 UTC 2020


Hello Fabrice, Yann,

On Mon, 28 Dec 2020 13:01:02 +0100, Fabrice Fontaine <fontaine.fabrice at gmail.com> wrote:

> Fixes:
>  - http://autobuild.buildroot.net/results/7c2db184ee200d1719308f38f42382bb39d8d5c6
>
> Signed-off-by: Fabrice Fontaine <fontaine.fabrice at 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

Note that this patch is enough to re-fix the musl compile (as it is the complete
one from which the small patch was extracted which you removed/reverted with
'[PATCH 1/3] Revert "package/assimp: fix musl zlib/zip  related compile failure"'

Regards,
Peter

>  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 at 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 at 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 at 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 at 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);




More information about the buildroot mailing list