summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMai M <mathew1800@gmail.com>2022-02-08 00:28:20 -0500
committerGitHub <noreply@github.com>2022-02-08 00:28:20 -0500
commitbd83bdb73238511a95bd4e07205c3f90aa14876c (patch)
tree088f7f22a9e54bbaf01dfc1a34c7e66c09a1a69a
parent0d5786059b8c36f3c8536c6a8f0f6769eac89492 (diff)
parentca31964833a41b2968b933144eeec86242dbd67a (diff)
Merge pull request #10437 from AdmiralCurtiss/minizip-ng
Externals: Update minizip to minizip-ng version 3.0.4.
-rw-r--r--Externals/minizip/CMakeLists.txt69
-rw-r--r--Externals/minizip/CMakeLists.txt.original1015
-rw-r--r--Externals/minizip/LICENSE2
-rw-r--r--Externals/minizip/README5
-rw-r--r--Externals/minizip/ioapi.c351
-rw-r--r--Externals/minizip/ioapi.h146
-rw-r--r--Externals/minizip/minigzip.c182
-rw-r--r--Externals/minizip/minizip.c671
-rw-r--r--Externals/minizip/minizip.pc.cmakein14
-rw-r--r--Externals/minizip/minizip.vcxproj30
-rw-r--r--Externals/minizip/mz.h274
-rw-r--r--Externals/minizip/mz_compat.c1303
-rw-r--r--Externals/minizip/mz_compat.h396
-rw-r--r--Externals/minizip/mz_crypt.c196
-rw-r--r--Externals/minizip/mz_crypt.h65
-rw-r--r--Externals/minizip/mz_crypt_apple.c487
-rw-r--r--Externals/minizip/mz_crypt_openssl.c638
-rw-r--r--Externals/minizip/mz_crypt_win32.c739
-rw-r--r--Externals/minizip/mz_os.c354
-rw-r--r--Externals/minizip/mz_os.h175
-rw-r--r--Externals/minizip/mz_os_posix.c367
-rw-r--r--Externals/minizip/mz_os_win32.c659
-rw-r--r--Externals/minizip/mz_strm.c560
-rw-r--r--Externals/minizip/mz_strm.h132
-rw-r--r--Externals/minizip/mz_strm_buf.c385
-rw-r--r--Externals/minizip/mz_strm_buf.h42
-rw-r--r--Externals/minizip/mz_strm_bzip.c374
-rw-r--r--Externals/minizip/mz_strm_bzip.h45
-rw-r--r--Externals/minizip/mz_strm_libcomp.c356
-rw-r--r--Externals/minizip/mz_strm_libcomp.h45
-rw-r--r--Externals/minizip/mz_strm_lzma.c470
-rw-r--r--Externals/minizip/mz_strm_lzma.h43
-rw-r--r--Externals/minizip/mz_strm_mem.c272
-rw-r--r--Externals/minizip/mz_strm_mem.h48
-rw-r--r--Externals/minizip/mz_strm_os.h40
-rw-r--r--Externals/minizip/mz_strm_os_posix.c206
-rw-r--r--Externals/minizip/mz_strm_os_win32.c296
-rw-r--r--Externals/minizip/mz_strm_pkcrypt.c338
-rw-r--r--Externals/minizip/mz_strm_pkcrypt.h46
-rw-r--r--Externals/minizip/mz_strm_split.c438
-rw-r--r--Externals/minizip/mz_strm_split.h43
-rw-r--r--Externals/minizip/mz_strm_wzaes.c362
-rw-r--r--Externals/minizip/mz_strm_wzaes.h46
-rw-r--r--Externals/minizip/mz_strm_zlib.c393
-rw-r--r--Externals/minizip/mz_strm_zlib.h43
-rw-r--r--Externals/minizip/mz_strm_zstd.c351
-rw-r--r--Externals/minizip/mz_strm_zstd.h44
-rw-r--r--Externals/minizip/mz_zip.c2771
-rw-r--r--Externals/minizip/mz_zip.h259
-rw-r--r--Externals/minizip/mz_zip_rw.c1943
-rw-r--r--Externals/minizip/mz_zip_rw.h285
-rw-r--r--Externals/minizip/unzip.c1991
-rw-r--r--Externals/minizip/unzip.h303
-rw-r--r--Externals/minizip/zip.h13
54 files changed, 18319 insertions, 2802 deletions
diff --git a/Externals/minizip/CMakeLists.txt b/Externals/minizip/CMakeLists.txt
index e911124296..b28e136681 100644
--- a/Externals/minizip/CMakeLists.txt
+++ b/Externals/minizip/CMakeLists.txt
@@ -1,18 +1,69 @@
project(minizip C)
-set(SRCS ioapi.c unzip.c)
-
-add_definitions(-DNOUNCRYPT)
-if(UNIX)
- add_definitions(-D__USE_FILE_OFFSET64)
- add_definitions(-D__USE_LARGEFILE64)
- add_definitions(-D_LARGEFILE64_SOURCE)
- add_definitions(-D_FILE_OFFSET_BIT=64)
+add_library(minizip STATIC
+ mz.h
+ mz_compat.c
+ mz_compat.h
+ mz_crypt.c
+ mz_crypt.h
+ mz_os.c
+ mz_os.h
+ mz_strm.c
+ mz_strm.h
+ mz_strm_buf.c
+ mz_strm_buf.h
+ mz_strm_mem.c
+ mz_strm_mem.h
+ mz_strm_os.h
+ mz_strm_split.c
+ mz_strm_split.h
+ mz_strm_zlib.c
+ mz_strm_zlib.h
+ mz_zip.c
+ mz_zip.h
+ mz_zip_rw.c
+ mz_zip_rw.h
+ unzip.h
+ zip.h
+)
+
+if (UNIX)
+ target_sources(minizip PRIVATE
+ mz_os_posix.c
+ mz_strm_os_posix.c
+ )
+endif()
+
+if (WIN32)
+ target_sources(minizip PRIVATE
+ mz_os_win32.c
+ mz_strm_os_win32.c
+ )
endif()
-add_library(minizip STATIC ${SRCS})
target_include_directories(minizip PUBLIC .)
+target_compile_definitions(minizip PRIVATE HAVE_ZLIB ZLIB_COMPAT MZ_ZIP_NO_CRYPTO MZ_ZIP_NO_ENCRYPTION)
+if (UNIX)
+ target_compile_definitions(minizip PRIVATE _POSIX_C_SOURCE=200112L)
+ target_compile_definitions(minizip PRIVATE __USE_LARGEFILE64 _LARGEFILE64_SOURCE)
+endif()
+
+check_include_file(stdint.h HAVE_STDINT_H)
+if (HAVE_STDINT_H)
+ target_compile_definitions(minizip PRIVATE HAVE_STDINT_H)
+endif()
+
+check_include_file(inttypes.h HAVE_INTTYPES_H)
+if (HAVE_INTTYPES_H)
+ target_compile_definitions(minizip PRIVATE HAVE_INTTYPES_H)
+endif()
+
+check_function_exists(fseeko HAVE_FSEEKO)
+if (NOT HAVE_FSEEKO)
+ target_compile_definitions(minizip PRIVATE NO_FSEEKO)
+endif()
+
target_link_libraries(minizip PUBLIC ZLIB::ZLIB)
add_library(MiniZip::minizip ALIAS minizip)
diff --git a/Externals/minizip/CMakeLists.txt.original b/Externals/minizip/CMakeLists.txt.original
new file mode 100644
index 0000000000..38bbf82bbb
--- /dev/null
+++ b/Externals/minizip/CMakeLists.txt.original
@@ -0,0 +1,1015 @@
+#***************************************************************************
+# Copyright (C) 2017-2020 Nathan Moinvaziri
+# https://github.com/zlib-ng/minizip-ng
+# Copyright (C) 2016 Matthias Schmieder
+# schmieder.matthias@gmail.com
+#***************************************************************************
+
+cmake_minimum_required(VERSION 3.13)
+
+message(STATUS "Using CMake version ${CMAKE_VERSION}")
+
+# Compatibility options
+option(MZ_COMPAT "Enables compatibility layer" ON)
+# Compression library options
+option(MZ_ZLIB "Enables ZLIB compression" ON)
+option(MZ_BZIP2 "Enables BZIP2 compression" ON)
+option(MZ_LZMA "Enables LZMA & XZ compression" ON)
+option(MZ_ZSTD "Enables ZSTD compression" ON)
+option(MZ_LIBCOMP "Enables Apple compression" ${APPLE})
+option(MZ_FETCH_LIBS "Enables fetching third-party libraries if not found" ${WIN32})
+option(MZ_FORCE_FETCH_LIBS "Enables fetching third-party libraries always" OFF)
+# Encryption support options
+option(MZ_PKCRYPT "Enables PKWARE traditional encryption" ON)
+option(MZ_WZAES "Enables WinZIP AES encryption" ON)
+option(MZ_OPENSSL "Enables OpenSSL for encryption" ${UNIX})
+option(MZ_LIBBSD "Enable libbsd crypto random" ${UNIX})
+option(MZ_SIGNING "Enables zip signing support" ON)
+# Character conversion options
+option(MZ_ICONV "Enables iconv for string encoding conversion" ON)
+# Code generation options
+option(MZ_COMPRESS_ONLY "Only support compression" OFF)
+option(MZ_DECOMPRESS_ONLY "Only support decompression" OFF)
+option(MZ_FILE32_API "Builds using posix 32-bit file api" OFF)
+# Build and continuous integration options
+option(MZ_BUILD_TESTS "Builds minizip test executable" OFF)
+option(MZ_BUILD_UNIT_TESTS "Builds minizip unit test project" OFF)
+option(MZ_BUILD_FUZZ_TESTS "Builds minizip fuzzer executables" OFF)
+option(MZ_CODE_COVERAGE "Builds with code coverage flags" OFF)
+# Package management options
+set(MZ_PROJECT_SUFFIX "" CACHE STRING "Project name suffix for package managers")
+
+mark_as_advanced(MZ_FILE32_API MZ_PROJECT_SUFFIX)
+
+# Backwards compatibility
+if(DEFINED MZ_BUILD_TEST)
+ set(MZ_BUILD_TESTS ${MZ_BUILD_TEST})
+endif()
+if(DEFINED MZ_BUILD_UNIT_TEST)
+ set(MZ_BUILD_UNIT_TESTS ${MZ_BUILD_UNIT_TEST})
+endif()
+if(DEFINED MZ_BUILD_FUZZ_TEST)
+ set(MZ_BUILD_FUZZ_TESTS ${MZ_BUILD_FUZZ_TEST})
+endif()
+
+if(POLICY CMP0074)
+ cmake_policy(SET CMP0074 OLD)
+endif()
+if(POLICY CMP0054)
+ cmake_policy(SET CMP0054 NEW)
+endif()
+
+# ZLIB_ROOT - Parent directory of zlib installation
+# BZIP2_ROOT - Parent directory of BZip2 installation
+# OPENSSL_ROOT - Parent directory of OpenSSL installation
+
+enable_language(C)
+
+# Library version
+set(VERSION "3.0.4")
+
+# API version
+set(SOVERSION "3")
+
+include(CheckLibraryExists)
+include(CheckSymbolExists)
+include(CheckFunctionExists)
+include(CheckIncludeFile)
+include(CheckTypeSize)
+include(GNUInstallDirs)
+include(FeatureSummary)
+
+set(INSTALL_BIN_DIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Installation directory for executables")
+set(INSTALL_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Installation directory for libraries")
+set(INSTALL_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Installation directory for headers")
+set(INSTALL_MAN_DIR ${CMAKE_INSTALL_MANDIR} CACHE PATH "Installation directory for manual pages")
+
+set(STDLIB_DEF)
+set(MINIZIP_DEF)
+set(MINIZIP_INC)
+set(MINIZIP_LIB)
+set(MINIZIP_LBD)
+set(MINIZIP_DEP)
+set(MINIZIP_DEP_PKG)
+set(MINIZIP_LFG)
+
+# Initial source files
+set(MINIZIP_SRC
+ mz_crypt.c
+ mz_os.c
+ mz_strm.c
+ mz_strm_buf.c
+ mz_strm_mem.c
+ mz_strm_split.c
+ mz_zip.c
+ mz_zip_rw.c)
+
+# Initial header files
+set(MINIZIP_HDR
+ mz.h
+ mz_os.h
+ mz_crypt.h
+ mz_strm.h
+ mz_strm_buf.h
+ mz_strm_mem.h
+ mz_strm_split.h
+ mz_strm_os.h
+ mz_zip.h
+ mz_zip_rw.h)
+
+set(PC_PRIVATE_LIBS)
+
+# Check for system includes
+check_include_file(stdint.h HAVE_STDINT_H)
+check_include_file(inttypes.h HAVE_INTTYPES_H)
+
+if(HAVE_STDINT_H)
+ list(APPEND STDLIB_DEF -DHAVE_STDINT_H)
+endif()
+if(HAVE_INTTYPES_H)
+ list(APPEND STDLIB_DEF -DHAVE_INTTYPES_H)
+endif()
+
+# Check for large file support
+check_type_size(off64_t OFF64_T)
+if(HAVE_OFF64_T)
+ list(APPEND STDLIB_DEF -D__USE_LARGEFILE64)
+ list(APPEND STDLIB_DEF -D_LARGEFILE64_SOURCE)
+endif()
+# Check for fseeko support
+check_function_exists(fseeko HAVE_FSEEKO)
+if(NOT HAVE_FSEEKO)
+ list(APPEND STDLIB_DEF -DNO_FSEEKO)
+endif()
+
+# Checkout remote repository
+macro(clone_repo name url)
+ if(NOT ${name}_REPOSITORY)
+ set(${name}_REPOSITORY ${url})
+ endif()
+ if(NOT ${name}_TAG)
+ set(${name}_TAG master)
+ endif()
+
+ message(STATUS "Fetching ${name} ${${name}_REPOSITORY} ${${name}_TAG}")
+
+ # Check for FetchContent cmake support
+ if(${CMAKE_VERSION} VERSION_LESS "3.11")
+ message(FATAL_ERROR "CMake 3.11 required to fetch ${name}")
+ else()
+ include(FetchContent)
+
+ string(TOLOWER ${name} name_lower)
+ string(TOUPPER ${name} name_upper)
+
+ FetchContent_Declare(${name}
+ GIT_REPOSITORY ${${name}_REPOSITORY}
+ GIT_TAG ${${name}_TAG}
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/${name_lower})
+
+ FetchContent_GetProperties(${name} POPULATED ${name_lower}_POPULATED)
+
+ if(NOT ${name_lower}_POPULATED)
+ FetchContent_Populate(${name})
+ endif()
+
+ set(${name_upper}_SOURCE_DIR ${${name_lower}_SOURCE_DIR})
+ set(${name_upper}_BINARY_DIR ${${name_lower}_BINARY_DIR})
+ endif()
+endmacro()
+
+if(MZ_LIBCOMP)
+ if(APPLE)
+ # Use Apple libcompression
+ list(APPEND MINIZIP_DEF -DHAVE_LIBCOMP)
+ list(APPEND MINIZIP_SRC mz_strm_libcomp.c)
+ list(APPEND MINIZIP_HDR mz_strm_libcomp.h)
+ list(APPEND MINIZIP_LIB compression)
+
+ # Disable zlib as libcompression is preferred
+ set(MZ_ZLIB OFF)
+ else()
+ message(STATUS "LibCompression not supported on the current platform")
+
+ set(MZ_LIBCOMP OFF)
+ endif()
+endif()
+
+if(MZ_ZLIB)
+ # Check if zlib is present
+ if(NOT MZ_FORCE_FETCH_LIBS)
+ find_package(ZLIB QUIET)
+ set(ZLIB_VERSION ${ZLIB_VERSION_STRING})
+ endif()
+
+ if(ZLIB_FOUND AND NOT MZ_FORCE_FETCH_LIBS)
+ message(STATUS "Using ZLIB ${ZLIB_VERSION}")
+
+ list(APPEND MINIZIP_INC ${ZLIB_INCLUDE_DIRS})
+ list(APPEND MINIZIP_LIB ${ZLIB_LIBRARIES})
+ list(APPEND MINIZIP_LBD ${ZLIB_LIBRARY_DIRS})
+
+ set(PC_PRIVATE_LIBS " -lz")
+ elseif(MZ_FETCH_LIBS)
+ clone_repo(zlib https://github.com/madler/zlib)
+
+ # Don't automatically add all targets to the solution
+ add_subdirectory(${ZLIB_SOURCE_DIR} ${ZLIB_BINARY_DIR} EXCLUDE_FROM_ALL)
+
+ list(APPEND MINIZIP_INC ${ZLIB_SOURCE_DIR})
+ list(APPEND MINIZIP_INC ${ZLIB_BINARY_DIR})
+
+ # Have to add zlib to install targets
+ if(NOT DEFINED BUILD_SHARED_LIBS OR NOT ${BUILD_SHARED_LIBS})
+ list(APPEND MINIZIP_DEP zlibstatic)
+ else()
+ list(APPEND MINIZIP_DEP zlib)
+ endif()
+ else()
+ message(STATUS "ZLIB library not found")
+
+ set(MZ_ZLIB OFF)
+ endif()
+
+ if(MZ_ZLIB)
+ list(APPEND MINIZIP_DEP_PKG ZLIB)
+ list(APPEND MINIZIP_DEF -DHAVE_ZLIB)
+ if(ZLIB_COMPAT)
+ list(APPEND MINIZIP_DEF -DZLIB_COMPAT)
+ endif()
+ list(APPEND MINIZIP_SRC mz_strm_zlib.c)
+ list(APPEND MINIZIP_HDR mz_strm_zlib.h)
+ endif()
+endif()
+
+if(MZ_BZIP2)
+ # Check if bzip2 is present
+ if(NOT MZ_FORCE_FETCH_LIBS)
+ find_package(BZip2 QUIET)
+ endif()
+
+ if(BZIP2_FOUND AND NOT MZ_FORCE_FETCH_LIBS)
+ message(STATUS "Using BZIP2 ${BZIP2_VERSION_STRING}")
+
+ list(APPEND MINIZIP_INC ${BZIP2_INCLUDE_DIRS})
+ list(APPEND MINIZIP_LIB ${BZIP2_LIBRARIES})
+ list(APPEND MINIZIP_LBD ${BZIP2_LIBRARY_DIRS})
+
+ set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -lbzip2")
+ elseif(MZ_FETCH_LIBS)
+ clone_repo(bzip2 https://sourceware.org/git/bzip2.git)
+
+ # BZip2 repository does not support cmake so we have to create
+ # the bzip2 library ourselves
+ set(BZIP2_SRC
+ ${BZIP2_SOURCE_DIR}/blocksort.c
+ ${BZIP2_SOURCE_DIR}/bzlib.c
+ ${BZIP2_SOURCE_DIR}/compress.c
+ ${BZIP2_SOURCE_DIR}/crctable.c
+ ${BZIP2_SOURCE_DIR}/decompress.c
+ ${BZIP2_SOURCE_DIR}/huffman.c
+ ${BZIP2_SOURCE_DIR}/randtable.c)
+
+ set(BZIP2_HDR
+ ${BZIP2_SOURCE_DIR}/bzlib.h
+ ${BZIP2_SOURCE_DIR}/bzlib_private.h)
+
+ add_library(bzip2 STATIC ${BZIP2_SRC} ${BZIP2_HDR})
+
+ target_compile_definitions(bzip2 PRIVATE -DBZ_NO_STDIO)
+
+ list(APPEND MINIZIP_DEP bzip2)
+ list(APPEND MINIZIP_INC ${BZIP2_SOURCE_DIR})
+ else()
+ message(STATUS "BZip2 library not found")
+
+ set(MZ_BZIP2 OFF)
+ endif()
+
+ if(MZ_BZIP2)
+ list(APPEND MINIZIP_DEP_PKG BZip2)
+ list(APPEND MINIZIP_DEF -DHAVE_BZIP2)
+ list(APPEND MINIZIP_SRC mz_strm_bzip.c)
+ list(APPEND MINIZIP_HDR mz_strm_bzip.h)
+ endif()
+endif()
+
+if(MZ_LZMA)
+ # Check if liblzma is present
+ if(NOT MZ_FORCE_FETCH_LIBS)
+ find_package(PkgConfig QUIET)
+ if(PKGCONFIG_FOUND)
+ pkg_check_modules(LIBLZMA liblzma)
+ endif()
+ if(NOT LIBLZMA_FOUND)
+ find_package(LibLZMA QUIET)
+ set(LIBLZMA_VERSION ${LIBLZMA_VERSION_STRING})
+ endif()
+ endif()
+
+ if(LIBLZMA_FOUND AND NOT MZ_FORCE_FETCH_LIBS)
+ message(STATUS "Using LZMA ${LIBLZMA_VERSION}")
+
+ list(APPEND MINIZIP_INC ${LIBLZMA_INCLUDE_DIRS})
+ list(APPEND MINIZIP_LIB ${LIBLZMA_LIBRARIES})
+
+ set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -lliblzma")
+ elseif(MZ_FETCH_LIBS)
+ clone_repo(liblzma https://git.tukaani.org/xz.git)
+
+ # Don't automatically add all targets to the solution
+ add_subdirectory(${LIBLZMA_SOURCE_DIR} ${LIBLZMA_BINARY_DIR} EXCLUDE_FROM_ALL)
+
+ list(APPEND MINIZIP_INC ${LIBLZMA_SOURCE_DIR}/src/liblzma/api)
+ list(APPEND MINIZIP_DEP liblzma)
+ list(APPEND MINIZIP_LIB ${LIBLZMA_TARGET})
+ else()
+ message(STATUS "LibLZMA library not found")
+
+ set(MZ_LZMA OFF)
+ endif()
+
+ if(MZ_LZMA)
+ list(APPEND MINIZIP_DEP_PKG LibLZMA)
+ list(APPEND MINIZIP_DEF -DHAVE_LZMA -DLZMA_API_STATIC)
+ list(APPEND MINIZIP_SRC mz_strm_lzma.c)
+ list(APPEND MINIZIP_HDR mz_strm_lzma.h)
+ endif()
+endif()
+
+if(MZ_ZSTD)
+ # Check if zstd is present
+ if(NOT MZ_FORCE_FETCH_LIBS)
+ find_package(PkgConfig QUIET)
+ if(PKGCONFIG_FOUND)
+ pkg_check_modules(ZSTD libzstd)
+ endif()
+ if(NOT ZSTD_FOUND)
+ find_package(ZSTD QUIET)
+ if(ZSTD_FOUND)
+ if(TARGET zstd::libzstd_static)
+ list(APPEND ZSTD_LIBRARIES zstd::libzstd_static)
+ else()
+ list(APPEND ZSTD_LIBRARIES zstd::libzstd_shared)
+ endif()
+ endif()
+ endif()
+ endif()
+
+ if(ZSTD_FOUND AND NOT MZ_FORCE_FETCH_LIBS)
+ message(STATUS "Using ZSTD ${ZSTD_VERSION}")
+
+ list(APPEND MINIZIP_INC ${ZSTD_INCLUDE_DIRS})
+ list(APPEND MINIZIP_LIB ${ZSTD_LIBRARIES})
+ list(APPEND MINIZIP_LBD ${ZSTD_LIBRARY_DIRS})
+
+ set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -lzstd")
+ elseif(MZ_FETCH_LIBS)
+ clone_repo(zstd https://github.com/facebook/zstd)
+
+ # Don't automatically add all targets to the solution
+ add_subdirectory(${ZSTD_SOURCE_DIR}/build/cmake ${ZSTD_BINARY_DIR} EXCLUDE_FROM_ALL)
+
+ list(APPEND MINIZIP_INC ${ZSTD_SOURCE_DIR}/lib)
+ if(NOT DEFINED BUILD_SHARED_LIBS OR NOT ${BUILD_SHARED_LIBS})
+ list(APPEND MINIZIP_DEP libzstd_static)
+ else()
+ list(APPEND MINIZIP_DEP libzstd_shared)
+ endif()
+ else()
+ message(STATUS "ZSTD library not found")
+
+ set(MZ_ZSTD OFF)
+ endif()
+
+ if(MZ_ZSTD)
+ list(APPEND MINIZIP_DEP_PKG zstd)
+ list(APPEND MINIZIP_DEF -DHAVE_ZSTD)
+ list(APPEND MINIZIP_SRC mz_strm_zstd.c)
+ list(APPEND MINIZIP_HDR mz_strm_zstd.h)
+ endif()
+endif()
+
+if(NOT MZ_LIBCOMP AND NOT MZ_ZLIB AND NOT MZ_ZSTD AND NOT MZ_BZIP2 AND NOT MZ_LZMA)
+ message(STATUS "Compression not supported due to missing libraries")
+
+ list(APPEND MINIZIP_DEF -DMZ_ZIP_NO_DECOMPRESSION)
+ list(APPEND MINIZIP_DEF -DMZ_ZIP_NO_COMPRESSION)
+endif()
+
+if(MZ_OPENSSL)
+ # Check to see if openssl installation is present
+ find_package(PkgConfig)
+ if(PKGCONFIG_FOUND)
+ pkg_check_modules(OPENSSL openssl)
+ endif()
+ if(NOT OPENSSL_FOUND)
+ find_package(OpenSSL)
+ endif()
+
+ if(OPENSSL_FOUND)
+ message(STATUS "Using OpenSSL ${OPENSSL_VERSION}")
+
+ list(APPEND MINIZIP_SRC mz_crypt_openssl.c)
+ list(APPEND MINIZIP_LIB ${OPENSSL_LIBRARIES})
+ list(APPEND MINIZIP_LBD ${OPENSSL_LIBRARY_DIRS})
+ list(APPEND MINIZIP_INC ${OPENSSL_INCLUDE_DIR})
+
+ if(OPENSSL_INCLUDE_DIRS)
+ list(APPEND MINIZIP_INC ${OPENSSL_INCLUDE_DIRS})
+ endif()
+ else()
+ message(STATUS "OpenSSL library not found")
+
+ set(MZ_OPENSSL OFF)
+ endif()
+endif()
+
+# Windows specific
+if(WIN32)
+ list(APPEND MINIZIP_DEF -D_CRT_SECURE_NO_DEPRECATE)
+ list(APPEND MINIZIP_SRC mz_os_win32.c mz_strm_os_win32.c)
+
+ if(MZ_PKCRYPT OR MZ_WZAES OR MZ_SIGNING)
+ if(MZ_OPENSSL)
+ list(APPEND MINIZIP_DEP_PKG OpenSSL)
+ else()
+ message(STATUS "Using CryptoAPI")
+
+ list(APPEND MINIZIP_SRC mz_crypt_win32.c)
+ list(APPEND MINIZIP_LIB crypt32.lib)
+ endif()
+ else()
+ list(APPEND MINIZIP_DEF -DMZ_ZIP_NO_CRYPTO)
+ endif()
+endif()
+if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
+ list(APPEND MINIZIP_DEF -DMZ_WINRT_API)
+endif()
+
+# Unix specific
+if(UNIX)
+ list(APPEND STDLIB_DEF -D_POSIX_C_SOURCE=200112L)
+ list(APPEND MINIZIP_SRC mz_os_posix.c mz_strm_os_posix.c)
+
+ if(MZ_PKCRYPT OR MZ_WZAES OR MZ_SIGNING)
+ if(MZ_OPENSSL)
+ list(APPEND MINIZIP_DEP_PKG OpenSSL)
+ else()
+ if(APPLE)
+ message(STATUS "Using CoreFoundation Framework")
+ find_library(COREFOUNDATION_LIBRARY CoreFoundation)
+
+ list(APPEND MINIZIP_LIB ${COREFOUNDATION_LIBRARY})
+
+ message(STATUS "Using Security Framework")
+ find_library(SECURITY_LIBRARY Security)
+
+ list(APPEND MINIZIP_LIB ${SECURITY_LIBRARY})
+ list(APPEND MINIZIP_LFG "-Wl,-F/Library/Frameworks")
+
+ check_include_file(CommonCrypto/CommonCrypto.h COMMONCRYPTO_FOUND)
+ if(COMMONCRYPTO_FOUND)
+ message(STATUS "Using CommonCrypto")
+
+ list(APPEND MINIZIP_SRC mz_crypt_apple.c)
+
+ set(MZ_LIBBSD OFF)
+ else()
+ message(STATUS "CommonCrypto library not found")
+
+ list(APPEND MINIZIP_DEF -DMZ_ZIP_NO_CRYPTO)
+
+ if(MZ_WZAES)
+ message(STATUS "WinZIP AES support requires CommonCrypto or OpenSSL")
+
+ set(MZ_WZAES OFF)
+ endif()
+ if(MZ_SIGNING)
+ message(STATUS "Signing support requires CommonCrypto or OpenSSL")
+
+ set(MZ_SIGNING OFF)
+ endif()
+ endif()
+ else()
+ list(APPEND MINIZIP_DEF -DMZ_ZIP_NO_CRYPTO)
+
+ if(MZ_WZAES)
+ message(STATUS "WinZIP AES support requires OpenSSL")
+
+ set(MZ_WZAES OFF)
+ endif()
+ if(MZ_SIGNING)
+ message(STATUS "Signing support requires OpenSSL")
+
+ set(MZ_SIGNING OFF)
+ endif()
+ endif()
+
+ if(MZ_PKCRYPT AND NOT MZ_WZAES)
+ # Check to see which random generation functions we have
+ check_symbol_exists("getrandom" "sys/random.h" HAVE_GETRANDOM)
+ if(HAVE_GETRANDOM)
+ list(APPEND MINIZIP_DEF -DHAVE_GETRANDOM)
+ endif()
+ check_symbol_exists("arc4random_buf" "stdlib.h" HAVE_ARC4RANDOM_BUF)
+ if(HAVE_ARC4RANDOM_BUF)
+ list(APPEND MINIZIP_DEF -DHAVE_ARC4RANDOM_BUF)
+ else()
+ check_symbol_exists("arc4random" "stdlib.h" HAVE_ARC4RANDOM)
+ if(HAVE_ARC4RANDOM)
+ list(APPEND MINIZIP_DEF -DHAVE_ARC4RANDOM)
+ endif()
+ endif()
+
+ if(APPLE)
+ # Requires _DARWIN_C_SOURCE for arcrandom functions
+ list(APPEND MINIZIP_DEF -D_DARWIN_C_SOURCE)
+ endif()
+
+ if(MZ_LIBBSD AND NOT HAVE_ARC4RANDOM_BUF)
+ find_package(PkgConfig REQUIRED)
+
+ pkg_check_modules(LIBBSD libbsd)
+ if(LIBBSD_FOUND)
+ check_library_exists("${LIBBSD_LIBRARIES}" "arc4random_buf"
+ "${LIBBSD_LIBRARY_DIRS}" HAVE_LIBBSD_ARC4RANDOM_BUF)
+
+ if(HAVE_LIBBSD_ARC4RANDOM_BUF)
+ list(APPEND MINIZIP_DEF -DHAVE_LIBBSD -DHAVE_ARC4RANDOM_BUF)
+ list(APPEND MINIZIP_INC ${LIBBSD_INCLUDE_DIRS})
+ list(APPEND MINIZIP_LIB ${LIBBSD_LIBRARIES})
+ list(APPEND MINIZIP_LBD ${LIBBSD_LIBRARY_DIRS})
+
+ link_directories(${LIBBSD_LIBRARY_DIRS})
+ endif()
+ else()
+ set(MZ_LIBBSD OFF)
+ endif()
+ else()
+ set(MZ_LIBBSD OFF)
+ endif()
+
+ if(NOT MZ_LIBBSD AND NOT HAVE_GETRANDOM AND NOT HAVE_ARC4RANDOM_BUF AND NOT HAVE_ARC4RANDOM)
+ message(WARNING "Low quality entropy function used for encryption")
+ endif()
+ endif()
+ endif()
+ else()
+ list(APPEND MINIZIP_DEF -DMZ_ZIP_NO_CRYPTO)
+ endif()
+
+ # Iconv is only necessary when it is not already built-in
+ # FindIconv requires cmake 3.11 or higher
+ if (MZ_ICONV)
+ find_package(Iconv QUIET)
+ endif()
+
+ if(Iconv_FOUND)
+ message(STATUS "Using Iconv")
+
+ list(APPEND MINIZIP_DEF -DHAVE_ICONV)
+ list(APPEND MINIZIP_INC ${Iconv_INCLUDE_DIRS})
+ list(APPEND MINIZIP_DEP_PKG Iconv)
+ if(NOT Iconv_IS_BUILT_IN)
+ list(APPEND MINIZIP_LIB ${Iconv_LIBRARIES})
+ list(APPEND MINIZIP_LBD ${Iconv_LIBRARY_DIRS})
+ endif()
+
+ set(PC_PRIVATE_LIBS "${PC_PRIVATE_LIBS} -liconv")
+ else()
+ message(STATUS "Character encoding support requires iconv")
+
+ set(MZ_ICONV OFF)
+ endif()
+else()
+ set(MZ_LIBBSD OFF)
+ set(MZ_ICONV OFF)
+endif()
+
+# Setup predefined macros
+if(MZ_COMPRESS_ONLY)
+ list(APPEND MINIZIP_DEF -DMZ_ZIP_NO_DECOMPRESSION)
+endif()
+if(MZ_DECOMPRESS_ONLY)
+ list(APPEND MINIZIP_DEF -DMZ_ZIP_NO_COMPRESSION)
+endif()
+if(NOT MZ_PKCRYPT AND NOT MZ_WZAES)
+ list(APPEND MINIZIP_DEF -DMZ_ZIP_NO_ENCRYPTION)
+endif()
+if(MZ_SIGNING)
+ list(APPEND MINIZIP_DEF -DMZ_ZIP_SIGNING)
+endif()
+if(MZ_FILE32_API)
+ list(APPEND MINIZIP_DEF -DMZ_FILE32_API)
+endif()
+
+# Include traditional PKWare encryption
+if(MZ_PKCRYPT)
+ list(APPEND MINIZIP_DEF -DHAVE_PKCRYPT)
+ list(APPEND MINIZIP_SRC mz_strm_pkcrypt.c)
+ list(APPEND MINIZIP_HDR mz_strm_pkcrypt.h)
+endif()
+
+# Include WinZIP AES encryption
+if(MZ_WZAES)
+ list(APPEND MINIZIP_DEF -DHAVE_WZAES)
+ list(APPEND MINIZIP_SRC mz_strm_wzaes.c)
+ list(APPEND MINIZIP_HDR mz_strm_wzaes.h)
+endif()
+
+# Include compatibility layer
+if(MZ_COMPAT)
+ set(COMPAT_HEADER "\
+/* file.h -- Compatibility layer shim\n\
+ part of the minizip-ng project\n\n\
+ This program is distributed under the terms of the same license as zlib.\n\
+ See the accompanying LICENSE file for the full text of the license.\n\
+*/\n\n\
+#ifndef MZ_COMPAT_FILE\n\
+#define MZ_COMPAT_FILE\n\n\
+#include \"mz_compat.h\"\n\n\
+#endif\n")
+
+ string(REPLACE "file.h" "zip.h" ZIP_COMPAT_HEADER ${COMPAT_HEADER})
+ string(REPLACE "MZ_COMPAT_FILE" "MZ_COMPAT_ZIP" ZIP_COMPAT_HEADER ${ZIP_COMPAT_HEADER})
+ file(WRITE "zip.h" ${ZIP_COMPAT_HEADER})
+
+ string(REPLACE "file.h" "unzip.h" UNZIP_COMPAT_HEADER ${COMPAT_HEADER})
+ string(REPLACE "MZ_COMPAT_FILE" "MZ_COMPAT_UNZIP" UNZIP_COMPAT_HEADER ${UNZIP_COMPAT_HEADER})
+ file(WRITE "unzip.h" ${UNZIP_COMPAT_HEADER})
+
+ if(MZ_COMPAT_VERSION)
+ list(APPEND MINIZIP_DEF -DMZ_COMPAT_VERSION=${MZ_COMPAT_VERSION})
+ endif()
+ list(APPEND MINIZIP_SRC mz_compat.c)
+ list(APPEND MINIZIP_HDR mz_compat.h zip.h unzip.h)
+endif()
+
+# Set compiler options
+if(MZ_CODE_COVERAGE)
+ if(NOT MSVC)
+ message(STATUS "Code coverage enabled")
+ add_compile_options(-O0 -g -fprofile-arcs -ftest-coverage)
+ if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
+ elseif(CMAKE_C_COMPILER_ID MATCHES "GNU")
+ link_libraries(gcov)
+ endif()
+ set_property(DIRECTORY PROPERTY
+ GCC_INSTRUMENT_PROGRAM_FLOW_ARCS YES
+ GCC_GENERATE_TEST_COVERAGE_FILES YES)
+ else()
+ set(MZ_CODE_COVERAGE OFF)
+ endif()
+else()
+ if(MSVC)
+ add_compile_options(
+ $<$<CONFIG:Debug>:/Zi>
+ $<$<CONFIG:Debug>:/Od>
+ $<$<CONFIG:Debug>:/W3>
+ $<$<CONFIG:Release>:/Ox>
+ $<$<CONFIG:Release>:/Os>)
+ else()
+ add_compile_options(
+ $<$<CONFIG:Debug>:-g>
+ $<$<CONFIG:Debug>:-Wall>
+ $<$<CONFIG:Release>:-Os>)
+ endif()
+endif()
+
+list(APPEND MINIZIP_INC ${CMAKE_CURRENT_SOURCE_DIR})
+
+# Create minizip library
+project(minizip${MZ_PROJECT_SUFFIX} VERSION ${VERSION})
+
+if(NOT ${MZ_PROJECT_SUFFIX} STREQUAL "")
+ message(STATUS "Project configured as ${PROJECT_NAME}")
+endif()
+
+set(MINIZIP_PC ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc)
+configure_file(minizip.pc.cmakein ${MINIZIP_PC} @ONLY)
+
+set(INSTALL_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
+ CACHE PATH "Installation directory for cmake files.")
+set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
+ CACHE PATH "Installation directory for pkgconfig (.pc) files")
+
+add_library(${PROJECT_NAME} ${MINIZIP_SRC} ${MINIZIP_HDR})
+
+set_target_properties(${PROJECT_NAME} PROPERTIES
+ VERSION ${VERSION}
+ SOVERSION ${SOVERSION}
+ LINKER_LANGUAGE C
+ DEFINE_SYMBOL "MZ_EXPORTS")
+
+if(MINIZIP_LFG)
+ set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS ${MINIZIP_LFG})
+endif()
+if(MSVC)
+ # VS debugger has problems when executable and static library are named the same
+ set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME lib${PROJECT_NAME})
+endif()
+if(NOT RISCOS)
+ set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE 1)
+endif()
+if(MZ_LZMA)
+ set_target_properties(${PROJECT_NAME} PROPERTIES C_STANDARD 99)
+endif()
+
+target_link_libraries(${PROJECT_NAME} PUBLIC ${MINIZIP_LIB} ${MINIZIP_DEP})
+target_link_directories(${PROJECT_NAME} PUBLIC ${MINIZIP_LBD})
+target_compile_definitions(${PROJECT_NAME} PRIVATE ${STDLIB_DEF} ${MINIZIP_DEF})
+target_include_directories(${PROJECT_NAME} PRIVATE ${MINIZIP_INC})
+target_include_directories(${PROJECT_NAME} PUBLIC
+ $<INSTALL_INTERFACE:${INSTALL_INC_DIR}>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
+
+# Create minizip alias
+add_library(MINIZIP::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
+
+# Install files
+if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
+ install(TARGETS ${PROJECT_NAME} ${MINIZIP_DEP}
+ EXPORT ${PROJECT_NAME}
+ INCLUDES DESTINATION "${INSTALL_INC_DIR}"
+ RUNTIME DESTINATION "${INSTALL_BIN_DIR}"
+ ARCHIVE DESTINATION "${INSTALL_LIB_DIR}"
+ LIBRARY DESTINATION "${INSTALL_LIB_DIR}")
+ install(EXPORT ${PROJECT_NAME}
+ DESTINATION "${INSTALL_CMAKE_DIR}"
+ NAMESPACE "MINIZIP::")
+
+ # Create and install CMake package config version file to allow find_package()
+ include(CMakePackageConfigHelpers)
+ write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
+ COMPATIBILITY SameMajorVersion)
+ set(MINIZIP_CONFIG_CONTENT "@PACKAGE_INIT@\n")
+ if(MINIZIP_DEP_PKG)
+ string(APPEND MINIZIP_CONFIG_CONTENT "include(CMakeFindDependencyMacro)\n")
+ foreach(PKG_NAME ${MINIZIP_DEP_PKG})
+ string(APPEND MINIZIP_CONFIG_CONTENT "find_dependency(${PKG_NAME} REQUIRED)\n")
+ endforeach()
+ endif()
+ string(APPEND MINIZIP_CONFIG_CONTENT "include(\"\${CMAKE_CURRENT_LIST_DIR}/${PROJECT_NAME}.cmake\")")
+ file(WRITE minizip-config.cmake.in ${MINIZIP_CONFIG_CONTENT})
+
+ # Create config for find_package()
+ configure_package_config_file(minizip-config.cmake.in ${PROJECT_NAME}-config.cmake
+ INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}")
+
+ file(REMOVE minizip-config.cmake.in)
+
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
+ DESTINATION "${INSTALL_CMAKE_DIR}")
+endif()
+if(NOT SKIP_INSTALL_HDR AND NOT SKIP_INSTALL_ALL)
+ install(FILES ${MINIZIP_HDR} DESTINATION "${INSTALL_INC_DIR}")
+endif()
+if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL)
+ install(FILES ${MINIZIP_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}")
+endif()
+
+# Build test executables
+if(MZ_BUILD_TESTS)
+ if(MZ_ZLIB AND NOT MZ_LIBCOMP)
+ add_executable(minigzip_cmd minigzip.c)
+ set_target_properties(minigzip_cmd PROPERTIES OUTPUT_NAME minigzip)
+ target_compile_definitions(minigzip_cmd PRIVATE ${STDLIB_DEF} ${MINIZIP_DEF})
+ target_include_directories(minigzip_cmd PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+ target_link_libraries(minigzip_cmd ${PROJECT_NAME})
+
+ if(NOT SKIP_INSTALL_BINARIES AND NOT SKIP_INSTALL_ALL)
+ install(TARGETS minigzip_cmd RUNTIME DESTINATION "bin")
+ endif()
+ endif()
+
+ add_executable(minizip_cmd minizip.c)
+ set_target_properties(minizip_cmd PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
+ target_compile_definitions(minizip_cmd PRIVATE ${STDLIB_DEF} ${MINIZIP_DEF})
+ target_include_directories(minizip_cmd PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+ target_link_libraries(minizip_cmd ${PROJECT_NAME})
+
+ if(NOT SKIP_INSTALL_BINARIES AND NOT SKIP_INSTALL_ALL)
+ install(TARGETS minizip_cmd RUNTIME DESTINATION "bin")
+ endif()
+
+ add_executable(test_cmd test/test.c test/test.h)
+ target_compile_definitions(test_cmd PRIVATE ${STDLIB_DEF} ${MINIZIP_DEF})
+ if(MZ_COMPAT)
+ target_compile_definitions(test_cmd PRIVATE -DHAVE_COMPAT)
+ endif()
+ target_include_directories(test_cmd PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+ target_link_libraries(test_cmd ${PROJECT_NAME})
+endif()
+
+if(MZ_BUILD_TESTS AND MZ_BUILD_UNIT_TESTS)
+ enable_testing()
+
+ # Can't disable zlib testing so ctest tries to run zlib example app
+ if(MZ_ZLIB AND NOT MZ_LIBCOMP AND NOT ZLIB_FOUND)
+ add_dependencies(${PROJECT_NAME} example)
+ if(HAVE_OFF64_T)
+ add_dependencies(${PROJECT_NAME} example64)
+ endif()
+ endif()
+
+ add_test(NAME test_cmd COMMAND test_cmd WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+
+ function(create_compress_tests EXTRA_NAME EXTRA_ARGS)
+ if(MZ_DECOMPRESS_ONLY)
+ return()
+ endif()
+ list(FIND EXTRA_ARGS "-z" ZIPCD_IDX)
+ if(${ZIPCD_IDX} EQUAL -1)
+ set(COMPRESS_METHOD_NAMES "raw")
+ set(COMPRESS_METHOD_ARGS "-0")
+ endif()
+ if(MZ_ZLIB OR MZ_LIBCOMP)
+ list(APPEND COMPRESS_METHOD_NAMES "deflate")
+ list(APPEND COMPRESS_METHOD_ARGS "-9")
+ endif()
+ if(MZ_BZIP2)
+ list(APPEND COMPRESS_METHOD_NAMES "bzip2")
+ list(APPEND COMPRESS_METHOD_ARGS "-b")
+ endif()
+ if(MZ_LZMA)
+ list(APPEND COMPRESS_METHOD_NAMES "lzma")
+ list(APPEND COMPRESS_METHOD_ARGS "-m")
+ endif()
+ if(MZ_LZMA OR MZ_LIBCOMP)
+ list(APPEND COMPRESS_METHOD_NAMES "xz")
+ list(APPEND COMPRESS_METHOD_ARGS "-n")
+ endif()
+ if(MZ_ZSTD)
+ list(APPEND COMPRESS_METHOD_NAMES "zstd")
+ list(APPEND COMPRESS_METHOD_ARGS "-t")
+ endif()
+ list(LENGTH COMPRESS_METHOD_NAMES COMPRESS_METHOD_COUNT)
+ math(EXPR COMPRESS_METHOD_COUNT "${COMPRESS_METHOD_COUNT}-1")
+ foreach(INDEX RANGE ${COMPRESS_METHOD_COUNT})
+ list(GET COMPRESS_METHOD_NAMES ${INDEX} COMPRESS_METHOD_NAME)
+ list(GET COMPRESS_METHOD_ARGS ${INDEX} COMPRESS_METHOD_ARG)
+ add_test(NAME ${COMPRESS_METHOD_NAME}-zip-${EXTRA_NAME}
+ COMMAND minizip_cmd ${COMPRESS_METHOD_ARG} -o ${EXTRA_ARGS}
+ result.zip test.c test.h empty.txt random.bin uniform.bin fuzz
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ add_test(NAME ${COMPRESS_METHOD_NAME}-list-${EXTRA_NAME}
+ COMMAND minizip_cmd -l ${EXTRA_ARGS} result.zip
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ if(NOT MZ_COMPRESS_ONLY)
+ add_test(NAME ${COMPRESS_METHOD_NAME}-unzip-${EXTRA_NAME}
+ COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out result.zip
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ endif()
+ add_test(NAME ${COMPRESS_METHOD_NAME}-append-${EXTRA_NAME}
+ COMMAND minizip_cmd ${COMPRESS_METHOD_ARG} -a ${EXTRA_ARGS}
+ result.zip single.txt
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ if(NOT MZ_COMPRESS_ONLY)
+ add_test(NAME ${COMPRESS_METHOD_NAME}-append-unzip-${EXTRA_NAME}
+ COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out result.zip
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ endif()
+ add_test(NAME ${COMPRESS_METHOD_NAME}-erase-${EXTRA_NAME}
+ COMMAND minizip_cmd -o -e result.zip test.c test.h
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ if(NOT MZ_COMPRESS_ONLY)
+ add_test(NAME ${COMPRESS_METHOD_NAME}-erase-unzip-${EXTRA_NAME}
+ COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out result.zip
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ endif()
+ endforeach()
+ endfunction()
+
+ # Perform tests against ourself
+ create_compress_tests("generic" "")
+ create_compress_tests("span" "-k;1024")
+ create_compress_tests("zipcd" "-z")
+ if(MZ_PKCRYPT)
+ create_compress_tests("pkcrypt" "-p;test123")
+ endif()
+ if(MZ_WZAES)
+ create_compress_tests("wzaes" "-s;-p;test123")
+ endif()
+ if(MZ_SIGNING)
+ create_compress_tests("signed" "-h;test.p12;-w;test")
+ create_compress_tests("secure" "-z;-h;test.p12;-w;test")
+ endif()
+
+ # Perform tests on others
+ if(NOT MZ_COMPRESS_ONLY)
+ if(MZ_ZLIB OR MZ_LIBCOMP)
+ add_test(NAME unzip-tiny
+ COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out
+ fuzz/unzip_fuzzer_seed_corpus/tiny.zip
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ endif()
+ if(MZ_BZIP2)
+ add_test(NAME unzip-bzip2
+ COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out
+ fuzz/unzip_fuzzer_seed_corpus/bzip2.zip
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ endif()
+ if(MZ_LZMA)
+ add_test(NAME unzip-lzma
+ COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out
+ fuzz/unzip_fuzzer_seed_corpus/lzma.zip
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ endif()
+ if(MZ_PKCRYPT)
+ add_test(NAME unzip-pkcrypt
+ COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out -p test123
+ fuzz/unzip_fuzzer_seed_corpus/encrypted_pkcrypt.zip
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ endif()
+ if(MZ_WZAES)
+ add_test(NAME unzip-wzaes
+ COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out -p test123
+ fuzz/unzip_fuzzer_seed_corpus/encrypted_wzaes.zip
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ endif()
+ endif()
+ if(NOT MZ_COMPRESS_ONLY AND NOT MZ_DECOMPRESS_ONLY)
+ if(MZ_ZLIB AND NOT MZ_LIBCOMP)
+ add_test(NAME gz
+ COMMAND minigzip_cmd random.bin
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ add_test(NAME ungz
+ COMMAND minigzip_cmd -x -d out random.bin.gz
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ endif()
+ endif()
+endif()
+
+#Build fuzzer executables
+if(MZ_BUILD_FUZZ_TESTS)
+ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
+ enable_language(CXX)
+
+ if(DEFINED ENV{LIB_FUZZING_ENGINE})
+ set(FUZZING_ENGINE $ENV{LIB_FUZZING_ENGINE})
+ set(FUZZING_ENGINE_FOUND TRUE)
+ else()
+ find_library(FUZZING_ENGINE "FuzzingEngine")
+ endif()
+ endif()
+
+ if(NOT FUZZING_ENGINE_FOUND)
+ set(FUZZER_SRC "test/fuzz/standalone.c")
+ else()
+ set(FUZZER_SRC)
+ endif()
+
+ macro(configure_fuzz_test target)
+ add_executable(${target} "test/fuzz/${target}.c" ${FUZZER_SRC})
+ set_target_properties(${target} PROPERTIES LINKER_LANGUAGE CXX)
+ target_compile_definitions(${target} PRIVATE ${STDLIB_DEF})
+ target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+ target_link_libraries(${target} ${PROJECT_NAME})
+
+ add_dependencies(${target} ${PROJECT_NAME})
+ if(FUZZING_ENGINE_FOUND)
+ target_link_libraries(${target} ${FUZZING_ENGINE})
+ endif()
+ endmacro()
+
+ configure_fuzz_test(zip_fuzzer)
+ configure_fuzz_test(unzip_fuzzer)
+
+ if(NOT SKIP_INSTALL_BINARIES AND NOT SKIP_INSTALL_ALL)
+ install(TARGETS zip_fuzzer RUNTIME DESTINATION "bin")
+ install(TARGETS unzip_fuzzer RUNTIME DESTINATION "bin")
+ endif()
+endif()
+
+# Compatibility options
+add_feature_info(MZ_COMPAT MZ_COMPAT "Enables compatibility layer")
+# Compression library options
+add_feature_info(MZ_ZLIB MZ_ZLIB "Enables ZLIB compression")
+add_feature_info(MZ_BZIP2 MZ_BZIP2 "Enables BZIP2 compression")
+add_feature_info(MZ_LZMA MZ_LZMA "Enables LZMA & XZ compression")
+add_feature_info(MZ_ZSTD MZ_ZSTD "Enables ZSTD compression")
+add_feature_info(MZ_LIBCOMP MZ_LIBCOMP "Enables Apple compression")
+add_feature_info(MZ_FETCH_LIBS MZ_FETCH_LIBS "Enables fetching third-party libraries if not found")
+add_feature_info(MZ_FORCE_FETCH_LIBS MZ_FORCE_FETCH_LIBS "Enables fetching third-party libraries always")
+# Encryption support options
+add_feature_info(MZ_PKCRYPT MZ_PKCRYPT "Enables PKWARE traditional encryption")
+add_feature_info(MZ_WZAES MZ_WZAES "Enables WinZIP AES encryption")
+add_feature_info(MZ_OPENSSL MZ_OPENSSL "Enables OpenSSL for encryption")
+add_feature_info(MZ_LIBBSD MZ_LIBBSD "Build with libbsd for crypto random")
+add_feature_info(MZ_SIGNING MZ_SIGNING "Enables zip signing support")
+# Character conversion options
+add_feature_info(MZ_ICONV MZ_ICONV "Enables iconv string encoding conversion library")
+# Code generation options
+add_feature_info(MZ_COMPRESS_ONLY MZ_COMPRESS_ONLY "Only support compression")
+add_feature_info(MZ_DECOMPRESS_ONLY MZ_DECOMPRESS_ONLY "Only support decompression")
+add_feature_info(MZ_FILE32_API MZ_FILE32_API "Builds using posix 32-bit file api")
+# Build and continuous integration options
+add_feature_info(MZ_BUILD_TESTS MZ_BUILD_TESTS "Builds minizip test executable")
+add_feature_info(MZ_BUILD_UNIT_TESTS MZ_BUILD_UNIT_TESTS "Builds minizip unit test project")
+add_feature_info(MZ_BUILD_FUZZ_TESTS MZ_BUILD_FUZZ_TESTS "Builds minizip fuzzer executables")
+add_feature_info(MZ_CODE_COVERAGE MZ_CODE_COVERAGE "Builds with code coverage flags")
+
+feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES INCLUDE_QUIET_PACKAGES)
diff --git a/Externals/minizip/LICENSE b/Externals/minizip/LICENSE
index 086295a2b2..3b6c4e142e 100644
--- a/Externals/minizip/LICENSE
+++ b/Externals/minizip/LICENSE
@@ -14,4 +14,4 @@ freely, subject to the following restrictions:
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
-3. This notice may not be removed or altered from any source distribution. \ No newline at end of file
+3. This notice may not be removed or altered from any source distribution.
diff --git a/Externals/minizip/README b/Externals/minizip/README
index 8d311e116d..4b929d1504 100644
--- a/Externals/minizip/README
+++ b/Externals/minizip/README
@@ -1,2 +1,3 @@
-Partial import from https://github.com/nmoinvaz/minizip
-Revision: b3713abe7722f1b779e7cdbd527c6208abbe1121
+minizip-ng, Version 3.0.4 (2021-11-29)
+https://github.com/zlib-ng/minizip-ng
+Revision: 95987e98b4862c055b8cf91d6e7ce5f9153ddc24
diff --git a/Externals/minizip/ioapi.c b/Externals/minizip/ioapi.c
deleted file mode 100644
index bba26334dc..0000000000
--- a/Externals/minizip/ioapi.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/* ioapi.c -- IO base function header for compress/uncompress .zip
- part of the MiniZip project
-
- Copyright (C) 1998-2010 Gilles Vollant
- http://www.winimage.com/zLibDll/minizip.html
- Modifications for Zip64 support
- Copyright (C) 2009-2010 Mathias Svensson
- http://result42.com
-
- This program is distributed under the terms of the same license as zlib.
- See the accompanying LICENSE file for the full text of the license.
-*/
-
-#include <stdlib.h>
-#include <string.h>
-
-#if defined unix || defined __APPLE__
-#include <sys/types.h>
-#include <unistd.h>
-#endif
-
-#include "ioapi.h"
-
-#if defined(_WIN32)
-# define snprintf _snprintf
-#endif
-
-voidpf call_zopen64(const zlib_filefunc64_32_def *pfilefunc, const void *filename, int mode)
-{
- if (pfilefunc->zfile_func64.zopen64_file != NULL)
- return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque, filename, mode);
- return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque, (const char*)filename, mode);
-}
-
-voidpf call_zopendisk64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint32_t number_disk, int mode)
-{
- if (pfilefunc->zfile_func64.zopendisk64_file != NULL)
- return (*(pfilefunc->zfile_func64.zopendisk64_file)) (pfilefunc->zfile_func64.opaque, filestream, number_disk, mode);
- return (*(pfilefunc->zopendisk32_file))(pfilefunc->zfile_func64.opaque, filestream, number_disk, mode);
-}
-
-long call_zseek64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint64_t offset, int origin)
-{
- uint32_t offset_truncated = 0;
- if (pfilefunc->zfile_func64.zseek64_file != NULL)
- return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
- offset_truncated = (uint32_t)offset;
- if (offset_truncated != offset)
- return -1;
- return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream, offset_truncated, origin);
-}
-
-uint64_t call_ztell64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream)
-{
- uint64_t position;
- if (pfilefunc->zfile_func64.zseek64_file != NULL)
- return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque, filestream);
- position = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque, filestream);
- if ((position) == UINT32_MAX)
- return (uint64_t)-1;
- return position;
-}
-
-void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def *p_filefunc64_32, const zlib_filefunc_def *p_filefunc32)
-{
- p_filefunc64_32->zfile_func64.zopen64_file = NULL;
- p_filefunc64_32->zfile_func64.zopendisk64_file = NULL;
- p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
- p_filefunc64_32->zopendisk32_file = p_filefunc32->zopendisk_file;
- p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
- p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
- p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
- p_filefunc64_32->zfile_func64.ztell64_file = NULL;
- p_filefunc64_32->zfile_func64.zseek64_file = NULL;
- p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
- p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
- p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
- p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
- p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
-}
-
-static voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char *filename, int mode);
-static uint32_t ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size);
-static uint32_t ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void *buf, uint32_t size);
-static uint64_t ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream);
-static long ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, uint64_t offset, int origin);
-static int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream);
-static int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream);
-
-typedef struct
-{
- FILE *file;
- int filenameLength;
- void *filename;
-} FILE_IOPOSIX;
-
-static voidpf file_build_ioposix(FILE *file, const char *filename)
-{
- FILE_IOPOSIX *ioposix = NULL;
- if (file == NULL)
- return NULL;
- ioposix = (FILE_IOPOSIX*)malloc(sizeof(FILE_IOPOSIX));
- ioposix->file = file;
- ioposix->filenameLength = (int)strlen(filename) + 1;
- ioposix->filename = (char*)malloc(ioposix->filenameLength * sizeof(char));
- strncpy((char*)ioposix->filename, filename, ioposix->filenameLength);
- return (voidpf)ioposix;
-}
-
-static voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char *filename, int mode)
-{
- FILE* file = NULL;
- const char *mode_fopen = NULL;
- if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
- mode_fopen = "rb";
- else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
- mode_fopen = "r+b";
- else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
- mode_fopen = "wb";
-
- if ((filename != NULL) && (mode_fopen != NULL))
- {
- file = fopen(filename, mode_fopen);
- return file_build_ioposix(file, filename);
- }
- return file;
-}
-
-static voidpf ZCALLBACK fopen64_file_func(voidpf opaque, const void *filename, int mode)
-{
- FILE* file = NULL;
- const char *mode_fopen = NULL;
- if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
- mode_fopen = "rb";
- else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
- mode_fopen = "r+b";
- else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
- mode_fopen = "wb";
-
- if ((filename != NULL) && (mode_fopen != NULL))
- {
- file = fopen64((const char*)filename, mode_fopen);
- return file_build_ioposix(file, (const char*)filename);
- }
- return file;
-}
-
-static voidpf ZCALLBACK fopendisk64_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
-{
- FILE_IOPOSIX *ioposix = NULL;
- char *diskFilename = NULL;
- voidpf ret = NULL;
- int i = 0;
-
- if (stream == NULL)
- return NULL;
- ioposix = (FILE_IOPOSIX*)stream;
- diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char));
- strncpy(diskFilename, (const char*)ioposix->filename, ioposix->filenameLength);
- for (i = ioposix->filenameLength - 1; i >= 0; i -= 1)
- {
- if (diskFilename[i] != '.')
- continue;
- snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02u", number_disk + 1);
- break;
- }
- if (i >= 0)
- ret = fopen64_file_func(opaque, diskFilename, mode);
- free(diskFilename);
- return ret;
-}
-
-static voidpf ZCALLBACK fopendisk_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
-{
- FILE_IOPOSIX *ioposix = NULL;
- char *diskFilename = NULL;
- voidpf ret = NULL;
- int i = 0;
-
- if (stream == NULL)
- return NULL;
- ioposix = (FILE_IOPOSIX*)stream;
- diskFilename = (char*)malloc(ioposix->filenameLength * sizeof(char));
- strncpy(diskFilename, (const char*)ioposix->filename, ioposix->filenameLength);
- for (i = ioposix->filenameLength - 1; i >= 0; i -= 1)
- {
- if (diskFilename[i] != '.')
- continue;
- snprintf(&diskFilename[i], ioposix->filenameLength - i, ".z%02u", number_disk + 1);
- break;
- }
- if (i >= 0)
- ret = fopen_file_func(opaque, diskFilename, mode);
- free(diskFilename);
- return ret;
-}
-
-static uint32_t ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size)
-{
- FILE_IOPOSIX *ioposix = NULL;
- uint32_t read = (uint32_t)-1;
- if (stream == NULL)
- return read;
- ioposix = (FILE_IOPOSIX*)stream;
- read = (uint32_t)fread(buf, 1, (size_t)size, ioposix->file);
- return read;
-}
-
-static uint32_t ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void *buf, uint32_t size)
-{
- FILE_IOPOSIX *ioposix = NULL;
- uint32_t written = (uint32_t)-1;
- if (stream == NULL)
- return written;
- ioposix = (FILE_IOPOSIX*)stream;
- written = (uint32_t)fwrite(buf, 1, (size_t)size, ioposix->file);
- return written;
-}
-
-static long ZCALLBACK ftell_file_func(voidpf opaque, voidpf stream)
-{
- FILE_IOPOSIX *ioposix = NULL;
- long ret = -1;
- if (stream == NULL)
- return ret;
- ioposix = (FILE_IOPOSIX*)stream;
- ret = ftell(ioposix->file);
- return ret;
-}
-
-static uint64_t ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream)
-{
- FILE_IOPOSIX *ioposix = NULL;
- uint64_t ret = (uint64_t)-1;
- if (stream == NULL)
- return ret;
- ioposix = (FILE_IOPOSIX*)stream;
- ret = ftello64(ioposix->file);
- return ret;
-}
-
-static long ZCALLBACK fseek_file_func(voidpf opaque, voidpf stream, uint32_t offset, int origin)
-{
- FILE_IOPOSIX *ioposix = NULL;
- int fseek_origin = 0;
- long ret = 0;
-
- if (stream == NULL)
- return -1;
- ioposix = (FILE_IOPOSIX*)stream;
-
- switch (origin)
- {
- case ZLIB_FILEFUNC_SEEK_CUR:
- fseek_origin = SEEK_CUR;
- break;
- case ZLIB_FILEFUNC_SEEK_END:
- fseek_origin = SEEK_END;
- break;
- case ZLIB_FILEFUNC_SEEK_SET:
- fseek_origin = SEEK_SET;
- break;
- default:
- return -1;
- }
- if (fseek(ioposix->file, offset, fseek_origin) != 0)
- ret = -1;
- return ret;
-}
-
-static long ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, uint64_t offset, int origin)
-{
- FILE_IOPOSIX *ioposix = NULL;
- int fseek_origin = 0;
- long ret = 0;
-
- if (stream == NULL)
- return -1;
- ioposix = (FILE_IOPOSIX*)stream;
-
- switch (origin)
- {
- case ZLIB_FILEFUNC_SEEK_CUR:
- fseek_origin = SEEK_CUR;
- break;
- case ZLIB_FILEFUNC_SEEK_END:
- fseek_origin = SEEK_END;
- break;
- case ZLIB_FILEFUNC_SEEK_SET:
- fseek_origin = SEEK_SET;
- break;
- default:
- return -1;
- }
-
- if (fseeko64(ioposix->file, offset, fseek_origin) != 0)
- ret = -1;
-
- return ret;
-}
-
-static int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream)
-{
- FILE_IOPOSIX *ioposix = NULL;
- int ret = -1;
- if (stream == NULL)
- return ret;
- ioposix = (FILE_IOPOSIX*)stream;
- if (ioposix->filename != NULL)
- free(ioposix->filename);
- ret = fclose(ioposix->file);
- free(ioposix);
- return ret;
-}
-
-static int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream)
-{
- FILE_IOPOSIX *ioposix = NULL;
- int ret = -1;
- if (stream == NULL)
- return ret;
- ioposix = (FILE_IOPOSIX*)stream;
- ret = ferror(ioposix->file);
- return ret;
-}
-
-void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def)
-{
- pzlib_filefunc_def->zopen_file = fopen_file_func;
- pzlib_filefunc_def->zopendisk_file = fopendisk_file_func;
- pzlib_filefunc_def->zread_file = fread_file_func;
- pzlib_filefunc_def->zwrite_file = fwrite_file_func;
- pzlib_filefunc_def->ztell_file = ftell_file_func;
- pzlib_filefunc_def->zseek_file = fseek_file_func;
- pzlib_filefunc_def->zclose_file = fclose_file_func;
- pzlib_filefunc_def->zerror_file = ferror_file_func;
- pzlib_filefunc_def->opaque = NULL;
-}
-
-void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def)
-{
- pzlib_filefunc_def->zopen64_file = fopen64_file_func;
- pzlib_filefunc_def->zopendisk64_file = fopendisk64_file_func;
- pzlib_filefunc_def->zread_file = fread_file_func;
- pzlib_filefunc_def->zwrite_file = fwrite_file_func;
- pzlib_filefunc_def->ztell64_file = ftell64_file_func;
- pzlib_filefunc_def->zseek64_file = fseek64_file_func;
- pzlib_filefunc_def->zclose_file = fclose_file_func;
- pzlib_filefunc_def->zerror_file = ferror_file_func;
- pzlib_filefunc_def->opaque = NULL;
-}
diff --git a/Externals/minizip/ioapi.h b/Externals/minizip/ioapi.h
deleted file mode 100644
index efb94a4457..0000000000
--- a/Externals/minizip/ioapi.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/* ioapi.h -- IO base function header for compress/uncompress .zip
- part of the MiniZip project
-
- Copyright (C) 1998-2010 Gilles Vollant
- http://www.winimage.com/zLibDll/minizip.html
- Modifications for Zip64 support
- Copyright (C) 2009-2010 Mathias Svensson
- http://result42.com
-
- This program is distributed under the terms of the same license as zlib.
- See the accompanying LICENSE file for the full text of the license.
-*/
-
-#ifndef _ZLIBIOAPI64_H
-#define _ZLIBIOAPI64_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include "zlib.h"
-
-#if defined(USE_FILE32API)
-# define fopen64 fopen
-# define ftello64 ftell
-# define fseeko64 fseek
-#else
-# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__APPLE__)
-# define fopen64 fopen
-# define ftello64 ftello
-# define fseeko64 fseeko
-# endif
-# ifdef _MSC_VER
-# define fopen64 fopen
-# if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
-# define ftello64 _ftelli64
-# define fseeko64 _fseeki64
-# else /* old MSC */
-# define ftello64 ftell
-# define fseeko64 fseek
-# endif
-# endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define ZLIB_FILEFUNC_SEEK_CUR (1)
-#define ZLIB_FILEFUNC_SEEK_END (2)
-#define ZLIB_FILEFUNC_SEEK_SET (0)
-
-#define ZLIB_FILEFUNC_MODE_READ (1)
-#define ZLIB_FILEFUNC_MODE_WRITE (2)
-#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
-#define ZLIB_FILEFUNC_MODE_EXISTING (4)
-#define ZLIB_FILEFUNC_MODE_CREATE (8)
-
-#ifndef ZCALLBACK
-# if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || \
- defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
-# define ZCALLBACK CALLBACK
-# else
-# define ZCALLBACK
-# endif
-#endif
-
-typedef voidpf (ZCALLBACK *open_file_func) (voidpf opaque, const char *filename, int mode);
-typedef voidpf (ZCALLBACK *opendisk_file_func) (voidpf opaque, voidpf stream, uint32_t number_disk, int mode);
-typedef uint32_t (ZCALLBACK *read_file_func) (voidpf opaque, voidpf stream, void* buf, uint32_t size);
-typedef uint32_t (ZCALLBACK *write_file_func) (voidpf opaque, voidpf stream, const void *buf, uint32_t size);
-typedef int (ZCALLBACK *close_file_func) (voidpf opaque, voidpf stream);
-typedef int (ZCALLBACK *error_file_func) (voidpf opaque, voidpf stream);
-
-typedef long (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream);
-typedef long (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uint32_t offset, int origin);
-
-/* here is the "old" 32 bits structure structure */
-typedef struct zlib_filefunc_def_s
-{
- open_file_func zopen_file;
- opendisk_file_func zopendisk_file;
- read_file_func zread_file;
- write_file_func zwrite_file;
- tell_file_func ztell_file;
- seek_file_func zseek_file;
- close_file_func zclose_file;
- error_file_func zerror_file;
- voidpf opaque;
-} zlib_filefunc_def;
-
-typedef uint64_t (ZCALLBACK *tell64_file_func) (voidpf opaque, voidpf stream);
-typedef long (ZCALLBACK *seek64_file_func) (voidpf opaque, voidpf stream, uint64_t offset, int origin);
-typedef voidpf (ZCALLBACK *open64_file_func) (voidpf opaque, const void *filename, int mode);
-typedef voidpf (ZCALLBACK *opendisk64_file_func)(voidpf opaque, voidpf stream, uint32_t number_disk, int mode);
-
-typedef struct zlib_filefunc64_def_s
-{
- open64_file_func zopen64_file;
- opendisk64_file_func zopendisk64_file;
- read_file_func zread_file;
- write_file_func zwrite_file;
- tell64_file_func ztell64_file;
- seek64_file_func zseek64_file;
- close_file_func zclose_file;
- error_file_func zerror_file;
- voidpf opaque;
-} zlib_filefunc64_def;
-
-void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
-void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def);
-
-/* now internal definition, only for zip.c and unzip.h */
-typedef struct zlib_filefunc64_32_def_s
-{
- zlib_filefunc64_def zfile_func64;
- open_file_func zopen32_file;
- opendisk_file_func zopendisk32_file;
- tell_file_func ztell32_file;
- seek_file_func zseek32_file;
-} zlib_filefunc64_32_def;
-
-#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
-#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
-/*#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))*/
-/*#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))*/
-#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
-#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
-
-voidpf call_zopen64(const zlib_filefunc64_32_def *pfilefunc,const void*filename, int mode);
-voidpf call_zopendisk64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint32_t number_disk, int mode);
-long call_zseek64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream, uint64_t offset, int origin);
-uint64_t call_ztell64(const zlib_filefunc64_32_def *pfilefunc, voidpf filestream);
-
-void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def *p_filefunc64_32, const zlib_filefunc_def *p_filefunc32);
-
-#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
-#define ZOPENDISK64(filefunc,filestream,diskn,mode) (call_zopendisk64((&(filefunc)),(filestream),(diskn),(mode)))
-#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
-#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/Externals/minizip/minigzip.c b/Externals/minizip/minigzip.c
new file mode 100644
index 0000000000..0bd8c79895
--- /dev/null
+++ b/Externals/minizip/minigzip.c
@@ -0,0 +1,182 @@
+/* minigzip.c
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_os.h"
+#include "mz_strm.h"
+#include "mz_strm_os.h"
+#include "mz_strm_zlib.h"
+
+#include <stdio.h> /* printf */
+
+/***************************************************************************/
+
+#define MZ_GZIP_COMPRESS (1)
+#define MZ_GZIP_DECOMPRESS (2)
+
+int32_t minigzip_banner(void);
+int32_t minigzip_help(void);
+
+/***************************************************************************/
+
+int32_t minigzip_banner(void) {
+ printf("Minigzip %s - https://github.com/zlib-ng/minizip-ng\n", MZ_VERSION);
+ printf("---------------------------------------------------\n");
+ return MZ_OK;
+}
+
+int32_t minigzip_help(void) {
+ printf("Usage: minigzip [-x] [-d] [-0 to -9] [files]\n\n" \
+ " -x Extract file\n" \
+ " -d Destination directory\n" \
+ " -0 Store only\n" \
+ " -1 Compress faster\n" \
+ " -9 Compress better\n\n");
+ return MZ_OK;
+}
+
+/***************************************************************************/
+
+int32_t minigzip_copy(const char *path, const char *destination, int16_t operation, int16_t level) {
+ void *target_stream = NULL;
+ void *source_stream = NULL;
+ void *zlib_stream = NULL;
+ const char *filename = NULL;
+ char target_path[1024];
+ int32_t err = 0;
+
+
+ memset(target_path, 0, sizeof(target_path));
+
+ if (destination != NULL) {
+ if (mz_os_file_exists(destination) != MZ_OK)
+ mz_dir_make(destination);
+ }
+
+ if (operation == MZ_GZIP_COMPRESS) {
+ mz_path_combine(target_path, path, sizeof(target_path));
+ strncat(target_path, ".gz", sizeof(target_path) - strlen(target_path) - 1);
+ printf("Compressing to %s\n", target_path);
+ } else if (operation == MZ_GZIP_DECOMPRESS) {
+ if (destination != NULL)
+ mz_path_combine(target_path, destination, sizeof(target_path));
+
+ if (mz_path_get_filename(path, &filename) != MZ_OK)
+ filename = path;
+
+ mz_path_combine(target_path, filename, sizeof(target_path));
+ mz_path_remove_extension(target_path);
+ printf("Decompressing to %s\n", target_path);
+ }
+
+ mz_stream_zlib_create(&zlib_stream);
+ mz_stream_zlib_set_prop_int64(zlib_stream, MZ_STREAM_PROP_COMPRESS_WINDOW, 15 + 16);
+
+ mz_stream_os_create(&source_stream);
+ err = mz_stream_os_open(source_stream, path, MZ_OPEN_MODE_READ);
+
+ if (err == MZ_OK) {
+ mz_stream_os_create(&target_stream);
+ err = mz_stream_os_open(target_stream, target_path, MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_WRITE);
+
+ if (err == MZ_OK) {
+ if (operation == MZ_GZIP_COMPRESS) {
+ mz_stream_zlib_set_prop_int64(zlib_stream, MZ_STREAM_PROP_COMPRESS_LEVEL, level);
+ mz_stream_zlib_open(zlib_stream, target_path, MZ_OPEN_MODE_WRITE);
+ mz_stream_set_base(zlib_stream, target_stream);
+ err = mz_stream_copy_to_end(zlib_stream, source_stream);
+ } else if (operation == MZ_GZIP_DECOMPRESS) {
+ mz_stream_zlib_open(zlib_stream, path, MZ_OPEN_MODE_READ);
+ mz_stream_set_base(zlib_stream, source_stream);
+ err = mz_stream_copy_to_end(target_stream, zlib_stream);
+ }
+
+ if (err != MZ_OK)
+ printf("Error %d in zlib stream (%d)\n", err, mz_stream_zlib_error(zlib_stream));
+ else
+ printf("Operation completed successfully\n");
+
+ mz_stream_zlib_close(zlib_stream);
+ } else {
+ printf("Error %d opening target path %s\n", err, target_path);
+ }
+
+ mz_stream_os_close(target_stream);
+ mz_stream_os_delete(&target_stream);
+ } else {
+ printf("Error %d opening source path %s\n", err, path);
+ }
+
+ mz_stream_os_close(source_stream);
+ mz_stream_os_delete(&source_stream);
+
+ mz_stream_zlib_delete(&zlib_stream);
+ return err;
+}
+
+/***************************************************************************/
+
+#if !defined(MZ_ZIP_NO_MAIN)
+int main(int argc, const char *argv[]) {
+ int16_t operation_level = MZ_COMPRESS_LEVEL_DEFAULT;
+ int32_t path_arg = 0;
+ int32_t err = 0;
+ int32_t i = 0;
+ uint8_t operation = MZ_GZIP_COMPRESS;
+ const char *path = NULL;
+ const char *destination = NULL;
+
+
+ minigzip_banner();
+ if (argc == 1) {
+ minigzip_help();
+ return 0;
+ }
+
+ /* Parse command line options */
+ for (i = 1; i < argc; i += 1) {
+ printf("%s ", argv[i]);
+ if (argv[i][0] == '-') {
+ char c = argv[i][1];
+ if ((c == 'x') || (c == 'X'))
+ operation = MZ_GZIP_DECOMPRESS;
+ else if ((c >= '0') && (c <= '9'))
+ operation_level = (c - '0');
+ else if (((c == 'd') || (c == 'D')) && (i + 1 < argc)) {
+ destination = argv[i + 1];
+ printf("%s ", argv[i + 1]);
+ i += 1;
+ } else {
+ err = MZ_SUPPORT_ERROR;
+ }
+ } else if (path_arg == 0) {
+ path_arg = i;
+ break;
+ }
+ }
+ printf("\n");
+
+ if (err == MZ_SUPPORT_ERROR) {
+ printf("Feature not supported\n");
+ return err;
+ }
+
+ if (path_arg == 0) {
+ minigzip_help();
+ return 0;
+ }
+
+ path = argv[path_arg];
+ err = minigzip_copy(path, destination, operation, operation_level);
+
+ return err;
+}
+#endif
diff --git a/Externals/minizip/minizip.c b/Externals/minizip/minizip.c
new file mode 100644
index 0000000000..01bb559eb8
--- /dev/null
+++ b/Externals/minizip/minizip.c
@@ -0,0 +1,671 @@
+/* minizip.c
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Copyright (C) 1998-2010 Gilles Vollant
+ https://www.winimage.com/zLibDll/minizip.html
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_os.h"
+#include "mz_strm.h"
+#include "mz_strm_buf.h"
+#include "mz_strm_split.h"
+#include "mz_zip.h"
+#include "mz_zip_rw.h"
+
+#include <stdio.h> /* printf */
+
+/***************************************************************************/
+
+typedef struct minizip_opt_s {
+ uint8_t include_path;
+ int16_t compress_level;
+ uint8_t compress_method;
+ uint8_t overwrite;
+ uint8_t append;
+ int64_t disk_size;
+ uint8_t follow_links;
+ uint8_t store_links;
+ uint8_t zip_cd;
+ int32_t encoding;
+ uint8_t verbose;
+ uint8_t aes;
+ const char *cert_path;
+ const char *cert_pwd;
+} minizip_opt;
+
+/***************************************************************************/
+
+int32_t minizip_banner(void);
+int32_t minizip_help(void);
+
+int32_t minizip_list(const char *path);
+
+int32_t minizip_add_entry_cb(void *handle, void *userdata, mz_zip_file *file_info);
+int32_t minizip_add_progress_cb(void *handle, void *userdata, mz_zip_file *file_info, int64_t position);
+int32_t minizip_add_overwrite_cb(void *handle, void *userdata, const char *path);
+int32_t minizip_add(const char *path, const char *password, minizip_opt *options, int32_t arg_count, const char **args);
+
+int32_t minizip_extract_entry_cb(void *handle, void *userdata, mz_zip_file *file_info, const char *path);
+int32_t minizip_extract_progress_cb(void *handle, void *userdata, mz_zip_file *file_info, int64_t position);
+int32_t minizip_extract_overwrite_cb(void *handle, void *userdata, mz_zip_file *file_info, const char *path);
+int32_t minizip_extract(const char *path, const char *pattern, const char *destination, const char *password, minizip_opt *options);
+
+int32_t minizip_erase(const char *src_path, const char *target_path, int32_t arg_count, const char **args);
+
+/***************************************************************************/
+
+int32_t minizip_banner(void) {
+ printf("minizip-ng %s - https://github.com/zlib-ng/minizip-ng\n", MZ_VERSION);
+ printf("---------------------------------------------------\n");
+ return MZ_OK;
+}
+
+int32_t minizip_help(void) {
+ printf("Usage: minizip [-x][-d dir|-l|-e][-o][-f][-y][-c cp][-a][-0 to -9][-b|-m|-t][-k 512][-p pwd][-s] file.zip [files]\n\n" \
+ " -x Extract files\n" \
+ " -l List files\n" \
+ " -d Destination directory\n" \
+ " -e Erase files\n" \
+ " -o Overwrite existing files\n" \
+ " -c File names use cp437 encoding (or specified codepage)\n" \
+ " -a Append to existing zip file\n" \
+ " -i Include full path of files\n" \
+ " -f Follow symbolic links\n" \
+ " -y Store symbolic links\n" \
+ " -v Verbose info\n" \
+ " -0 Store only\n" \
+ " -1 Compress faster\n" \
+ " -9 Compress better\n" \
+ " -k Disk size in KB\n" \
+ " -z Zip central directory\n" \
+ " -p Encryption password\n" \
+ " -s AES encryption\n" \
+ " -h PKCS12 certificate path\n" \
+ " -w PKCS12 certificate password\n" \
+ " -b BZIP2 compression\n" \
+ " -m LZMA compression\n" \
+ " -n XZ compression\n" \
+ " -t ZSTD compression\n\n");
+ return MZ_OK;
+}
+
+/***************************************************************************/
+
+int32_t minizip_list(const char *path) {
+ mz_zip_file *file_info = NULL;
+ uint32_t ratio = 0;
+ int32_t err = MZ_OK;
+ struct tm tmu_date;
+ const char *method = NULL;
+ char crypt = ' ';
+ void *reader = NULL;
+
+
+ mz_zip_reader_create(&reader);
+ err = mz_zip_reader_open_file(reader, path);
+ if (err != MZ_OK) {
+ printf("Error %" PRId32 " opening archive %s\n", err, path);
+ mz_zip_reader_delete(&reader);
+ return err;
+ }
+
+ err = mz_zip_reader_goto_first_entry(reader);
+
+ if (err != MZ_OK && err != MZ_END_OF_LIST) {
+ printf("Error %" PRId32 " going to first entry in archive\n", err);
+ mz_zip_reader_delete(&reader);
+ return err;
+ }
+
+ printf(" Packed Unpacked Ratio Method Attribs Date Time CRC-32 Name\n");
+ printf(" ------ -------- ----- ------ ------- ---- ---- ------ ----\n");
+
+ /* Enumerate all entries in the archive */
+ do {
+ err = mz_zip_reader_entry_get_info(reader, &file_info);
+
+ if (err != MZ_OK) {
+ printf("Error %" PRId32 " getting entry info in archive\n", err);
+ break;
+ }
+
+ ratio = 0;
+ if (file_info->uncompressed_size > 0)
+ ratio = (uint32_t)((file_info->compressed_size * 100) / file_info->uncompressed_size);
+
+ /* Display a '*' if the file is encrypted */
+ if (file_info->flag & MZ_ZIP_FLAG_ENCRYPTED)
+ crypt = '*';
+ else
+ crypt = ' ';
+
+ method = mz_zip_get_compression_method_string(file_info->compression_method);
+ mz_zip_time_t_to_tm(file_info->modified_date, &tmu_date);
+
+ /* Print entry information */
+ printf("%12" PRId64 " %12" PRId64 " %3" PRIu32 "%% %6s%c %8" PRIx32 " %2.2" PRIu32 \
+ "-%2.2" PRIu32 "-%2.2" PRIu32 " %2.2" PRIu32 ":%2.2" PRIu32 " %8.8" PRIx32 " %s\n",
+ file_info->compressed_size, file_info->uncompressed_size, ratio,
+ method, crypt, file_info->external_fa,
+ (uint32_t)tmu_date.tm_mon + 1, (uint32_t)tmu_date.tm_mday,
+ (uint32_t)tmu_date.tm_year % 100,
+ (uint32_t)tmu_date.tm_hour, (uint32_t)tmu_date.tm_min,
+ file_info->crc, file_info->filename);
+
+ err = mz_zip_reader_goto_next_entry(reader);
+
+ if (err != MZ_OK && err != MZ_END_OF_LIST) {
+ printf("Error %" PRId32 " going to next entry in archive\n", err);
+ break;
+ }
+ } while (err == MZ_OK);
+
+ mz_zip_reader_delete(&reader);
+
+ if (err == MZ_END_OF_LIST)
+ return MZ_OK;
+
+ return err;
+}
+
+/***************************************************************************/
+
+int32_t minizip_add_entry_cb(void *handle, void *userdata, mz_zip_file *file_info) {
+ MZ_UNUSED(handle);
+ MZ_UNUSED(userdata);
+
+ /* Print the current file we are trying to compress */
+ printf("Adding %s\n", file_info->filename);
+ return MZ_OK;
+}
+
+int32_t minizip_add_progress_cb(void *handle, void *userdata, mz_zip_file *file_info, int64_t position) {
+ minizip_opt *options = (minizip_opt *)userdata;
+ double progress = 0;
+ uint8_t raw = 0;
+
+ MZ_UNUSED(userdata);
+
+ mz_zip_writer_get_raw(handle, &raw);
+
+ if (raw && file_info->compressed_size > 0)
+ progress = ((double)position / file_info->compressed_size) * 100;
+ else if (!raw && file_info->uncompressed_size > 0)
+ progress = ((double)position / file_info->uncompressed_size) * 100;
+
+ /* Print the progress of the current compress operation */
+ if (options->verbose)
+ printf("%s - %" PRId64 " / %" PRId64 " (%.02f%%)\n", file_info->filename, position,
+ file_info->uncompressed_size, progress);
+ return MZ_OK;
+}
+
+int32_t minizip_add_overwrite_cb(void *handle, void *userdata, const char *path) {
+ minizip_opt *options = (minizip_opt *)userdata;
+
+ MZ_UNUSED(handle);
+
+ if (options->overwrite == 0) {
+ /* If ask the user what to do because append and overwrite args not set */
+ char rep = 0;
+ do {
+ char answer[128];
+ printf("The file %s exists. Overwrite ? [y]es, [n]o, [a]ppend : ", path);
+ if (scanf("%1s", answer) != 1)
+ exit(EXIT_FAILURE);
+ rep = answer[0];
+
+ if ((rep >= 'a') && (rep <= 'z'))
+ rep -= 0x20;
+ } while ((rep != 'Y') && (rep != 'N') && (rep != 'A'));
+
+ if (rep == 'A') {
+ return MZ_EXIST_ERROR;
+ } else if (rep == 'N') {
+ return MZ_INTERNAL_ERROR;
+ }
+ }
+
+ return MZ_OK;
+}
+
+int32_t minizip_add(const char *path, const char *password, minizip_opt *options, int32_t arg_count, const char **args) {
+ void *writer = NULL;
+ int32_t err = MZ_OK;
+ int32_t err_close = MZ_OK;
+ int32_t i = 0;
+ const char *filename_in_zip = NULL;
+
+
+ printf("Archive %s\n", path);
+
+ /* Create zip writer */
+ mz_zip_writer_create(&writer);
+ mz_zip_writer_set_password(writer, password);
+ mz_zip_writer_set_aes(writer, options->aes);
+ mz_zip_writer_set_compress_method(writer, options->compress_method);
+ mz_zip_writer_set_compress_level(writer, options->compress_level);
+ mz_zip_writer_set_follow_links(writer, options->follow_links);
+ mz_zip_writer_set_store_links(writer, options->store_links);
+ mz_zip_writer_set_overwrite_cb(writer, options, minizip_add_overwrite_cb);
+ mz_zip_writer_set_progress_cb(writer, options, minizip_add_progress_cb);
+ mz_zip_writer_set_entry_cb(writer, options, minizip_add_entry_cb);
+ mz_zip_writer_set_zip_cd(writer, options->zip_cd);
+ if (options->cert_path != NULL)
+ mz_zip_writer_set_certificate(writer, options->cert_path, options->cert_pwd);
+
+ err = mz_zip_writer_open_file(writer, path, options->disk_size, options->append);
+
+ if (err == MZ_OK) {
+ for (i = 0; i < arg_count; i += 1) {
+ filename_in_zip = args[i];
+
+ /* Add file system path to archive */
+ err = mz_zip_writer_add_path(writer, filename_in_zip, NULL, options->include_path, 1);
+ if (err != MZ_OK)
+ printf("Error %" PRId32 " adding path to archive %s\n", err, filename_in_zip);
+ }
+ } else {
+ printf("Error %" PRId32 " opening archive for writing\n", err);
+ }
+
+ err_close = mz_zip_writer_close(writer);
+ if (err_close != MZ_OK) {
+ printf("Error %" PRId32 " closing archive for writing %s\n", err_close, path);
+ err = err_close;
+ }
+
+ mz_zip_writer_delete(&writer);
+ return err;
+}
+
+/***************************************************************************/
+
+int32_t minizip_extract_entry_cb(void *handle, void *userdata, mz_zip_file *file_info, const char *path) {
+ MZ_UNUSED(handle);
+ MZ_UNUSED(userdata);
+ MZ_UNUSED(path);
+
+ /* Print the current entry extracting */
+ printf("Extracting %s\n", file_info->filename);
+ return MZ_OK;
+}
+
+int32_t minizip_extract_progress_cb(void *handle, void *userdata, mz_zip_file *file_info, int64_t position) {
+ minizip_opt *options = (minizip_opt *)userdata;
+ double progress = 0;
+ uint8_t raw = 0;
+
+ MZ_UNUSED(userdata);
+
+ mz_zip_reader_get_raw(handle, &raw);
+
+ if (raw && file_info->compressed_size > 0)
+ progress = ((double)position / file_info->compressed_size) * 100;
+ else if (!raw && file_info->uncompressed_size > 0)
+ progress = ((double)position / file_info->uncompressed_size) * 100;
+
+ /* Print the progress of the current extraction */
+ if (options->verbose)
+ printf("%s - %" PRId64 " / %" PRId64 " (%.02f%%)\n", file_info->filename, position,
+ file_info->uncompressed_size, progress);
+
+ return MZ_OK;
+}
+
+int32_t minizip_extract_overwrite_cb(void *handle, void *userdata, mz_zip_file *file_info, const char *path) {
+ minizip_opt *options = (minizip_opt *)userdata;
+
+ MZ_UNUSED(handle);
+ MZ_UNUSED(file_info);
+
+ /* Verify if we want to overwrite current entry on disk */
+ if (options->overwrite == 0) {
+ char rep = 0;
+ do {
+ char answer[128];
+ printf("The file %s exists. Overwrite ? [y]es, [n]o, [A]ll: ", path);
+ if (scanf("%1s", answer) != 1)
+ exit(EXIT_FAILURE);
+ rep = answer[0];
+ if ((rep >= 'a') && (rep <= 'z'))
+ rep -= 0x20;
+ } while ((rep != 'Y') && (rep != 'N') && (rep != 'A'));
+
+ if (rep == 'N')
+ return MZ_EXIST_ERROR;
+ if (rep == 'A')
+ options->overwrite = 1;
+ }
+
+ return MZ_OK;
+}
+
+int32_t minizip_extract(const char *path, const char *pattern, const char *destination, const char *password, minizip_opt *options) {
+ void *reader = NULL;
+ int32_t err = MZ_OK;
+ int32_t err_close = MZ_OK;
+
+
+ printf("Archive %s\n", path);
+
+ /* Create zip reader */
+ mz_zip_reader_create(&reader);
+ mz_zip_reader_set_pattern(reader, pattern, 1);
+ mz_zip_reader_set_password(reader, password);
+ mz_zip_reader_set_encoding(reader, options->encoding);
+ mz_zip_reader_set_entry_cb(reader, options, minizip_extract_entry_cb);
+ mz_zip_reader_set_progress_cb(reader, options, minizip_extract_progress_cb);
+ mz_zip_reader_set_overwrite_cb(reader, options, minizip_extract_overwrite_cb);
+
+ err = mz_zip_reader_open_file(reader, path);
+
+ if (err != MZ_OK) {
+ printf("Error %" PRId32 " opening archive %s\n", err, path);
+ } else {
+ /* Save all entries in archive to destination directory */
+ err = mz_zip_reader_save_all(reader, destination);
+
+ if (err == MZ_END_OF_LIST) {
+ if (pattern != NULL) {
+ printf("Files matching %s not found in archive\n", pattern);
+ } else {
+ printf("No files in archive\n");
+ err = MZ_OK;
+ }
+ } else if (err != MZ_OK) {
+ printf("Error %" PRId32 " saving entries to disk %s\n", err, path);
+ }
+ }
+
+ err_close = mz_zip_reader_close(reader);
+ if (err_close != MZ_OK) {
+ printf("Error %" PRId32 " closing archive for reading\n", err_close);
+ err = err_close;
+ }
+
+ mz_zip_reader_delete(&reader);
+ return err;
+}
+
+/***************************************************************************/
+
+int32_t minizip_erase(const char *src_path, const char *target_path, int32_t arg_count, const char **args) {
+ mz_zip_file *file_info = NULL;
+ const char *filename_in_zip = NULL;
+ const char *target_path_ptr = target_path;
+ void *reader = NULL;
+ void *writer = NULL;
+ int32_t skip = 0;
+ int32_t err = MZ_OK;
+ int32_t i = 0;
+ uint8_t zip_cd = 0;
+ char bak_path[256];
+ char tmp_path[256];
+
+ if (target_path == NULL) {
+ /* Construct temporary zip name */
+ strncpy(tmp_path, src_path, sizeof(tmp_path) - 1);
+ tmp_path[sizeof(tmp_path) - 1] = 0;
+ strncat(tmp_path, ".tmp.zip", sizeof(tmp_path) - strlen(tmp_path) - 1);
+ target_path_ptr = tmp_path;
+ }
+
+ mz_zip_reader_create(&reader);
+ mz_zip_writer_create(&writer);
+
+ /* Open original archive we want to erase an entry in */
+ err = mz_zip_reader_open_file(reader, src_path);
+ if (err != MZ_OK) {
+ printf("Error %" PRId32 " opening archive for reading %s\n", err, src_path);
+ mz_zip_reader_delete(&reader);
+ return err;
+ }
+
+ /* Open temporary archive */
+ err = mz_zip_writer_open_file(writer, target_path_ptr, 0, 0);
+ if (err != MZ_OK) {
+ printf("Error %" PRId32 " opening archive for writing %s\n", err, target_path_ptr);
+ mz_zip_reader_delete(&reader);
+ mz_zip_writer_delete(&writer);
+ return err;
+ }
+
+ err = mz_zip_reader_goto_first_entry(reader);
+
+ if (err != MZ_OK && err != MZ_END_OF_LIST)
+ printf("Error %" PRId32 " going to first entry in archive\n", err);
+
+ while (err == MZ_OK) {
+ err = mz_zip_reader_entry_get_info(reader, &file_info);
+ if (err != MZ_OK) {
+ printf("Error %" PRId32 " getting info from archive\n", err);
+ break;
+ }
+
+ /* Copy all entries from original archive to temporary archive
+ except the ones we don't want */
+ for (i = 0, skip = 0; i < arg_count; i += 1) {
+ filename_in_zip = args[i];
+
+ if (mz_path_compare_wc(file_info->filename, filename_in_zip, 1) == MZ_OK)
+ skip = 1;
+ }
+
+ if (skip) {
+ printf("Skipping %s\n", file_info->filename);
+ } else {
+ printf("Copying %s\n", file_info->filename);
+ err = mz_zip_writer_copy_from_reader(writer, reader);
+ }
+
+ if (err != MZ_OK) {
+ printf("Error %" PRId32 " copying entry into new zip\n", err);
+ break;
+ }
+
+ err = mz_zip_reader_goto_next_entry(reader);
+
+ if (err != MZ_OK && err != MZ_END_OF_LIST)
+ printf("Error %" PRId32 " going to next entry in archive\n", err);
+ }
+
+ mz_zip_reader_get_zip_cd(reader, &zip_cd);
+ mz_zip_writer_set_zip_cd(writer, zip_cd);
+
+ mz_zip_reader_close(reader);
+ mz_zip_reader_delete(&reader);
+
+ mz_zip_writer_close(writer);
+ mz_zip_writer_delete(&writer);
+
+ if (err == MZ_END_OF_LIST) {
+ if (target_path == NULL) {
+ /* Swap original archive with temporary archive, backup old archive if possible */
+ strncpy(bak_path, src_path, sizeof(bak_path) - 1);
+ bak_path[sizeof(bak_path) - 1] = 0;
+ strncat(bak_path, ".bak", sizeof(bak_path) - strlen(bak_path) - 1);
+
+ if (mz_os_file_exists(bak_path) == MZ_OK)
+ mz_os_unlink(bak_path);
+
+ if (mz_os_rename(src_path, bak_path) != MZ_OK)
+ printf("Error backing up archive before replacing %s\n", bak_path);
+
+ if (mz_os_rename(tmp_path, src_path) != MZ_OK)
+ printf("Error replacing archive with temp %s\n", tmp_path);
+ }
+
+ return MZ_OK;
+ }
+
+ return err;
+}
+
+/***************************************************************************/
+
+#if !defined(MZ_ZIP_NO_MAIN)
+int main(int argc, const char *argv[]) {
+ minizip_opt options;
+ int32_t path_arg = 0;
+ int32_t err = 0;
+ int32_t i = 0;
+ uint8_t do_list = 0;
+ uint8_t do_extract = 0;
+ uint8_t do_erase = 0;
+ const char *path = NULL;
+ const char *password = NULL;
+ const char *destination = NULL;
+ const char *filename_to_extract = NULL;
+
+
+ minizip_banner();
+ if (argc == 1) {
+ minizip_help();
+ return 0;
+ }
+
+ memset(&options, 0, sizeof(options));
+
+ options.compress_method = MZ_COMPRESS_METHOD_DEFLATE;
+ options.compress_level = MZ_COMPRESS_LEVEL_DEFAULT;
+
+ /* Parse command line options */
+ for (i = 1; i < argc; i += 1) {
+ printf("%s ", argv[i]);
+ if (argv[i][0] == '-') {
+ char c = argv[i][1];
+ if ((c == 'l') || (c == 'L'))
+ do_list = 1;
+ else if ((c == 'x') || (c == 'X'))
+ do_extract = 1;
+ else if ((c == 'e') || (c == 'E'))
+ do_erase = 1;
+ else if ((c == 'a') || (c == 'A'))
+ options.append = 1;
+ else if ((c == 'o') || (c == 'O'))
+ options.overwrite = 1;
+ else if ((c == 'f') || (c == 'F'))
+ options.follow_links = 1;
+ else if ((c == 'y') || (c == 'Y'))
+ options.store_links = 1;
+ else if ((c == 'i') || (c == 'I'))
+ options.include_path = 1;
+ else if ((c == 'z') || (c == 'Z'))
+ options.zip_cd = 1;
+ else if ((c == 'v') || (c == 'V'))
+ options.verbose = 1;
+ else if ((c >= '0') && (c <= '9')) {
+ options.compress_level = (c - '0');
+ if (options.compress_level == 0)
+ options.compress_method = MZ_COMPRESS_METHOD_STORE;
+ } else if ((c == 'b') || (c == 'B'))
+#ifdef HAVE_BZIP2
+ options.compress_method = MZ_COMPRESS_METHOD_BZIP2;
+#else
+ err = MZ_SUPPORT_ERROR;
+#endif
+ else if ((c == 'm') || (c == 'M'))
+#ifdef HAVE_LZMA
+ options.compress_method = MZ_COMPRESS_METHOD_LZMA;
+#else
+ err = MZ_SUPPORT_ERROR;
+#endif
+ else if ((c == 'n') || (c == 'N'))
+#if defined(HAVE_LZMA) || defined(HAVE_LIBCOMP)
+ options.compress_method = MZ_COMPRESS_METHOD_XZ;
+#else
+ err = MZ_SUPPORT_ERROR;
+#endif
+ else if ((c == 't') || (c == 'T'))
+#ifdef HAVE_ZSTD
+ options.compress_method = MZ_COMPRESS_METHOD_ZSTD;
+#else
+ err = MZ_SUPPORT_ERROR;
+#endif
+ else if ((c == 's') || (c == 'S'))
+#ifdef HAVE_WZAES
+ options.aes = 1;
+#else
+ err = MZ_SUPPORT_ERROR;
+#endif
+ else if (((c == 'h') || (c == 'H')) && (i + 1 < argc)) {
+#ifdef MZ_ZIP_SIGNING
+ options.cert_path = argv[i + 1];
+ printf("%s ", argv[i + 1]);
+#else
+ err = MZ_SUPPORT_ERROR;
+#endif
+ i += 1;
+ } else if (((c == 'w') || (c == 'W')) && (i + 1 < argc)) {
+#ifdef MZ_ZIP_SIGNING
+ options.cert_pwd = argv[i + 1];
+ printf("%s ", argv[i + 1]);
+#else
+ err = MZ_SUPPORT_ERROR;
+#endif
+ i += 1;
+ } else if (((c == 'c') || (c == 'C')) && (i + 1 < argc)) {
+ options.encoding = (int32_t)atoi(argv[i + 1]);
+ i += 1;
+ } else if (((c == 'k') || (c == 'K')) && (i + 1 < argc)) {
+ options.disk_size = (int64_t)atoi(argv[i + 1]) * 1024;
+ printf("%s ", argv[i + 1]);
+ i += 1;
+ } else if (((c == 'd') || (c == 'D')) && (i + 1 < argc)) {
+ destination = argv[i + 1];
+ printf("%s ", argv[i + 1]);
+ i += 1;
+ } else if (((c == 'p') || (c == 'P')) && (i + 1 < argc)) {
+#ifndef MZ_ZIP_NO_ENCRYPTION
+ password = argv[i + 1];
+ printf("*** ");
+#else
+ err = MZ_SUPPORT_ERROR;
+#endif
+ i += 1;
+ }
+ } else if (path_arg == 0)
+ path_arg = i;
+ }
+ printf("\n");
+
+ if (err == MZ_SUPPORT_ERROR) {
+ printf("Feature not supported\n");
+ return err;
+ }
+
+ if (path_arg == 0) {
+ minizip_help();
+ return 0;
+ }
+
+ path = argv[path_arg];
+
+ if (do_list) {
+ /* List archive contents */
+ err = minizip_list(path);
+ } else if (do_extract) {
+ if (argc > path_arg + 1)
+ filename_to_extract = argv[path_arg + 1];
+
+ /* Extract archive */
+ err = minizip_extract(path, filename_to_extract, destination, password, &options);
+ } else if (do_erase) {
+ /* Erase file in archive */
+ err = minizip_erase(path, NULL, argc - (path_arg + 1), &argv[path_arg + 1]);
+ } else {
+ /* Add files to archive */
+ err = minizip_add(path, password, &options, argc - (path_arg + 1), &argv[path_arg + 1]);
+ }
+
+ return err;
+}
+#endif
diff --git a/Externals/minizip/minizip.pc.cmakein b/Externals/minizip/minizip.pc.cmakein
new file mode 100644
index 0000000000..d965a346c5
--- /dev/null
+++ b/Externals/minizip/minizip.pc.cmakein
@@ -0,0 +1,14 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+sharedlibdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
+
+Name: @PROJECT_NAME@
+Description: Minizip zip file manipulation library
+Version: @VERSION@
+
+Requires: zlib
+Libs: -L${libdir} -L${sharedlibdir} -l@PROJECT_NAME@
+Libs.private:@PC_PRIVATE_LIBS@
+Cflags: -I${includedir}
diff --git a/Externals/minizip/minizip.vcxproj b/Externals/minizip/minizip.vcxproj
index fe499a0825..e454f85ed8 100644
--- a/Externals/minizip/minizip.vcxproj
+++ b/Externals/minizip/minizip.vcxproj
@@ -17,19 +17,41 @@
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
- <PreprocessorDefinitions>NOUNCRYPT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>HAVE_ZLIB;ZLIB_COMPAT;MZ_ZIP_NO_CRYPTO;MZ_ZIP_NO_ENCRYPTION;HAVE_STDINT_H;HAVE_INTTYPES_H;NO_FSEEKO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
- <ClCompile Include="ioapi.c" />
- <ClCompile Include="unzip.c" />
+ <ClCompile Include="mz_compat.c" />
+ <ClCompile Include="mz_crypt.c" />
+ <ClCompile Include="mz_os.c" />
+ <ClCompile Include="mz_os_win32.c" />
+ <ClCompile Include="mz_strm.c" />
+ <ClCompile Include="mz_strm_buf.c" />
+ <ClCompile Include="mz_strm_mem.c" />
+ <ClCompile Include="mz_strm_os_win32.c" />
+ <ClCompile Include="mz_strm_split.c" />
+ <ClCompile Include="mz_strm_zlib.c" />
+ <ClCompile Include="mz_zip.c" />
+ <ClCompile Include="mz_zip_rw.c" />
</ItemGroup>
<ItemGroup>
- <ClInclude Include="ioapi.h" />
+ <ClInclude Include="mz.h" />
+ <ClInclude Include="mz_compat.h" />
+ <ClInclude Include="mz_crypt.h" />
+ <ClInclude Include="mz_os.h" />
+ <ClInclude Include="mz_strm.h" />
+ <ClInclude Include="mz_strm_buf.h" />
+ <ClInclude Include="mz_strm_mem.h" />
+ <ClInclude Include="mz_strm_os.h" />
+ <ClInclude Include="mz_strm_split.h" />
+ <ClInclude Include="mz_strm_zlib.h" />
+ <ClInclude Include="mz_zip.h" />
+ <ClInclude Include="mz_zip_rw.h" />
<ClInclude Include="unzip.h" />
+ <ClInclude Include="zip.h" />
</ItemGroup>
<ItemGroup>
<None Include="LICENSE" />
diff --git a/Externals/minizip/mz.h b/Externals/minizip/mz.h
new file mode 100644
index 0000000000..82a14a23e0
--- /dev/null
+++ b/Externals/minizip/mz.h
@@ -0,0 +1,274 @@
+/* mz.h -- Errors codes, zip flags and magic
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_H
+#define MZ_H
+
+/***************************************************************************/
+
+/* MZ_VERSION */
+#define MZ_VERSION ("3.0.4")
+#define MZ_VERSION_BUILD (030004)
+
+/* MZ_ERROR */
+#define MZ_OK (0) /* zlib */
+#define MZ_STREAM_ERROR (-1) /* zlib */
+#define MZ_DATA_ERROR (-3) /* zlib */
+#define MZ_MEM_ERROR (-4) /* zlib */
+#define MZ_BUF_ERROR (-5) /* zlib */
+#define MZ_VERSION_ERROR (-6) /* zlib */
+
+#define MZ_END_OF_LIST (-100)
+#define MZ_END_OF_STREAM (-101)
+
+#define MZ_PARAM_ERROR (-102)
+#define MZ_FORMAT_ERROR (-103)
+#define MZ_INTERNAL_ERROR (-104)
+#define MZ_CRC_ERROR (-105)
+#define MZ_CRYPT_ERROR (-106)
+#define MZ_EXIST_ERROR (-107)
+#define MZ_PASSWORD_ERROR (-108)
+#define MZ_SUPPORT_ERROR (-109)
+#define MZ_HASH_ERROR (-110)
+#define MZ_OPEN_ERROR (-111)
+#define MZ_CLOSE_ERROR (-112)
+#define MZ_SEEK_ERROR (-113)
+#define MZ_TELL_ERROR (-114)
+#define MZ_READ_ERROR (-115)
+#define MZ_WRITE_ERROR (-116)
+#define MZ_SIGN_ERROR (-117)
+#define MZ_SYMLINK_ERROR (-118)
+
+/* MZ_OPEN */
+#define MZ_OPEN_MODE_READ (0x01)
+#define MZ_OPEN_MODE_WRITE (0x02)
+#define MZ_OPEN_MODE_READWRITE (MZ_OPEN_MODE_READ | MZ_OPEN_MODE_WRITE)
+#define MZ_OPEN_MODE_APPEND (0x04)
+#define MZ_OPEN_MODE_CREATE (0x08)
+#define MZ_OPEN_MODE_EXISTING (0x10)
+
+/* MZ_SEEK */
+#define MZ_SEEK_SET (0)
+#define MZ_SEEK_CUR (1)
+#define MZ_SEEK_END (2)
+
+/* MZ_COMPRESS */
+#define MZ_COMPRESS_METHOD_STORE (0)
+#define MZ_COMPRESS_METHOD_DEFLATE (8)
+#define MZ_COMPRESS_METHOD_BZIP2 (12)
+#define MZ_COMPRESS_METHOD_LZMA (14)
+#define MZ_COMPRESS_METHOD_ZSTD (93)
+#define MZ_COMPRESS_METHOD_XZ (95)
+#define MZ_COMPRESS_METHOD_AES (99)
+
+#define MZ_COMPRESS_LEVEL_DEFAULT (-1)
+#define MZ_COMPRESS_LEVEL_FAST (2)
+#define MZ_COMPRESS_LEVEL_NORMAL (6)
+#define MZ_COMPRESS_LEVEL_BEST (9)
+
+/* MZ_ZIP_FLAG */
+#define MZ_ZIP_FLAG_ENCRYPTED (1 << 0)
+#define MZ_ZIP_FLAG_LZMA_EOS_MARKER (1 << 1)
+#define MZ_ZIP_FLAG_DEFLATE_MAX (1 << 1)
+#define MZ_ZIP_FLAG_DEFLATE_NORMAL (0)
+#define MZ_ZIP_FLAG_DEFLATE_FAST (1 << 2)
+#define MZ_ZIP_FLAG_DEFLATE_SUPER_FAST (MZ_ZIP_FLAG_DEFLATE_FAST | \
+ MZ_ZIP_FLAG_DEFLATE_MAX)
+#define MZ_ZIP_FLAG_DATA_DESCRIPTOR (1 << 3)
+#define MZ_ZIP_FLAG_UTF8 (1 << 11)
+#define MZ_ZIP_FLAG_MASK_LOCAL_INFO (1 << 13)
+
+/* MZ_ZIP_EXTENSION */
+#define MZ_ZIP_EXTENSION_ZIP64 (0x0001)
+#define MZ_ZIP_EXTENSION_NTFS (0x000a)
+#define MZ_ZIP_EXTENSION_AES (0x9901)
+#define MZ_ZIP_EXTENSION_UNIX1 (0x000d)
+#define MZ_ZIP_EXTENSION_SIGN (0x10c5)
+#define MZ_ZIP_EXTENSION_HASH (0x1a51)
+#define MZ_ZIP_EXTENSION_CDCD (0xcdcd)
+
+/* MZ_ZIP64 */
+#define MZ_ZIP64_AUTO (0)
+#define MZ_ZIP64_FORCE (1)
+#define MZ_ZIP64_DISABLE (2)
+
+/* MZ_HOST_SYSTEM */
+#define MZ_HOST_SYSTEM(VERSION_MADEBY) ((uint8_t)(VERSION_MADEBY >> 8))
+#define MZ_HOST_SYSTEM_MSDOS (0)
+#define MZ_HOST_SYSTEM_UNIX (3)
+#define MZ_HOST_SYSTEM_WINDOWS_NTFS (10)
+#define MZ_HOST_SYSTEM_RISCOS (13)
+#define MZ_HOST_SYSTEM_OSX_DARWIN (19)
+
+/* MZ_PKCRYPT */
+#define MZ_PKCRYPT_HEADER_SIZE (12)
+
+/* MZ_AES */
+#define MZ_AES_VERSION (1)
+#define MZ_AES_ENCRYPTION_MODE_128 (0x01)
+#define MZ_AES_ENCRYPTION_MODE_192 (0x02)
+#define MZ_AES_ENCRYPTION_MODE_256 (0x03)
+#define MZ_AES_KEY_LENGTH(MODE) (8 * (MODE & 3) + 8)
+#define MZ_AES_KEY_LENGTH_MAX (32)
+#define MZ_AES_BLOCK_SIZE (16)
+#define MZ_AES_HEADER_SIZE(MODE) ((4 * (MODE & 3) + 4) + 2)
+#define MZ_AES_FOOTER_SIZE (10)
+
+/* MZ_HASH */
+#define MZ_HASH_MD5 (10)
+#define MZ_HASH_MD5_SIZE (16)
+#define MZ_HASH_SHA1 (20)
+#define MZ_HASH_SHA1_SIZE (20)
+#define MZ_HASH_SHA256 (23)
+#define MZ_HASH_SHA256_SIZE (32)
+#define MZ_HASH_MAX_SIZE (256)
+
+/* MZ_ENCODING */
+#define MZ_ENCODING_CODEPAGE_437 (437)
+#define MZ_ENCODING_CODEPAGE_932 (932)
+#define MZ_ENCODING_CODEPAGE_936 (936)
+#define MZ_ENCODING_CODEPAGE_950 (950)
+#define MZ_ENCODING_UTF8 (65001)
+
+/* MZ_UTILITY */
+#define MZ_UNUSED(SYMBOL) ((void)SYMBOL)
+
+#ifndef MZ_CUSTOM_ALLOC
+#define MZ_ALLOC(SIZE) (malloc((SIZE)))
+#endif
+#ifndef MZ_CUSTOM_FREE
+#define MZ_FREE(PTR) (free(PTR))
+#endif
+
+#if defined(_WIN32) && defined(MZ_EXPORTS)
+#define MZ_EXPORT __declspec(dllexport)
+#else
+#define MZ_EXPORT
+#endif
+
+/***************************************************************************/
+
+#include <stdlib.h> /* size_t, NULL, malloc */
+#include <time.h> /* time_t, time() */
+#include <string.h> /* memset, strncpy, strlen */
+#include <limits.h>
+
+#if defined(HAVE_STDINT_H)
+# include <stdint.h>
+#elif defined(__has_include)
+# if __has_include(<stdint.h>)
+# include <stdint.h>
+# endif
+#endif
+
+#ifndef INT8_MAX
+typedef signed char int8_t;
+#endif
+#ifndef INT16_MAX
+typedef short int16_t;
+#endif
+#ifndef INT32_MAX
+typedef int int32_t;
+#endif
+#ifndef INT64_MAX
+typedef long long int64_t;
+#endif
+#ifndef UINT8_MAX
+typedef unsigned char uint8_t;
+#endif
+#ifndef UINT16_MAX
+typedef unsigned short uint16_t;
+#endif
+#ifndef UINT32_MAX
+typedef unsigned int uint32_t;
+#endif
+#ifndef UINT64_MAX
+typedef unsigned long long uint64_t;
+#endif
+
+#if defined(HAVE_INTTYPES_H)
+# include <inttypes.h>
+#elif defined(__has_include)
+# if __has_include(<inttypes.h>)
+# include <inttypes.h>
+# endif
+#endif
+
+#ifndef PRId8
+# define PRId8 "hhd"
+#endif
+#ifndef PRIu8
+# define PRIu8 "hhu"
+#endif
+#ifndef PRIx8
+# define PRIx8 "hhx"
+#endif
+#ifndef PRId16
+# define PRId16 "hd"
+#endif
+#ifndef PRIu16
+# define PRIu16 "hu"
+#endif
+#ifndef PRIx16
+# define PRIx16 "hx"
+#endif
+#ifndef PRId32
+# define PRId32 "d"
+#endif
+#ifndef PRIu32
+# define PRIu32 "u"
+#endif
+#ifndef PRIx32
+# define PRIx32 "x"
+#endif
+#if ULONG_MAX == 0xfffffffful
+# ifndef PRId64
+# define PRId64 "ld"
+# endif
+# ifndef PRIu64
+# define PRIu64 "lu"
+# endif
+# ifndef PRIx64
+# define PRIx64 "lx"
+# endif
+#else
+# ifndef PRId64
+# define PRId64 "lld"
+# endif
+# ifndef PRIu64
+# define PRIu64 "llu"
+# endif
+# ifndef PRIx64
+# define PRIx64 "llx"
+# endif
+#endif
+
+#ifndef INT16_MAX
+# define INT16_MAX 32767
+#endif
+#ifndef INT32_MAX
+# define INT32_MAX 2147483647L
+#endif
+#ifndef INT64_MAX
+# define INT64_MAX 9223372036854775807LL
+#endif
+#ifndef UINT16_MAX
+# define UINT16_MAX 65535U
+#endif
+#ifndef UINT32_MAX
+# define UINT32_MAX 4294967295UL
+#endif
+#ifndef UINT64_MAX
+# define UINT64_MAX 18446744073709551615ULL
+#endif
+
+/***************************************************************************/
+
+#endif
diff --git a/Externals/minizip/mz_compat.c b/Externals/minizip/mz_compat.c
new file mode 100644
index 0000000000..5a08046a7f
--- /dev/null
+++ b/Externals/minizip/mz_compat.c
@@ -0,0 +1,1303 @@
+/* mz_compat.c -- Backwards compatible interface for older versions
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Copyright (C) 1998-2010 Gilles Vollant
+ https://www.winimage.com/zLibDll/minizip.html
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_os.h"
+#include "mz_strm.h"
+#include "mz_strm_mem.h"
+#include "mz_strm_os.h"
+#include "mz_strm_zlib.h"
+#include "mz_zip.h"
+
+#include <stdio.h> /* SEEK */
+
+#include "mz_compat.h"
+
+/***************************************************************************/
+
+typedef struct mz_compat_s {
+ void *stream;
+ void *handle;
+ uint64_t entry_index;
+ int64_t entry_pos;
+ int64_t total_out;
+} mz_compat;
+
+/***************************************************************************/
+
+typedef struct mz_stream_ioapi_s {
+ mz_stream stream;
+ void *handle;
+ zlib_filefunc_def filefunc;
+ zlib_filefunc64_def filefunc64;
+} mz_stream_ioapi;
+
+/***************************************************************************/
+
+static int32_t mz_stream_ioapi_open(void *stream, const char *path, int32_t mode);
+static int32_t mz_stream_ioapi_is_open(void *stream);
+static int32_t mz_stream_ioapi_read(void *stream, void *buf, int32_t size);
+static int32_t mz_stream_ioapi_write(void *stream, const void *buf, int32_t size);
+static int64_t mz_stream_ioapi_tell(void *stream);
+static int32_t mz_stream_ioapi_seek(void *stream, int64_t offset, int32_t origin);
+static int32_t mz_stream_ioapi_close(void *stream);
+static int32_t mz_stream_ioapi_error(void *stream);
+static void *mz_stream_ioapi_create(void **stream);
+static void mz_stream_ioapi_delete(void **stream);
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_ioapi_vtbl = {
+ mz_stream_ioapi_open,
+ mz_stream_ioapi_is_open,
+ mz_stream_ioapi_read,
+ mz_stream_ioapi_write,
+ mz_stream_ioapi_tell,
+ mz_stream_ioapi_seek,
+ mz_stream_ioapi_close,
+ mz_stream_ioapi_error,
+ mz_stream_ioapi_create,
+ mz_stream_ioapi_delete,
+ NULL,
+ NULL
+};
+
+/***************************************************************************/
+
+static int32_t mz_stream_ioapi_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;
+ int32_t ioapi_mode = 0;
+
+ if ((mode & MZ_OPEN_MODE_READWRITE) == MZ_OPEN_MODE_READ)
+ ioapi_mode = ZLIB_FILEFUNC_MODE_READ;
+ else if (mode & MZ_OPEN_MODE_APPEND)
+ ioapi_mode = ZLIB_FILEFUNC_MODE_EXISTING;
+ else if (mode & MZ_OPEN_MODE_CREATE)
+ ioapi_mode = ZLIB_FILEFUNC_MODE_CREATE;
+ else
+ return MZ_OPEN_ERROR;
+
+ if (ioapi->filefunc64.zopen64_file != NULL)
+ ioapi->handle = ioapi->filefunc64.zopen64_file(ioapi->filefunc64.opaque, path, ioapi_mode);
+ else if (ioapi->filefunc.zopen_file != NULL)
+ ioapi->handle = ioapi->filefunc.zopen_file(ioapi->filefunc.opaque, path, ioapi_mode);
+
+ if (ioapi->handle == NULL)
+ return MZ_PARAM_ERROR;
+
+ return MZ_OK;
+}
+
+static int32_t mz_stream_ioapi_is_open(void *stream) {
+ mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;
+ if (ioapi->handle == NULL)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+static int32_t mz_stream_ioapi_read(void *stream, void *buf, int32_t size) {
+ mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;
+ read_file_func zread = NULL;
+ void *opaque = NULL;
+
+ if (mz_stream_ioapi_is_open(stream) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ if (ioapi->filefunc64.zread_file != NULL) {
+ zread = ioapi->filefunc64.zread_file;
+ opaque = ioapi->filefunc64.opaque;
+ } else if (ioapi->filefunc.zread_file != NULL) {
+ zread = ioapi->filefunc.zread_file;
+ opaque = ioapi->filefunc.opaque;
+ } else
+ return MZ_PARAM_ERROR;
+
+ return zread(opaque, ioapi->handle, buf, size);
+}
+
+static int32_t mz_stream_ioapi_write(void *stream, const void *buf, int32_t size) {
+ mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;
+ write_file_func zwrite = NULL;
+ int32_t written = 0;
+ void *opaque = NULL;
+
+ if (mz_stream_ioapi_is_open(stream) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ if (ioapi->filefunc64.zwrite_file != NULL) {
+ zwrite = ioapi->filefunc64.zwrite_file;
+ opaque = ioapi->filefunc64.opaque;
+ } else if (ioapi->filefunc.zwrite_file != NULL) {
+ zwrite = ioapi->filefunc.zwrite_file;
+ opaque = ioapi->filefunc.opaque;
+ } else
+ return MZ_PARAM_ERROR;
+
+ written = zwrite(opaque, ioapi->handle, buf, size);
+ return written;
+}
+
+static int64_t mz_stream_ioapi_tell(void *stream) {
+ mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;
+
+ if (mz_stream_ioapi_is_open(stream) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ if (ioapi->filefunc64.ztell64_file != NULL)
+ return ioapi->filefunc64.ztell64_file(ioapi->filefunc64.opaque, ioapi->handle);
+ else if (ioapi->filefunc.ztell_file != NULL)
+ return ioapi->filefunc.ztell_file(ioapi->filefunc.opaque, ioapi->handle);
+
+ return MZ_INTERNAL_ERROR;
+}
+
+static int32_t mz_stream_ioapi_seek(void *stream, int64_t offset, int32_t origin) {
+ mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;
+ int32_t written = 0;
+ void *opaque = NULL;
+
+ if (mz_stream_ioapi_is_open(stream) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ if (ioapi->filefunc64.zseek64_file != NULL) {
+ if (ioapi->filefunc64.zseek64_file(ioapi->filefunc64.opaque, ioapi->handle, offset, origin) != 0)
+ return MZ_INTERNAL_ERROR;
+ } else if (ioapi->filefunc.zseek_file != NULL) {
+ if (ioapi->filefunc.zseek_file(ioapi->filefunc.opaque, ioapi->handle, (int32_t)offset, origin) != 0)
+ return MZ_INTERNAL_ERROR;
+ } else
+ return MZ_PARAM_ERROR;
+
+ return MZ_OK;
+}
+
+static int32_t mz_stream_ioapi_close(void *stream) {
+ mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;
+ close_file_func zclose = NULL;
+ void *opaque = NULL;
+
+ if (mz_stream_ioapi_is_open(stream) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ if (ioapi->filefunc.zclose_file != NULL) {
+ zclose = ioapi->filefunc.zclose_file;
+ opaque = ioapi->filefunc.opaque;
+ } else if (ioapi->filefunc64.zclose_file != NULL) {
+ zclose = ioapi->filefunc64.zclose_file;
+ opaque = ioapi->filefunc64.opaque;
+ } else
+ return MZ_PARAM_ERROR;
+
+ if (zclose(opaque, ioapi->handle) != 0)
+ return MZ_CLOSE_ERROR;
+ ioapi->handle = NULL;
+ return MZ_OK;
+}
+
+static int32_t mz_stream_ioapi_error(void *stream) {
+ mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;
+ testerror_file_func zerror = NULL;
+ void *opaque = NULL;
+
+ if (mz_stream_ioapi_is_open(stream) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ if (ioapi->filefunc.zerror_file != NULL) {
+ zerror = ioapi->filefunc.zerror_file;
+ opaque = ioapi->filefunc.opaque;
+ } else if (ioapi->filefunc64.zerror_file != NULL) {
+ zerror = ioapi->filefunc64.zerror_file;
+ opaque = ioapi->filefunc64.opaque;
+ } else
+ return MZ_PARAM_ERROR;
+
+ return zerror(opaque, ioapi->handle);
+}
+
+static int32_t mz_stream_ioapi_set_filefunc(void *stream, zlib_filefunc_def *filefunc) {
+ mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;
+ memcpy(&ioapi->filefunc, filefunc, sizeof(zlib_filefunc_def));
+ return MZ_OK;
+}
+
+static int32_t mz_stream_ioapi_set_filefunc64(void *stream, zlib_filefunc64_def *filefunc) {
+ mz_stream_ioapi *ioapi = (mz_stream_ioapi *)stream;
+ memcpy(&ioapi->filefunc64, filefunc, sizeof(zlib_filefunc64_def));
+ return MZ_OK;
+}
+
+static void *mz_stream_ioapi_create(void **stream) {
+ mz_stream_ioapi *ioapi = NULL;
+
+ ioapi = (mz_stream_ioapi *)MZ_ALLOC(sizeof(mz_stream_ioapi));
+ if (ioapi != NULL) {
+ memset(ioapi, 0, sizeof(mz_stream_ioapi));
+ ioapi->stream.vtbl = &mz_stream_ioapi_vtbl;
+ }
+ if (stream != NULL)
+ *stream = ioapi;
+
+ return ioapi;
+}
+
+static void mz_stream_ioapi_delete(void **stream) {
+ mz_stream_ioapi *ioapi = NULL;
+ if (stream == NULL)
+ return;
+ ioapi = (mz_stream_ioapi *)*stream;
+ if (ioapi != NULL)
+ MZ_FREE(ioapi);
+ *stream = NULL;
+}
+
+/***************************************************************************/
+
+void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def) {
+ /* For 32-bit file support only, compile with MZ_FILE32_API */
+ if (pzlib_filefunc_def != NULL)
+ memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc_def));
+}
+
+void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def) {
+ /* All mz_stream_os_* support large files if compilation supports it */
+ if (pzlib_filefunc_def != NULL)
+ memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc64_def));
+}
+
+void fill_win32_filefunc(zlib_filefunc_def *pzlib_filefunc_def) {
+ /* Handled by mz_stream_os_win32 */
+ if (pzlib_filefunc_def != NULL)
+ memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc_def));
+}
+
+void fill_win32_filefunc64(zlib_filefunc64_def *pzlib_filefunc_def) {
+ /* Automatically supported in mz_stream_os_win32 */
+ if (pzlib_filefunc_def != NULL)
+ memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc64_def));
+}
+
+void fill_win32_filefunc64A(zlib_filefunc64_def *pzlib_filefunc_def) {
+ /* Automatically supported in mz_stream_os_win32 */
+ if (pzlib_filefunc_def != NULL)
+ memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc64_def));
+}
+
+/* NOTE: fill_win32_filefunc64W is no longer necessary since wide-character
+ support is automatically handled by the underlying os stream. Do not
+ pass wide-characters to zipOpen or unzOpen. */
+
+void fill_memory_filefunc(zlib_filefunc_def *pzlib_filefunc_def) {
+ /* Use opaque to indicate which stream interface to create */
+ if (pzlib_filefunc_def != NULL) {
+ memset(pzlib_filefunc_def, 0, sizeof(zlib_filefunc_def));
+ pzlib_filefunc_def->opaque = mz_stream_mem_get_interface();
+ }
+}
+
+/***************************************************************************/
+
+static int32_t zipConvertAppendToStreamMode(int append) {
+ int32_t mode = MZ_OPEN_MODE_WRITE;
+ switch (append) {
+ case APPEND_STATUS_CREATE:
+ mode |= MZ_OPEN_MODE_CREATE;
+ break;
+ case APPEND_STATUS_CREATEAFTER:
+ mode |= MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_APPEND;
+ break;
+ case APPEND_STATUS_ADDINZIP:
+ mode |= MZ_OPEN_MODE_READ | MZ_OPEN_MODE_APPEND;
+ break;
+ }
+ return mode;
+}
+
+zipFile zipOpen(const char *path, int append) {
+ return zipOpen2(path, append, NULL, NULL);
+}
+
+zipFile zipOpen64(const void *path, int append) {
+ return zipOpen2(path, append, NULL, NULL);
+}
+
+zipFile zipOpen2(const char *path, int append, const char **globalcomment,
+ zlib_filefunc_def *pzlib_filefunc_def) {
+ zipFile zip = NULL;
+ int32_t mode = zipConvertAppendToStreamMode(append);
+ void *stream = NULL;
+
+ if (pzlib_filefunc_def) {
+ if (pzlib_filefunc_def->zopen_file != NULL) {
+ if (mz_stream_ioapi_create(&stream) == NULL)
+ return NULL;
+ mz_stream_ioapi_set_filefunc(stream, pzlib_filefunc_def);
+ } else if (pzlib_filefunc_def->opaque != NULL) {
+ if (mz_stream_create(&stream, (mz_stream_vtbl *)pzlib_filefunc_def->opaque) == NULL)
+ return NULL;
+ }
+ }
+
+ if (stream == NULL) {
+ if (mz_stream_os_create(&stream) == NULL)
+ return NULL;
+ }
+
+ if (mz_stream_open(stream, path, mode) != MZ_OK) {
+ mz_stream_delete(&stream);
+ return NULL;
+ }
+
+ zip = zipOpen_MZ(stream, append, globalcomment);
+
+ if (zip == NULL) {
+ mz_stream_delete(&stream);
+ return NULL;
+ }
+
+ return zip;
+}
+
+zipFile zipOpen2_64(const void *path, int append, const char **globalcomment,
+ zlib_filefunc64_def *pzlib_filefunc_def) {
+ zipFile zip = NULL;
+ int32_t mode = zipConvertAppendToStreamMode(append);
+ void *stream = NULL;
+
+ if (pzlib_filefunc_def) {
+ if (pzlib_filefunc_def->zopen64_file != NULL) {
+ if (mz_stream_ioapi_create(&stream) == NULL)
+ return NULL;
+ mz_stream_ioapi_set_filefunc64(stream, pzlib_filefunc_def);
+ } else if (pzlib_filefunc_def->opaque != NULL) {
+ if (mz_stream_create(&stream, (mz_stream_vtbl *)pzlib_filefunc_def->opaque) == NULL)
+ return NULL;
+ }
+ }
+
+ if (stream == NULL) {
+ if (mz_stream_os_create(&stream) == NULL)
+ return NULL;
+ }
+
+ if (mz_stream_open(stream, path, mode) != MZ_OK) {
+ mz_stream_delete(&stream);
+ return NULL;
+ }
+
+ zip = zipOpen_MZ(stream, append, globalcomment);
+
+ if (zip == NULL) {
+ mz_stream_delete(&stream);
+ return NULL;
+ }
+
+ return zip;
+}
+
+zipFile zipOpen_MZ(void *stream, int append, const char **globalcomment) {
+ mz_compat *compat = NULL;
+ int32_t err = MZ_OK;
+ int32_t mode = zipConvertAppendToStreamMode(append);
+ void *handle = NULL;
+
+ mz_zip_create(&handle);
+ err = mz_zip_open(handle, stream, mode);
+
+ if (err != MZ_OK) {
+ mz_zip_delete(&handle);
+ return NULL;
+ }
+
+ if (globalcomment != NULL)
+ mz_zip_get_comment(handle, globalcomment);
+
+ compat = (mz_compat *)MZ_ALLOC(sizeof(mz_compat));
+ if (compat != NULL) {
+ compat->handle = handle;
+ compat->stream = stream;
+ } else {
+ mz_zip_delete(&handle);
+ }
+
+ return (zipFile)compat;
+}
+
+void* zipGetHandle_MZ(zipFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ if (compat == NULL)
+ return NULL;
+ return compat->handle;
+}
+
+void* zipGetStream_MZ(zipFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ if (compat == NULL)
+ return NULL;
+ return (void *)compat->stream;
+}
+
+int zipOpenNewFileInZip5(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int windowBits, int memLevel, int strategy, const char *password,
+ unsigned long crc_for_crypting, unsigned long version_madeby, unsigned long flag_base, int zip64) {
+ mz_compat *compat = (mz_compat *)file;
+ mz_zip_file file_info;
+
+ MZ_UNUSED(strategy);
+ MZ_UNUSED(memLevel);
+ MZ_UNUSED(windowBits);
+ MZ_UNUSED(size_extrafield_local);
+ MZ_UNUSED(extrafield_local);
+ MZ_UNUSED(crc_for_crypting);
+
+ if (compat == NULL)
+ return ZIP_PARAMERROR;
+
+ memset(&file_info, 0, sizeof(file_info));
+
+ if (zipfi != NULL) {
+ uint64_t dos_date = 0;
+
+ if (zipfi->mz_dos_date != 0)
+ dos_date = zipfi->mz_dos_date;
+ else
+ dos_date = mz_zip_tm_to_dosdate(&zipfi->tmz_date);
+
+ file_info.modified_date = mz_zip_dosdate_to_time_t(dos_date);
+ file_info.external_fa = zipfi->external_fa;
+ file_info.internal_fa = zipfi->internal_fa;
+ }
+
+ if (filename == NULL)
+ filename = "-";
+
+ file_info.compression_method = (uint16_t)compression_method;
+ file_info.filename = filename;
+ /* file_info.extrafield_local = extrafield_local; */
+ /* file_info.extrafield_local_size = size_extrafield_local; */
+ file_info.extrafield = extrafield_global;
+ file_info.extrafield_size = size_extrafield_global;
+ file_info.version_madeby = (uint16_t)version_madeby;
+ file_info.comment = comment;
+ if (file_info.comment != NULL)
+ file_info.comment_size = (uint16_t)strlen(file_info.comment);
+ file_info.flag = (uint16_t)flag_base;
+ if (zip64)
+ file_info.zip64 = MZ_ZIP64_FORCE;
+ else
+ file_info.zip64 = MZ_ZIP64_DISABLE;
+#ifdef HAVE_WZAES
+ if ((password != NULL) || (raw && (file_info.flag & MZ_ZIP_FLAG_ENCRYPTED)))
+ file_info.aes_version = MZ_AES_VERSION;
+#endif
+
+ return mz_zip_entry_write_open(compat->handle, &file_info, (int16_t)level, (uint8_t)raw, password);
+}
+
+int zipOpenNewFileInZip4_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int windowBits, int memLevel, int strategy, const char *password,
+ unsigned long crc_for_crypting, unsigned long version_madeby, unsigned long flag_base, int zip64) {
+ return zipOpenNewFileInZip5(file, filename, zipfi, extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global, comment, compression_method, level, raw, windowBits,
+ memLevel, strategy, password, crc_for_crypting, version_madeby, flag_base, zip64);
+}
+
+int zipOpenNewFileInZip4(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int windowBits, int memLevel, int strategy, const char *password,
+ unsigned long crc_for_crypting, unsigned long version_madeby, unsigned long flag_base) {
+ return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global, comment, compression_method, level, raw, windowBits,
+ memLevel, strategy, password, crc_for_crypting, version_madeby, flag_base, 0);
+}
+
+int zipOpenNewFileInZip3(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int windowBits, int memLevel, int strategy, const char *password,
+ unsigned long crc_for_crypting) {
+ return zipOpenNewFileInZip3_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global, comment, compression_method, level, raw, windowBits,
+ memLevel, strategy, password, crc_for_crypting, 0);
+}
+
+int zipOpenNewFileInZip3_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int windowBits, int memLevel, int strategy, const char *password,
+ uint32_t crc_for_crypting, int zip64) {
+ return zipOpenNewFileInZip4_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global, comment, compression_method, level, raw, windowBits,
+ memLevel, strategy, password, crc_for_crypting, MZ_VERSION_MADEBY, 0, zip64);
+}
+
+int zipOpenNewFileInZip2(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw) {
+ return zipOpenNewFileInZip3_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global, comment, compression_method, level, raw,
+ 0, 0, 0, NULL, 0, 0);
+}
+
+int zipOpenNewFileInZip2_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int zip64) {
+ return zipOpenNewFileInZip3_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global, comment, compression_method, level, raw, 0,
+ 0, 0, NULL, 0, zip64);
+}
+
+int zipOpenNewFileInZip(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level) {
+ return zipOpenNewFileInZip_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global, comment, compression_method, level, 0);
+}
+
+int zipOpenNewFileInZip_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int zip64) {
+ return zipOpenNewFileInZip2_64(file, filename, zipfi, extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global, comment, compression_method, level, 0, zip64);
+}
+
+int zipWriteInFileInZip(zipFile file, const void *buf, uint32_t len) {
+ mz_compat *compat = (mz_compat *)file;
+ int32_t written = 0;
+ if (compat == NULL || len >= INT32_MAX)
+ return ZIP_PARAMERROR;
+ written = mz_zip_entry_write(compat->handle, buf, (int32_t)len);
+ if ((written < 0) || ((uint32_t)written != len))
+ return ZIP_ERRNO;
+ return ZIP_OK;
+}
+
+int zipCloseFileInZipRaw(zipFile file, unsigned long uncompressed_size, unsigned long crc32) {
+ return zipCloseFileInZipRaw64(file, uncompressed_size, crc32);
+}
+
+int zipCloseFileInZipRaw64(zipFile file, uint64_t uncompressed_size, unsigned long crc32) {
+ mz_compat *compat = (mz_compat *)file;
+ if (compat == NULL)
+ return ZIP_PARAMERROR;
+ return mz_zip_entry_close_raw(compat->handle, (int64_t)uncompressed_size, crc32);
+}
+
+int zipCloseFileInZip(zipFile file) {
+ return zipCloseFileInZip64(file);
+}
+
+int zipCloseFileInZip64(zipFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ if (compat == NULL)
+ return ZIP_PARAMERROR;
+ return mz_zip_entry_close(compat->handle);
+}
+
+int zipClose(zipFile file, const char *global_comment) {
+ return zipClose_64(file, global_comment);
+}
+
+int zipClose_64(zipFile file, const char *global_comment) {
+ return zipClose2_64(file, global_comment, MZ_VERSION_MADEBY);
+}
+
+int zipClose2_64(zipFile file, const char *global_comment, uint16_t version_madeby) {
+ mz_compat *compat = (mz_compat *)file;
+ int32_t err = MZ_OK;
+
+ if (compat->handle != NULL)
+ err = zipClose2_MZ(file, global_comment, version_madeby);
+
+ if (compat->stream != NULL) {
+ mz_stream_close(compat->stream);
+ mz_stream_delete(&compat->stream);
+ }
+
+ MZ_FREE(compat);
+
+ return err;
+}
+
+/* Only closes the zip handle, does not close the stream */
+int zipClose_MZ(zipFile file, const char *global_comment) {
+ return zipClose2_MZ(file, global_comment, MZ_VERSION_MADEBY);
+}
+
+/* Only closes the zip handle, does not close the stream */
+int zipClose2_MZ(zipFile file, const char *global_comment, uint16_t version_madeby) {
+ mz_compat *compat = (mz_compat *)file;
+ int32_t err = MZ_OK;
+
+ if (compat == NULL)
+ return ZIP_PARAMERROR;
+ if (compat->handle == NULL)
+ return err;
+
+ if (global_comment != NULL)
+ mz_zip_set_comment(compat->handle, global_comment);
+
+ mz_zip_set_version_madeby(compat->handle, version_madeby);
+ err = mz_zip_close(compat->handle);
+ mz_zip_delete(&compat->handle);
+
+ return err;
+}
+
+/***************************************************************************/
+
+unzFile unzOpen(const char *path) {
+ return unzOpen64(path);
+}
+
+unzFile unzOpen64(const void *path) {
+ return unzOpen2(path, NULL);
+}
+
+unzFile unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def) {
+ unzFile unz = NULL;
+ void *stream = NULL;
+
+ if (pzlib_filefunc_def) {
+ if (pzlib_filefunc_def->zopen_file != NULL) {
+ if (mz_stream_ioapi_create(&stream) == NULL)
+ return NULL;
+ mz_stream_ioapi_set_filefunc(stream, pzlib_filefunc_def);
+ } else if (pzlib_filefunc_def->opaque != NULL) {
+ if (mz_stream_create(&stream, (mz_stream_vtbl *)pzlib_filefunc_def->opaque) == NULL)
+ return NULL;
+ }
+ }
+
+ if (stream == NULL) {
+ if (mz_stream_os_create(&stream) == NULL)
+ return NULL;
+ }
+
+ if (mz_stream_open(stream, path, MZ_OPEN_MODE_READ) != MZ_OK) {
+ mz_stream_delete(&stream);
+ return NULL;
+ }
+
+ unz = unzOpen_MZ(stream);
+ if (unz == NULL) {
+ mz_stream_close(stream);
+ mz_stream_delete(&stream);
+ return NULL;
+ }
+ return unz;
+}
+
+unzFile unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def) {
+ unzFile unz = NULL;
+ void *stream = NULL;
+
+ if (pzlib_filefunc_def) {
+ if (pzlib_filefunc_def->zopen64_file != NULL) {
+ if (mz_stream_ioapi_create(&stream) == NULL)
+ return NULL;
+ mz_stream_ioapi_set_filefunc64(stream, pzlib_filefunc_def);
+ } else if (pzlib_filefunc_def->opaque != NULL) {
+ if (mz_stream_create(&stream, (mz_stream_vtbl *)pzlib_filefunc_def->opaque) == NULL)
+ return NULL;
+ }
+ }
+
+ if (stream == NULL) {
+ if (mz_stream_os_create(&stream) == NULL)
+ return NULL;
+ }
+
+ if (mz_stream_open(stream, path, MZ_OPEN_MODE_READ) != MZ_OK) {
+ mz_stream_delete(&stream);
+ return NULL;
+ }
+
+ unz = unzOpen_MZ(stream);
+ if (unz == NULL) {
+ mz_stream_close(stream);
+ mz_stream_delete(&stream);
+ return NULL;
+ }
+ return unz;
+}
+
+void* unzGetHandle_MZ(unzFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ if (compat == NULL)
+ return NULL;
+ return compat->handle;
+}
+
+void* unzGetStream_MZ(unzFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ if (compat == NULL)
+ return NULL;
+ return compat->stream;
+}
+
+unzFile unzOpen_MZ(void *stream) {
+ mz_compat *compat = NULL;
+ int32_t err = MZ_OK;
+ void *handle = NULL;
+
+ mz_zip_create(&handle);
+ err = mz_zip_open(handle, stream, MZ_OPEN_MODE_READ);
+
+ if (err != MZ_OK) {
+ mz_zip_delete(&handle);
+ return NULL;
+ }
+
+ compat = (mz_compat *)MZ_ALLOC(sizeof(mz_compat));
+ if (compat != NULL) {
+ compat->handle = handle;
+ compat->stream = stream;
+
+ mz_zip_goto_first_entry(compat->handle);
+ } else {
+ mz_zip_delete(&handle);
+ }
+
+ return (unzFile)compat;
+}
+
+int unzClose(unzFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ int32_t err = MZ_OK;
+
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+
+ if (compat->handle != NULL)
+ err = unzClose_MZ(file);
+
+ if (compat->stream != NULL) {
+ mz_stream_close(compat->stream);
+ mz_stream_delete(&compat->stream);
+ }
+
+ MZ_FREE(compat);
+
+ return err;
+}
+
+/* Only closes the zip handle, does not close the stream */
+int unzClose_MZ(unzFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ int32_t err = MZ_OK;
+
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+
+ err = mz_zip_close(compat->handle);
+ mz_zip_delete(&compat->handle);
+
+ return err;
+}
+
+int unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32) {
+ mz_compat *compat = (mz_compat *)file;
+ unz_global_info64 global_info64;
+ int32_t err = MZ_OK;
+
+ memset(pglobal_info32, 0, sizeof(unz_global_info));
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+
+ err = unzGetGlobalInfo64(file, &global_info64);
+ if (err == MZ_OK) {
+ pglobal_info32->number_entry = (uint32_t)global_info64.number_entry;
+ pglobal_info32->size_comment = global_info64.size_comment;
+ pglobal_info32->number_disk_with_CD = global_info64.number_disk_with_CD;
+ }
+ return err;
+}
+
+int unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info) {
+ mz_compat *compat = (mz_compat *)file;
+ const char *comment_ptr = NULL;
+ int32_t err = MZ_OK;
+
+ memset(pglobal_info, 0, sizeof(unz_global_info64));
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+ err = mz_zip_get_comment(compat->handle, &comment_ptr);
+ if (err == MZ_OK)
+ pglobal_info->size_comment = (uint16_t)strlen(comment_ptr);
+ if ((err == MZ_OK) || (err == MZ_EXIST_ERROR))
+ err = mz_zip_get_number_entry(compat->handle, &pglobal_info->number_entry);
+ if (err == MZ_OK)
+ err = mz_zip_get_disk_number_with_cd(compat->handle, &pglobal_info->number_disk_with_CD);
+ return err;
+}
+
+int unzGetGlobalComment(unzFile file, char *comment, unsigned long comment_size) {
+ mz_compat *compat = (mz_compat *)file;
+ const char *comment_ptr = NULL;
+ int32_t err = MZ_OK;
+
+ if (comment == NULL || comment_size == 0)
+ return UNZ_PARAMERROR;
+ err = mz_zip_get_comment(compat->handle, &comment_ptr);
+ if (err == MZ_OK) {
+ strncpy(comment, comment_ptr, comment_size - 1);
+ comment[comment_size - 1] = 0;
+ }
+ return err;
+}
+
+int unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password) {
+ mz_compat *compat = (mz_compat *)file;
+ mz_zip_file *file_info = NULL;
+ int32_t err = MZ_OK;
+ void *stream = NULL;
+
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+ if (method != NULL)
+ *method = 0;
+ if (level != NULL)
+ *level = 0;
+
+ compat->total_out = 0;
+ err = mz_zip_entry_read_open(compat->handle, (uint8_t)raw, password);
+ if (err == MZ_OK)
+ err = mz_zip_entry_get_info(compat->handle, &file_info);
+ if (err == MZ_OK) {
+ if (method != NULL) {
+ *method = file_info->compression_method;
+ }
+
+ if (level != NULL) {
+ *level = 6;
+ switch (file_info->flag & 0x06) {
+ case MZ_ZIP_FLAG_DEFLATE_SUPER_FAST:
+ *level = 1;
+ break;
+ case MZ_ZIP_FLAG_DEFLATE_FAST:
+ *level = 2;
+ break;
+ case MZ_ZIP_FLAG_DEFLATE_MAX:
+ *level = 9;
+ break;
+ }
+ }
+ }
+ if (err == MZ_OK)
+ err = mz_zip_get_stream(compat->handle, &stream);
+ if (err == MZ_OK)
+ compat->entry_pos = mz_stream_tell(stream);
+ return err;
+}
+
+int unzOpenCurrentFile(unzFile file) {
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
+}
+
+int unzOpenCurrentFilePassword(unzFile file, const char *password) {
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
+}
+
+int unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw) {
+ return unzOpenCurrentFile3(file, method, level, raw, NULL);
+}
+
+int unzReadCurrentFile(unzFile file, void *buf, uint32_t len) {
+ mz_compat *compat = (mz_compat *)file;
+ int32_t err = MZ_OK;
+ if (compat == NULL || len >= INT32_MAX)
+ return UNZ_PARAMERROR;
+ err = mz_zip_entry_read(compat->handle, buf, (int32_t)len);
+ if (err > 0)
+ compat->total_out += (uint32_t)err;
+ return err;
+}
+
+int unzCloseCurrentFile(unzFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ int32_t err = MZ_OK;
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+ err = mz_zip_entry_close(compat->handle);
+ return err;
+}
+
+int unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,
+ unsigned long filename_size, void *extrafield, unsigned long extrafield_size, char *comment,
+ unsigned long comment_size) {
+ mz_compat *compat = (mz_compat *)file;
+ mz_zip_file *file_info = NULL;
+ uint16_t bytes_to_copy = 0;
+ int32_t err = MZ_OK;
+
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+
+ err = mz_zip_entry_get_info(compat->handle, &file_info);
+ if (err != MZ_OK)
+ return err;
+
+ if (pfile_info != NULL) {
+ pfile_info->version = file_info->version_madeby;
+ pfile_info->version_needed = file_info->version_needed;
+ pfile_info->flag = file_info->flag;
+ pfile_info->compression_method = file_info->compression_method;
+ pfile_info->mz_dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date);
+ mz_zip_time_t_to_tm(file_info->modified_date, &pfile_info->tmu_date);
+ pfile_info->tmu_date.tm_year += 1900;
+ pfile_info->crc = file_info->crc;
+
+ pfile_info->size_filename = file_info->filename_size;
+ pfile_info->size_file_extra = file_info->extrafield_size;
+ pfile_info->size_file_comment = file_info->comment_size;
+
+ pfile_info->disk_num_start = (uint16_t)file_info->disk_number;
+ pfile_info->internal_fa = file_info->internal_fa;
+ pfile_info->external_fa = file_info->external_fa;
+
+ pfile_info->compressed_size = (uint32_t)file_info->compressed_size;
+ pfile_info->uncompressed_size = (uint32_t)file_info->uncompressed_size;
+ }
+ if (filename_size > 0 && filename != NULL && file_info->filename != NULL) {
+ bytes_to_copy = (uint16_t)filename_size;
+ if (bytes_to_copy > file_info->filename_size)
+ bytes_to_copy = file_info->filename_size;
+ memcpy(filename, file_info->filename, bytes_to_copy);
+ if (bytes_to_copy < filename_size)
+ filename[bytes_to_copy] = 0;
+ }
+ if (extrafield_size > 0 && extrafield != NULL) {
+ bytes_to_copy = (uint16_t)extrafield_size;
+ if (bytes_to_copy > file_info->extrafield_size)
+ bytes_to_copy = file_info->extrafield_size;
+ memcpy(extrafield, file_info->extrafield, bytes_to_copy);
+ }
+ if (comment_size > 0 && comment != NULL && file_info->comment != NULL) {
+ bytes_to_copy = (uint16_t)comment_size;
+ if (bytes_to_copy > file_info->comment_size)
+ bytes_to_copy = file_info->comment_size;
+ memcpy(comment, file_info->comment, bytes_to_copy);
+ if (bytes_to_copy < comment_size)
+ comment[bytes_to_copy] = 0;
+ }
+ return err;
+}
+
+int unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename,
+ unsigned long filename_size, void *extrafield, unsigned long extrafield_size, char *comment,
+ unsigned long comment_size) {
+ mz_compat *compat = (mz_compat *)file;
+ mz_zip_file *file_info = NULL;
+ uint16_t bytes_to_copy = 0;
+ int32_t err = MZ_OK;
+
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+
+ err = mz_zip_entry_get_info(compat->handle, &file_info);
+ if (err != MZ_OK)
+ return err;
+
+ if (pfile_info != NULL) {
+ pfile_info->version = file_info->version_madeby;
+ pfile_info->version_needed = file_info->version_needed;
+ pfile_info->flag = file_info->flag;
+ pfile_info->compression_method = file_info->compression_method;
+ pfile_info->mz_dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date);
+ mz_zip_time_t_to_tm(file_info->modified_date, &pfile_info->tmu_date);
+ pfile_info->tmu_date.tm_year += 1900;
+ pfile_info->crc = file_info->crc;
+
+ pfile_info->size_filename = file_info->filename_size;
+ pfile_info->size_file_extra = file_info->extrafield_size;
+ pfile_info->size_file_comment = file_info->comment_size;
+
+ pfile_info->disk_num_start = file_info->disk_number;
+ pfile_info->internal_fa = file_info->internal_fa;
+ pfile_info->external_fa = file_info->external_fa;
+
+ pfile_info->compressed_size = (uint64_t)file_info->compressed_size;
+ pfile_info->uncompressed_size = (uint64_t)file_info->uncompressed_size;
+ }
+ if (filename_size > 0 && filename != NULL && file_info->filename != NULL) {
+ bytes_to_copy = (uint16_t)filename_size;
+ if (bytes_to_copy > file_info->filename_size)
+ bytes_to_copy = file_info->filename_size;
+ memcpy(filename, file_info->filename, bytes_to_copy);
+ if (bytes_to_copy < filename_size)
+ filename[bytes_to_copy] = 0;
+ }
+ if (extrafield_size > 0 && extrafield != NULL) {
+ bytes_to_copy = (uint16_t)extrafield_size;
+ if (bytes_to_copy > file_info->extrafield_size)
+ bytes_to_copy = file_info->extrafield_size;
+ memcpy(extrafield, file_info->extrafield, bytes_to_copy);
+ }
+ if (comment_size > 0 && comment != NULL && file_info->comment != NULL) {
+ bytes_to_copy = (uint16_t)comment_size;
+ if (bytes_to_copy > file_info->comment_size)
+ bytes_to_copy = file_info->comment_size;
+ memcpy(comment, file_info->comment, bytes_to_copy);
+ if (bytes_to_copy < comment_size)
+ comment[bytes_to_copy] = 0;
+ }
+ return err;
+}
+
+int unzGoToFirstFile(unzFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+ compat->entry_index = 0;
+ return mz_zip_goto_first_entry(compat->handle);
+}
+
+int unzGoToNextFile(unzFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ int32_t err = MZ_OK;
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+ err = mz_zip_goto_next_entry(compat->handle);
+ if (err != MZ_END_OF_LIST)
+ compat->entry_index += 1;
+ return err;
+}
+
+int unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func) {
+ mz_compat *compat = (mz_compat *)file;
+ mz_zip_file *file_info = NULL;
+ uint64_t preserve_index = 0;
+ int32_t err = MZ_OK;
+ int32_t result = 0;
+
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+
+ preserve_index = compat->entry_index;
+
+ err = mz_zip_goto_first_entry(compat->handle);
+ while (err == MZ_OK) {
+ err = mz_zip_entry_get_info(compat->handle, &file_info);
+ if (err != MZ_OK)
+ break;
+
+ if ((intptr_t)filename_compare_func > 2) {
+ result = filename_compare_func(file, filename, file_info->filename);
+ } else {
+ int32_t case_sensitive = (int32_t)(intptr_t)filename_compare_func;
+ result = mz_path_compare_wc(filename, file_info->filename, !case_sensitive);
+ }
+
+ if (result == 0)
+ return MZ_OK;
+
+ err = mz_zip_goto_next_entry(compat->handle);
+ }
+
+ compat->entry_index = preserve_index;
+ return err;
+}
+
+/***************************************************************************/
+
+int unzGetFilePos(unzFile file, unz_file_pos *file_pos) {
+ unz64_file_pos file_pos64;
+ int32_t err = 0;
+
+ err = unzGetFilePos64(file, &file_pos64);
+ if (err < 0)
+ return err;
+
+ file_pos->pos_in_zip_directory = (uint32_t)file_pos64.pos_in_zip_directory;
+ file_pos->num_of_file = (uint32_t)file_pos64.num_of_file;
+ return err;
+}
+
+int unzGoToFilePos(unzFile file, unz_file_pos *file_pos) {
+ mz_compat *compat = (mz_compat *)file;
+ unz64_file_pos file_pos64;
+
+ if (compat == NULL || file_pos == NULL)
+ return UNZ_PARAMERROR;
+
+ file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
+ file_pos64.num_of_file = file_pos->num_of_file;
+
+ return unzGoToFilePos64(file, &file_pos64);
+}
+
+int unzGetFilePos64(unzFile file, unz64_file_pos *file_pos) {
+ mz_compat *compat = (mz_compat *)file;
+ int64_t offset = 0;
+
+ if (compat == NULL || file_pos == NULL)
+ return UNZ_PARAMERROR;
+
+ offset = unzGetOffset64(file);
+ if (offset < 0)
+ return (int)offset;
+
+ file_pos->pos_in_zip_directory = offset;
+ file_pos->num_of_file = compat->entry_index;
+ return UNZ_OK;
+}
+
+int unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos) {
+ mz_compat *compat = (mz_compat *)file;
+ int32_t err = MZ_OK;
+
+ if (compat == NULL || file_pos == NULL)
+ return UNZ_PARAMERROR;
+
+ err = mz_zip_goto_entry(compat->handle, file_pos->pos_in_zip_directory);
+ if (err == MZ_OK)
+ compat->entry_index = file_pos->num_of_file;
+ return err;
+}
+
+unsigned long unzGetOffset(unzFile file) {
+ return (uint32_t)unzGetOffset64(file);
+}
+
+int64_t unzGetOffset64(unzFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+ return mz_zip_get_entry(compat->handle);
+}
+
+int unzSetOffset(unzFile file, unsigned long pos) {
+ return unzSetOffset64(file, pos);
+}
+
+int unzSetOffset64(unzFile file, int64_t pos) {
+ mz_compat *compat = (mz_compat *)file;
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+ return (int)mz_zip_goto_entry(compat->handle, pos);
+}
+
+int unzGetLocalExtrafield(unzFile file, void *buf, unsigned int len) {
+ mz_compat *compat = (mz_compat *)file;
+ mz_zip_file *file_info = NULL;
+ int32_t err = MZ_OK;
+ int32_t bytes_to_copy = 0;
+
+ if (compat == NULL || buf == NULL || len >= INT32_MAX)
+ return UNZ_PARAMERROR;
+
+ err = mz_zip_entry_get_local_info(compat->handle, &file_info);
+ if (err != MZ_OK)
+ return err;
+
+ bytes_to_copy = (int32_t)len;
+ if (bytes_to_copy > file_info->extrafield_size)
+ bytes_to_copy = file_info->extrafield_size;
+
+ memcpy(buf, file_info->extrafield, bytes_to_copy);
+ return MZ_OK;
+}
+
+int32_t unzTell(unzFile file) {
+ return unztell(file);
+}
+
+int32_t unztell(unzFile file) {
+ return (int32_t)unztell64(file);
+}
+
+uint64_t unzTell64(unzFile file) {
+ return unztell64(file);
+}
+
+uint64_t unztell64(unzFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+ return compat->total_out;
+}
+
+int unzSeek(unzFile file, int32_t offset, int origin) {
+ return unzSeek64(file, offset, origin);
+}
+
+int unzSeek64(unzFile file, int64_t offset, int origin) {
+ mz_compat *compat = (mz_compat *)file;
+ mz_zip_file *file_info = NULL;
+ int64_t position = 0;
+ int32_t err = MZ_OK;
+ void *stream = NULL;
+
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+ err = mz_zip_entry_get_info(compat->handle, &file_info);
+ if (err != MZ_OK)
+ return err;
+ if (file_info->compression_method != MZ_COMPRESS_METHOD_STORE)
+ return UNZ_ERRNO;
+
+ if (origin == SEEK_SET)
+ position = offset;
+ else if (origin == SEEK_CUR)
+ position = compat->total_out + offset;
+ else if (origin == SEEK_END)
+ position = (int64_t)file_info->compressed_size + offset;
+ else
+ return UNZ_PARAMERROR;
+
+ if (position > (int64_t)file_info->compressed_size)
+ return UNZ_PARAMERROR;
+
+ err = mz_zip_get_stream(compat->handle, &stream);
+ if (err == MZ_OK)
+ err = mz_stream_seek(stream, compat->entry_pos + position, MZ_SEEK_SET);
+ if (err == MZ_OK)
+ compat->total_out = position;
+ return err;
+}
+
+int unzEndOfFile(unzFile file) {
+ return unzeof(file);
+}
+
+int unzeof(unzFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ mz_zip_file *file_info = NULL;
+ int32_t err = MZ_OK;
+
+ if (compat == NULL)
+ return UNZ_PARAMERROR;
+ err = mz_zip_entry_get_info(compat->handle, &file_info);
+ if (err != MZ_OK)
+ return err;
+ if (compat->total_out == (int64_t)file_info->uncompressed_size)
+ return 1;
+ return 0;
+}
+
+void* unzGetStream(unzFile file) {
+ mz_compat *compat = (mz_compat *)file;
+ if (compat == NULL)
+ return NULL;
+ return (void *)compat->stream;
+}
+
+/***************************************************************************/
diff --git a/Externals/minizip/mz_compat.h b/Externals/minizip/mz_compat.h
new file mode 100644
index 0000000000..808cc74e1f
--- /dev/null
+++ b/Externals/minizip/mz_compat.h
@@ -0,0 +1,396 @@
+/* mz_compat.h -- Backwards compatible interface for older versions
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Copyright (C) 1998-2010 Gilles Vollant
+ https://www.winimage.com/zLibDll/minizip.html
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_COMPAT_H
+#define MZ_COMPAT_H
+
+#include "mz.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+#if defined(HAVE_ZLIB) && defined(MAX_MEM_LEVEL)
+#ifndef DEF_MEM_LEVEL
+# if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+# else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+# endif
+#endif
+#endif
+#ifndef MAX_WBITS
+#define MAX_WBITS (15)
+#endif
+#ifndef DEF_MEM_LEVEL
+#define DEF_MEM_LEVEL (8)
+#endif
+
+#ifndef ZEXPORT
+# define ZEXPORT MZ_EXPORT
+#endif
+
+/***************************************************************************/
+
+#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagzipFile__ { int unused; } zip_file__;
+typedef zip_file__ *zipFile;
+#else
+typedef void *zipFile;
+#endif
+
+/***************************************************************************/
+
+typedef uint64_t ZPOS64_T;
+
+#ifndef ZCALLBACK
+#define ZCALLBACK
+#endif
+
+typedef void* (ZCALLBACK *open_file_func) (void *opaque, const char *filename, int mode);
+typedef void* (ZCALLBACK *open64_file_func) (void *opaque, const void *filename, int mode);
+typedef unsigned long (ZCALLBACK *read_file_func) (void *opaque, void *stream, void* buf, unsigned long size);
+typedef unsigned long (ZCALLBACK *write_file_func) (void *opaque, void *stream, const void* buf,
+ unsigned long size);
+typedef int (ZCALLBACK *close_file_func) (void *opaque, void *stream);
+typedef int (ZCALLBACK *testerror_file_func)(void *opaque, void *stream);
+typedef long (ZCALLBACK *tell_file_func) (void *opaque, void *stream);
+typedef ZPOS64_T (ZCALLBACK *tell64_file_func) (void *opaque, void *stream);
+typedef long (ZCALLBACK *seek_file_func) (void *opaque, void *stream, unsigned long offset, int origin);
+typedef long (ZCALLBACK *seek64_file_func) (void *opaque, void *stream, ZPOS64_T offset, int origin);
+
+typedef struct zlib_filefunc_def_s
+{
+ open_file_func zopen_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell_file_func ztell_file;
+ seek_file_func zseek_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ void* opaque;
+} zlib_filefunc_def;
+
+typedef struct zlib_filefunc64_def_s
+{
+ open64_file_func zopen64_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell64_file_func ztell64_file;
+ seek64_file_func zseek64_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ void* opaque;
+} zlib_filefunc64_def;
+
+/***************************************************************************/
+
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+
+#define ZLIB_FILEFUNC_MODE_READ (1)
+#define ZLIB_FILEFUNC_MODE_WRITE (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
+
+#define ZLIB_FILEFUNC_MODE_EXISTING (4)
+#define ZLIB_FILEFUNC_MODE_CREATE (8)
+
+/***************************************************************************/
+
+ZEXPORT void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
+ZEXPORT void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def);
+ZEXPORT void fill_win32_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
+ZEXPORT void fill_win32_filefunc64(zlib_filefunc64_def *pzlib_filefunc_def);
+ZEXPORT void fill_win32_filefunc64A(zlib_filefunc64_def *pzlib_filefunc_def);
+ZEXPORT void fill_memory_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
+
+/***************************************************************************/
+
+#if MZ_COMPAT_VERSION <= 110
+#define mz_dos_date dosDate
+#else
+#define mz_dos_date dos_date
+#endif
+
+typedef struct tm tm_unz;
+typedef struct tm tm_zip;
+
+typedef struct {
+ uint32_t mz_dos_date;
+ struct tm tmz_date;
+ uint16_t internal_fa; /* internal file attributes 2 bytes */
+ uint32_t external_fa; /* external file attributes 4 bytes */
+} zip_fileinfo;
+
+typedef const char *zipcharpc;
+
+/***************************************************************************/
+
+#define ZIP_OK (0)
+#define ZIP_EOF (0)
+#define ZIP_ERRNO (-1)
+#define ZIP_PARAMERROR (-102)
+#define ZIP_BADZIPFILE (-103)
+#define ZIP_INTERNALERROR (-104)
+
+#ifndef Z_DEFLATED
+#define Z_DEFLATED (8)
+#endif
+#define Z_BZIP2ED (12)
+
+#define APPEND_STATUS_CREATE (0)
+#define APPEND_STATUS_CREATEAFTER (1)
+#define APPEND_STATUS_ADDINZIP (2)
+
+/***************************************************************************/
+/* Writing a zip file */
+
+ZEXPORT zipFile zipOpen(const char *path, int append);
+ZEXPORT zipFile zipOpen64(const void *path, int append);
+ZEXPORT zipFile zipOpen2(const char *path, int append, const char **globalcomment,
+ zlib_filefunc_def *pzlib_filefunc_def);
+
+ZEXPORT zipFile zipOpen2_64(const void *path, int append, const char **globalcomment,
+ zlib_filefunc64_def *pzlib_filefunc_def);
+ZEXPORT zipFile zipOpen_MZ(void *stream, int append, const char **globalcomment);
+
+ZEXPORT void* zipGetHandle_MZ(zipFile);
+ZEXPORT void* zipGetStream_MZ(zipFile file);
+
+ZEXPORT int zipOpenNewFileInZip(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level);
+ZEXPORT int zipOpenNewFileInZip_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int zip64);
+ZEXPORT int zipOpenNewFileInZip2(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw);
+ZEXPORT int zipOpenNewFileInZip2_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int zip64);
+ZEXPORT int zipOpenNewFileInZip3(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int windowBits, int memLevel, int strategy, const char *password,
+ unsigned long crc_for_crypting);
+ZEXPORT int zipOpenNewFileInZip3_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int windowBits, int memLevel, int strategy, const char *password,
+ uint32_t crc_for_crypting, int zip64);
+ZEXPORT int zipOpenNewFileInZip4(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int windowBits, int memLevel, int strategy, const char *password,
+ unsigned long crc_for_crypting, unsigned long version_madeby, unsigned long flag_base);
+ZEXPORT int zipOpenNewFileInZip4_64(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int windowBits, int memLevel, int strategy, const char *password,
+ unsigned long crc_for_crypting, unsigned long version_madeby, unsigned long flag_base, int zip64);
+ZEXPORT int zipOpenNewFileInZip5(zipFile file, const char *filename, const zip_fileinfo *zipfi,
+ const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
+ uint16_t size_extrafield_global, const char *comment, int compression_method, int level,
+ int raw, int windowBits, int memLevel, int strategy, const char *password,
+ unsigned long crc_for_crypting, unsigned long version_madeby, unsigned long flag_base, int zip64);
+
+ZEXPORT int zipWriteInFileInZip(zipFile file, const void *buf, uint32_t len);
+
+ZEXPORT int zipCloseFileInZipRaw(zipFile file, unsigned long uncompressed_size, unsigned long crc32);
+ZEXPORT int zipCloseFileInZipRaw64(zipFile file, uint64_t uncompressed_size, unsigned long crc32);
+ZEXPORT int zipCloseFileInZip(zipFile file);
+ZEXPORT int zipCloseFileInZip64(zipFile file);
+
+ZEXPORT int zipClose(zipFile file, const char *global_comment);
+ZEXPORT int zipClose_64(zipFile file, const char *global_comment);
+ZEXPORT int zipClose2_64(zipFile file, const char *global_comment, uint16_t version_madeby);
+ int zipClose_MZ(zipFile file, const char *global_comment);
+ int zipClose2_MZ(zipFile file, const char *global_comment, uint16_t version_madeby);
+
+/***************************************************************************/
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unz_file__;
+typedef unz_file__ *unzFile;
+#else
+typedef void *unzFile;
+#endif
+
+/***************************************************************************/
+
+#define UNZ_OK (0)
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO (-1)
+#define UNZ_EOF (0)
+#define UNZ_PARAMERROR (-102)
+#define UNZ_BADZIPFILE (-103)
+#define UNZ_INTERNALERROR (-104)
+#define UNZ_CRCERROR (-105)
+#define UNZ_BADPASSWORD (-106)
+
+/***************************************************************************/
+
+typedef struct unz_global_info64_s {
+ uint64_t number_entry; /* total number of entries in the central dir on this disk */
+ uint32_t number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP */
+ uint16_t size_comment; /* size of the global comment of the zipfile */
+} unz_global_info64;
+
+typedef struct unz_global_info_s {
+ uint32_t number_entry; /* total number of entries in the central dir on this disk */
+ uint32_t number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP */
+ uint16_t size_comment; /* size of the global comment of the zipfile */
+} unz_global_info;
+
+typedef struct unz_file_info64_s {
+ uint16_t version; /* version made by 2 bytes */
+ uint16_t version_needed; /* version needed to extract 2 bytes */
+ uint16_t flag; /* general purpose bit flag 2 bytes */
+ uint16_t compression_method; /* compression method 2 bytes */
+ uint32_t mz_dos_date; /* last mod file date in Dos fmt 4 bytes */
+ struct tm tmu_date;
+ uint32_t crc; /* crc-32 4 bytes */
+ uint64_t compressed_size; /* compressed size 8 bytes */
+ uint64_t uncompressed_size; /* uncompressed size 8 bytes */
+ uint16_t size_filename; /* filename length 2 bytes */
+ uint16_t size_file_extra; /* extra field length 2 bytes */
+ uint16_t size_file_comment; /* file comment length 2 bytes */
+
+ uint32_t disk_num_start; /* disk number start 4 bytes */
+ uint16_t internal_fa; /* internal file attributes 2 bytes */
+ uint32_t external_fa; /* external file attributes 4 bytes */
+
+ uint64_t disk_offset;
+
+ uint16_t size_file_extra_internal;
+} unz_file_info64;
+
+typedef struct unz_file_info_s {
+ uint16_t version; /* version made by 2 bytes */
+ uint16_t version_needed; /* version needed to extract 2 bytes */
+ uint16_t flag; /* general purpose bit flag 2 bytes */
+ uint16_t compression_method; /* compression method 2 bytes */
+ uint32_t mz_dos_date; /* last mod file date in Dos fmt 4 bytes */
+ struct tm tmu_date;
+ uint32_t crc; /* crc-32 4 bytes */
+ uint32_t compressed_size; /* compressed size 4 bytes */
+ uint32_t uncompressed_size; /* uncompressed size 4 bytes */
+ uint16_t size_filename; /* filename length 2 bytes */
+ uint16_t size_file_extra; /* extra field length 2 bytes */
+ uint16_t size_file_comment; /* file comment length 2 bytes */
+
+ uint16_t disk_num_start; /* disk number start 2 bytes */
+ uint16_t internal_fa; /* internal file attributes 2 bytes */
+ uint32_t external_fa; /* external file attributes 4 bytes */
+
+ uint64_t disk_offset;
+} unz_file_info;
+
+/***************************************************************************/
+
+typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2);
+typedef int (*unzIteratorFunction)(unzFile file);
+typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename,
+ uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment,
+ uint16_t comment_size);
+
+/***************************************************************************/
+/* Reading a zip file */
+
+ZEXPORT unzFile unzOpen(const char *path);
+ZEXPORT unzFile unzOpen64(const void *path);
+ZEXPORT unzFile unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def);
+ZEXPORT unzFile unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def);
+ unzFile unzOpen_MZ(void *stream);
+
+ZEXPORT int unzClose(unzFile file);
+ZEXPORT int unzClose_MZ(unzFile file);
+
+ZEXPORT void* unzGetHandle_MZ(unzFile file);
+ZEXPORT void* unzGetStream_MZ(zipFile file);
+
+ZEXPORT int unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32);
+ZEXPORT int unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info);
+ZEXPORT int unzGetGlobalComment(unzFile file, char *comment, unsigned long comment_size);
+
+ZEXPORT int unzOpenCurrentFile(unzFile file);
+ZEXPORT int unzOpenCurrentFilePassword(unzFile file, const char *password);
+ZEXPORT int unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw);
+ZEXPORT int unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password);
+ZEXPORT int unzReadCurrentFile(unzFile file, void *buf, uint32_t len);
+ZEXPORT int unzCloseCurrentFile(unzFile file);
+
+ZEXPORT int unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,
+ unsigned long filename_size, void *extrafield, unsigned long extrafield_size, char *comment,
+ unsigned long comment_size);
+ZEXPORT int unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename,
+ unsigned long filename_size, void *extrafield, unsigned long extrafield_size, char *comment,
+ unsigned long comment_size);
+
+ZEXPORT int unzGoToFirstFile(unzFile file);
+ZEXPORT int unzGoToNextFile(unzFile file);
+ZEXPORT int unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func);
+
+ZEXPORT int unzGetLocalExtrafield(unzFile file, void *buf, unsigned int len);
+
+/***************************************************************************/
+/* Raw access to zip file */
+
+typedef struct unz_file_pos_s {
+ uint32_t pos_in_zip_directory; /* offset in zip file directory */
+ uint32_t num_of_file; /* # of file */
+} unz_file_pos;
+
+ZEXPORT int unzGetFilePos(unzFile file, unz_file_pos *file_pos);
+ZEXPORT int unzGoToFilePos(unzFile file, unz_file_pos *file_pos);
+
+typedef struct unz64_file_pos_s {
+ int64_t pos_in_zip_directory; /* offset in zip file directory */
+ uint64_t num_of_file; /* # of file */
+} unz64_file_pos;
+
+ZEXPORT int unzGetFilePos64(unzFile file, unz64_file_pos *file_pos);
+ZEXPORT int unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos);
+
+ZEXPORT int64_t unzGetOffset64(unzFile file);
+ZEXPORT unsigned long
+ unzGetOffset(unzFile file);
+ZEXPORT int unzSetOffset64(unzFile file, int64_t pos);
+ZEXPORT int unzSetOffset(unzFile file, unsigned long pos);
+ZEXPORT int32_t unztell(unzFile file);
+ZEXPORT int32_t unzTell(unzFile file);
+ZEXPORT uint64_t unztell64(unzFile file);
+ZEXPORT uint64_t unzTell64(unzFile file);
+ZEXPORT int unzSeek(unzFile file, int32_t offset, int origin);
+ZEXPORT int unzSeek64(unzFile file, int64_t offset, int origin);
+ZEXPORT int unzEndOfFile(unzFile file);
+ZEXPORT int unzeof(unzFile file);
+ZEXPORT void* unzGetStream(unzFile file);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_crypt.c b/Externals/minizip/mz_crypt.c
new file mode 100644
index 0000000000..dd2cd427c8
--- /dev/null
+++ b/Externals/minizip/mz_crypt.c
@@ -0,0 +1,196 @@
+/* mz_crypt.c -- Crypto/hash functions
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_os.h"
+#include "mz_crypt.h"
+
+#if defined(HAVE_ZLIB)
+# include "zlib.h"
+# if defined(ZLIBNG_VERNUM) && !defined(ZLIB_COMPAT)
+# include "zlib-ng.h"
+# endif
+#elif defined(HAVE_LZMA)
+# include "lzma.h"
+#endif
+
+/***************************************************************************/
+/* Define z_crc_t in zlib 1.2.5 and less or if using zlib-ng */
+
+#if defined(HAVE_ZLIB) && defined(ZLIBNG_VERNUM)
+# if defined(ZLIB_COMPAT)
+# define ZLIB_PREFIX(x) x
+# else
+# define ZLIB_PREFIX(x) zng_ ## x
+# endif
+ typedef uint32_t z_crc_t;
+#elif defined(HAVE_ZLIB)
+# define ZLIB_PREFIX(x) x
+# if (ZLIB_VERNUM < 0x1270)
+ typedef unsigned long z_crc_t;
+# endif
+#endif
+
+/***************************************************************************/
+
+#if defined(MZ_ZIP_NO_CRYPTO)
+int32_t mz_crypt_rand(uint8_t *buf, int32_t size) {
+ return mz_os_rand(buf, size);
+}
+#endif
+
+uint32_t mz_crypt_crc32_update(uint32_t value, const uint8_t *buf, int32_t size) {
+#if defined(HAVE_ZLIB)
+ return (uint32_t)ZLIB_PREFIX(crc32)((z_crc_t)value, buf, (uInt)size);
+#elif defined(HAVE_LZMA)
+ return (uint32_t)lzma_crc32(buf, (size_t)size, (uint32_t)value);
+#else
+ static uint32_t crc32_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+ };
+ value = ~value;
+
+ while (size > 0) {
+ value = (value >> 8) ^ crc32_table[(value ^ *buf) & 0xFF];
+
+ buf += 1;
+ size -= 1;
+ }
+
+ return ~value;
+#endif
+}
+
+#if defined(HAVE_WZAES)
+int32_t mz_crypt_pbkdf2(uint8_t *password, int32_t password_length, uint8_t *salt,
+ int32_t salt_length, int32_t iteration_count, uint8_t *key, int32_t key_length) {
+ void *hmac1 = NULL;
+ void *hmac2 = NULL;
+ void *hmac3 = NULL;
+ int32_t err = MZ_OK;
+ uint16_t i = 0;
+ uint16_t j = 0;
+ uint16_t k = 0;
+ uint16_t block_count = 0;
+ uint8_t uu[MZ_HASH_SHA1_SIZE];
+ uint8_t ux[MZ_HASH_SHA1_SIZE];
+
+ if (password == NULL || salt == NULL || key == NULL)
+ return MZ_PARAM_ERROR;
+
+ memset(key, 0, key_length);
+
+ mz_crypt_hmac_create(&hmac1);
+ mz_crypt_hmac_create(&hmac2);
+ mz_crypt_hmac_create(&hmac3);
+
+ mz_crypt_hmac_set_algorithm(hmac1, MZ_HASH_SHA1);
+ mz_crypt_hmac_set_algorithm(hmac2, MZ_HASH_SHA1);
+ mz_crypt_hmac_set_algorithm(hmac3, MZ_HASH_SHA1);
+
+ err = mz_crypt_hmac_init(hmac1, password, password_length);
+ if (err == MZ_OK)
+ err = mz_crypt_hmac_init(hmac2, password, password_length);
+ if (err == MZ_OK)
+ err = mz_crypt_hmac_update(hmac2, salt, salt_length);
+
+ block_count = 1 + ((uint16_t)key_length - 1) / MZ_HASH_SHA1_SIZE;
+
+ for (i = 0; (err == MZ_OK) && (i < block_count); i += 1) {
+ memset(ux, 0, sizeof(ux));
+
+ err = mz_crypt_hmac_copy(hmac2, hmac3);
+ if (err != MZ_OK)
+ break;
+
+ uu[0] = (uint8_t)((i + 1) >> 24);
+ uu[1] = (uint8_t)((i + 1) >> 16);
+ uu[2] = (uint8_t)((i + 1) >> 8);
+ uu[3] = (uint8_t)(i + 1);
+
+ for (j = 0, k = 4; j < iteration_count; j += 1) {
+ err = mz_crypt_hmac_update(hmac3, uu, k);
+ if (err == MZ_OK)
+ err = mz_crypt_hmac_end(hmac3, uu, sizeof(uu));
+ if (err != MZ_OK)
+ break;
+
+ for(k = 0; k < MZ_HASH_SHA1_SIZE; k += 1)
+ ux[k] ^= uu[k];
+
+ err = mz_crypt_hmac_copy(hmac1, hmac3);
+ if (err != MZ_OK)
+ break;
+ }
+
+ if (err != MZ_OK)
+ break;
+
+ j = 0;
+ k = i * MZ_HASH_SHA1_SIZE;
+
+ while (j < MZ_HASH_SHA1_SIZE && k < key_length)
+ key[k++] = ux[j++];
+ }
+
+ /* hmac3 uses the same provider as hmac2, so it must be deleted
+ before the context is destroyed. */
+ mz_crypt_hmac_delete(&hmac3);
+ mz_crypt_hmac_delete(&hmac1);
+ mz_crypt_hmac_delete(&hmac2);
+
+ return err;
+}
+#endif
+
+/***************************************************************************/
diff --git a/Externals/minizip/mz_crypt.h b/Externals/minizip/mz_crypt.h
new file mode 100644
index 0000000000..59a193c02b
--- /dev/null
+++ b/Externals/minizip/mz_crypt.h
@@ -0,0 +1,65 @@
+/* mz_crypt.h -- Crypto/hash functions
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_CRYPT_H
+#define MZ_CRYPT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+uint32_t mz_crypt_crc32_update(uint32_t value, const uint8_t *buf, int32_t size);
+
+int32_t mz_crypt_pbkdf2(uint8_t *password, int32_t password_length, uint8_t *salt,
+ int32_t salt_length, int32_t iteration_count, uint8_t *key, int32_t key_length);
+
+/***************************************************************************/
+
+int32_t mz_crypt_rand(uint8_t *buf, int32_t size);
+
+void mz_crypt_sha_reset(void *handle);
+int32_t mz_crypt_sha_begin(void *handle);
+int32_t mz_crypt_sha_update(void *handle, const void *buf, int32_t size);
+int32_t mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size);
+void mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm);
+void* mz_crypt_sha_create(void **handle);
+void mz_crypt_sha_delete(void **handle);
+
+void mz_crypt_aes_reset(void *handle);
+int32_t mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size);
+int32_t mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size);
+int32_t mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length);
+int32_t mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length);
+void mz_crypt_aes_set_mode(void *handle, int32_t mode);
+void* mz_crypt_aes_create(void **handle);
+void mz_crypt_aes_delete(void **handle);
+
+void mz_crypt_hmac_reset(void *handle);
+int32_t mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length);
+int32_t mz_crypt_hmac_update(void *handle, const void *buf, int32_t size);
+int32_t mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size);
+int32_t mz_crypt_hmac_copy(void *src_handle, void *target_handle);
+void mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm);
+void* mz_crypt_hmac_create(void **handle);
+void mz_crypt_hmac_delete(void **handle);
+
+int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size,
+ const char *cert_pwd, uint8_t **signature, int32_t *signature_size);
+int32_t mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_crypt_apple.c b/Externals/minizip/mz_crypt_apple.c
new file mode 100644
index 0000000000..4519753fa4
--- /dev/null
+++ b/Externals/minizip/mz_crypt_apple.c
@@ -0,0 +1,487 @@
+/* mz_crypt_apple.c -- Crypto/hash functions for Apple
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CommonCrypto/CommonCryptor.h>
+#include <CommonCrypto/CommonDigest.h>
+#include <CommonCrypto/CommonHMAC.h>
+#include <Security/Security.h>
+#include <Security/SecPolicy.h>
+
+/***************************************************************************/
+
+int32_t mz_crypt_rand(uint8_t *buf, int32_t size) {
+ if (SecRandomCopyBytes(kSecRandomDefault, size, buf) != errSecSuccess)
+ return 0;
+ return size;
+}
+
+/***************************************************************************/
+
+typedef struct mz_crypt_sha_s {
+ CC_SHA1_CTX ctx1;
+ CC_SHA256_CTX ctx256;
+ int32_t error;
+ int32_t initialized;
+ uint16_t algorithm;
+} mz_crypt_sha;
+
+/***************************************************************************/
+
+void mz_crypt_sha_reset(void *handle) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+
+ sha->error = 0;
+ sha->initialized = 0;
+}
+
+int32_t mz_crypt_sha_begin(void *handle) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+
+ if (sha == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_sha_reset(handle);
+
+ if (sha->algorithm == MZ_HASH_SHA1)
+ sha->error = CC_SHA1_Init(&sha->ctx1);
+ else if (sha->algorithm == MZ_HASH_SHA256)
+ sha->error = CC_SHA256_Init(&sha->ctx256);
+ else
+ return MZ_PARAM_ERROR;
+
+ if (!sha->error)
+ return MZ_HASH_ERROR;
+
+ sha->initialized = 1;
+ return MZ_OK;
+}
+
+int32_t mz_crypt_sha_update(void *handle, const void *buf, int32_t size) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+
+ if (sha == NULL || buf == NULL || !sha->initialized)
+ return MZ_PARAM_ERROR;
+
+ if (sha->algorithm == MZ_HASH_SHA1)
+ sha->error = CC_SHA1_Update(&sha->ctx1, buf, size);
+ else
+ sha->error = CC_SHA256_Update(&sha->ctx256, buf, size);
+
+ if (!sha->error)
+ return MZ_HASH_ERROR;
+
+ return size;
+}
+
+int32_t mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+
+ if (sha == NULL || digest == NULL || !sha->initialized)
+ return MZ_PARAM_ERROR;
+
+ if (sha->algorithm == MZ_HASH_SHA1) {
+ if (digest_size < MZ_HASH_SHA1_SIZE)
+ return MZ_BUF_ERROR;
+ sha->error = CC_SHA1_Final(digest, &sha->ctx1);
+ } else {
+ if (digest_size < MZ_HASH_SHA256_SIZE)
+ return MZ_BUF_ERROR;
+ sha->error = CC_SHA256_Final(digest, &sha->ctx256);
+ }
+
+ if (!sha->error)
+ return MZ_HASH_ERROR;
+
+ return MZ_OK;
+}
+
+void mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+ sha->algorithm = algorithm;
+}
+
+void *mz_crypt_sha_create(void **handle) {
+ mz_crypt_sha *sha = NULL;
+
+ sha = (mz_crypt_sha *)MZ_ALLOC(sizeof(mz_crypt_sha));
+ if (sha != NULL) {
+ memset(sha, 0, sizeof(mz_crypt_sha));
+ sha->algorithm = MZ_HASH_SHA256;
+ }
+ if (handle != NULL)
+ *handle = sha;
+
+ return sha;
+}
+
+void mz_crypt_sha_delete(void **handle) {
+ mz_crypt_sha *sha = NULL;
+ if (handle == NULL)
+ return;
+ sha = (mz_crypt_sha *)*handle;
+ if (sha != NULL) {
+ mz_crypt_sha_reset(*handle);
+ MZ_FREE(sha);
+ }
+ *handle = NULL;
+}
+
+/***************************************************************************/
+
+typedef struct mz_crypt_aes_s {
+ CCCryptorRef crypt;
+ int32_t mode;
+ int32_t error;
+} mz_crypt_aes;
+
+/***************************************************************************/
+
+void mz_crypt_aes_reset(void *handle) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+
+ if (aes->crypt != NULL)
+ CCCryptorRelease(aes->crypt);
+ aes->crypt = NULL;
+}
+
+int32_t mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ size_t data_moved = 0;
+
+ if (aes == NULL || buf == NULL)
+ return MZ_PARAM_ERROR;
+ if (size != MZ_AES_BLOCK_SIZE)
+ return MZ_PARAM_ERROR;
+
+ aes->error = CCCryptorUpdate(aes->crypt, buf, size, buf, size, &data_moved);
+
+ if (aes->error != kCCSuccess)
+ return MZ_HASH_ERROR;
+
+ return size;
+}
+
+int32_t mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ size_t data_moved = 0;
+
+ if (aes == NULL || buf == NULL)
+ return MZ_PARAM_ERROR;
+ if (size != MZ_AES_BLOCK_SIZE)
+ return MZ_PARAM_ERROR;
+
+ aes->error = CCCryptorUpdate(aes->crypt, buf, size, buf, size, &data_moved);
+
+ if (aes->error != kCCSuccess)
+ return MZ_HASH_ERROR;
+
+ return size;
+}
+
+int32_t mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+
+
+ if (aes == NULL || key == NULL || key_length == 0)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_aes_reset(handle);
+
+ aes->error = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionECBMode,
+ key, key_length, NULL, &aes->crypt);
+
+ if (aes->error != kCCSuccess)
+ return MZ_HASH_ERROR;
+
+ return MZ_OK;
+}
+
+int32_t mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+
+
+ if (aes == NULL || key == NULL || key_length == 0)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_aes_reset(handle);
+
+ aes->error = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES, kCCOptionECBMode,
+ key, key_length, NULL, &aes->crypt);
+
+ if (aes->error != kCCSuccess)
+ return MZ_HASH_ERROR;
+
+ return MZ_OK;
+}
+
+void mz_crypt_aes_set_mode(void *handle, int32_t mode) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ aes->mode = mode;
+}
+
+void *mz_crypt_aes_create(void **handle) {
+ mz_crypt_aes *aes = NULL;
+
+ aes = (mz_crypt_aes *)MZ_ALLOC(sizeof(mz_crypt_aes));
+ if (aes != NULL)
+ memset(aes, 0, sizeof(mz_crypt_aes));
+ if (handle != NULL)
+ *handle = aes;
+
+ return aes;
+}
+
+void mz_crypt_aes_delete(void **handle) {
+ mz_crypt_aes *aes = NULL;
+ if (handle == NULL)
+ return;
+ aes = (mz_crypt_aes *)*handle;
+ if (aes != NULL) {
+ mz_crypt_aes_reset(*handle);
+ MZ_FREE(aes);
+ }
+ *handle = NULL;
+}
+
+/***************************************************************************/
+
+typedef struct mz_crypt_hmac_s {
+ CCHmacContext ctx;
+ int32_t initialized;
+ int32_t error;
+ uint16_t algorithm;
+} mz_crypt_hmac;
+
+/***************************************************************************/
+
+static void mz_crypt_hmac_free(void *handle) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ memset(&hmac->ctx, 0, sizeof(hmac->ctx));
+}
+
+void mz_crypt_hmac_reset(void *handle) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ mz_crypt_hmac_free(handle);
+ hmac->error = 0;
+}
+
+int32_t mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ CCHmacAlgorithm algorithm = 0;
+
+ if (hmac == NULL || key == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_hmac_reset(handle);
+
+ if (hmac->algorithm == MZ_HASH_SHA1)
+ algorithm = kCCHmacAlgSHA1;
+ else if (hmac->algorithm == MZ_HASH_SHA256)
+ algorithm = kCCHmacAlgSHA256;
+ else
+ return MZ_PARAM_ERROR;
+
+ CCHmacInit(&hmac->ctx, algorithm, key, key_length);
+ return MZ_OK;
+}
+
+int32_t mz_crypt_hmac_update(void *handle, const void *buf, int32_t size) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+
+ if (hmac == NULL || buf == NULL)
+ return MZ_PARAM_ERROR;
+
+ CCHmacUpdate(&hmac->ctx, buf, size);
+ return MZ_OK;
+}
+
+int32_t mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+
+ if (hmac == NULL || digest == NULL)
+ return MZ_PARAM_ERROR;
+
+ if (hmac->algorithm == MZ_HASH_SHA1) {
+ if (digest_size < MZ_HASH_SHA1_SIZE)
+ return MZ_BUF_ERROR;
+ CCHmacFinal(&hmac->ctx, digest);
+ } else {
+ if (digest_size < MZ_HASH_SHA256_SIZE)
+ return MZ_BUF_ERROR;
+ CCHmacFinal(&hmac->ctx, digest);
+ }
+
+ return MZ_OK;
+}
+
+void mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ hmac->algorithm = algorithm;
+}
+
+int32_t mz_crypt_hmac_copy(void *src_handle, void *target_handle) {
+ mz_crypt_hmac *source = (mz_crypt_hmac *)src_handle;
+ mz_crypt_hmac *target = (mz_crypt_hmac *)target_handle;
+
+ if (source == NULL || target == NULL)
+ return MZ_PARAM_ERROR;
+
+ memcpy(&target->ctx, &source->ctx, sizeof(CCHmacContext));
+ return MZ_OK;
+}
+
+void *mz_crypt_hmac_create(void **handle) {
+ mz_crypt_hmac *hmac = NULL;
+
+ hmac = (mz_crypt_hmac *)MZ_ALLOC(sizeof(mz_crypt_hmac));
+ if (hmac != NULL) {
+ memset(hmac, 0, sizeof(mz_crypt_hmac));
+ hmac->algorithm = MZ_HASH_SHA256;
+ }
+ if (handle != NULL)
+ *handle = hmac;
+
+ return hmac;
+}
+
+void mz_crypt_hmac_delete(void **handle) {
+ mz_crypt_hmac *hmac = NULL;
+ if (handle == NULL)
+ return;
+ hmac = (mz_crypt_hmac *)*handle;
+ if (hmac != NULL) {
+ mz_crypt_hmac_free(*handle);
+ MZ_FREE(hmac);
+ }
+ *handle = NULL;
+}
+
+/***************************************************************************/
+
+#if defined(MZ_ZIP_SIGNING)
+int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size,
+ const char *cert_pwd, uint8_t **signature, int32_t *signature_size) {
+ CFStringRef password_ref = NULL;
+ CFDictionaryRef options_dict = NULL;
+ CFDictionaryRef identity_trust = NULL;
+ CFDataRef signature_out = NULL;
+ CFDataRef pkcs12_data = NULL;
+ CFArrayRef items = 0;
+ SecIdentityRef identity = NULL;
+ SecTrustRef trust = NULL;
+ OSStatus status = noErr;
+ const void *options_key[2] = { kSecImportExportPassphrase, kSecReturnRef };
+ const void *options_values[2] = { 0, kCFBooleanTrue };
+ int32_t err = MZ_SIGN_ERROR;
+
+
+ if (message == NULL || cert_data == NULL || signature == NULL || signature_size == NULL)
+ return MZ_PARAM_ERROR;
+
+ *signature = NULL;
+ *signature_size = 0;
+
+ password_ref = CFStringCreateWithCString(0, cert_pwd, kCFStringEncodingUTF8);
+ options_values[0] = password_ref;
+
+ options_dict = CFDictionaryCreate(0, options_key, options_values, 2, 0, 0);
+ if (options_dict)
+ pkcs12_data = CFDataCreate(0, cert_data, cert_data_size);
+ if (pkcs12_data)
+ status = SecPKCS12Import(pkcs12_data, options_dict, &items);
+ if (status == noErr)
+ identity_trust = CFArrayGetValueAtIndex(items, 0);
+ if (identity_trust)
+ identity = (SecIdentityRef)CFDictionaryGetValue(identity_trust, kSecImportItemIdentity);
+ if (identity)
+ trust = (SecTrustRef)CFDictionaryGetValue(identity_trust, kSecImportItemTrust);
+ if (trust) {
+ status = CMSEncodeContent(identity, NULL, NULL, FALSE, 0, message, message_size, &signature_out);
+
+ if (status == errSecSuccess) {
+ *signature_size = CFDataGetLength(signature_out);
+ *signature = (uint8_t *)MZ_ALLOC(*signature_size);
+
+ memcpy(*signature, CFDataGetBytePtr(signature_out), *signature_size);
+
+ err = MZ_OK;
+ }
+ }
+
+ if (signature_out)
+ CFRelease(signature_out);
+ if (items)
+ CFRelease(items);
+ if (pkcs12_data)
+ CFRelease(pkcs12_data);
+ if (options_dict)
+ CFRelease(options_dict);
+ if (password_ref)
+ CFRelease(password_ref);
+
+ return err;
+}
+
+int32_t mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size) {
+ CMSDecoderRef decoder = NULL;
+ CMSSignerStatus signer_status = 0;
+ CFDataRef message_out = NULL;
+ SecPolicyRef trust_policy = NULL;
+ OSStatus status = noErr;
+ OSStatus verify_status = noErr;
+ size_t signer_count = 0;
+ size_t i = 0;
+ int32_t err = MZ_SIGN_ERROR;
+
+ if (message == NULL || signature == NULL)
+ return MZ_PARAM_ERROR;
+
+ status = CMSDecoderCreate(&decoder);
+ if (status == errSecSuccess)
+ status = CMSDecoderUpdateMessage(decoder, signature, signature_size);
+ if (status == errSecSuccess)
+ status = CMSDecoderFinalizeMessage(decoder);
+ if (status == errSecSuccess)
+ trust_policy = SecPolicyCreateBasicX509();
+
+ if (status == errSecSuccess && trust_policy) {
+ CMSDecoderGetNumSigners(decoder, &signer_count);
+ if (signer_count > 0)
+ err = MZ_OK;
+ for (i = 0; i < signer_count; i += 1) {
+ status = CMSDecoderCopySignerStatus(decoder, i, trust_policy, TRUE, &signer_status, NULL, &verify_status);
+ if (status != errSecSuccess || verify_status != 0 || signer_status != kCMSSignerValid) {
+ err = MZ_SIGN_ERROR;
+ break;
+ }
+ }
+ }
+
+ if (err == MZ_OK) {
+ status = CMSDecoderCopyContent(decoder, &message_out);
+ if ((status != errSecSuccess) ||
+ (CFDataGetLength(message_out) != message_size) ||
+ (memcmp(message, CFDataGetBytePtr(message_out), message_size) != 0))
+ err = MZ_SIGN_ERROR;
+ }
+
+ if (trust_policy)
+ CFRelease(trust_policy);
+ if (decoder)
+ CFRelease(decoder);
+
+ return err;
+}
+
+#endif
diff --git a/Externals/minizip/mz_crypt_openssl.c b/Externals/minizip/mz_crypt_openssl.c
new file mode 100644
index 0000000000..2a6a4ac875
--- /dev/null
+++ b/Externals/minizip/mz_crypt_openssl.c
@@ -0,0 +1,638 @@
+/* mz_crypt_openssl.c -- Crypto/hash functions for OpenSSL
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+
+#include <openssl/err.h>
+#include <openssl/engine.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+#include <openssl/aes.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+#if defined(MZ_ZIP_SIGNING)
+/* Note: https://www.imperialviolet.org/2015/10/17/boringssl.html says that
+ BoringSSL does not support CMS. "#include <etc/cms.h>" will fail. See
+ https://bugs.chromium.org/p/boringssl/issues/detail?id=421
+*/
+#include <openssl/cms.h>
+#include <openssl/pkcs12.h>
+#include <openssl/x509.h>
+#endif
+
+/***************************************************************************/
+
+static void mz_crypt_init(void) {
+ static int32_t openssl_initialized = 0;
+ if (openssl_initialized == 0) {
+ OpenSSL_add_all_algorithms();
+
+ ERR_load_BIO_strings();
+ ERR_load_crypto_strings();
+
+ ENGINE_load_builtin_engines();
+ ENGINE_register_all_complete();
+
+ openssl_initialized = 1;
+ }
+}
+
+int32_t mz_crypt_rand(uint8_t *buf, int32_t size) {
+ int32_t result = 0;
+
+ result = RAND_bytes(buf, size);
+
+ if (!result)
+ return MZ_CRYPT_ERROR;
+
+ return size;
+}
+
+/***************************************************************************/
+
+typedef struct mz_crypt_sha_s {
+ SHA256_CTX ctx256;
+ SHA_CTX ctx1;
+ int32_t initialized;
+ int32_t error;
+ uint16_t algorithm;
+} mz_crypt_sha;
+
+/***************************************************************************/
+
+void mz_crypt_sha_reset(void *handle) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+
+ sha->error = 0;
+ sha->initialized = 0;
+
+ mz_crypt_init();
+}
+
+int32_t mz_crypt_sha_begin(void *handle) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+ int32_t result = 0;
+
+
+ if (sha == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_sha_reset(handle);
+
+ if (sha->algorithm == MZ_HASH_SHA1)
+ result = SHA1_Init(&sha->ctx1);
+ else
+ result = SHA256_Init(&sha->ctx256);
+
+ if (!result) {
+ sha->error = ERR_get_error();
+ return MZ_HASH_ERROR;
+ }
+
+ sha->initialized = 1;
+ return MZ_OK;
+}
+
+int32_t mz_crypt_sha_update(void *handle, const void *buf, int32_t size) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+ int32_t result = 0;
+
+ if (sha == NULL || buf == NULL || !sha->initialized)
+ return MZ_PARAM_ERROR;
+
+ if (sha->algorithm == MZ_HASH_SHA1)
+ result = SHA1_Update(&sha->ctx1, buf, size);
+ else
+ result = SHA256_Update(&sha->ctx256, buf, size);
+
+ if (!result) {
+ sha->error = ERR_get_error();
+ return MZ_HASH_ERROR;
+ }
+
+ return size;
+}
+
+int32_t mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+ int32_t result = 0;
+
+ if (sha == NULL || digest == NULL || !sha->initialized)
+ return MZ_PARAM_ERROR;
+
+ if (sha->algorithm == MZ_HASH_SHA1) {
+ if (digest_size < MZ_HASH_SHA1_SIZE)
+ return MZ_BUF_ERROR;
+ result = SHA1_Final(digest, &sha->ctx1);
+ } else {
+ if (digest_size < MZ_HASH_SHA256_SIZE)
+ return MZ_BUF_ERROR;
+ result = SHA256_Final(digest, &sha->ctx256);
+ }
+
+ if (!result) {
+ sha->error = ERR_get_error();
+ return MZ_HASH_ERROR;
+ }
+
+ return MZ_OK;
+}
+
+void mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+ sha->algorithm = algorithm;
+}
+
+void *mz_crypt_sha_create(void **handle) {
+ mz_crypt_sha *sha = NULL;
+
+ sha = (mz_crypt_sha *)MZ_ALLOC(sizeof(mz_crypt_sha));
+ if (sha != NULL) {
+ memset(sha, 0, sizeof(mz_crypt_sha));
+ sha->algorithm = MZ_HASH_SHA256;
+ }
+ if (handle != NULL)
+ *handle = sha;
+
+ return sha;
+}
+
+void mz_crypt_sha_delete(void **handle) {
+ mz_crypt_sha *sha = NULL;
+ if (handle == NULL)
+ return;
+ sha = (mz_crypt_sha *)*handle;
+ if (sha != NULL) {
+ mz_crypt_sha_reset(*handle);
+ MZ_FREE(sha);
+ }
+ *handle = NULL;
+}
+
+/***************************************************************************/
+
+typedef struct mz_crypt_aes_s {
+ AES_KEY key;
+ int32_t mode;
+ int32_t error;
+ uint8_t *key_copy;
+ int32_t key_length;
+} mz_crypt_aes;
+
+/***************************************************************************/
+
+void mz_crypt_aes_reset(void *handle) {
+ MZ_UNUSED(handle);
+
+ mz_crypt_init();
+}
+
+int32_t mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+
+ if (aes == NULL || buf == NULL)
+ return MZ_PARAM_ERROR;
+ if (size != MZ_AES_BLOCK_SIZE)
+ return MZ_PARAM_ERROR;
+
+ AES_encrypt(buf, buf, &aes->key);
+ /* Equivalent to AES_ecb_encrypt with AES_ENCRYPT */
+ return size;
+}
+
+int32_t mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ if (aes == NULL || buf == NULL)
+ return MZ_PARAM_ERROR;
+ if (size != MZ_AES_BLOCK_SIZE)
+ return MZ_PARAM_ERROR;
+
+ AES_decrypt(buf, buf, &aes->key);
+ /* Equivalent to AES_ecb_encrypt with AES_DECRYPT */
+ return size;
+}
+
+int32_t mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ int32_t result = 0;
+ int32_t key_bits = 0;
+
+
+ if (aes == NULL || key == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_aes_reset(handle);
+
+ key_bits = key_length * 8;
+ result = AES_set_encrypt_key(key, key_bits, &aes->key);
+ if (result) {
+ aes->error = ERR_get_error();
+ return MZ_HASH_ERROR;
+ }
+
+ return MZ_OK;
+}
+
+int32_t mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ int32_t result = 0;
+ int32_t key_bits = 0;
+
+
+ if (aes == NULL || key == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_aes_reset(handle);
+
+ key_bits = key_length * 8;
+ result = AES_set_decrypt_key(key, key_bits, &aes->key);
+ if (result) {
+ aes->error = ERR_get_error();
+ return MZ_HASH_ERROR;
+ }
+
+ return MZ_OK;
+}
+
+void mz_crypt_aes_set_mode(void *handle, int32_t mode) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ aes->mode = mode;
+}
+
+void *mz_crypt_aes_create(void **handle) {
+ mz_crypt_aes *aes = NULL;
+
+ aes = (mz_crypt_aes *)MZ_ALLOC(sizeof(mz_crypt_aes));
+ if (aes != NULL)
+ memset(aes, 0, sizeof(mz_crypt_aes));
+ if (handle != NULL)
+ *handle = aes;
+
+ return aes;
+}
+
+void mz_crypt_aes_delete(void **handle) {
+ mz_crypt_aes *aes = NULL;
+ if (handle == NULL)
+ return;
+ aes = (mz_crypt_aes *)*handle;
+ if (aes != NULL)
+ MZ_FREE(aes);
+ *handle = NULL;
+}
+
+/***************************************************************************/
+
+typedef struct mz_crypt_hmac_s {
+ HMAC_CTX *ctx;
+ int32_t initialized;
+ int32_t error;
+ uint16_t algorithm;
+} mz_crypt_hmac;
+
+/***************************************************************************/
+
+#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2070000fL))
+static HMAC_CTX *HMAC_CTX_new(void) {
+ HMAC_CTX *ctx = OPENSSL_malloc(sizeof(HMAC_CTX));
+ if (ctx != NULL)
+ HMAC_CTX_init(ctx);
+ return ctx;
+}
+
+static void HMAC_CTX_free(HMAC_CTX *ctx) {
+ if (ctx != NULL) {
+ HMAC_CTX_cleanup(ctx);
+ OPENSSL_free(ctx);
+ }
+}
+#endif
+
+/***************************************************************************/
+
+void mz_crypt_hmac_reset(void *handle) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+
+ HMAC_CTX_free(hmac->ctx);
+
+ hmac->ctx = NULL;
+ hmac->error = 0;
+
+ mz_crypt_init();
+}
+
+int32_t mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ int32_t result = 0;
+ const EVP_MD *evp_md = NULL;
+
+ if (hmac == NULL || key == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_hmac_reset(handle);
+
+ hmac->ctx = HMAC_CTX_new();
+
+ if (hmac->algorithm == MZ_HASH_SHA1)
+ evp_md = EVP_sha1();
+ else
+ evp_md = EVP_sha256();
+
+ result = HMAC_Init_ex(hmac->ctx, key, key_length, evp_md, NULL);
+ if (!result) {
+ hmac->error = ERR_get_error();
+ return MZ_HASH_ERROR;
+ }
+
+ return MZ_OK;
+}
+
+int32_t mz_crypt_hmac_update(void *handle, const void *buf, int32_t size) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ int32_t result = 0;
+
+ if (hmac == NULL || buf == NULL)
+ return MZ_PARAM_ERROR;
+
+ result = HMAC_Update(hmac->ctx, buf, size);
+ if (!result) {
+ hmac->error = ERR_get_error();
+ return MZ_HASH_ERROR;
+ }
+
+ return MZ_OK;
+}
+
+int32_t mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ int32_t result = 0;
+
+ if (hmac == NULL || digest == NULL)
+ return MZ_PARAM_ERROR;
+
+ if (hmac->algorithm == MZ_HASH_SHA1) {
+ if (digest_size < MZ_HASH_SHA1_SIZE)
+ return MZ_BUF_ERROR;
+
+ result = HMAC_Final(hmac->ctx, digest, (uint32_t *)&digest_size);
+ } else {
+ if (digest_size < MZ_HASH_SHA256_SIZE)
+ return MZ_BUF_ERROR;
+ result = HMAC_Final(hmac->ctx, digest, (uint32_t *)&digest_size);
+ }
+
+ if (!result) {
+ hmac->error = ERR_get_error();
+ return MZ_HASH_ERROR;
+ }
+
+ return MZ_OK;
+}
+
+void mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ hmac->algorithm = algorithm;
+}
+
+int32_t mz_crypt_hmac_copy(void *src_handle, void *target_handle) {
+ mz_crypt_hmac *source = (mz_crypt_hmac *)src_handle;
+ mz_crypt_hmac *target = (mz_crypt_hmac *)target_handle;
+ int32_t result = 0;
+
+ if (source == NULL || target == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_hmac_reset(target_handle);
+
+ if (target->ctx == NULL)
+ target->ctx = HMAC_CTX_new();
+
+ result = HMAC_CTX_copy(target->ctx, source->ctx);
+ if (!result) {
+ target->error = ERR_get_error();
+ return MZ_HASH_ERROR;
+ }
+
+ return MZ_OK;
+}
+
+void *mz_crypt_hmac_create(void **handle) {
+ mz_crypt_hmac *hmac = NULL;
+
+ hmac = (mz_crypt_hmac *)MZ_ALLOC(sizeof(mz_crypt_hmac));
+ if (hmac != NULL) {
+ memset(hmac, 0, sizeof(mz_crypt_hmac));
+ hmac->algorithm = MZ_HASH_SHA256;
+ }
+ if (handle != NULL)
+ *handle = hmac;
+
+ return hmac;
+}
+
+void mz_crypt_hmac_delete(void **handle) {
+ mz_crypt_hmac *hmac = NULL;
+ if (handle == NULL)
+ return;
+ hmac = (mz_crypt_hmac *)*handle;
+ if (hmac != NULL) {
+ mz_crypt_hmac_reset(*handle);
+ MZ_FREE(hmac);
+ }
+ *handle = NULL;
+}
+
+/***************************************************************************/
+
+#if defined(MZ_ZIP_SIGNING)
+int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size,
+ const char *cert_pwd, uint8_t **signature, int32_t *signature_size) {
+ PKCS12 *p12 = NULL;
+ EVP_PKEY *evp_pkey = NULL;
+ BUF_MEM *buf_mem = NULL;
+ BIO *cert_bio = NULL;
+ BIO *message_bio = NULL;
+ BIO *signature_bio = NULL;
+ CMS_ContentInfo *cms = NULL;
+ CMS_SignerInfo *signer_info = NULL;
+ STACK_OF(X509) *ca_stack = NULL;
+ X509 *cert = NULL;
+ int32_t result = 0;
+ int32_t err = MZ_OK;
+
+
+ if (message == NULL || cert_data == NULL || signature == NULL || signature_size == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_init();
+
+ *signature = NULL;
+ *signature_size = 0;
+
+ cert_bio = BIO_new_mem_buf(cert_data, cert_data_size);
+
+ if (d2i_PKCS12_bio(cert_bio, &p12) == NULL)
+ err = MZ_SIGN_ERROR;
+ if (err == MZ_OK)
+ result = PKCS12_parse(p12, cert_pwd, &evp_pkey, &cert, &ca_stack);
+ if (result) {
+ cms = CMS_sign(NULL, NULL, ca_stack, NULL, CMS_BINARY | CMS_PARTIAL);
+ if (cms)
+ signer_info = CMS_add1_signer(cms, cert, evp_pkey, EVP_sha256(), 0);
+ if (signer_info == NULL) {
+ err = MZ_SIGN_ERROR;
+ } else {
+ message_bio = BIO_new_mem_buf(message, message_size);
+ signature_bio = BIO_new(BIO_s_mem());
+
+ result = CMS_final(cms, message_bio, NULL, CMS_BINARY);
+ if (result)
+ result = i2d_CMS_bio(signature_bio, cms);
+ if (result) {
+ BIO_flush(signature_bio);
+ BIO_get_mem_ptr(signature_bio, &buf_mem);
+
+ *signature_size = buf_mem->length;
+ *signature = MZ_ALLOC(buf_mem->length);
+
+ memcpy(*signature, buf_mem->data, buf_mem->length);
+ }
+#if 0
+ BIO *yy = BIO_new_file("xyz", "wb");
+ BIO_write(yy, *signature, *signature_size);
+ BIO_flush(yy);
+ BIO_free(yy);
+#endif
+ }
+ }
+
+ if (!result)
+ err = MZ_SIGN_ERROR;
+
+ if (cms)
+ CMS_ContentInfo_free(cms);
+ if (signature_bio)
+ BIO_free(signature_bio);
+ if (cert_bio)
+ BIO_free(cert_bio);
+ if (message_bio)
+ BIO_free(message_bio);
+ if (p12)
+ PKCS12_free(p12);
+
+ if (err != MZ_OK && *signature != NULL) {
+ MZ_FREE(*signature);
+ *signature = NULL;
+ *signature_size = 0;
+ }
+
+ return err;
+}
+
+int32_t mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size) {
+ CMS_ContentInfo *cms = NULL;
+ STACK_OF(X509) *signers = NULL;
+ STACK_OF(X509) *intercerts = NULL;
+ X509_STORE *cert_store = NULL;
+ X509_LOOKUP *lookup = NULL;
+ X509_STORE_CTX *store_ctx = NULL;
+ BIO *message_bio = NULL;
+ BIO *signature_bio = NULL;
+ BUF_MEM *buf_mem = NULL;
+ int32_t signer_count = 0;
+ int32_t result = 0;
+ int32_t i = 0;
+ int32_t err = MZ_SIGN_ERROR;
+
+
+ if (message == NULL || message_size == 0 || signature == NULL || signature_size == 0)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_init();
+
+ cert_store = X509_STORE_new();
+
+ X509_STORE_load_locations(cert_store, "cacert.pem", NULL);
+ X509_STORE_set_default_paths(cert_store);
+
+#if 0
+ BIO *yy = BIO_new_file("xyz", "wb");
+ BIO_write(yy, signature, signature_size);
+ BIO_flush(yy);
+ BIO_free(yy);
+#endif
+
+ lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_file());
+ if (lookup != NULL)
+ X509_LOOKUP_load_file(lookup, "cacert.pem", X509_FILETYPE_PEM);
+ lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_hash_dir());
+ if (lookup != NULL)
+ X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
+
+ signature_bio = BIO_new_mem_buf(signature, signature_size);
+ message_bio = BIO_new(BIO_s_mem());
+
+ cms = d2i_CMS_bio(signature_bio, NULL);
+ if (cms) {
+ result = CMS_verify(cms, NULL, cert_store, NULL, message_bio, CMS_NO_SIGNER_CERT_VERIFY | CMS_BINARY);
+ if (result)
+ signers = CMS_get0_signers(cms);
+ if (signers)
+ intercerts = CMS_get1_certs(cms);
+ if (intercerts) {
+ /* Verify signer certificates */
+ signer_count = sk_X509_num(signers);
+ if (signer_count > 0)
+ err = MZ_OK;
+
+ for (i = 0; i < signer_count; i++) {
+ store_ctx = X509_STORE_CTX_new();
+ X509_STORE_CTX_init(store_ctx, cert_store, sk_X509_value(signers, i), intercerts);
+ result = X509_verify_cert(store_ctx);
+ if (store_ctx)
+ X509_STORE_CTX_free(store_ctx);
+
+ if (!result) {
+ err = MZ_SIGN_ERROR;
+ break;
+ }
+ }
+ }
+
+ BIO_get_mem_ptr(message_bio, &buf_mem);
+
+ if (err == MZ_OK) {
+ /* Verify the message */
+ if (((int32_t)buf_mem->length != message_size) ||
+ (memcmp(buf_mem->data, message, message_size) != 0))
+ err = MZ_SIGN_ERROR;
+ }
+ }
+
+#if 0
+ if (!result)
+ printf(ERR_error_string(ERR_get_error(), NULL));
+#endif
+
+ if (cms)
+ CMS_ContentInfo_free(cms);
+ if (message_bio)
+ BIO_free(message_bio);
+ if (signature_bio)
+ BIO_free(signature_bio);
+ if (cert_store)
+ X509_STORE_free(cert_store);
+
+ return err;
+}
+#endif
diff --git a/Externals/minizip/mz_crypt_win32.c b/Externals/minizip/mz_crypt_win32.c
new file mode 100644
index 0000000000..6ec6a848d0
--- /dev/null
+++ b/Externals/minizip/mz_crypt_win32.c
@@ -0,0 +1,739 @@
+/* mz_crypt_win32.c -- Crypto/hash functions for Windows
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include "mz.h"
+#include "mz_os.h"
+#include "mz_crypt.h"
+
+#include <windows.h>
+#include <wincrypt.h>
+
+/***************************************************************************/
+
+int32_t mz_crypt_rand(uint8_t *buf, int32_t size) {
+ HCRYPTPROV provider;
+ int32_t result = 0;
+
+
+ result = CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
+ if (result) {
+ result = CryptGenRandom(provider, size, buf);
+ CryptReleaseContext(provider, 0);
+ if (result)
+ return size;
+ }
+
+ return mz_os_rand(buf, size);
+}
+
+/***************************************************************************/
+
+typedef struct mz_crypt_sha_s {
+ HCRYPTPROV provider;
+ HCRYPTHASH hash;
+ int32_t error;
+ uint16_t algorithm;
+} mz_crypt_sha;
+
+/***************************************************************************/
+
+void mz_crypt_sha_reset(void *handle) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+ if (sha->hash)
+ CryptDestroyHash(sha->hash);
+ sha->hash = 0;
+ if (sha->provider)
+ CryptReleaseContext(sha->provider, 0);
+ sha->provider = 0;
+ sha->error = 0;
+}
+
+int32_t mz_crypt_sha_begin(void *handle) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+ ALG_ID alg_id = 0;
+ int32_t result = 0;
+ int32_t err = MZ_OK;
+
+
+ if (sha == NULL)
+ return MZ_PARAM_ERROR;
+
+ if (sha->algorithm == MZ_HASH_SHA1)
+ alg_id = CALG_SHA1;
+ else
+ alg_id = CALG_SHA_256;
+
+ result = CryptAcquireContext(&sha->provider, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
+ if (!result) {
+ sha->error = GetLastError();
+ err = MZ_CRYPT_ERROR;
+ }
+
+ if (result) {
+ result = CryptCreateHash(sha->provider, alg_id, 0, 0, &sha->hash);
+ if (!result) {
+ sha->error = GetLastError();
+ err = MZ_HASH_ERROR;
+ }
+ }
+
+ return err;
+}
+
+int32_t mz_crypt_sha_update(void *handle, const void *buf, int32_t size) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+ int32_t result = 0;
+
+ if (sha == NULL || buf == NULL || sha->hash == 0)
+ return MZ_PARAM_ERROR;
+ result = CryptHashData(sha->hash, buf, size, 0);
+ if (!result) {
+ sha->error = GetLastError();
+ return MZ_HASH_ERROR;
+ }
+ return size;
+}
+
+int32_t mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+ int32_t result = 0;
+ int32_t expected_size = 0;
+
+ if (sha == NULL || digest == NULL || sha->hash == 0)
+ return MZ_PARAM_ERROR;
+ result = CryptGetHashParam(sha->hash, HP_HASHVAL, NULL, (DWORD *)&expected_size, 0);
+ if (expected_size > digest_size)
+ return MZ_BUF_ERROR;
+ if (!result)
+ return MZ_HASH_ERROR;
+ result = CryptGetHashParam(sha->hash, HP_HASHVAL, digest, (DWORD *)&digest_size, 0);
+ if (!result) {
+ sha->error = GetLastError();
+ return MZ_HASH_ERROR;
+ }
+ return MZ_OK;
+}
+
+void mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm) {
+ mz_crypt_sha *sha = (mz_crypt_sha *)handle;
+ sha->algorithm = algorithm;
+}
+
+void *mz_crypt_sha_create(void **handle) {
+ mz_crypt_sha *sha = NULL;
+
+ sha = (mz_crypt_sha *)MZ_ALLOC(sizeof(mz_crypt_sha));
+ if (sha != NULL) {
+ memset(sha, 0, sizeof(mz_crypt_sha));
+ sha->algorithm = MZ_HASH_SHA256;
+ }
+ if (handle != NULL)
+ *handle = sha;
+
+ return sha;
+}
+
+void mz_crypt_sha_delete(void **handle) {
+ mz_crypt_sha *sha = NULL;
+ if (handle == NULL)
+ return;
+ sha = (mz_crypt_sha *)*handle;
+ if (sha != NULL) {
+ mz_crypt_sha_reset(*handle);
+ MZ_FREE(sha);
+ }
+ *handle = NULL;
+}
+
+/***************************************************************************/
+
+typedef struct mz_crypt_aes_s {
+ HCRYPTPROV provider;
+ HCRYPTKEY key;
+ int32_t mode;
+ int32_t error;
+} mz_crypt_aes;
+
+/***************************************************************************/
+
+static void mz_crypt_aes_free(void *handle) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ if (aes->key)
+ CryptDestroyKey(aes->key);
+ aes->key = 0;
+ if (aes->provider)
+ CryptReleaseContext(aes->provider, 0);
+ aes->provider = 0;
+}
+
+void mz_crypt_aes_reset(void *handle) {
+ mz_crypt_aes_free(handle);
+}
+
+int32_t mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ int32_t result = 0;
+
+ if (aes == NULL || buf == NULL)
+ return MZ_PARAM_ERROR;
+ if (size != MZ_AES_BLOCK_SIZE)
+ return MZ_PARAM_ERROR;
+ result = CryptEncrypt(aes->key, 0, 0, 0, buf, (DWORD *)&size, size);
+ if (!result) {
+ aes->error = GetLastError();
+ return MZ_CRYPT_ERROR;
+ }
+ return size;
+}
+
+int32_t mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ int32_t result = 0;
+ if (aes == NULL || buf == NULL)
+ return MZ_PARAM_ERROR;
+ if (size != MZ_AES_BLOCK_SIZE)
+ return MZ_PARAM_ERROR;
+ result = CryptDecrypt(aes->key, 0, 0, 0, buf, (DWORD *)&size);
+ if (!result) {
+ aes->error = GetLastError();
+ return MZ_CRYPT_ERROR;
+ }
+ return size;
+}
+
+static int32_t mz_crypt_aes_set_key(void *handle, const void *key, int32_t key_length) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ HCRYPTHASH hash = 0;
+ ALG_ID alg_id = 0;
+ typedef struct key_blob_header_s {
+ BLOBHEADER hdr;
+ uint32_t key_length;
+ } key_blob_header_s;
+ key_blob_header_s *key_blob_s = NULL;
+ uint32_t mode = CRYPT_MODE_ECB;
+ uint8_t *key_blob = NULL;
+ int32_t key_blob_size = 0;
+ int32_t result = 0;
+ int32_t err = MZ_OK;
+
+
+ if (aes == NULL || key == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_aes_reset(handle);
+
+ if (key_length == MZ_AES_KEY_LENGTH(MZ_AES_ENCRYPTION_MODE_128))
+ alg_id = CALG_AES_128;
+ else if (key_length == MZ_AES_KEY_LENGTH(MZ_AES_ENCRYPTION_MODE_192))
+ alg_id = CALG_AES_192;
+ else if (key_length == MZ_AES_KEY_LENGTH(MZ_AES_ENCRYPTION_MODE_256))
+ alg_id = CALG_AES_256;
+ else
+ return MZ_PARAM_ERROR;
+
+ result = CryptAcquireContext(&aes->provider, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
+ if (result) {
+ key_blob_size = sizeof(key_blob_header_s) + key_length;
+ key_blob = (uint8_t *)MZ_ALLOC(key_blob_size);
+ if (key_blob) {
+ key_blob_s = (key_blob_header_s *)key_blob;
+ key_blob_s->hdr.bType = PLAINTEXTKEYBLOB;
+ key_blob_s->hdr.bVersion = CUR_BLOB_VERSION;
+ key_blob_s->hdr.aiKeyAlg = alg_id;
+ key_blob_s->hdr.reserved = 0;
+ key_blob_s->key_length = key_length;
+
+ memcpy(key_blob + sizeof(key_blob_header_s), key, key_length);
+
+ result = CryptImportKey(aes->provider, key_blob, key_blob_size, 0, 0, &aes->key);
+
+ SecureZeroMemory(key_blob, key_blob_size);
+ MZ_FREE(key_blob);
+ } else {
+ err = MZ_MEM_ERROR;
+ }
+ }
+
+ if (result && err == MZ_OK)
+ result = CryptSetKeyParam(aes->key, KP_MODE, (const uint8_t *)&mode, 0);
+
+ if (!result && err == MZ_OK) {
+ aes->error = GetLastError();
+ err = MZ_CRYPT_ERROR;
+ }
+
+ if (hash)
+ CryptDestroyHash(hash);
+
+ return err;
+}
+
+int32_t mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length) {
+ return mz_crypt_aes_set_key(handle, key, key_length);
+}
+
+int32_t mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length) {
+ return mz_crypt_aes_set_key(handle, key, key_length);
+}
+
+void mz_crypt_aes_set_mode(void *handle, int32_t mode) {
+ mz_crypt_aes *aes = (mz_crypt_aes *)handle;
+ aes->mode = mode;
+}
+
+void *mz_crypt_aes_create(void **handle) {
+ mz_crypt_aes *aes = NULL;
+
+ aes = (mz_crypt_aes *)MZ_ALLOC(sizeof(mz_crypt_aes));
+ if (aes != NULL)
+ memset(aes, 0, sizeof(mz_crypt_aes));
+ if (handle != NULL)
+ *handle = aes;
+
+ return aes;
+}
+
+void mz_crypt_aes_delete(void **handle) {
+ mz_crypt_aes *aes = NULL;
+ if (handle == NULL)
+ return;
+ aes = (mz_crypt_aes *)*handle;
+ if (aes != NULL) {
+ mz_crypt_aes_free(*handle);
+ MZ_FREE(aes);
+ }
+ *handle = NULL;
+}
+
+/***************************************************************************/
+
+typedef struct mz_crypt_hmac_s {
+ HCRYPTPROV provider;
+ HCRYPTHASH hash;
+ HCRYPTKEY key;
+ HMAC_INFO info;
+ int32_t mode;
+ int32_t error;
+ uint16_t algorithm;
+} mz_crypt_hmac;
+
+/***************************************************************************/
+
+static void mz_crypt_hmac_free(void *handle) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ if (hmac->key)
+ CryptDestroyKey(hmac->key);
+ hmac->key = 0;
+ if (hmac->hash)
+ CryptDestroyHash(hmac->hash);
+ hmac->hash = 0;
+ if (hmac->provider)
+ CryptReleaseContext(hmac->provider, 0);
+ hmac->provider = 0;
+ memset(&hmac->info, 0, sizeof(hmac->info));
+}
+
+void mz_crypt_hmac_reset(void *handle) {
+ mz_crypt_hmac_free(handle);
+}
+
+int32_t mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ ALG_ID alg_id = 0;
+ typedef struct key_blob_header_s {
+ BLOBHEADER hdr;
+ uint32_t key_length;
+ } key_blob_header_s;
+ key_blob_header_s *key_blob_s = NULL;
+ uint8_t *key_blob = NULL;
+ int32_t key_blob_size = 0;
+ int32_t result = 0;
+ int32_t err = MZ_OK;
+
+
+ if (hmac == NULL || key == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_crypt_hmac_reset(handle);
+
+ if (hmac->algorithm == MZ_HASH_SHA1)
+ alg_id = CALG_SHA1;
+ else
+ alg_id = CALG_SHA_256;
+
+ hmac->info.HashAlgid = alg_id;
+
+ result = CryptAcquireContext(&hmac->provider, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
+
+ if (!result) {
+ hmac->error = GetLastError();
+ err = MZ_CRYPT_ERROR;
+ } else {
+ /* Zero-pad odd key lengths */
+ if (key_length % 2 == 1)
+ key_length += 1;
+ key_blob_size = sizeof(key_blob_header_s) + key_length;
+ key_blob = (uint8_t *)MZ_ALLOC(key_blob_size);
+ }
+
+ if (key_blob) {
+ memset(key_blob, 0, key_blob_size);
+ key_blob_s = (key_blob_header_s *)key_blob;
+ key_blob_s->hdr.bType = PLAINTEXTKEYBLOB;
+ key_blob_s->hdr.bVersion = CUR_BLOB_VERSION;
+ key_blob_s->hdr.aiKeyAlg = CALG_RC2;
+ key_blob_s->hdr.reserved = 0;
+ key_blob_s->key_length = key_length;
+
+ memcpy(key_blob + sizeof(key_blob_header_s), key, key_length);
+
+ result = CryptImportKey(hmac->provider, key_blob, key_blob_size, 0, CRYPT_IPSEC_HMAC_KEY, &hmac->key);
+ if (result)
+ result = CryptCreateHash(hmac->provider, CALG_HMAC, hmac->key, 0, &hmac->hash);
+ if (result)
+ result = CryptSetHashParam(hmac->hash, HP_HMAC_INFO, (uint8_t *)&hmac->info, 0);
+
+ SecureZeroMemory(key_blob, key_blob_size);
+ MZ_FREE(key_blob);
+ } else if (err == MZ_OK) {
+ err = MZ_MEM_ERROR;
+ }
+
+ if (!result) {
+ hmac->error = GetLastError();
+ err = MZ_CRYPT_ERROR;
+ }
+
+ if (err != MZ_OK)
+ mz_crypt_hmac_free(handle);
+
+ return err;
+}
+
+int32_t mz_crypt_hmac_update(void *handle, const void *buf, int32_t size) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ int32_t result = 0;
+
+ if (hmac == NULL || buf == NULL || hmac->hash == 0)
+ return MZ_PARAM_ERROR;
+
+ result = CryptHashData(hmac->hash, buf, size, 0);
+ if (!result) {
+ hmac->error = GetLastError();
+ return MZ_HASH_ERROR;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ int32_t result = 0;
+ int32_t expected_size = 0;
+
+ if (hmac == NULL || digest == NULL || hmac->hash == 0)
+ return MZ_PARAM_ERROR;
+ result = CryptGetHashParam(hmac->hash, HP_HASHVAL, NULL, (DWORD *)&expected_size, 0);
+ if (expected_size > digest_size)
+ return MZ_BUF_ERROR;
+ if (!result)
+ return MZ_HASH_ERROR;
+ result = CryptGetHashParam(hmac->hash, HP_HASHVAL, digest, (DWORD *)&digest_size, 0);
+ if (!result) {
+ hmac->error = GetLastError();
+ return MZ_HASH_ERROR;
+ }
+ return MZ_OK;
+}
+
+void mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm) {
+ mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
+ hmac->algorithm = algorithm;
+}
+
+int32_t mz_crypt_hmac_copy(void *src_handle, void *target_handle) {
+ mz_crypt_hmac *source = (mz_crypt_hmac *)src_handle;
+ mz_crypt_hmac *target = (mz_crypt_hmac *)target_handle;
+ int32_t result = 0;
+ int32_t err = MZ_OK;
+
+ if (target->hash) {
+ CryptDestroyHash(target->hash);
+ target->hash = 0;
+ }
+
+ result = CryptDuplicateHash(source->hash, NULL, 0, &target->hash);
+
+ if (!result) {
+ target->error = GetLastError();
+ err = MZ_HASH_ERROR;
+ }
+ return err;
+}
+
+void *mz_crypt_hmac_create(void **handle) {
+ mz_crypt_hmac *hmac = NULL;
+
+ hmac = (mz_crypt_hmac *)MZ_ALLOC(sizeof(mz_crypt_hmac));
+ if (hmac != NULL) {
+ memset(hmac, 0, sizeof(mz_crypt_hmac));
+ hmac->algorithm = MZ_HASH_SHA256;
+ }
+ if (handle != NULL)
+ *handle = hmac;
+
+ return hmac;
+}
+
+void mz_crypt_hmac_delete(void **handle) {
+ mz_crypt_hmac *hmac = NULL;
+ if (handle == NULL)
+ return;
+ hmac = (mz_crypt_hmac *)*handle;
+ if (hmac != NULL) {
+ mz_crypt_hmac_free(*handle);
+ MZ_FREE(hmac);
+ }
+ *handle = NULL;
+}
+
+/***************************************************************************/
+
+#if defined(MZ_ZIP_SIGNING)
+int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size,
+ const char *cert_pwd, uint8_t **signature, int32_t *signature_size) {
+ CRYPT_SIGN_MESSAGE_PARA sign_params;
+ CRYPT_DATA_BLOB cert_data_blob;
+ PCCERT_CONTEXT cert_context = NULL;
+ HCERTSTORE cert_store = 0;
+ wchar_t *password_wide = NULL;
+ int32_t result = 0;
+ int32_t err = MZ_OK;
+ uint32_t messages_sizes[1];
+ uint8_t *messages[1];
+
+
+ if (message == NULL || cert_data == NULL || signature == NULL || signature_size == NULL)
+ return MZ_PARAM_ERROR;
+
+ *signature = NULL;
+ *signature_size = 0;
+
+ cert_data_blob.pbData = cert_data;
+ cert_data_blob.cbData = cert_data_size;
+
+ password_wide = mz_os_unicode_string_create(cert_pwd, MZ_ENCODING_UTF8);
+ if (password_wide) {
+ cert_store = PFXImportCertStore(&cert_data_blob, password_wide, 0);
+ mz_os_unicode_string_delete(&password_wide);
+ }
+
+ if (cert_store == NULL)
+ cert_store = PFXImportCertStore(&cert_data_blob, L"", 0);
+ if (cert_store == NULL)
+ cert_store = PFXImportCertStore(&cert_data_blob, NULL, 0);
+ if (cert_store == NULL)
+ return MZ_PARAM_ERROR;
+
+ if (err == MZ_OK) {
+ cert_context = CertFindCertificateInStore(cert_store,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_HAS_PRIVATE_KEY, NULL, NULL);
+ if (cert_context == NULL)
+ err = MZ_PARAM_ERROR;
+ }
+ if (err == MZ_OK) {
+ memset(&sign_params, 0, sizeof(sign_params));
+
+ sign_params.cbSize = sizeof(sign_params);
+ sign_params.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
+ sign_params.pSigningCert = cert_context;
+ sign_params.HashAlgorithm.pszObjId = szOID_NIST_sha256;
+ sign_params.cMsgCert = 1;
+ sign_params.rgpMsgCert = &cert_context;
+
+ messages[0] = message;
+ messages_sizes[0] = message_size;
+
+#if 0 /* Timestamp support */
+ CRYPT_ATTR_BLOB crypt_blob;
+ CRYPT_TIMESTAMP_CONTEXT *ts_context = NULL;
+ CRYPT_ATTRIBUTE unauth_attribs[1];
+ wchar_t *timestamp_url_wide = NULL;
+ const char *timestamp_url = NULL;
+
+ if (timestamp_url != NULL)
+ timestamp_url_wide = mz_os_unicode_string_create(timestamp_url);
+ if (timestamp_url_wide != NULL) {
+ result = CryptRetrieveTimeStamp(timestamp_url_wide,
+ TIMESTAMP_NO_AUTH_RETRIEVAL | TIMESTAMP_VERIFY_CONTEXT_SIGNATURE, 0, szOID_NIST_sha256,
+ NULL, message, message_size, &ts_context, NULL, NULL);
+
+ mz_os_unicode_string_delete(&timestamp_url_wide);
+
+ if ((result) && (ts_context != NULL)) {
+ crypt_blob.cbData = ts_context->cbEncoded;
+ crypt_blob.pbData = ts_context->pbEncoded;
+
+ unauth_attribs[0].pszObjId = "1.2.840.113549.1.9.16.2.14"; //id-smime-aa-timeStampToken
+ unauth_attribs[0].cValue = 1;
+ unauth_attribs[0].rgValue = &crypt_blob;
+
+ sign_params.rgUnauthAttr = &unauth_attribs[0];
+ sign_params.cUnauthAttr = 1;
+ }
+ }
+
+ if (ts_context != NULL)
+ CryptMemFree(ts_context);
+
+ if (result)
+#endif
+
+ result = CryptSignMessage(&sign_params, FALSE, 1, (const BYTE **)messages, (DWORD *)messages_sizes,
+ NULL, (DWORD *)signature_size);
+
+ if (result && *signature_size > 0)
+ *signature = (uint8_t *)MZ_ALLOC(*signature_size);
+
+ if (result && *signature != NULL)
+ result = CryptSignMessage(&sign_params, FALSE, 1, (const BYTE **)messages, (DWORD *)messages_sizes,
+ *signature, (DWORD *)signature_size);
+
+ if (!result)
+ err = MZ_SIGN_ERROR;
+ }
+
+ if (cert_context != NULL)
+ CertFreeCertificateContext(cert_context);
+ if (cert_store != NULL)
+ CertCloseStore(cert_store, 0);
+
+ return err;
+}
+
+int32_t mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size) {
+ CRYPT_VERIFY_MESSAGE_PARA verify_params;
+ CERT_CONTEXT *signer_cert = NULL;
+ CERT_CHAIN_PARA chain_para;
+ CERT_CHAIN_CONTEXT *chain_context = NULL;
+ CERT_CHAIN_POLICY_PARA chain_policy;
+ CERT_CHAIN_POLICY_STATUS chain_policy_status;
+ HCRYPTMSG crypt_msg = 0;
+ int32_t result = 0;
+ int32_t err = MZ_SIGN_ERROR;
+ uint8_t *decoded = NULL;
+ int32_t decoded_size = 0;
+
+
+ memset(&verify_params, 0, sizeof(verify_params));
+
+ verify_params.cbSize = sizeof(verify_params);
+ verify_params.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
+
+ result = CryptVerifyMessageSignature(&verify_params, 0, signature, signature_size,
+ NULL, (DWORD *)&decoded_size, NULL);
+
+ if (result && decoded_size > 0)
+ decoded = (uint8_t *)MZ_ALLOC(decoded_size);
+
+ if (result && decoded != NULL)
+ result = CryptVerifyMessageSignature(&verify_params, 0, signature, signature_size,
+ decoded, (DWORD *)&decoded_size, (const CERT_CONTEXT **)&signer_cert);
+
+ /* Get and validate certificate chain */
+ memset(&chain_para, 0, sizeof(chain_para));
+
+ if (result && signer_cert != NULL)
+ result = CertGetCertificateChain(NULL, signer_cert, NULL, NULL, &chain_para,
+ CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, NULL, (const CERT_CHAIN_CONTEXT **)&chain_context);
+
+ memset(&chain_policy, 0, sizeof(chain_policy));
+ chain_policy.cbSize = sizeof(CERT_CHAIN_POLICY_PARA);
+
+ memset(&chain_policy_status, 0, sizeof(chain_policy_status));
+ chain_policy_status.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS);
+
+ if (result && chain_context != NULL)
+ result = CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE, chain_context,
+ &chain_policy, &chain_policy_status);
+
+ if (chain_policy_status.dwError != S_OK)
+ result = 0;
+
+#if 0
+ crypt_msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, 0, 0, NULL, NULL);
+ if (crypt_msg != NULL) {
+ /* Timestamp support */
+ PCRYPT_ATTRIBUTES unauth_attribs = NULL;
+ HCRYPTMSG ts_msg = 0;
+ uint8_t *ts_content = NULL;
+ int32_t ts_content_size = 0;
+ uint8_t *ts_signature = NULL;
+ int32_t ts_signature_size = 0;
+
+ result = CryptMsgUpdate(crypt_msg, signature, signature_size, 1);
+
+ if (result)
+ CryptMsgGetParam(crypt_msg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, NULL, &ts_signature_size);
+
+ if ((result) && (ts_signature_size > 0))
+ ts_signature = (uint8_t *)MZ_ALLOC(ts_signature_size);
+
+ if ((result) && (ts_signature != NULL)) {
+ result = CryptMsgGetParam(crypt_msg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, ts_signature,
+ &ts_signature_size);
+ if (result)
+ {
+ unauth_attribs = (PCRYPT_ATTRIBUTES)ts_signature;
+
+ if ((unauth_attribs->cAttr > 0) && (unauth_attribs->rgAttr[0].cValue > 0))
+ {
+ ts_content = unauth_attribs->rgAttr[0].rgValue->pbData;
+ ts_content_size = unauth_attribs->rgAttr[0].rgValue->cbData;
+ }
+ }
+
+ if ((result) && (ts_content != NULL))
+ result = CryptVerifyTimeStampSignature(ts_content, ts_content_size, decoded,
+ decoded_size, 0, &crypt_context, NULL, NULL);
+
+ if (result)
+ err = MZ_OK;
+ }
+
+ if (ts_signature != NULL)
+ MZ_FREE(ts_signature);
+
+ if (crypt_context != NULL)
+ CryptMemFree(crypt_context);
+ } else {
+ result = 0;
+ }
+#endif
+
+ if ((result) && (decoded != NULL) && (decoded_size == message_size)) {
+ /* Verify cms message with our stored message */
+ if (memcmp(decoded, message, message_size) == 0)
+ err = MZ_OK;
+ }
+
+ if (chain_context != NULL)
+ CertFreeCertificateChain(chain_context);
+ if (signer_cert != NULL)
+ CertFreeCertificateContext(signer_cert);
+ if (crypt_msg != NULL)
+ CryptMsgClose(crypt_msg);
+
+ if (decoded != NULL)
+ MZ_FREE(decoded);
+
+ return err;
+}
+#endif
diff --git a/Externals/minizip/mz_os.c b/Externals/minizip/mz_os.c
new file mode 100644
index 0000000000..f96befe64c
--- /dev/null
+++ b/Externals/minizip/mz_os.c
@@ -0,0 +1,354 @@
+/* mz_os.c -- System functions
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Copyright (C) 1998-2010 Gilles Vollant
+ https://www.winimage.com/zLibDll/minizip.html
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include "mz.h"
+#include "mz_crypt.h"
+#include "mz_os.h"
+#include "mz_strm.h"
+#include "mz_strm_os.h"
+
+#include <ctype.h> /* tolower */
+
+/***************************************************************************/
+
+int32_t mz_path_combine(char *path, const char *join, int32_t max_path) {
+ int32_t path_len = 0;
+
+ if (path == NULL || join == NULL || max_path == 0)
+ return MZ_PARAM_ERROR;
+
+ path_len = (int32_t)strlen(path);
+
+ if (path_len == 0) {
+ strncpy(path, join, max_path - 1);
+ path[max_path - 1] = 0;
+ } else {
+ mz_path_append_slash(path, max_path, MZ_PATH_SLASH_PLATFORM);
+ strncat(path, join, max_path - path_len);
+ }
+
+ return MZ_OK;
+}
+
+int32_t mz_path_append_slash(char *path, int32_t max_path, char slash) {
+ int32_t path_len = (int32_t)strlen(path);
+ if ((path_len + 2) >= max_path)
+ return MZ_BUF_ERROR;
+ if (path[path_len - 1] != '\\' && path[path_len - 1] != '/') {
+ path[path_len] = slash;
+ path[path_len + 1] = 0;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_path_remove_slash(char *path) {
+ int32_t path_len = (int32_t)strlen(path);
+ while (path_len > 0) {
+ if (path[path_len - 1] == '\\' || path[path_len - 1] == '/')
+ path[path_len - 1] = 0;
+ else
+ break;
+
+ path_len -= 1;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_path_has_slash(const char *path) {
+ int32_t path_len = (int32_t)strlen(path);
+ if (path[path_len - 1] != '\\' && path[path_len - 1] != '/')
+ return MZ_EXIST_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_path_convert_slashes(char *path, char slash) {
+ int32_t i = 0;
+
+ for (i = 0; i < (int32_t)strlen(path); i += 1) {
+ if (path[i] == '\\' || path[i] == '/')
+ path[i] = slash;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_path_compare_wc(const char *path, const char *wildcard, uint8_t ignore_case) {
+ while (*path != 0) {
+ switch (*wildcard) {
+ case '*':
+
+ if (*(wildcard + 1) == 0)
+ return MZ_OK;
+
+ while (*path != 0) {
+ if (mz_path_compare_wc(path, (wildcard + 1), ignore_case) == MZ_OK)
+ return MZ_OK;
+
+ path += 1;
+ }
+
+ return MZ_EXIST_ERROR;
+
+ default:
+ /* Ignore differences in path slashes on platforms */
+ if ((*path == '\\' && *wildcard == '/') || (*path == '/' && *wildcard == '\\'))
+ break;
+
+ if (ignore_case) {
+ if (tolower(*path) != tolower(*wildcard))
+ return MZ_EXIST_ERROR;
+ } else {
+ if (*path != *wildcard)
+ return MZ_EXIST_ERROR;
+ }
+
+ break;
+ }
+
+ path += 1;
+ wildcard += 1;
+ }
+
+ if ((*wildcard != 0) && (*wildcard != '*'))
+ return MZ_EXIST_ERROR;
+
+ return MZ_OK;
+}
+
+int32_t mz_path_resolve(const char *path, char *output, int32_t max_output) {
+ const char *source = path;
+ const char *check = output;
+ char *target = output;
+
+
+ if (max_output <= 0)
+ return MZ_PARAM_ERROR;
+
+ while (*source != 0 && max_output > 1) {
+ check = source;
+ if ((*check == '\\') || (*check == '/'))
+ check += 1;
+
+ if ((source == path) || (target == output) || (check != source)) {
+ /* Skip double paths */
+ if ((*check == '\\') || (*check == '/')) {
+ source += 1;
+ continue;
+ }
+ if (*check == '.') {
+ check += 1;
+
+ /* Remove . if at end of string and not at the beginning */
+ if ((*check == 0) && (source != path && target != output)) {
+ /* Copy last slash */
+ *target = *source;
+ target += 1;
+ max_output -= 1;
+ source += (check - source);
+ continue;
+ }
+ /* Remove . if not at end of string */
+ else if ((*check == '\\') || (*check == '/')) {
+ source += (check - source);
+ /* Skip slash if at beginning of string */
+ if (target == output && *source != 0)
+ source += 1;
+ continue;
+ }
+ /* Go to parent directory .. */
+ else if (*check == '.') {
+ check += 1;
+ if ((*check == 0) || (*check == '\\' || *check == '/')) {
+ source += (check - source);
+
+ /* Search backwards for previous slash */
+ if (target != output) {
+ target -= 1;
+ do {
+ if ((*target == '\\') || (*target == '/'))
+ break;
+
+ target -= 1;
+ max_output += 1;
+ } while (target > output);
+ }
+
+ if ((target == output) && (*source != 0))
+ source += 1;
+ if ((*target == '\\' || *target == '/') && (*source == 0))
+ target += 1;
+
+ *target = 0;
+ continue;
+ }
+ }
+ }
+ }
+
+ *target = *source;
+
+ source += 1;
+ target += 1;
+ max_output -= 1;
+ }
+
+ *target = 0;
+
+ if (*path == 0)
+ return MZ_INTERNAL_ERROR;
+
+ return MZ_OK;
+}
+
+int32_t mz_path_remove_filename(char *path) {
+ char *path_ptr = NULL;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+
+ path_ptr = path + strlen(path) - 1;
+
+ while (path_ptr > path) {
+ if ((*path_ptr == '/') || (*path_ptr == '\\')) {
+ *path_ptr = 0;
+ break;
+ }
+
+ path_ptr -= 1;
+ }
+
+ if (path_ptr == path)
+ *path_ptr = 0;
+
+ return MZ_OK;
+}
+
+int32_t mz_path_remove_extension(char *path) {
+ char *path_ptr = NULL;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+
+ path_ptr = path + strlen(path) - 1;
+
+ while (path_ptr > path) {
+ if ((*path_ptr == '/') || (*path_ptr == '\\'))
+ break;
+ if (*path_ptr == '.') {
+ *path_ptr = 0;
+ break;
+ }
+
+ path_ptr -= 1;
+ }
+
+ if (path_ptr == path)
+ *path_ptr = 0;
+
+ return MZ_OK;
+}
+
+int32_t mz_path_get_filename(const char *path, const char **filename) {
+ const char *match = NULL;
+
+ if (path == NULL || filename == NULL)
+ return MZ_PARAM_ERROR;
+
+ *filename = NULL;
+
+ for (match = path; *match != 0; match += 1) {
+ if ((*match == '\\') || (*match == '/'))
+ *filename = match + 1;
+ }
+
+ if (*filename == NULL)
+ return MZ_EXIST_ERROR;
+
+ return MZ_OK;
+}
+
+int32_t mz_dir_make(const char *path) {
+ int32_t err = MZ_OK;
+ int16_t len = 0;
+ char *current_dir = NULL;
+ char *match = NULL;
+ char hold = 0;
+
+
+ len = (int16_t)strlen(path);
+ if (len <= 0)
+ return 0;
+
+ current_dir = (char *)MZ_ALLOC((uint16_t)len + 1);
+ if (current_dir == NULL)
+ return MZ_MEM_ERROR;
+
+ strcpy(current_dir, path);
+ mz_path_remove_slash(current_dir);
+
+ err = mz_os_make_dir(current_dir);
+ if (err != MZ_OK) {
+ match = current_dir + 1;
+ while (1) {
+ while (*match != 0 && *match != '\\' && *match != '/')
+ match += 1;
+ hold = *match;
+ *match = 0;
+
+ err = mz_os_make_dir(current_dir);
+ if (err != MZ_OK)
+ break;
+ if (hold == 0)
+ break;
+
+ *match = hold;
+ match += 1;
+ }
+ }
+
+ MZ_FREE(current_dir);
+ return err;
+}
+
+int32_t mz_file_get_crc(const char *path, uint32_t *result_crc) {
+ void *stream = NULL;
+ uint32_t crc32 = 0;
+ int32_t read = 0;
+ int32_t err = MZ_OK;
+ uint8_t buf[16384];
+
+ mz_stream_os_create(&stream);
+
+ err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ);
+
+ if (err == MZ_OK) {
+ do {
+ read = mz_stream_os_read(stream, buf, sizeof(buf));
+
+ if (read < 0) {
+ err = read;
+ break;
+ }
+
+ crc32 = mz_crypt_crc32_update(crc32, buf, read);
+ } while ((err == MZ_OK) && (read > 0));
+
+ mz_stream_os_close(stream);
+ }
+
+ *result_crc = crc32;
+
+ mz_stream_os_delete(&stream);
+
+ return err;
+}
+
+/***************************************************************************/
diff --git a/Externals/minizip/mz_os.h b/Externals/minizip/mz_os.h
new file mode 100644
index 0000000000..b3e2a58c19
--- /dev/null
+++ b/Externals/minizip/mz_os.h
@@ -0,0 +1,175 @@
+/* mz_os.h -- System functions
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_OS_H
+#define MZ_OS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+#if defined(__APPLE__)
+# define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_OSX_DARWIN)
+#elif defined(__riscos__)
+# define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_RISCOS)
+#elif defined(_WIN32)
+# define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_WINDOWS_NTFS)
+#else
+# define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_UNIX)
+#endif
+
+#if defined(HAVE_LZMA) || defined(HAVE_LIBCOMP)
+# define MZ_VERSION_MADEBY_ZIP_VERSION (63)
+#elif defined(HAVE_WZAES)
+# define MZ_VERSION_MADEBY_ZIP_VERSION (51)
+#elif defined(HAVE_BZIP2)
+# define MZ_VERSION_MADEBY_ZIP_VERSION (46)
+#else
+# define MZ_VERSION_MADEBY_ZIP_VERSION (45)
+#endif
+
+#define MZ_VERSION_MADEBY ((MZ_VERSION_MADEBY_HOST_SYSTEM << 8) | \
+ (MZ_VERSION_MADEBY_ZIP_VERSION))
+
+#define MZ_PATH_SLASH_UNIX ('/')
+#if defined(_WIN32)
+# define MZ_PATH_SLASH_PLATFORM ('\\')
+#else
+# define MZ_PATH_SLASH_PLATFORM (MZ_PATH_SLASH_UNIX)
+#endif
+
+/***************************************************************************/
+
+#if defined(_WIN32)
+struct dirent {
+ char d_name[256];
+};
+typedef void* DIR;
+#else
+#include <dirent.h>
+#endif
+
+/***************************************************************************/
+/* Shared functions */
+
+int32_t mz_path_combine(char *path, const char *join, int32_t max_path);
+/* Combines two paths */
+
+int32_t mz_path_append_slash(char *path, int32_t max_path, char slash);
+/* Appends a path slash on to the end of the path */
+
+int32_t mz_path_remove_slash(char *path);
+/* Removes a path slash from the end of the path */
+
+int32_t mz_path_has_slash(const char *path);
+/* Returns whether or not the path ends with slash */
+
+int32_t mz_path_convert_slashes(char *path, char slash);
+/* Converts the slashes in a path */
+
+int32_t mz_path_compare_wc(const char *path, const char *wildcard, uint8_t ignore_case);
+/* Compare two paths with wildcard */
+
+int32_t mz_path_resolve(const char *path, char *target, int32_t max_target);
+/* Resolves path */
+
+int32_t mz_path_remove_filename(char *path);
+/* Remove the filename from a path */
+
+int32_t mz_path_remove_extension(char *path);
+/* Remove the extension from a path */
+
+int32_t mz_path_get_filename(const char *path, const char **filename);
+/* Get the filename from a path */
+
+int32_t mz_dir_make(const char *path);
+/* Creates a directory recursively */
+
+int32_t mz_file_get_crc(const char *path, uint32_t *result_crc);
+/* Gets the crc32 hash of a file */
+
+/***************************************************************************/
+/* Platform specific functions */
+
+wchar_t *mz_os_unicode_string_create(const char *string, int32_t encoding);
+/* Create unicode string from a utf8 string */
+
+void mz_os_unicode_string_delete(wchar_t **string);
+/* Delete a unicode string that was created */
+
+uint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding);
+/* Create a utf8 string from a string with another encoding */
+
+void mz_os_utf8_string_delete(uint8_t **string);
+/* Delete a utf8 string that was created */
+
+int32_t mz_os_rand(uint8_t *buf, int32_t size);
+/* Random number generator (not cryptographically secure) */
+
+int32_t mz_os_rename(const char *source_path, const char *target_path);
+/* Rename a file */
+
+int32_t mz_os_unlink(const char *path);
+/* Delete an existing file */
+
+int32_t mz_os_file_exists(const char *path);
+/* Check to see if a file exists */
+
+int64_t mz_os_get_file_size(const char *path);
+/* Gets the length of a file */
+
+int32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date);
+/* Gets a file's modified, access, and creation dates if supported */
+
+int32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date);
+/* Sets a file's modified, access, and creation dates if supported */
+
+int32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes);
+/* Gets a file's attributes */
+
+int32_t mz_os_set_file_attribs(const char *path, uint32_t attributes);
+/* Sets a file's attributes */
+
+int32_t mz_os_make_dir(const char *path);
+/* Recursively creates a directory */
+
+DIR* mz_os_open_dir(const char *path);
+/* Opens a directory for listing */
+struct
+dirent* mz_os_read_dir(DIR *dir);
+/* Reads a directory listing entry */
+
+int32_t mz_os_close_dir(DIR *dir);
+/* Closes a directory that has been opened for listing */
+
+int32_t mz_os_is_dir(const char *path);
+/* Checks to see if path is a directory */
+
+int32_t mz_os_is_symlink(const char *path);
+/* Checks to see if path is a symbolic link */
+
+int32_t mz_os_make_symlink(const char *path, const char *target_path);
+/* Creates a symbolic link pointing to a target */
+
+int32_t mz_os_read_symlink(const char *path, char *target_path, int32_t max_target_path);
+/* Gets the target path for a symbolic link */
+
+uint64_t mz_os_ms_time(void);
+/* Gets the time in milliseconds */
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_os_posix.c b/Externals/minizip/mz_os_posix.c
new file mode 100644
index 0000000000..576943d162
--- /dev/null
+++ b/Externals/minizip/mz_os_posix.c
@@ -0,0 +1,367 @@
+/* mz_os_posix.c -- System functions for posix
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include "mz.h"
+#include "mz_strm.h"
+#include "mz_os.h"
+
+#include <stdio.h> /* rename */
+#include <errno.h>
+#if defined(HAVE_ICONV)
+#include <iconv.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef _WIN32
+# include <utime.h>
+# include <unistd.h>
+#endif
+#if defined(__APPLE__)
+# include <mach/clock.h>
+# include <mach/mach.h>
+#endif
+
+#if defined(HAVE_GETRANDOM)
+# include <sys/random.h>
+#endif
+#if defined(HAVE_LIBBSD)
+# include <sys/types.h>
+# ifndef __u_char_defined
+ typedef unsigned char u_char;
+# endif
+# include <bsd/stdlib.h> /* arc4random_buf */
+#endif
+
+/***************************************************************************/
+
+#if defined(HAVE_ICONV)
+uint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding) {
+ iconv_t cd;
+ const char *from_encoding = NULL;
+ size_t result = 0;
+ size_t string_length = 0;
+ size_t string_utf8_size = 0;
+ uint8_t *string_utf8 = NULL;
+ uint8_t *string_utf8_ptr = NULL;
+
+ if (string == NULL)
+ return NULL;
+
+ if (encoding == MZ_ENCODING_CODEPAGE_437)
+ from_encoding = "CP437";
+ else if (encoding == MZ_ENCODING_CODEPAGE_932)
+ from_encoding = "CP932";
+ else if (encoding == MZ_ENCODING_CODEPAGE_936)
+ from_encoding = "CP936";
+ else if (encoding == MZ_ENCODING_CODEPAGE_950)
+ from_encoding = "CP950";
+ else if (encoding == MZ_ENCODING_UTF8)
+ from_encoding = "UTF-8";
+ else
+ return NULL;
+
+ cd = iconv_open("UTF-8", from_encoding);
+ if (cd == (iconv_t)-1)
+ return NULL;
+
+ string_length = strlen(string);
+ string_utf8_size = string_length * 2;
+ string_utf8 = (uint8_t *)MZ_ALLOC((int32_t)(string_utf8_size + 1));
+ string_utf8_ptr = string_utf8;
+
+ if (string_utf8) {
+ memset(string_utf8, 0, string_utf8_size + 1);
+
+ result = iconv(cd, (char **)&string, &string_length,
+ (char **)&string_utf8_ptr, &string_utf8_size);
+ }
+
+ iconv_close(cd);
+
+ if (result == (size_t)-1) {
+ MZ_FREE(string_utf8);
+ string_utf8 = NULL;
+ }
+
+ return string_utf8;
+}
+#else
+uint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding) {
+ size_t string_length = 0;
+ uint8_t *string_copy = NULL;
+
+ string_length = strlen(string);
+ string_copy = (uint8_t *)MZ_ALLOC((int32_t)(string_length + 1));
+ strncpy((char *)string_copy, string, string_length);
+ string_copy[string_length] = 0;
+
+ return string_copy;
+}
+#endif
+
+void mz_os_utf8_string_delete(uint8_t **string) {
+ if (string != NULL) {
+ MZ_FREE(*string);
+ *string = NULL;
+ }
+}
+
+/***************************************************************************/
+
+#if defined(HAVE_ARC4RANDOM_BUF)
+int32_t mz_os_rand(uint8_t *buf, int32_t size) {
+ if (size < 0)
+ return 0;
+ arc4random_buf(buf, (uint32_t)size);
+ return size;
+}
+#elif defined(HAVE_ARC4RANDOM)
+int32_t mz_os_rand(uint8_t *buf, int32_t size) {
+ int32_t left = size;
+ for (; left > 2; left -= 3, buf += 3) {
+ uint32_t val = arc4random();
+
+ buf[0] = (val) & 0xFF;
+ buf[1] = (val >> 8) & 0xFF;
+ buf[2] = (val >> 16) & 0xFF;
+ }
+ for (; left > 0; left--, buf++) {
+ *buf = arc4random() & 0xFF;
+ }
+ return size - left;
+}
+#elif defined(HAVE_GETRANDOM)
+int32_t mz_os_rand(uint8_t *buf, int32_t size) {
+ int32_t left = size;
+ int32_t written = 0;
+
+ while (left > 0) {
+ written = getrandom(buf, left, 0);
+ if (written < 0)
+ return MZ_INTERNAL_ERROR;
+
+ buf += written;
+ left -= written;
+ }
+ return size - left;
+}
+#else
+int32_t mz_os_rand(uint8_t *buf, int32_t size) {
+ static unsigned calls = 0;
+ int32_t i = 0;
+
+ /* Ensure different random header each time */
+ if (++calls == 1) {
+ #define PI_SEED 3141592654UL
+ srand((unsigned)(time(NULL) ^ PI_SEED));
+ }
+
+ while (i < size)
+ buf[i++] = (rand() >> 7) & 0xff;
+
+ return size;
+}
+#endif
+
+int32_t mz_os_rename(const char *source_path, const char *target_path) {
+ if (rename(source_path, target_path) == -1)
+ return MZ_EXIST_ERROR;
+
+ return MZ_OK;
+}
+
+int32_t mz_os_unlink(const char *path) {
+ if (unlink(path) == -1)
+ return MZ_EXIST_ERROR;
+
+ return MZ_OK;
+}
+
+int32_t mz_os_file_exists(const char *path) {
+ struct stat path_stat;
+
+ memset(&path_stat, 0, sizeof(path_stat));
+ if (stat(path, &path_stat) == 0)
+ return MZ_OK;
+ return MZ_EXIST_ERROR;
+}
+
+int64_t mz_os_get_file_size(const char *path) {
+ struct stat path_stat;
+
+ memset(&path_stat, 0, sizeof(path_stat));
+ if (stat(path, &path_stat) == 0) {
+ /* Stat returns size taken up by directory entry, so return 0 */
+ if (S_ISDIR(path_stat.st_mode))
+ return 0;
+
+ return path_stat.st_size;
+ }
+
+ return 0;
+}
+
+int32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date) {
+ struct stat path_stat;
+ char *name = NULL;
+ size_t len = 0;
+ int32_t err = MZ_INTERNAL_ERROR;
+
+ memset(&path_stat, 0, sizeof(path_stat));
+
+ if (strcmp(path, "-") != 0) {
+ /* Not all systems allow stat'ing a file with / appended */
+ len = strlen(path);
+ name = (char *)malloc(len + 1);
+ strncpy(name, path, len + 1);
+ mz_path_remove_slash(name);
+
+ if (stat(name, &path_stat) == 0) {
+ if (modified_date != NULL)
+ *modified_date = path_stat.st_mtime;
+ if (accessed_date != NULL)
+ *accessed_date = path_stat.st_atime;
+ /* Creation date not supported */
+ if (creation_date != NULL)
+ *creation_date = 0;
+
+ err = MZ_OK;
+ }
+
+ free(name);
+ }
+
+ return err;
+}
+
+int32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date) {
+ struct utimbuf ut;
+
+ ut.actime = accessed_date;
+ ut.modtime = modified_date;
+
+ /* Creation date not supported */
+ MZ_UNUSED(creation_date);
+
+ if (utime(path, &ut) != 0)
+ return MZ_INTERNAL_ERROR;
+
+ return MZ_OK;
+}
+
+int32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes) {
+ struct stat path_stat;
+ int32_t err = MZ_OK;
+
+ memset(&path_stat, 0, sizeof(path_stat));
+ if (lstat(path, &path_stat) == -1)
+ err = MZ_INTERNAL_ERROR;
+ *attributes = path_stat.st_mode;
+ return err;
+}
+
+int32_t mz_os_set_file_attribs(const char *path, uint32_t attributes) {
+ int32_t err = MZ_OK;
+
+ if (chmod(path, (mode_t)attributes) == -1)
+ err = MZ_INTERNAL_ERROR;
+
+ return err;
+}
+
+int32_t mz_os_make_dir(const char *path) {
+ int32_t err = 0;
+
+ err = mkdir(path, 0755);
+
+ if (err != 0 && errno != EEXIST)
+ return MZ_INTERNAL_ERROR;
+
+ return MZ_OK;
+}
+
+DIR* mz_os_open_dir(const char *path) {
+ return opendir(path);
+}
+
+struct dirent* mz_os_read_dir(DIR *dir) {
+ if (dir == NULL)
+ return NULL;
+ return readdir(dir);
+}
+
+int32_t mz_os_close_dir(DIR *dir) {
+ if (dir == NULL)
+ return MZ_PARAM_ERROR;
+ if (closedir(dir) == -1)
+ return MZ_INTERNAL_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_os_is_dir(const char *path) {
+ struct stat path_stat;
+
+ memset(&path_stat, 0, sizeof(path_stat));
+ stat(path, &path_stat);
+ if (S_ISDIR(path_stat.st_mode))
+ return MZ_OK;
+
+ return MZ_EXIST_ERROR;
+}
+
+int32_t mz_os_is_symlink(const char *path) {
+ struct stat path_stat;
+
+ memset(&path_stat, 0, sizeof(path_stat));
+ lstat(path, &path_stat);
+ if (S_ISLNK(path_stat.st_mode))
+ return MZ_OK;
+
+ return MZ_EXIST_ERROR;
+}
+
+int32_t mz_os_make_symlink(const char *path, const char *target_path) {
+ if (symlink(target_path, path) != 0)
+ return MZ_INTERNAL_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_os_read_symlink(const char *path, char *target_path, int32_t max_target_path) {
+ size_t length = 0;
+
+ length = (size_t)readlink(path, target_path, max_target_path - 1);
+ if (length == (size_t)-1)
+ return MZ_EXIST_ERROR;
+
+ target_path[length] = 0;
+ return MZ_OK;
+}
+
+uint64_t mz_os_ms_time(void) {
+ struct timespec ts;
+
+#if defined(__APPLE__)
+ clock_serv_t cclock;
+ mach_timespec_t mts;
+
+ host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
+ clock_get_time(cclock, &mts);
+ mach_port_deallocate(mach_task_self(), cclock);
+
+ ts.tv_sec = mts.tv_sec;
+ ts.tv_nsec = mts.tv_nsec;
+#else
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+#endif
+
+ return ((uint64_t)ts.tv_sec * 1000) + ((uint64_t)ts.tv_nsec / 1000000);
+}
diff --git a/Externals/minizip/mz_os_win32.c b/Externals/minizip/mz_os_win32.c
new file mode 100644
index 0000000000..182bdbb840
--- /dev/null
+++ b/Externals/minizip/mz_os_win32.c
@@ -0,0 +1,659 @@
+/* mz_os_win32.c -- System functions for Windows
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_os.h"
+#include "mz_strm_os.h"
+
+#include <windows.h>
+#include <winioctl.h>
+
+/***************************************************************************/
+
+#if defined(WINAPI_FAMILY_PARTITION) && (!(defined(MZ_WINRT_API)))
+# if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# define MZ_WINRT_API 1
+# endif
+#endif
+
+#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
+# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
+#endif
+
+/***************************************************************************/
+
+typedef struct DIR_int_s {
+ void *find_handle;
+ WIN32_FIND_DATAW find_data;
+ struct dirent entry;
+ uint8_t end;
+} DIR_int;
+
+/***************************************************************************/
+
+wchar_t *mz_os_unicode_string_create(const char *string, int32_t encoding) {
+ wchar_t *string_wide = NULL;
+ uint32_t string_wide_size = 0;
+
+ string_wide_size = MultiByteToWideChar(encoding, 0, string, -1, NULL, 0);
+ if (string_wide_size == 0)
+ return NULL;
+ string_wide = (wchar_t *)MZ_ALLOC((string_wide_size + 1) * sizeof(wchar_t));
+ if (string_wide == NULL)
+ return NULL;
+
+ memset(string_wide, 0, sizeof(wchar_t) * (string_wide_size + 1));
+ MultiByteToWideChar(encoding, 0, string, -1, string_wide, string_wide_size);
+
+ return string_wide;
+}
+
+void mz_os_unicode_string_delete(wchar_t **string) {
+ if (string != NULL) {
+ MZ_FREE(*string);
+ *string = NULL;
+ }
+}
+
+uint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding) {
+ wchar_t *string_wide = NULL;
+ uint8_t *string_utf8 = NULL;
+ uint32_t string_utf8_size = 0;
+
+ string_wide = mz_os_unicode_string_create(string, encoding);
+ if (string_wide) {
+ string_utf8_size = WideCharToMultiByte(CP_UTF8, 0, string_wide, -1, NULL, 0, NULL, NULL);
+ string_utf8 = (uint8_t *)MZ_ALLOC((string_utf8_size + 1) * sizeof(wchar_t));
+
+ if (string_utf8) {
+ memset(string_utf8, 0, string_utf8_size + 1);
+ WideCharToMultiByte(CP_UTF8, 0, string_wide, -1, (char *)string_utf8, string_utf8_size, NULL, NULL);
+ }
+
+ mz_os_unicode_string_delete(&string_wide);
+ }
+
+ return string_utf8;
+}
+
+uint8_t *mz_os_utf8_string_create_from_unicode(const wchar_t *string, int32_t encoding) {
+ uint8_t *string_utf8 = NULL;
+ uint32_t string_utf8_size = 0;
+
+ MZ_UNUSED(encoding);
+
+ string_utf8_size = WideCharToMultiByte(CP_UTF8, 0, string, -1, NULL, 0, NULL, NULL);
+ string_utf8 = (uint8_t *)MZ_ALLOC((string_utf8_size + 1) * sizeof(wchar_t));
+
+ if (string_utf8) {
+ memset(string_utf8, 0, string_utf8_size + 1);
+ WideCharToMultiByte(CP_UTF8, 0, string, -1, (char *)string_utf8, string_utf8_size, NULL, NULL);
+ }
+
+ return string_utf8;
+}
+
+void mz_os_utf8_string_delete(uint8_t **string) {
+ if (string != NULL) {
+ MZ_FREE(*string);
+ *string = NULL;
+ }
+}
+
+/***************************************************************************/
+
+int32_t mz_os_rand(uint8_t *buf, int32_t size) {
+ unsigned __int64 pentium_tsc[1];
+ int32_t len = 0;
+
+ for (len = 0; len < (int)size; len += 1) {
+ if (len % 8 == 0)
+ QueryPerformanceCounter((LARGE_INTEGER *)pentium_tsc);
+ buf[len] = ((unsigned char*)pentium_tsc)[len % 8];
+ }
+
+ return len;
+}
+
+int32_t mz_os_rename(const char *source_path, const char *target_path) {
+ wchar_t *source_path_wide = NULL;
+ wchar_t *target_path_wide = NULL;
+ int32_t result = 0;
+ int32_t err = MZ_OK;
+
+ if (source_path == NULL || target_path == NULL)
+ return MZ_PARAM_ERROR;
+
+ source_path_wide = mz_os_unicode_string_create(source_path, MZ_ENCODING_UTF8);
+ if (source_path_wide == NULL) {
+ err = MZ_PARAM_ERROR;
+ } else {
+ target_path_wide = mz_os_unicode_string_create(target_path, MZ_ENCODING_UTF8);
+ if (target_path_wide == NULL)
+ err = MZ_PARAM_ERROR;
+ }
+
+ if (err == MZ_OK) {
+#ifdef MZ_WINRT_API
+ result = MoveFileExW(source_path_wide, target_path_wide, MOVEFILE_WRITE_THROUGH);
+#else
+ result = MoveFileW(source_path_wide, target_path_wide);
+#endif
+ if (result == 0)
+ err = MZ_EXIST_ERROR;
+ }
+
+ if (target_path_wide)
+ mz_os_unicode_string_delete(&target_path_wide);
+ if (source_path_wide)
+ mz_os_unicode_string_delete(&source_path_wide);
+
+ return err;
+}
+
+int32_t mz_os_unlink(const char *path) {
+ wchar_t *path_wide = NULL;
+ int32_t result = 0;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+
+ if (mz_os_is_dir(path) == MZ_OK)
+ result = RemoveDirectoryW(path_wide);
+ else
+ result = DeleteFileW(path_wide);
+
+ mz_os_unicode_string_delete(&path_wide);
+
+ if (result == 0)
+ return MZ_EXIST_ERROR;
+
+ return MZ_OK;
+}
+
+int32_t mz_os_file_exists(const char *path) {
+ wchar_t *path_wide = NULL;
+ DWORD attribs = 0;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+
+ attribs = GetFileAttributesW(path_wide);
+ mz_os_unicode_string_delete(&path_wide);
+
+ if (attribs == 0xFFFFFFFF)
+ return MZ_EXIST_ERROR;
+
+ return MZ_OK;
+}
+
+int64_t mz_os_get_file_size(const char *path) {
+ HANDLE handle = NULL;
+ LARGE_INTEGER large_size;
+ wchar_t *path_wide = NULL;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+#ifdef MZ_WINRT_API
+ handle = CreateFile2(path_wide, GENERIC_READ, 0, OPEN_EXISTING, NULL);
+#else
+ handle = CreateFileW(path_wide, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+#endif
+ mz_os_unicode_string_delete(&path_wide);
+
+ large_size.QuadPart = 0;
+
+ if (handle != INVALID_HANDLE_VALUE) {
+ GetFileSizeEx(handle, &large_size);
+ CloseHandle(handle);
+ }
+
+ return large_size.QuadPart;
+}
+
+static void mz_os_file_to_unix_time(FILETIME file_time, time_t *unix_time) {
+ uint64_t quad_file_time = 0;
+ quad_file_time = file_time.dwLowDateTime;
+ quad_file_time |= ((uint64_t)file_time.dwHighDateTime << 32);
+ *unix_time = (time_t)((quad_file_time - 116444736000000000LL) / 10000000);
+}
+
+static void mz_os_unix_to_file_time(time_t unix_time, FILETIME *file_time) {
+ uint64_t quad_file_time = 0;
+ quad_file_time = ((uint64_t)unix_time * 10000000) + 116444736000000000LL;
+ file_time->dwHighDateTime = (quad_file_time >> 32);
+ file_time->dwLowDateTime = (uint32_t)(quad_file_time);
+}
+
+int32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date) {
+ WIN32_FIND_DATAW ff32;
+ HANDLE handle = NULL;
+ wchar_t *path_wide = NULL;
+ int32_t err = MZ_INTERNAL_ERROR;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+
+ handle = FindFirstFileW(path_wide, &ff32);
+ MZ_FREE(path_wide);
+
+ if (handle != INVALID_HANDLE_VALUE) {
+ if (modified_date != NULL)
+ mz_os_file_to_unix_time(ff32.ftLastWriteTime, modified_date);
+ if (accessed_date != NULL)
+ mz_os_file_to_unix_time(ff32.ftLastAccessTime, accessed_date);
+ if (creation_date != NULL)
+ mz_os_file_to_unix_time(ff32.ftCreationTime, creation_date);
+
+ FindClose(handle);
+ err = MZ_OK;
+ }
+
+ return err;
+}
+
+int32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date) {
+ HANDLE handle = NULL;
+ FILETIME ftm_creation, ftm_accessed, ftm_modified;
+ wchar_t *path_wide = NULL;
+ int32_t err = MZ_OK;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+
+#ifdef MZ_WINRT_API
+ handle = CreateFile2(path_wide, GENERIC_READ | GENERIC_WRITE, 0, OPEN_EXISTING, NULL);
+#else
+ handle = CreateFileW(path_wide, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+#endif
+ mz_os_unicode_string_delete(&path_wide);
+
+ if (handle != INVALID_HANDLE_VALUE) {
+ GetFileTime(handle, &ftm_creation, &ftm_accessed, &ftm_modified);
+
+ if (modified_date != 0)
+ mz_os_unix_to_file_time(modified_date, &ftm_modified);
+ if (accessed_date != 0)
+ mz_os_unix_to_file_time(accessed_date, &ftm_accessed);
+ if (creation_date != 0)
+ mz_os_unix_to_file_time(creation_date, &ftm_creation);
+
+ if (SetFileTime(handle, &ftm_creation, &ftm_accessed, &ftm_modified) == 0)
+ err = MZ_INTERNAL_ERROR;
+
+ CloseHandle(handle);
+ }
+
+ return err;
+}
+
+int32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes) {
+ wchar_t *path_wide = NULL;
+ int32_t err = MZ_OK;
+
+ if (path == NULL || attributes == NULL)
+ return MZ_PARAM_ERROR;
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+
+ *attributes = GetFileAttributesW(path_wide);
+ mz_os_unicode_string_delete(&path_wide);
+
+ if (*attributes == INVALID_FILE_ATTRIBUTES)
+ err = MZ_INTERNAL_ERROR;
+
+ return err;
+}
+
+int32_t mz_os_set_file_attribs(const char *path, uint32_t attributes) {
+ wchar_t *path_wide = NULL;
+ int32_t err = MZ_OK;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+
+ if (SetFileAttributesW(path_wide, attributes) == 0)
+ err = MZ_INTERNAL_ERROR;
+ mz_os_unicode_string_delete(&path_wide);
+
+ return err;
+}
+
+int32_t mz_os_make_dir(const char *path) {
+ wchar_t *path_wide = NULL;
+ int32_t err = MZ_OK;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+
+ /* Don't try to create a drive letter */
+ if ((path[0] != 0) && (strlen(path) <= 3) && (path[1] == ':'))
+ return mz_os_is_dir(path);
+
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+
+ if (CreateDirectoryW(path_wide, NULL) == 0) {
+ if (GetLastError() != ERROR_ALREADY_EXISTS)
+ err = MZ_INTERNAL_ERROR;
+ }
+
+ mz_os_unicode_string_delete(&path_wide);
+
+ return err;
+}
+
+DIR *mz_os_open_dir(const char *path) {
+ WIN32_FIND_DATAW find_data;
+ DIR_int *dir_int = NULL;
+ wchar_t *path_wide = NULL;
+ char fixed_path[320];
+ void *handle = NULL;
+
+
+ if (path == NULL)
+ return NULL;
+
+ strncpy(fixed_path, path, sizeof(fixed_path) - 1);
+ fixed_path[sizeof(fixed_path) - 1] = 0;
+
+ mz_path_append_slash(fixed_path, sizeof(fixed_path), MZ_PATH_SLASH_PLATFORM);
+ mz_path_combine(fixed_path, "*", sizeof(fixed_path));
+
+ path_wide = mz_os_unicode_string_create(fixed_path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return NULL;
+
+ handle = FindFirstFileW(path_wide, &find_data);
+ mz_os_unicode_string_delete(&path_wide);
+
+ if (handle == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ dir_int = (DIR_int *)MZ_ALLOC(sizeof(DIR_int));
+ if (dir_int == NULL)
+ return NULL;
+ dir_int->find_handle = handle;
+ dir_int->end = 0;
+
+ memcpy(&dir_int->find_data, &find_data, sizeof(dir_int->find_data));
+
+ return (DIR *)dir_int;
+}
+
+struct dirent* mz_os_read_dir(DIR *dir) {
+ DIR_int *dir_int;
+
+ if (dir == NULL)
+ return NULL;
+
+ dir_int = (DIR_int *)dir;
+ if (dir_int->end)
+ return NULL;
+
+ WideCharToMultiByte(CP_UTF8, 0, dir_int->find_data.cFileName, -1,
+ dir_int->entry.d_name, sizeof(dir_int->entry.d_name), NULL, NULL);
+
+ if (FindNextFileW(dir_int->find_handle, &dir_int->find_data) == 0) {
+ if (GetLastError() != ERROR_NO_MORE_FILES)
+ return NULL;
+
+ dir_int->end = 1;
+ }
+
+ return &dir_int->entry;
+}
+
+int32_t mz_os_close_dir(DIR *dir) {
+ DIR_int *dir_int;
+
+ if (dir == NULL)
+ return MZ_PARAM_ERROR;
+
+ dir_int = (DIR_int *)dir;
+ if (dir_int->find_handle != INVALID_HANDLE_VALUE)
+ FindClose(dir_int->find_handle);
+ MZ_FREE(dir_int);
+ return MZ_OK;
+}
+
+int32_t mz_os_is_dir(const char *path) {
+ wchar_t *path_wide = NULL;
+ uint32_t attribs = 0;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+
+ attribs = GetFileAttributesW(path_wide);
+ mz_os_unicode_string_delete(&path_wide);
+
+ if (attribs != 0xFFFFFFFF) {
+ if (attribs & FILE_ATTRIBUTE_DIRECTORY)
+ return MZ_OK;
+ }
+
+ return MZ_EXIST_ERROR;
+}
+
+int32_t mz_os_is_symlink(const char *path) {
+ wchar_t *path_wide = NULL;
+ uint32_t attribs = 0;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+
+ attribs = GetFileAttributesW(path_wide);
+ mz_os_unicode_string_delete(&path_wide);
+
+ if (attribs != 0xFFFFFFFF) {
+ if (attribs & FILE_ATTRIBUTE_REPARSE_POINT)
+ return MZ_OK;
+ }
+
+ return MZ_EXIST_ERROR;
+}
+
+int32_t mz_os_make_symlink(const char *path, const char *target_path) {
+ typedef BOOLEAN (WINAPI *LPCREATESYMBOLICLINKW)(LPCWSTR, LPCWSTR, DWORD);
+ LPCREATESYMBOLICLINKW create_symbolic_link_w = NULL;
+ HMODULE kernel32_mod = NULL;
+ wchar_t *path_wide = NULL;
+ wchar_t *target_path_wide = NULL;
+ int32_t err = MZ_OK;
+ int32_t flags = 0;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+
+#ifdef MZ_WINRT_API
+ MEMORY_BASIC_INFORMATION mbi;
+ memset(&mbi, 0, sizeof(mbi));
+ VirtualQuery(VirtualQuery, &mbi, sizeof(mbi));
+ kernel32_mod = (HMODULE)mbi.AllocationBase;
+#else
+ kernel32_mod = GetModuleHandleW(L"kernel32.dll");
+#endif
+
+ if (kernel32_mod == NULL)
+ return MZ_SUPPORT_ERROR;
+
+ create_symbolic_link_w = (LPCREATESYMBOLICLINKW)GetProcAddress(kernel32_mod, "CreateSymbolicLinkW");
+ if (create_symbolic_link_w == NULL) {
+ return MZ_SUPPORT_ERROR;
+ }
+
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL) {
+ return MZ_PARAM_ERROR;
+ }
+
+ target_path_wide = mz_os_unicode_string_create(target_path, MZ_ENCODING_UTF8);
+ if (target_path_wide != NULL) {
+ if (mz_path_has_slash(target_path) == MZ_OK)
+ flags |= SYMBOLIC_LINK_FLAG_DIRECTORY;
+
+ if (create_symbolic_link_w(path_wide, target_path_wide, flags) == FALSE)
+ err = MZ_SYMLINK_ERROR;
+
+ mz_os_unicode_string_delete(&target_path_wide);
+ } else {
+ err = MZ_PARAM_ERROR;
+ }
+
+ mz_os_unicode_string_delete(&path_wide);
+
+ return err;
+}
+
+int32_t mz_os_read_symlink(const char *path, char *target_path, int32_t max_target_path) {
+ typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+ } REPARSE_DATA_BUFFER;
+ REPARSE_DATA_BUFFER *reparse_data = NULL;
+ DWORD length = 0;
+ HANDLE handle = NULL;
+ wchar_t *path_wide = NULL;
+ wchar_t *target_path_wide = NULL;
+ uint8_t buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ int32_t target_path_len = 0;
+ int32_t target_path_idx = 0;
+ int32_t err = MZ_OK;
+ uint8_t *target_path_utf8 = NULL;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+
+#ifdef MZ_WINRT_API
+ CREATEFILE2_EXTENDED_PARAMETERS extended_params;
+ memset(&extended_params, 0, sizeof(extended_params));
+ extended_params.dwSize = sizeof(extended_params);
+ extended_params.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
+ extended_params.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT;
+ extended_params.dwSecurityQosFlags = SECURITY_ANONYMOUS;
+ extended_params.lpSecurityAttributes = NULL;
+ extended_params.hTemplateFile = NULL;
+ handle = CreateFile2(path_wide, FILE_READ_EA, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, &extended_params);
+#else
+ handle = CreateFileW(path_wide, FILE_READ_EA, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
+#endif
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ mz_os_unicode_string_delete(&path_wide);
+ return MZ_OPEN_ERROR;
+ }
+
+ if (DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, sizeof(buffer), &length, NULL) == TRUE) {
+ reparse_data = (REPARSE_DATA_BUFFER *)buffer;
+ if ((IsReparseTagMicrosoft(reparse_data->ReparseTag)) &&
+ (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK)) {
+ target_path_len = max_target_path * sizeof(wchar_t);
+ if (target_path_len > reparse_data->SymbolicLinkReparseBuffer.PrintNameLength)
+ target_path_len = reparse_data->SymbolicLinkReparseBuffer.PrintNameLength;
+
+ target_path_wide = (wchar_t *)MZ_ALLOC(target_path_len + sizeof(wchar_t));
+ if (target_path_wide) {
+ target_path_idx = reparse_data->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(wchar_t);
+ memcpy(target_path_wide, &reparse_data->SymbolicLinkReparseBuffer.PathBuffer[target_path_idx],
+ target_path_len);
+
+ target_path_wide[target_path_len / sizeof(wchar_t)] = 0;
+ target_path_utf8 = mz_os_utf8_string_create_from_unicode(target_path_wide, MZ_ENCODING_UTF8);
+
+ if (target_path_utf8) {
+ strncpy(target_path, (const char *)target_path_utf8, max_target_path - 1);
+ target_path[max_target_path - 1] = 0;
+ /* Ensure directories have slash at the end so we can recreate them later */
+ if (mz_os_is_dir((const char *)target_path_utf8) == MZ_OK)
+ mz_path_append_slash(target_path, max_target_path, MZ_PATH_SLASH_PLATFORM);
+ mz_os_utf8_string_delete(&target_path_utf8);
+ } else {
+ err = MZ_MEM_ERROR;
+ }
+
+ MZ_FREE(target_path_wide);
+ } else {
+ err = MZ_MEM_ERROR;
+ }
+ }
+ } else {
+ err = MZ_INTERNAL_ERROR;
+ }
+
+ CloseHandle(handle);
+ mz_os_unicode_string_delete(&path_wide);
+ return err;
+}
+
+uint64_t mz_os_ms_time(void) {
+ SYSTEMTIME system_time;
+ FILETIME file_time;
+ uint64_t quad_file_time = 0;
+
+ GetSystemTime(&system_time);
+ SystemTimeToFileTime(&system_time, &file_time);
+
+ quad_file_time = file_time.dwLowDateTime;
+ quad_file_time |= ((uint64_t)file_time.dwHighDateTime << 32);
+
+ return quad_file_time / 10000 - 11644473600000LL;
+}
diff --git a/Externals/minizip/mz_strm.c b/Externals/minizip/mz_strm.c
new file mode 100644
index 0000000000..da7d5872d6
--- /dev/null
+++ b/Externals/minizip/mz_strm.c
@@ -0,0 +1,560 @@
+/* mz_strm.c -- Stream interface
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include "mz.h"
+#include "mz_strm.h"
+
+/***************************************************************************/
+
+#define MZ_STREAM_FIND_SIZE (1024)
+
+/***************************************************************************/
+
+int32_t mz_stream_open(void *stream, const char *path, int32_t mode) {
+ mz_stream *strm = (mz_stream *)stream;
+ if (strm == NULL || strm->vtbl == NULL || strm->vtbl->open == NULL)
+ return MZ_STREAM_ERROR;
+ return strm->vtbl->open(strm, path, mode);
+}
+
+int32_t mz_stream_is_open(void *stream) {
+ mz_stream *strm = (mz_stream *)stream;
+ if (strm == NULL || strm->vtbl == NULL || strm->vtbl->is_open == NULL)
+ return MZ_STREAM_ERROR;
+ return strm->vtbl->is_open(strm);
+}
+
+int32_t mz_stream_read(void *stream, void *buf, int32_t size) {
+ mz_stream *strm = (mz_stream *)stream;
+ if (strm == NULL || strm->vtbl == NULL || strm->vtbl->read == NULL)
+ return MZ_PARAM_ERROR;
+ if (mz_stream_is_open(stream) != MZ_OK)
+ return MZ_STREAM_ERROR;
+ return strm->vtbl->read(strm, buf, size);
+}
+
+static int32_t mz_stream_read_value(void *stream, uint64_t *value, int32_t len) {
+ uint8_t buf[8];
+ int32_t n = 0;
+ int32_t i = 0;
+
+ *value = 0;
+ if (mz_stream_read(stream, buf, len) == len) {
+ for (n = 0; n < len; n += 1, i += 8)
+ *value += ((uint64_t)buf[n]) << i;
+ } else if (mz_stream_error(stream))
+ return MZ_STREAM_ERROR;
+ else
+ return MZ_END_OF_STREAM;
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_read_uint8(void *stream, uint8_t *value) {
+ int32_t err = MZ_OK;
+ uint64_t value64 = 0;
+
+ *value = 0;
+ err = mz_stream_read_value(stream, &value64, sizeof(uint8_t));
+ if (err == MZ_OK)
+ *value = (uint8_t)value64;
+ return err;
+}
+
+int32_t mz_stream_read_uint16(void *stream, uint16_t *value) {
+ int32_t err = MZ_OK;
+ uint64_t value64 = 0;
+
+ *value = 0;
+ err = mz_stream_read_value(stream, &value64, sizeof(uint16_t));
+ if (err == MZ_OK)
+ *value = (uint16_t)value64;
+ return err;
+}
+
+int32_t mz_stream_read_uint32(void *stream, uint32_t *value) {
+ int32_t err = MZ_OK;
+ uint64_t value64 = 0;
+
+ *value = 0;
+ err = mz_stream_read_value(stream, &value64, sizeof(uint32_t));
+ if (err == MZ_OK)
+ *value = (uint32_t)value64;
+ return err;
+}
+
+int32_t mz_stream_read_int64(void *stream, int64_t *value) {
+ return mz_stream_read_value(stream, (uint64_t *)value, sizeof(uint64_t));
+}
+
+int32_t mz_stream_read_uint64(void *stream, uint64_t *value) {
+ return mz_stream_read_value(stream, value, sizeof(uint64_t));
+}
+
+int32_t mz_stream_write(void *stream, const void *buf, int32_t size) {
+ mz_stream *strm = (mz_stream *)stream;
+ if (size == 0)
+ return size;
+ if (strm == NULL || strm->vtbl == NULL || strm->vtbl->write == NULL)
+ return MZ_PARAM_ERROR;
+ if (mz_stream_is_open(stream) != MZ_OK)
+ return MZ_STREAM_ERROR;
+ return strm->vtbl->write(strm, buf, size);
+}
+
+static int32_t mz_stream_write_value(void *stream, uint64_t value, int32_t len) {
+ uint8_t buf[8];
+ int32_t n = 0;
+
+ for (n = 0; n < len; n += 1) {
+ buf[n] = (uint8_t)(value & 0xff);
+ value >>= 8;
+ }
+
+ if (value != 0) {
+ /* Data overflow - hack for ZIP64 (X Roche) */
+ for (n = 0; n < len; n += 1)
+ buf[n] = 0xff;
+ }
+
+ if (mz_stream_write(stream, buf, len) != len)
+ return MZ_STREAM_ERROR;
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_write_uint8(void *stream, uint8_t value) {
+ return mz_stream_write_value(stream, value, sizeof(uint8_t));
+}
+
+int32_t mz_stream_write_uint16(void *stream, uint16_t value) {
+ return mz_stream_write_value(stream, value, sizeof(uint16_t));
+}
+
+int32_t mz_stream_write_uint32(void *stream, uint32_t value) {
+ return mz_stream_write_value(stream, value, sizeof(uint32_t));
+}
+
+int32_t mz_stream_write_int64(void *stream, int64_t value) {
+ return mz_stream_write_value(stream, (uint64_t)value, sizeof(uint64_t));
+}
+
+int32_t mz_stream_write_uint64(void *stream, uint64_t value) {
+ return mz_stream_write_value(stream, value, sizeof(uint64_t));
+}
+
+int32_t mz_stream_copy(void *target, void *source, int32_t len) {
+ return mz_stream_copy_stream(target, NULL, source, NULL, len);
+}
+
+int32_t mz_stream_copy_to_end(void *target, void *source) {
+ return mz_stream_copy_stream_to_end(target, NULL, source, NULL);
+}
+
+int32_t mz_stream_copy_stream(void *target, mz_stream_write_cb write_cb, void *source,
+ mz_stream_read_cb read_cb, int32_t len) {
+ uint8_t buf[16384];
+ int32_t bytes_to_copy = 0;
+ int32_t read = 0;
+ int32_t written = 0;
+
+ if (write_cb == NULL)
+ write_cb = mz_stream_write;
+ if (read_cb == NULL)
+ read_cb = mz_stream_read;
+
+ while (len > 0) {
+ bytes_to_copy = len;
+ if (bytes_to_copy > (int32_t)sizeof(buf))
+ bytes_to_copy = sizeof(buf);
+ read = read_cb(source, buf, bytes_to_copy);
+ if (read <= 0)
+ return MZ_STREAM_ERROR;
+ written = write_cb(target, buf, read);
+ if (written != read)
+ return MZ_STREAM_ERROR;
+ len -= read;
+ }
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_copy_stream_to_end(void *target, mz_stream_write_cb write_cb, void *source,
+ mz_stream_read_cb read_cb) {
+ uint8_t buf[16384];
+ int32_t read = 0;
+ int32_t written = 0;
+
+ if (write_cb == NULL)
+ write_cb = mz_stream_write;
+ if (read_cb == NULL)
+ read_cb = mz_stream_read;
+
+ read = read_cb(source, buf, sizeof(buf));
+ while (read > 0) {
+ written = write_cb(target, buf, read);
+ if (written != read)
+ return MZ_STREAM_ERROR;
+ read = read_cb(source, buf, sizeof(buf));
+ }
+
+ if (read < 0)
+ return MZ_STREAM_ERROR;
+
+ return MZ_OK;
+}
+
+int64_t mz_stream_tell(void *stream) {
+ mz_stream *strm = (mz_stream *)stream;
+ if (strm == NULL || strm->vtbl == NULL || strm->vtbl->tell == NULL)
+ return MZ_PARAM_ERROR;
+ if (mz_stream_is_open(stream) != MZ_OK)
+ return MZ_STREAM_ERROR;
+ return strm->vtbl->tell(strm);
+}
+
+int32_t mz_stream_seek(void *stream, int64_t offset, int32_t origin) {
+ mz_stream *strm = (mz_stream *)stream;
+ if (strm == NULL || strm->vtbl == NULL || strm->vtbl->seek == NULL)
+ return MZ_PARAM_ERROR;
+ if (mz_stream_is_open(stream) != MZ_OK)
+ return MZ_STREAM_ERROR;
+ if (origin == MZ_SEEK_SET && offset < 0)
+ return MZ_SEEK_ERROR;
+ return strm->vtbl->seek(strm, offset, origin);
+}
+
+int32_t mz_stream_find(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position) {
+ uint8_t buf[MZ_STREAM_FIND_SIZE];
+ int32_t buf_pos = 0;
+ int32_t read_size = sizeof(buf);
+ int32_t read = 0;
+ int64_t read_pos = 0;
+ int64_t start_pos = 0;
+ int64_t disk_pos = 0;
+ int32_t i = 0;
+ uint8_t first = 1;
+ int32_t err = MZ_OK;
+
+ if (stream == NULL || find == NULL || position == NULL)
+ return MZ_PARAM_ERROR;
+ if (find_size < 0 || find_size >= (int32_t)sizeof(buf))
+ return MZ_PARAM_ERROR;
+
+ *position = -1;
+
+ start_pos = mz_stream_tell(stream);
+
+ while (read_pos < max_seek) {
+ if (read_size > (int32_t)(max_seek - read_pos - buf_pos) && (max_seek - read_pos - buf_pos) < (int64_t)sizeof(buf))
+ read_size = (int32_t)(max_seek - read_pos - buf_pos);
+
+ read = mz_stream_read(stream, buf + buf_pos, read_size);
+ if ((read <= 0) || (read + buf_pos < find_size))
+ break;
+
+ for (i = 0; i <= read + buf_pos - find_size; i += 1) {
+ if (memcmp(&buf[i], find, find_size) != 0)
+ continue;
+
+ disk_pos = mz_stream_tell(stream);
+
+ /* Seek to position on disk where the data was found */
+ err = mz_stream_seek(stream, disk_pos - ((int64_t)read + buf_pos - i), MZ_SEEK_SET);
+ if (err != MZ_OK)
+ return MZ_EXIST_ERROR;
+
+ *position = start_pos + read_pos + i;
+ return MZ_OK;
+ }
+
+ if (first) {
+ read -= find_size;
+ read_size -= find_size;
+ buf_pos = find_size;
+ first = 0;
+ }
+
+ memmove(buf, buf + read, find_size);
+ read_pos += read;
+ }
+
+ return MZ_EXIST_ERROR;
+}
+
+int32_t mz_stream_find_reverse(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position) {
+ uint8_t buf[MZ_STREAM_FIND_SIZE];
+ int32_t buf_pos = 0;
+ int32_t read_size = MZ_STREAM_FIND_SIZE;
+ int64_t read_pos = 0;
+ int32_t read = 0;
+ int64_t start_pos = 0;
+ int64_t disk_pos = 0;
+ uint8_t first = 1;
+ int32_t i = 0;
+ int32_t err = MZ_OK;
+
+ if (stream == NULL || find == NULL || position == NULL)
+ return MZ_PARAM_ERROR;
+ if (find_size < 0 || find_size >= (int32_t)sizeof(buf))
+ return MZ_PARAM_ERROR;
+
+ *position = -1;
+
+ start_pos = mz_stream_tell(stream);
+
+ while (read_pos < max_seek) {
+ if (read_size > (int32_t)(max_seek - read_pos) && (max_seek - read_pos) < (int64_t)sizeof(buf))
+ read_size = (int32_t)(max_seek - read_pos);
+
+ if (mz_stream_seek(stream, start_pos - (read_pos + read_size), MZ_SEEK_SET) != MZ_OK)
+ break;
+ read = mz_stream_read(stream, buf, read_size);
+ if ((read <= 0) || (read + buf_pos < find_size))
+ break;
+ if (read + buf_pos < MZ_STREAM_FIND_SIZE)
+ memmove(buf + MZ_STREAM_FIND_SIZE - (read + buf_pos), buf, read);
+
+ for (i = find_size; i <= (read + buf_pos); i += 1) {
+ if (memcmp(&buf[MZ_STREAM_FIND_SIZE - i], find, find_size) != 0)
+ continue;
+
+ disk_pos = mz_stream_tell(stream);
+
+ /* Seek to position on disk where the data was found */
+ err = mz_stream_seek(stream, disk_pos + buf_pos - i, MZ_SEEK_SET);
+ if (err != MZ_OK)
+ return MZ_EXIST_ERROR;
+
+ *position = start_pos - (read_pos - buf_pos + i);
+ return MZ_OK;
+ }
+
+ if (first) {
+ read -= find_size;
+ read_size -= find_size;
+ buf_pos = find_size;
+ first = 0;
+ }
+
+ if (read == 0)
+ break;
+
+ memmove(buf + read_size, buf, find_size);
+ read_pos += read;
+ }
+
+ return MZ_EXIST_ERROR;
+}
+
+int32_t mz_stream_close(void *stream) {
+ mz_stream *strm = (mz_stream *)stream;
+ if (strm == NULL || strm->vtbl == NULL || strm->vtbl->close == NULL)
+ return MZ_PARAM_ERROR;
+ if (mz_stream_is_open(stream) != MZ_OK)
+ return MZ_STREAM_ERROR;
+ return strm->vtbl->close(strm);
+}
+
+int32_t mz_stream_error(void *stream) {
+ mz_stream *strm = (mz_stream *)stream;
+ if (strm == NULL || strm->vtbl == NULL || strm->vtbl->error == NULL)
+ return MZ_PARAM_ERROR;
+ return strm->vtbl->error(strm);
+}
+
+int32_t mz_stream_set_base(void *stream, void *base) {
+ mz_stream *strm = (mz_stream *)stream;
+ strm->base = (mz_stream *)base;
+ return MZ_OK;
+}
+
+void* mz_stream_get_interface(void *stream) {
+ mz_stream *strm = (mz_stream *)stream;
+ if (strm == NULL || strm->vtbl == NULL)
+ return NULL;
+ return (void *)strm->vtbl;
+}
+
+int32_t mz_stream_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
+ mz_stream *strm = (mz_stream *)stream;
+ if (strm == NULL || strm->vtbl == NULL || strm->vtbl->get_prop_int64 == NULL)
+ return MZ_PARAM_ERROR;
+ return strm->vtbl->get_prop_int64(stream, prop, value);
+}
+
+int32_t mz_stream_set_prop_int64(void *stream, int32_t prop, int64_t value) {
+ mz_stream *strm = (mz_stream *)stream;
+ if (strm == NULL || strm->vtbl == NULL || strm->vtbl->set_prop_int64 == NULL)
+ return MZ_PARAM_ERROR;
+ return strm->vtbl->set_prop_int64(stream, prop, value);
+}
+
+void *mz_stream_create(void **stream, mz_stream_vtbl *vtbl) {
+ if (stream == NULL)
+ return NULL;
+ if (vtbl == NULL || vtbl->create == NULL)
+ return NULL;
+ return vtbl->create(stream);
+}
+
+void mz_stream_delete(void **stream) {
+ mz_stream *strm = NULL;
+ if (stream == NULL)
+ return;
+ strm = (mz_stream *)*stream;
+ if (strm != NULL && strm->vtbl != NULL && strm->vtbl->destroy != NULL)
+ strm->vtbl->destroy(stream);
+ *stream = NULL;
+}
+
+/***************************************************************************/
+
+typedef struct mz_stream_raw_s {
+ mz_stream stream;
+ int64_t total_in;
+ int64_t total_out;
+ int64_t max_total_in;
+} mz_stream_raw;
+
+/***************************************************************************/
+
+int32_t mz_stream_raw_open(void *stream, const char *path, int32_t mode) {
+ MZ_UNUSED(stream);
+ MZ_UNUSED(path);
+ MZ_UNUSED(mode);
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_raw_is_open(void *stream) {
+ mz_stream_raw *raw = (mz_stream_raw *)stream;
+ return mz_stream_is_open(raw->stream.base);
+}
+
+int32_t mz_stream_raw_read(void *stream, void *buf, int32_t size) {
+ mz_stream_raw *raw = (mz_stream_raw *)stream;
+ int32_t bytes_to_read = size;
+ int32_t read = 0;
+
+ if (raw->max_total_in > 0) {
+ if ((int64_t)bytes_to_read > (raw->max_total_in - raw->total_in))
+ bytes_to_read = (int32_t)(raw->max_total_in - raw->total_in);
+ }
+
+ read = mz_stream_read(raw->stream.base, buf, bytes_to_read);
+
+ if (read > 0) {
+ raw->total_in += read;
+ raw->total_out += read;
+ }
+
+ return read;
+}
+
+int32_t mz_stream_raw_write(void *stream, const void *buf, int32_t size) {
+ mz_stream_raw *raw = (mz_stream_raw *)stream;
+ int32_t written = 0;
+
+ written = mz_stream_write(raw->stream.base, buf, size);
+
+ if (written > 0) {
+ raw->total_out += written;
+ raw->total_in += written;
+ }
+
+ return written;
+}
+
+int64_t mz_stream_raw_tell(void *stream) {
+ mz_stream_raw *raw = (mz_stream_raw *)stream;
+ return mz_stream_tell(raw->stream.base);
+}
+
+int32_t mz_stream_raw_seek(void *stream, int64_t offset, int32_t origin) {
+ mz_stream_raw *raw = (mz_stream_raw *)stream;
+ return mz_stream_seek(raw->stream.base, offset, origin);
+}
+
+int32_t mz_stream_raw_close(void *stream) {
+ MZ_UNUSED(stream);
+ return MZ_OK;
+}
+
+int32_t mz_stream_raw_error(void *stream) {
+ mz_stream_raw *raw = (mz_stream_raw *)stream;
+ return mz_stream_error(raw->stream.base);
+}
+
+int32_t mz_stream_raw_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
+ mz_stream_raw *raw = (mz_stream_raw *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_IN:
+ *value = raw->total_in;
+ return MZ_OK;
+ case MZ_STREAM_PROP_TOTAL_OUT:
+ *value = raw->total_out;
+ return MZ_OK;
+ }
+ return MZ_EXIST_ERROR;
+}
+
+int32_t mz_stream_raw_set_prop_int64(void *stream, int32_t prop, int64_t value) {
+ mz_stream_raw *raw = (mz_stream_raw *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ raw->max_total_in = value;
+ return MZ_OK;
+ }
+ return MZ_EXIST_ERROR;
+}
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_raw_vtbl = {
+ mz_stream_raw_open,
+ mz_stream_raw_is_open,
+ mz_stream_raw_read,
+ mz_stream_raw_write,
+ mz_stream_raw_tell,
+ mz_stream_raw_seek,
+ mz_stream_raw_close,
+ mz_stream_raw_error,
+ mz_stream_raw_create,
+ mz_stream_raw_delete,
+ mz_stream_raw_get_prop_int64,
+ mz_stream_raw_set_prop_int64
+};
+
+/***************************************************************************/
+
+void *mz_stream_raw_create(void **stream) {
+ mz_stream_raw *raw = NULL;
+
+ raw = (mz_stream_raw *)MZ_ALLOC(sizeof(mz_stream_raw));
+ if (raw != NULL) {
+ memset(raw, 0, sizeof(mz_stream_raw));
+ raw->stream.vtbl = &mz_stream_raw_vtbl;
+ }
+ if (stream != NULL)
+ *stream = raw;
+
+ return raw;
+}
+
+void mz_stream_raw_delete(void **stream) {
+ mz_stream_raw *raw = NULL;
+ if (stream == NULL)
+ return;
+ raw = (mz_stream_raw *)*stream;
+ if (raw != NULL)
+ MZ_FREE(raw);
+ *stream = NULL;
+}
diff --git a/Externals/minizip/mz_strm.h b/Externals/minizip/mz_strm.h
new file mode 100644
index 0000000000..8b0027cf50
--- /dev/null
+++ b/Externals/minizip/mz_strm.h
@@ -0,0 +1,132 @@
+/* mz_strm.h -- Stream interface
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_H
+#define MZ_STREAM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+#define MZ_STREAM_PROP_TOTAL_IN (1)
+#define MZ_STREAM_PROP_TOTAL_IN_MAX (2)
+#define MZ_STREAM_PROP_TOTAL_OUT (3)
+#define MZ_STREAM_PROP_TOTAL_OUT_MAX (4)
+#define MZ_STREAM_PROP_HEADER_SIZE (5)
+#define MZ_STREAM_PROP_FOOTER_SIZE (6)
+#define MZ_STREAM_PROP_DISK_SIZE (7)
+#define MZ_STREAM_PROP_DISK_NUMBER (8)
+#define MZ_STREAM_PROP_COMPRESS_LEVEL (9)
+#define MZ_STREAM_PROP_COMPRESS_METHOD (10)
+#define MZ_STREAM_PROP_COMPRESS_WINDOW (11)
+
+/***************************************************************************/
+
+typedef int32_t (*mz_stream_open_cb) (void *stream, const char *path, int32_t mode);
+typedef int32_t (*mz_stream_is_open_cb) (void *stream);
+typedef int32_t (*mz_stream_read_cb) (void *stream, void *buf, int32_t size);
+typedef int32_t (*mz_stream_write_cb) (void *stream, const void *buf, int32_t size);
+typedef int64_t (*mz_stream_tell_cb) (void *stream);
+typedef int32_t (*mz_stream_seek_cb) (void *stream, int64_t offset, int32_t origin);
+typedef int32_t (*mz_stream_close_cb) (void *stream);
+typedef int32_t (*mz_stream_error_cb) (void *stream);
+typedef void* (*mz_stream_create_cb) (void **stream);
+typedef void (*mz_stream_destroy_cb) (void **stream);
+
+typedef int32_t (*mz_stream_get_prop_int64_cb) (void *stream, int32_t prop, int64_t *value);
+typedef int32_t (*mz_stream_set_prop_int64_cb) (void *stream, int32_t prop, int64_t value);
+
+typedef int32_t (*mz_stream_find_cb) (void *stream, const void *find, int32_t find_size,
+ int64_t max_seek, int64_t *position);
+
+/***************************************************************************/
+
+typedef struct mz_stream_vtbl_s {
+ mz_stream_open_cb open;
+ mz_stream_is_open_cb is_open;
+ mz_stream_read_cb read;
+ mz_stream_write_cb write;
+ mz_stream_tell_cb tell;
+ mz_stream_seek_cb seek;
+ mz_stream_close_cb close;
+ mz_stream_error_cb error;
+ mz_stream_create_cb create;
+ mz_stream_destroy_cb destroy;
+
+ mz_stream_get_prop_int64_cb get_prop_int64;
+ mz_stream_set_prop_int64_cb set_prop_int64;
+} mz_stream_vtbl;
+
+typedef struct mz_stream_s {
+ mz_stream_vtbl *vtbl;
+ struct mz_stream_s *base;
+} mz_stream;
+
+/***************************************************************************/
+
+int32_t mz_stream_open(void *stream, const char *path, int32_t mode);
+int32_t mz_stream_is_open(void *stream);
+int32_t mz_stream_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_read_uint8(void *stream, uint8_t *value);
+int32_t mz_stream_read_uint16(void *stream, uint16_t *value);
+int32_t mz_stream_read_uint32(void *stream, uint32_t *value);
+int32_t mz_stream_read_int64(void *stream, int64_t *value);
+int32_t mz_stream_read_uint64(void *stream, uint64_t *value);
+int32_t mz_stream_write(void *stream, const void *buf, int32_t size);
+int32_t mz_stream_write_uint8(void *stream, uint8_t value);
+int32_t mz_stream_write_uint16(void *stream, uint16_t value);
+int32_t mz_stream_write_uint32(void *stream, uint32_t value);
+int32_t mz_stream_write_int64(void *stream, int64_t value);
+int32_t mz_stream_write_uint64(void *stream, uint64_t value);
+int32_t mz_stream_copy(void *target, void *source, int32_t len);
+int32_t mz_stream_copy_to_end(void *target, void *source);
+int32_t mz_stream_copy_stream(void *target, mz_stream_write_cb write_cb, void *source, mz_stream_read_cb read_cb, int32_t len);
+int32_t mz_stream_copy_stream_to_end(void *target, mz_stream_write_cb write_cb, void *source, mz_stream_read_cb read_cb);
+int64_t mz_stream_tell(void *stream);
+int32_t mz_stream_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_find(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position);
+int32_t mz_stream_find_reverse(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position);
+int32_t mz_stream_close(void *stream);
+int32_t mz_stream_error(void *stream);
+
+int32_t mz_stream_set_base(void *stream, void *base);
+void* mz_stream_get_interface(void *stream);
+int32_t mz_stream_get_prop_int64(void *stream, int32_t prop, int64_t *value);
+int32_t mz_stream_set_prop_int64(void *stream, int32_t prop, int64_t value);
+
+void* mz_stream_create(void **stream, mz_stream_vtbl *vtbl);
+void mz_stream_delete(void **stream);
+
+/***************************************************************************/
+
+int32_t mz_stream_raw_open(void *stream, const char *filename, int32_t mode);
+int32_t mz_stream_raw_is_open(void *stream);
+int32_t mz_stream_raw_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_raw_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_raw_tell(void *stream);
+int32_t mz_stream_raw_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_raw_close(void *stream);
+int32_t mz_stream_raw_error(void *stream);
+
+int32_t mz_stream_raw_get_prop_int64(void *stream, int32_t prop, int64_t *value);
+int32_t mz_stream_raw_set_prop_int64(void *stream, int32_t prop, int64_t value);
+
+void* mz_stream_raw_create(void **stream);
+void mz_stream_raw_delete(void **stream);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_strm_buf.c b/Externals/minizip/mz_strm_buf.c
new file mode 100644
index 0000000000..1dfdfdf5fd
--- /dev/null
+++ b/Externals/minizip/mz_strm_buf.c
@@ -0,0 +1,385 @@
+/* mz_strm_buf.c -- Stream for buffering reads/writes
+ part of the minizip-ng project
+
+ This version of ioapi is designed to buffer IO.
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include "mz.h"
+#include "mz_strm.h"
+#include "mz_strm_buf.h"
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_buffered_vtbl = {
+ mz_stream_buffered_open,
+ mz_stream_buffered_is_open,
+ mz_stream_buffered_read,
+ mz_stream_buffered_write,
+ mz_stream_buffered_tell,
+ mz_stream_buffered_seek,
+ mz_stream_buffered_close,
+ mz_stream_buffered_error,
+ mz_stream_buffered_create,
+ mz_stream_buffered_delete,
+ NULL,
+ NULL
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_buffered_s {
+ mz_stream stream;
+ int32_t error;
+ char readbuf[INT16_MAX];
+ int32_t readbuf_len;
+ int32_t readbuf_pos;
+ int32_t readbuf_hits;
+ int32_t readbuf_misses;
+ char writebuf[INT16_MAX];
+ int32_t writebuf_len;
+ int32_t writebuf_pos;
+ int32_t writebuf_hits;
+ int32_t writebuf_misses;
+ int64_t position;
+} mz_stream_buffered;
+
+/***************************************************************************/
+
+#if 0
+# define mz_stream_buffered_print printf
+#else
+# define mz_stream_buffered_print(fmt,...)
+#endif
+
+/***************************************************************************/
+
+static int32_t mz_stream_buffered_reset(void *stream) {
+ mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
+
+ buffered->readbuf_len = 0;
+ buffered->readbuf_pos = 0;
+ buffered->writebuf_len = 0;
+ buffered->writebuf_pos = 0;
+ buffered->position = 0;
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_buffered_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
+ mz_stream_buffered_print("Buffered - Open (mode %" PRId32 ")\n", mode);
+ mz_stream_buffered_reset(buffered);
+ return mz_stream_open(buffered->stream.base, path, mode);
+}
+
+int32_t mz_stream_buffered_is_open(void *stream) {
+ mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
+ return mz_stream_is_open(buffered->stream.base);
+}
+
+static int32_t mz_stream_buffered_flush(void *stream, int32_t *written) {
+ mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
+ int32_t total_bytes_written = 0;
+ int32_t bytes_to_write = buffered->writebuf_len;
+ int32_t bytes_left_to_write = buffered->writebuf_len;
+ int32_t bytes_written = 0;
+
+ *written = 0;
+
+ while (bytes_left_to_write > 0) {
+ bytes_written = mz_stream_write(buffered->stream.base,
+ buffered->writebuf + (bytes_to_write - bytes_left_to_write), bytes_left_to_write);
+
+ if (bytes_written != bytes_left_to_write)
+ return MZ_WRITE_ERROR;
+
+ buffered->writebuf_misses += 1;
+
+ mz_stream_buffered_print("Buffered - Write flush (%" PRId32 ":%" PRId32 " len %" PRId32 ")\n",
+ bytes_to_write, bytes_left_to_write, buffered->writebuf_len);
+
+ total_bytes_written += bytes_written;
+ bytes_left_to_write -= bytes_written;
+ buffered->position += bytes_written;
+ }
+
+ buffered->writebuf_len = 0;
+ buffered->writebuf_pos = 0;
+
+ *written = total_bytes_written;
+ return MZ_OK;
+}
+
+int32_t mz_stream_buffered_read(void *stream, void *buf, int32_t size) {
+ mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
+ int32_t buf_len = 0;
+ int32_t bytes_to_read = 0;
+ int32_t bytes_to_copy = 0;
+ int32_t bytes_left_to_read = size;
+ int32_t bytes_read = 0;
+ int32_t bytes_flushed = 0;
+
+ mz_stream_buffered_print("Buffered - Read (size %" PRId32 " pos %" PRId64 ")\n", size, buffered->position);
+
+ if (buffered->writebuf_len > 0) {
+ int64_t position = buffered->position + buffered->writebuf_pos
+
+ mz_stream_buffered_print("Buffered - Switch from write to read, flushing (pos %" PRId64 ")\n", position);
+
+ mz_stream_buffered_flush(stream, &bytes_flushed);
+ mz_stream_buffered_seek(stream, position, MZ_SEEK_SET);
+ }
+
+ while (bytes_left_to_read > 0) {
+ if ((buffered->readbuf_len == 0) || (buffered->readbuf_pos == buffered->readbuf_len)) {
+ if (buffered->readbuf_len == sizeof(buffered->readbuf)) {
+ buffered->readbuf_pos = 0;
+ buffered->readbuf_len = 0;
+ }
+
+ bytes_to_read = (int32_t)sizeof(buffered->readbuf) - (buffered->readbuf_len - buffered->readbuf_pos);
+ bytes_read = mz_stream_read(buffered->stream.base, buffered->readbuf + buffered->readbuf_pos, bytes_to_read);
+ if (bytes_read < 0)
+ return bytes_read;
+
+ buffered->readbuf_misses += 1;
+ buffered->readbuf_len += bytes_read;
+ buffered->position += bytes_read;
+
+ mz_stream_buffered_print("Buffered - Filled (read %" PRId32 "/%" PRId32 " buf %" PRId32 ":%" PRId32 " pos %" PRId64 ")\n",
+ bytes_read, bytes_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position);
+
+ if (bytes_read == 0)
+ break;
+ }
+
+ if ((buffered->readbuf_len - buffered->readbuf_pos) > 0) {
+ bytes_to_copy = buffered->readbuf_len - buffered->readbuf_pos;
+ if (bytes_to_copy > bytes_left_to_read)
+ bytes_to_copy = bytes_left_to_read;
+
+ memcpy((char *)buf + buf_len, buffered->readbuf + buffered->readbuf_pos, bytes_to_copy);
+
+ buf_len += bytes_to_copy;
+ bytes_left_to_read -= bytes_to_copy;
+
+ buffered->readbuf_hits += 1;
+ buffered->readbuf_pos += bytes_to_copy;
+
+ mz_stream_buffered_print("Buffered - Emptied (copied %" PRId32 " remaining %" PRId32 " buf %" PRId32 ":%" PRId32 " pos %" PRId64 ")\n",
+ bytes_to_copy, bytes_left_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position);
+ }
+ }
+
+ return size - bytes_left_to_read;
+}
+
+int32_t mz_stream_buffered_write(void *stream, const void *buf, int32_t size) {
+ mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
+ int32_t bytes_to_write = size;
+ int32_t bytes_left_to_write = size;
+ int32_t bytes_to_copy = 0;
+ int32_t bytes_used = 0;
+ int32_t bytes_flushed = 0;
+ int32_t err = MZ_OK;
+
+
+ mz_stream_buffered_print("Buffered - Write (size %" PRId32 " len %" PRId32 " pos %" PRId64 ")\n",
+ size, buffered->writebuf_len, buffered->position);
+
+ if (buffered->readbuf_len > 0) {
+ buffered->position -= buffered->readbuf_len;
+ buffered->position += buffered->readbuf_pos;
+
+ buffered->readbuf_len = 0;
+ buffered->readbuf_pos = 0;
+
+ mz_stream_buffered_print("Buffered - Switch from read to write (pos %" PRId64 ")\n", buffered->position);
+
+ err = mz_stream_seek(buffered->stream.base, buffered->position, MZ_SEEK_SET);
+ if (err != MZ_OK)
+ return err;
+ }
+
+ while (bytes_left_to_write > 0) {
+ bytes_used = buffered->writebuf_len;
+ if (bytes_used > buffered->writebuf_pos)
+ bytes_used = buffered->writebuf_pos;
+ bytes_to_copy = (int32_t)sizeof(buffered->writebuf) - bytes_used;
+ if (bytes_to_copy > bytes_left_to_write)
+ bytes_to_copy = bytes_left_to_write;
+
+ if (bytes_to_copy == 0) {
+ err = mz_stream_buffered_flush(stream, &bytes_flushed);
+ if (err != MZ_OK)
+ return err;
+ if (bytes_flushed == 0)
+ return 0;
+
+ continue;
+ }
+
+ memcpy(buffered->writebuf + buffered->writebuf_pos,
+ (const char *)buf + (bytes_to_write - bytes_left_to_write), bytes_to_copy);
+
+ mz_stream_buffered_print("Buffered - Write copy (remaining %" PRId32 " write %" PRId32 ":%" PRId32 " len %" PRId32 ")\n",
+ bytes_to_copy, bytes_to_write, bytes_left_to_write, buffered->writebuf_len);
+
+ bytes_left_to_write -= bytes_to_copy;
+
+ buffered->writebuf_pos += bytes_to_copy;
+ buffered->writebuf_hits += 1;
+ if (buffered->writebuf_pos > buffered->writebuf_len)
+ buffered->writebuf_len += buffered->writebuf_pos - buffered->writebuf_len;
+ }
+
+ return size - bytes_left_to_write;
+}
+
+int64_t mz_stream_buffered_tell(void *stream) {
+ mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
+ int64_t position = mz_stream_tell(buffered->stream.base);
+
+ buffered->position = position;
+
+ mz_stream_buffered_print("Buffered - Tell (pos %" PRId64 " readpos %" PRId32 " writepos %" PRId32 ")\n",
+ buffered->position, buffered->readbuf_pos, buffered->writebuf_pos);
+
+ if (buffered->readbuf_len > 0)
+ position -= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos);
+ if (buffered->writebuf_len > 0)
+ position += buffered->writebuf_pos;
+ return position;
+}
+
+int32_t mz_stream_buffered_seek(void *stream, int64_t offset, int32_t origin) {
+ mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
+ int32_t bytes_flushed = 0;
+ int32_t err = MZ_OK;
+
+ mz_stream_buffered_print("Buffered - Seek (origin %" PRId32 " offset %" PRId64 " pos %" PRId64 ")\n",
+ origin, offset, buffered->position);
+
+ switch (origin) {
+ case MZ_SEEK_SET:
+
+ if ((buffered->readbuf_len > 0) && (offset < buffered->position) &&
+ (offset >= buffered->position - buffered->readbuf_len)) {
+ buffered->readbuf_pos = (int32_t)(offset - (buffered->position - buffered->readbuf_len));
+ return MZ_OK;
+ }
+ if (buffered->writebuf_len > 0) {
+ if ((offset >= buffered->position) && (offset <= buffered->position + buffered->writebuf_len)) {
+ buffered->writebuf_pos = (int32_t)(offset - buffered->position);
+ return MZ_OK;
+ }
+ }
+
+ err = mz_stream_buffered_flush(stream, &bytes_flushed);
+ if (err != MZ_OK)
+ return err;
+
+ buffered->position = offset;
+ break;
+
+ case MZ_SEEK_CUR:
+
+ if (buffered->readbuf_len > 0) {
+ if (offset <= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos)) {
+ buffered->readbuf_pos += (uint32_t)offset;
+ return MZ_OK;
+ }
+ offset -= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos);
+ buffered->position += offset;
+ }
+ if (buffered->writebuf_len > 0) {
+ if (offset <= ((int64_t)buffered->writebuf_len - buffered->writebuf_pos)) {
+ buffered->writebuf_pos += (uint32_t)offset;
+ return MZ_OK;
+ }
+ /* offset -= (buffered->writebuf_len - buffered->writebuf_pos); */
+ }
+
+ err = mz_stream_buffered_flush(stream, &bytes_flushed);
+ if (err != MZ_OK)
+ return err;
+
+ break;
+
+ case MZ_SEEK_END:
+
+ if (buffered->writebuf_len > 0) {
+ buffered->writebuf_pos = buffered->writebuf_len;
+ return MZ_OK;
+ }
+ break;
+ }
+
+ buffered->readbuf_len = 0;
+ buffered->readbuf_pos = 0;
+ buffered->writebuf_len = 0;
+ buffered->writebuf_pos = 0;
+
+ return mz_stream_seek(buffered->stream.base, offset, origin);
+}
+
+int32_t mz_stream_buffered_close(void *stream) {
+ mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
+ int32_t bytes_flushed = 0;
+
+ mz_stream_buffered_flush(stream, &bytes_flushed);
+ mz_stream_buffered_print("Buffered - Close (flushed %" PRId32 ")\n", bytes_flushed);
+
+ if (buffered->readbuf_hits + buffered->readbuf_misses > 0) {
+ mz_stream_buffered_print("Buffered - Read efficiency %.02f%%\n",
+ (buffered->readbuf_hits / ((float)buffered->readbuf_hits + buffered->readbuf_misses)) * 100);
+ }
+
+ if (buffered->writebuf_hits + buffered->writebuf_misses > 0) {
+ mz_stream_buffered_print("Buffered - Write efficiency %.02f%%\n",
+ (buffered->writebuf_hits / ((float)buffered->writebuf_hits + buffered->writebuf_misses)) * 100);
+ }
+
+ mz_stream_buffered_reset(buffered);
+
+ return mz_stream_close(buffered->stream.base);
+}
+
+int32_t mz_stream_buffered_error(void *stream) {
+ mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
+ return mz_stream_error(buffered->stream.base);
+}
+
+void *mz_stream_buffered_create(void **stream) {
+ mz_stream_buffered *buffered = NULL;
+
+ buffered = (mz_stream_buffered *)MZ_ALLOC(sizeof(mz_stream_buffered));
+ if (buffered != NULL) {
+ memset(buffered, 0, sizeof(mz_stream_buffered));
+ buffered->stream.vtbl = &mz_stream_buffered_vtbl;
+ }
+ if (stream != NULL)
+ *stream = buffered;
+
+ return buffered;
+}
+
+void mz_stream_buffered_delete(void **stream) {
+ mz_stream_buffered *buffered = NULL;
+ if (stream == NULL)
+ return;
+ buffered = (mz_stream_buffered *)*stream;
+ if (buffered != NULL)
+ MZ_FREE(buffered);
+ *stream = NULL;
+}
+
+void *mz_stream_buffered_get_interface(void) {
+ return (void *)&mz_stream_buffered_vtbl;
+}
diff --git a/Externals/minizip/mz_strm_buf.h b/Externals/minizip/mz_strm_buf.h
new file mode 100644
index 0000000000..b71e6e4e92
--- /dev/null
+++ b/Externals/minizip/mz_strm_buf.h
@@ -0,0 +1,42 @@
+/* mz_strm_buf.h -- Stream for buffering reads/writes
+ part of the minizip-ng project
+
+ This version of ioapi is designed to buffer IO.
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_BUFFERED_H
+#define MZ_STREAM_BUFFERED_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_buffered_open(void *stream, const char *path, int32_t mode);
+int32_t mz_stream_buffered_is_open(void *stream);
+int32_t mz_stream_buffered_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_buffered_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_buffered_tell(void *stream);
+int32_t mz_stream_buffered_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_buffered_close(void *stream);
+int32_t mz_stream_buffered_error(void *stream);
+
+void* mz_stream_buffered_create(void **stream);
+void mz_stream_buffered_delete(void **stream);
+
+void* mz_stream_buffered_get_interface(void);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_strm_bzip.c b/Externals/minizip/mz_strm_bzip.c
new file mode 100644
index 0000000000..31d8bf9a5e
--- /dev/null
+++ b/Externals/minizip/mz_strm_bzip.c
@@ -0,0 +1,374 @@
+/* mz_strm_bzip.c -- Stream for bzip inflate/deflate
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_strm.h"
+#include "mz_strm_bzip.h"
+
+#include "bzlib.h"
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_bzip_vtbl = {
+ mz_stream_bzip_open,
+ mz_stream_bzip_is_open,
+ mz_stream_bzip_read,
+ mz_stream_bzip_write,
+ mz_stream_bzip_tell,
+ mz_stream_bzip_seek,
+ mz_stream_bzip_close,
+ mz_stream_bzip_error,
+ mz_stream_bzip_create,
+ mz_stream_bzip_delete,
+ mz_stream_bzip_get_prop_int64,
+ mz_stream_bzip_set_prop_int64
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_bzip_s {
+ mz_stream stream;
+ bz_stream bzstream;
+ int32_t mode;
+ int32_t error;
+ uint8_t buffer[INT16_MAX];
+ int32_t buffer_len;
+ int16_t stream_end;
+ int64_t total_in;
+ int64_t total_out;
+ int64_t max_total_in;
+ int8_t initialized;
+ int16_t level;
+} mz_stream_bzip;
+
+/***************************************************************************/
+
+int32_t mz_stream_bzip_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_bzip *bzip = (mz_stream_bzip *)stream;
+
+ MZ_UNUSED(path);
+
+ bzip->bzstream.bzalloc = 0;
+ bzip->bzstream.bzfree = 0;
+ bzip->bzstream.opaque = 0;
+ bzip->bzstream.total_in_lo32 = 0;
+ bzip->bzstream.total_in_hi32 = 0;
+ bzip->bzstream.total_out_lo32 = 0;
+ bzip->bzstream.total_out_hi32 = 0;
+
+ bzip->total_in = 0;
+ bzip->total_out = 0;
+
+ if (mode & MZ_OPEN_MODE_WRITE) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ bzip->bzstream.next_out = (char *)bzip->buffer;
+ bzip->bzstream.avail_out = sizeof(bzip->buffer);
+
+ bzip->error = BZ2_bzCompressInit(&bzip->bzstream, bzip->level, 0, 0);
+#endif
+ } else if (mode & MZ_OPEN_MODE_READ) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ bzip->bzstream.next_in = (char *)bzip->buffer;
+ bzip->bzstream.avail_in = 0;
+
+ bzip->error = BZ2_bzDecompressInit(&bzip->bzstream, 0, 0);
+#endif
+ }
+
+ if (bzip->error != BZ_OK)
+ return MZ_OPEN_ERROR;
+
+ bzip->initialized = 1;
+ bzip->stream_end = 0;
+ bzip->mode = mode;
+ return MZ_OK;
+}
+
+int32_t mz_stream_bzip_is_open(void *stream) {
+ mz_stream_bzip *bzip = (mz_stream_bzip *)stream;
+ if (bzip->initialized != 1)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_bzip_read(void *stream, void *buf, int32_t size) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ MZ_UNUSED(stream);
+ MZ_UNUSED(buf);
+ MZ_UNUSED(size);
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_bzip *bzip = (mz_stream_bzip *)stream;
+ uint64_t total_in_before = 0;
+ uint64_t total_out_before = 0;
+ uint64_t total_in_after = 0;
+ uint64_t total_out_after = 0;
+ int32_t total_in = 0;
+ int32_t total_out = 0;
+ int32_t in_bytes = 0;
+ int32_t out_bytes = 0;
+ int32_t bytes_to_read = sizeof(bzip->buffer);
+ int32_t read = 0;
+ int32_t err = BZ_OK;
+
+
+ if (bzip->stream_end)
+ return 0;
+
+ bzip->bzstream.next_out = (char *)buf;
+ bzip->bzstream.avail_out = (unsigned int)size;
+
+ do {
+ if (bzip->bzstream.avail_in == 0) {
+ if (bzip->max_total_in > 0) {
+ if ((int64_t)bytes_to_read > (bzip->max_total_in - bzip->total_in))
+ bytes_to_read = (int32_t)(bzip->max_total_in - bzip->total_in);
+ }
+
+ read = mz_stream_read(bzip->stream.base, bzip->buffer, bytes_to_read);
+
+ if (read < 0)
+ return read;
+
+ bzip->bzstream.next_in = (char *)bzip->buffer;
+ bzip->bzstream.avail_in = (uint32_t)read;
+ }
+
+ total_in_before = bzip->bzstream.avail_in;
+ total_out_before = bzip->bzstream.total_out_lo32 +
+ (((uint64_t)bzip->bzstream.total_out_hi32) << 32);
+
+ err = BZ2_bzDecompress(&bzip->bzstream);
+
+ total_in_after = bzip->bzstream.avail_in;
+ total_out_after = bzip->bzstream.total_out_lo32 +
+ (((uint64_t)bzip->bzstream.total_out_hi32) << 32);
+
+ in_bytes = (int32_t)(total_in_before - total_in_after);
+ out_bytes = (int32_t)(total_out_after - total_out_before);
+
+ total_in += in_bytes;
+ total_out += out_bytes;
+
+ bzip->total_in += in_bytes;
+ bzip->total_out += out_bytes;
+
+ if (err == BZ_STREAM_END) {
+ bzip->stream_end = 1;
+ break;
+ }
+ if (err != BZ_OK && err != BZ_RUN_OK) {
+ bzip->error = err;
+ break;
+ }
+ } while (bzip->bzstream.avail_out > 0);
+
+ if (bzip->error != 0)
+ return MZ_DATA_ERROR;
+
+ return total_out;
+#endif
+}
+
+#ifndef MZ_ZIP_NO_COMPRESSION
+static int32_t mz_stream_bzip_flush(void *stream) {
+ mz_stream_bzip *bzip = (mz_stream_bzip *)stream;
+ if (mz_stream_write(bzip->stream.base, bzip->buffer, bzip->buffer_len) != bzip->buffer_len)
+ return MZ_WRITE_ERROR;
+ return MZ_OK;
+}
+
+static int32_t mz_stream_bzip_compress(void *stream, int flush) {
+ mz_stream_bzip *bzip = (mz_stream_bzip *)stream;
+ uint64_t total_out_before = 0;
+ uint64_t total_out_after = 0;
+ uint32_t out_bytes = 0;
+ int32_t err = BZ_OK;
+
+ do {
+ if (bzip->bzstream.avail_out == 0) {
+ err = mz_stream_bzip_flush(bzip);
+ if (err != MZ_OK)
+ return err;
+
+ bzip->bzstream.avail_out = sizeof(bzip->buffer);
+ bzip->bzstream.next_out = (char *)bzip->buffer;
+
+ bzip->buffer_len = 0;
+ }
+
+ total_out_before = bzip->bzstream.total_out_lo32 +
+ (((uint64_t)bzip->bzstream.total_out_hi32) << 32);
+
+ err = BZ2_bzCompress(&bzip->bzstream, flush);
+
+ total_out_after = bzip->bzstream.total_out_lo32 +
+ (((uint64_t)bzip->bzstream.total_out_hi32) << 32);
+
+ out_bytes = (uint32_t)(total_out_after - total_out_before);
+
+ bzip->buffer_len += out_bytes;
+ bzip->total_out += out_bytes;
+
+ if (err == BZ_STREAM_END)
+ break;
+ if (err < 0) {
+ bzip->error = err;
+ return MZ_DATA_ERROR;
+ }
+ } while ((bzip->bzstream.avail_in > 0) || (flush == BZ_FINISH && err == BZ_FINISH_OK));
+
+ return MZ_OK;
+}
+#endif
+
+int32_t mz_stream_bzip_write(void *stream, const void *buf, int32_t size) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ MZ_UNUSED(stream);
+ MZ_UNUSED(buf);
+ MZ_UNUSED(size);
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_bzip *bzip = (mz_stream_bzip *)stream;
+ int32_t err = MZ_OK;
+
+ bzip->bzstream.next_in = (char *)(intptr_t)buf;
+ bzip->bzstream.avail_in = (unsigned int)size;
+
+ err = mz_stream_bzip_compress(stream, BZ_RUN);
+ if (err != MZ_OK) {
+ return err;
+ }
+
+ bzip->total_in += size;
+ return size;
+#endif
+}
+
+int64_t mz_stream_bzip_tell(void *stream) {
+ MZ_UNUSED(stream);
+
+ return MZ_TELL_ERROR;
+}
+
+int32_t mz_stream_bzip_seek(void *stream, int64_t offset, int32_t origin) {
+ MZ_UNUSED(stream);
+ MZ_UNUSED(offset);
+ MZ_UNUSED(origin);
+
+ return MZ_SEEK_ERROR;
+}
+
+int32_t mz_stream_bzip_close(void *stream) {
+ mz_stream_bzip *bzip = (mz_stream_bzip *)stream;
+
+ if (bzip->mode & MZ_OPEN_MODE_WRITE) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_bzip_compress(stream, BZ_FINISH);
+ mz_stream_bzip_flush(stream);
+
+ BZ2_bzCompressEnd(&bzip->bzstream);
+#endif
+ } else if (bzip->mode & MZ_OPEN_MODE_READ) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ BZ2_bzDecompressEnd(&bzip->bzstream);
+#endif
+ }
+
+ bzip->initialized = 0;
+
+ if (bzip->error != BZ_OK)
+ return MZ_CLOSE_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_bzip_error(void *stream) {
+ mz_stream_bzip *bzip = (mz_stream_bzip *)stream;
+ return bzip->error;
+}
+
+int32_t mz_stream_bzip_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
+ mz_stream_bzip *bzip = (mz_stream_bzip *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_IN:
+ *value = bzip->total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ *value = bzip->max_total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_OUT:
+ *value = bzip->total_out;
+ break;
+ case MZ_STREAM_PROP_HEADER_SIZE:
+ *value = 0;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_stream_bzip_set_prop_int64(void *stream, int32_t prop, int64_t value) {
+ mz_stream_bzip *bzip = (mz_stream_bzip *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_COMPRESS_LEVEL:
+ if (value < 0)
+ bzip->level = 6;
+ else
+ bzip->level = (int16_t)value;
+ return MZ_OK;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ bzip->max_total_in = value;
+ return MZ_OK;
+ }
+ return MZ_EXIST_ERROR;
+}
+
+void *mz_stream_bzip_create(void **stream) {
+ mz_stream_bzip *bzip = NULL;
+
+ bzip = (mz_stream_bzip *)MZ_ALLOC(sizeof(mz_stream_bzip));
+ if (bzip != NULL) {
+ memset(bzip, 0, sizeof(mz_stream_bzip));
+ bzip->stream.vtbl = &mz_stream_bzip_vtbl;
+ bzip->level = 6;
+ }
+ if (stream != NULL)
+ *stream = bzip;
+
+ return bzip;
+}
+
+void mz_stream_bzip_delete(void **stream) {
+ mz_stream_bzip *bzip = NULL;
+ if (stream == NULL)
+ return;
+ bzip = (mz_stream_bzip *)*stream;
+ if (bzip != NULL)
+ MZ_FREE(bzip);
+ *stream = NULL;
+}
+
+void *mz_stream_bzip_get_interface(void) {
+ return (void *)&mz_stream_bzip_vtbl;
+}
+
+extern void bz_internal_error(int errcode) {
+ MZ_UNUSED(errcode);
+}
diff --git a/Externals/minizip/mz_strm_bzip.h b/Externals/minizip/mz_strm_bzip.h
new file mode 100644
index 0000000000..71b2b380ba
--- /dev/null
+++ b/Externals/minizip/mz_strm_bzip.h
@@ -0,0 +1,45 @@
+/* mz_strm_bzip.h -- Stream for bzip inflate/deflate
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_BZIP_H
+#define MZ_STREAM_BZIP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_bzip_open(void *stream, const char *filename, int32_t mode);
+int32_t mz_stream_bzip_is_open(void *stream);
+int32_t mz_stream_bzip_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_bzip_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_bzip_tell(void *stream);
+int32_t mz_stream_bzip_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_bzip_close(void *stream);
+int32_t mz_stream_bzip_error(void *stream);
+
+int32_t mz_stream_bzip_get_prop_int64(void *stream, int32_t prop, int64_t *value);
+int32_t mz_stream_bzip_set_prop_int64(void *stream, int32_t prop, int64_t value);
+
+void* mz_stream_bzip_create(void **stream);
+void mz_stream_bzip_delete(void **stream);
+
+void* mz_stream_bzip_get_interface(void);
+
+void bz_internal_error(int errcode);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_strm_libcomp.c b/Externals/minizip/mz_strm_libcomp.c
new file mode 100644
index 0000000000..27eb933453
--- /dev/null
+++ b/Externals/minizip/mz_strm_libcomp.c
@@ -0,0 +1,356 @@
+/* mz_strm_libcomp.c -- Stream for apple compression
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_strm.h"
+#include "mz_strm_libcomp.h"
+
+#include <compression.h>
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_libcomp_vtbl = {
+ mz_stream_libcomp_open,
+ mz_stream_libcomp_is_open,
+ mz_stream_libcomp_read,
+ mz_stream_libcomp_write,
+ mz_stream_libcomp_tell,
+ mz_stream_libcomp_seek,
+ mz_stream_libcomp_close,
+ mz_stream_libcomp_error,
+ mz_stream_libcomp_create,
+ mz_stream_libcomp_delete,
+ mz_stream_libcomp_get_prop_int64,
+ mz_stream_libcomp_set_prop_int64
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_libcomp_s {
+ mz_stream stream;
+ compression_stream
+ cstream;
+ uint8_t buffer[INT16_MAX];
+ int32_t buffer_len;
+ int64_t total_in;
+ int64_t total_out;
+ int64_t max_total_in;
+ int8_t initialized;
+ int32_t mode;
+ int32_t error;
+ int16_t method;
+} mz_stream_libcomp;
+
+/***************************************************************************/
+
+int32_t mz_stream_libcomp_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_libcomp *libcomp = (mz_stream_libcomp *)stream;
+ int32_t err = 0;
+ int16_t operation = 0;
+ compression_algorithm algorithm = 0;
+
+ MZ_UNUSED(path);
+
+ if (libcomp->method == 0)
+ return MZ_PARAM_ERROR;
+
+ libcomp->total_in = 0;
+ libcomp->total_out = 0;
+
+ if (mode & MZ_OPEN_MODE_WRITE) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ operation = COMPRESSION_STREAM_ENCODE;
+#endif
+ } else if (mode & MZ_OPEN_MODE_READ) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ operation = COMPRESSION_STREAM_DECODE;
+#endif
+ }
+
+ if (libcomp->method == MZ_COMPRESS_METHOD_DEFLATE)
+ algorithm = COMPRESSION_ZLIB;
+ else if (libcomp->method == MZ_COMPRESS_METHOD_XZ)
+ algorithm = COMPRESSION_LZMA;
+ else
+ return MZ_SUPPORT_ERROR;
+
+ err = compression_stream_init(&libcomp->cstream, (compression_stream_operation)operation, algorithm);
+
+ if (err == COMPRESSION_STATUS_ERROR) {
+ libcomp->error = err;
+ return MZ_OPEN_ERROR;
+ }
+
+ libcomp->initialized = 1;
+ libcomp->mode = mode;
+ return MZ_OK;
+}
+
+int32_t mz_stream_libcomp_is_open(void *stream) {
+ mz_stream_libcomp *libcomp = (mz_stream_libcomp *)stream;
+ if (libcomp->initialized != 1)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_libcomp_read(void *stream, void *buf, int32_t size) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ MZ_UNUSED(stream);
+ MZ_UNUSED(buf);
+ MZ_UNUSED(size);
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_libcomp *libcomp = (mz_stream_libcomp *)stream;
+ uint64_t total_in_before = 0;
+ uint64_t total_in_after = 0;
+ uint64_t total_out_before = 0;
+ uint64_t total_out_after = 0;
+ int32_t total_in = 0;
+ int32_t total_out = 0;
+ int32_t in_bytes = 0;
+ int32_t out_bytes = 0;
+ int32_t bytes_to_read = sizeof(libcomp->buffer);
+ int32_t read = 0;
+ int32_t err = MZ_OK;
+ int16_t flags = 0;
+
+ libcomp->cstream.dst_ptr = buf;
+ libcomp->cstream.dst_size = (size_t)size;
+
+ do {
+ if (libcomp->cstream.src_size == 0) {
+ if (libcomp->max_total_in > 0) {
+ if ((int64_t)bytes_to_read > (libcomp->max_total_in - libcomp->total_in))
+ bytes_to_read = (int32_t)(libcomp->max_total_in - libcomp->total_in);
+ }
+
+ read = mz_stream_read(libcomp->stream.base, libcomp->buffer, bytes_to_read);
+
+ if (read < 0)
+ return read;
+ if (read == 0)
+ flags = COMPRESSION_STREAM_FINALIZE;
+
+ libcomp->cstream.src_ptr = libcomp->buffer;
+ libcomp->cstream.src_size = (size_t)read;
+ }
+
+ total_in_before = libcomp->cstream.src_size;
+ total_out_before = libcomp->cstream.dst_size;
+
+ err = compression_stream_process(&libcomp->cstream, flags);
+ if (err == COMPRESSION_STATUS_ERROR) {
+ libcomp->error = err;
+ break;
+ }
+
+ total_in_after = libcomp->cstream.src_size;
+ total_out_after = libcomp->cstream.dst_size;
+
+ in_bytes = (int32_t)(total_in_before - total_in_after);
+ out_bytes = (int32_t)(total_out_before - total_out_after);
+
+ total_in += in_bytes;
+ total_out += out_bytes;
+
+ libcomp->total_in += in_bytes;
+ libcomp->total_out += out_bytes;
+
+ if (err == COMPRESSION_STATUS_END)
+ break;
+ if (err != COMPRESSION_STATUS_OK) {
+ libcomp->error = err;
+ break;
+ }
+ } while (libcomp->cstream.dst_size > 0);
+
+ if (libcomp->error != 0)
+ return MZ_DATA_ERROR;
+
+ return total_out;
+#endif
+}
+
+static int32_t mz_stream_libcomp_flush(void *stream) {
+ mz_stream_libcomp *libcomp = (mz_stream_libcomp *)stream;
+ if (mz_stream_write(libcomp->stream.base, libcomp->buffer, libcomp->buffer_len) != libcomp->buffer_len)
+ return MZ_WRITE_ERROR;
+ return MZ_OK;
+}
+
+static int32_t mz_stream_libcomp_deflate(void *stream, int flush) {
+ mz_stream_libcomp *libcomp = (mz_stream_libcomp *)stream;
+ uint64_t total_out_before = 0;
+ uint64_t total_out_after = 0;
+ uint32_t out_bytes = 0;
+ int32_t err = MZ_OK;
+
+
+ do {
+ if (libcomp->cstream.dst_size == 0) {
+ err = mz_stream_libcomp_flush(libcomp);
+ if (err != MZ_OK) {
+ libcomp->error = err;
+ return err;
+ }
+
+ libcomp->cstream.dst_size = sizeof(libcomp->buffer);
+ libcomp->cstream.dst_ptr = libcomp->buffer;
+
+ libcomp->buffer_len = 0;
+ }
+
+ total_out_before = libcomp->cstream.dst_size;
+ err = compression_stream_process(&libcomp->cstream, flush);
+ total_out_after = libcomp->cstream.dst_size;
+
+ out_bytes = (uint32_t)(total_out_before - total_out_after);
+
+ libcomp->buffer_len += out_bytes;
+ libcomp->total_out += out_bytes;
+
+ if (err == COMPRESSION_STATUS_END)
+ break;
+ if (err != COMPRESSION_STATUS_OK) {
+ libcomp->error = err;
+ return MZ_DATA_ERROR;
+ }
+ } while ((libcomp->cstream.src_size > 0) || (flush == COMPRESSION_STREAM_FINALIZE && err == COMPRESSION_STATUS_OK));
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_libcomp_write(void *stream, const void *buf, int32_t size) {
+ mz_stream_libcomp *libcomp = (mz_stream_libcomp *)stream;
+ int32_t err = size;
+
+#ifdef MZ_ZIP_NO_COMPRESSION
+ MZ_UNUSED(libcomp);
+ err = MZ_SUPPORT_ERROR;
+#else
+ libcomp->cstream.src_ptr = buf;
+ libcomp->cstream.src_size = (size_t)size;
+
+ mz_stream_libcomp_deflate(stream, 0);
+
+ libcomp->total_in += size;
+#endif
+ return err;
+}
+
+int64_t mz_stream_libcomp_tell(void *stream) {
+ MZ_UNUSED(stream);
+
+ return MZ_TELL_ERROR;
+}
+
+int32_t mz_stream_libcomp_seek(void *stream, int64_t offset, int32_t origin) {
+ MZ_UNUSED(stream);
+ MZ_UNUSED(offset);
+ MZ_UNUSED(origin);
+
+ return MZ_SEEK_ERROR;
+}
+
+int32_t mz_stream_libcomp_close(void *stream) {
+ mz_stream_libcomp *libcomp = (mz_stream_libcomp *)stream;
+
+
+ if (libcomp->mode & MZ_OPEN_MODE_WRITE) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_libcomp_deflate(stream, COMPRESSION_STREAM_FINALIZE);
+ mz_stream_libcomp_flush(stream);
+#endif
+ } else if (libcomp->mode & MZ_OPEN_MODE_READ) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ return MZ_SUPPORT_ERROR;
+#endif
+ }
+
+ compression_stream_destroy(&libcomp->cstream);
+
+ libcomp->initialized = 0;
+
+ if (libcomp->error != MZ_OK)
+ return MZ_CLOSE_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_libcomp_error(void *stream) {
+ mz_stream_libcomp *libcomp = (mz_stream_libcomp *)stream;
+ return libcomp->error;
+}
+
+int32_t mz_stream_libcomp_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
+ mz_stream_libcomp *libcomp = (mz_stream_libcomp *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_IN:
+ *value = libcomp->total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ *value = libcomp->max_total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_OUT:
+ *value = libcomp->total_out;
+ break;
+ case MZ_STREAM_PROP_HEADER_SIZE:
+ *value = 0;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_stream_libcomp_set_prop_int64(void *stream, int32_t prop, int64_t value) {
+ mz_stream_libcomp *libcomp = (mz_stream_libcomp *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_COMPRESS_METHOD:
+ libcomp->method = (int16_t)value;
+ break;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ libcomp->max_total_in = value;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+void *mz_stream_libcomp_create(void **stream) {
+ mz_stream_libcomp *libcomp = NULL;
+
+ libcomp = (mz_stream_libcomp *)MZ_ALLOC(sizeof(mz_stream_libcomp));
+ if (libcomp != NULL) {
+ memset(libcomp, 0, sizeof(mz_stream_libcomp));
+ libcomp->stream.vtbl = &mz_stream_libcomp_vtbl;
+ }
+ if (stream != NULL)
+ *stream = libcomp;
+
+ return libcomp;
+}
+
+void mz_stream_libcomp_delete(void **stream) {
+ mz_stream_libcomp *libcomp = NULL;
+ if (stream == NULL)
+ return;
+ libcomp = (mz_stream_libcomp *)*stream;
+ if (libcomp != NULL)
+ MZ_FREE(libcomp);
+ *stream = NULL;
+}
diff --git a/Externals/minizip/mz_strm_libcomp.h b/Externals/minizip/mz_strm_libcomp.h
new file mode 100644
index 0000000000..5c3fee8df9
--- /dev/null
+++ b/Externals/minizip/mz_strm_libcomp.h
@@ -0,0 +1,45 @@
+/* mz_strm_libcomp.h -- Stream for apple compression
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_LIBCOMP_H
+#define MZ_STREAM_LIBCOMP_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_libcomp_open(void *stream, const char *filename, int32_t mode);
+int32_t mz_stream_libcomp_is_open(void *stream);
+int32_t mz_stream_libcomp_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_libcomp_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_libcomp_tell(void *stream);
+int32_t mz_stream_libcomp_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_libcomp_close(void *stream);
+int32_t mz_stream_libcomp_error(void *stream);
+
+int32_t mz_stream_libcomp_get_prop_int64(void *stream, int32_t prop, int64_t *value);
+int32_t mz_stream_libcomp_set_prop_int64(void *stream, int32_t prop, int64_t value);
+
+void* mz_stream_libcomp_create(void **stream);
+void mz_stream_libcomp_delete(void **stream);
+
+void* mz_stream_libcomp_get_interface(void);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_strm_lzma.c b/Externals/minizip/mz_strm_lzma.c
new file mode 100644
index 0000000000..22fb972ef3
--- /dev/null
+++ b/Externals/minizip/mz_strm_lzma.c
@@ -0,0 +1,470 @@
+/* mz_strm_lzma.c -- Stream for lzma inflate/deflate
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_strm.h"
+#include "mz_strm_lzma.h"
+
+#include "lzma.h"
+
+/***************************************************************************/
+
+#define MZ_LZMA_MAGIC_SIZE (4)
+#define MZ_LZMA_ZIP_HEADER_SIZE (5)
+#define MZ_LZMA_ALONE_HEADER_SIZE (MZ_LZMA_ZIP_HEADER_SIZE + 8)
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_lzma_vtbl = {
+ mz_stream_lzma_open,
+ mz_stream_lzma_is_open,
+ mz_stream_lzma_read,
+ mz_stream_lzma_write,
+ mz_stream_lzma_tell,
+ mz_stream_lzma_seek,
+ mz_stream_lzma_close,
+ mz_stream_lzma_error,
+ mz_stream_lzma_create,
+ mz_stream_lzma_delete,
+ mz_stream_lzma_get_prop_int64,
+ mz_stream_lzma_set_prop_int64
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_lzma_s {
+ mz_stream stream;
+ lzma_stream lstream;
+ int32_t mode;
+ int32_t error;
+ uint8_t buffer[INT16_MAX];
+ int32_t buffer_len;
+ int64_t total_in;
+ int64_t total_out;
+ int64_t max_total_in;
+ int64_t max_total_out;
+ int8_t initialized;
+ int8_t header;
+ int32_t header_size;
+ uint32_t preset;
+ int16_t method;
+} mz_stream_lzma;
+
+/***************************************************************************/
+
+int32_t mz_stream_lzma_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
+ lzma_options_lzma opt_lzma;
+ uint32_t size = 0;
+ uint8_t major = 0;
+ uint8_t minor = 0;
+
+ MZ_UNUSED(path);
+
+ memset(&opt_lzma, 0, sizeof(opt_lzma));
+
+ lzma->lstream.total_in = 0;
+ lzma->lstream.total_out = 0;
+
+ lzma->total_in = 0;
+ lzma->total_out = 0;
+ lzma->header = 0;
+
+ if (mode & MZ_OPEN_MODE_WRITE) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ MZ_UNUSED(filters);
+ MZ_UNUSED(major);
+ MZ_UNUSED(minor);
+ return MZ_SUPPORT_ERROR;
+#else
+ lzma->lstream.next_out = lzma->buffer;
+ lzma->lstream.avail_out = sizeof(lzma->buffer);
+
+ if (lzma_lzma_preset(&opt_lzma, lzma->preset))
+ return MZ_OPEN_ERROR;
+
+ memset(&filters, 0, sizeof(filters));
+
+ if (lzma->method == MZ_COMPRESS_METHOD_LZMA)
+ filters[0].id = LZMA_FILTER_LZMA1;
+ else if (lzma->method == MZ_COMPRESS_METHOD_XZ)
+ filters[0].id = LZMA_FILTER_LZMA2;
+
+ filters[0].options = &opt_lzma;
+ filters[1].id = LZMA_VLI_UNKNOWN;
+
+ lzma_properties_size(&size, (lzma_filter *)&filters);
+
+ if (lzma->method == MZ_COMPRESS_METHOD_LZMA) {
+ mz_stream_write_uint8(lzma->stream.base, LZMA_VERSION_MAJOR);
+ mz_stream_write_uint8(lzma->stream.base, LZMA_VERSION_MINOR);
+ mz_stream_write_uint16(lzma->stream.base, (uint16_t)size);
+
+ lzma->header = 1;
+ lzma->total_out += MZ_LZMA_MAGIC_SIZE;
+
+ lzma->error = lzma_alone_encoder(&lzma->lstream, &opt_lzma);
+ } else if (lzma->method == MZ_COMPRESS_METHOD_XZ)
+ lzma->error = lzma_stream_encoder(&lzma->lstream, filters, LZMA_CHECK_CRC64);
+#endif
+ } else if (mode & MZ_OPEN_MODE_READ) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ MZ_UNUSED(filters);
+ MZ_UNUSED(major);
+ MZ_UNUSED(minor);
+ return MZ_SUPPORT_ERROR;
+#else
+ lzma->lstream.next_in = lzma->buffer;
+ lzma->lstream.avail_in = 0;
+
+ if (lzma->method == MZ_COMPRESS_METHOD_LZMA) {
+ mz_stream_read_uint8(lzma->stream.base, &major);
+ mz_stream_read_uint8(lzma->stream.base, &minor);
+ mz_stream_read_uint16(lzma->stream.base, (uint16_t *)&size);
+
+ lzma->header = 1;
+ lzma->total_in += MZ_LZMA_MAGIC_SIZE;
+
+ lzma->error = lzma_alone_decoder(&lzma->lstream, UINT64_MAX);
+ } else if (lzma->method == MZ_COMPRESS_METHOD_XZ)
+ lzma->error = lzma_stream_decoder(&lzma->lstream, UINT64_MAX, 0);
+#endif
+ }
+
+ if (lzma->error != LZMA_OK)
+ return MZ_OPEN_ERROR;
+
+ lzma->initialized = 1;
+ lzma->mode = mode;
+ return MZ_OK;
+}
+
+int32_t mz_stream_lzma_is_open(void *stream) {
+ mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
+ if (lzma->initialized != 1)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_lzma_read(void *stream, void *buf, int32_t size) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ MZ_UNUSED(stream);
+ MZ_UNUSED(buf);
+ MZ_UNUSED(size);
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
+ uint64_t total_in_before = 0;
+ uint64_t total_out_before = 0;
+ uint64_t total_in_after = 0;
+ uint64_t total_out_after = 0;
+ int32_t total_in = 0;
+ int32_t total_out = 0;
+ int32_t in_bytes = 0;
+ int32_t out_bytes = 0;
+ int32_t bytes_to_read = sizeof(lzma->buffer);
+ int32_t read = 0;
+ int32_t err = LZMA_OK;
+
+
+ lzma->lstream.next_out = (uint8_t*)buf;
+ lzma->lstream.avail_out = (size_t)size;
+
+ do {
+ if (lzma->lstream.avail_in == 0) {
+ if (lzma->max_total_in > 0) {
+ if ((int64_t)bytes_to_read > (lzma->max_total_in - lzma->total_in))
+ bytes_to_read = (int32_t)(lzma->max_total_in - lzma->total_in);
+ }
+
+ if (lzma->header) {
+ bytes_to_read = MZ_LZMA_ZIP_HEADER_SIZE - lzma->header_size;
+ }
+
+ read = mz_stream_read(lzma->stream.base, lzma->buffer, bytes_to_read);
+
+ if (read < 0)
+ return read;
+
+ /* Write uncompressed size for lzma alone header not in zip format */
+ if (lzma->header) {
+ lzma->header_size += read;
+
+ if (lzma->header_size == MZ_LZMA_ZIP_HEADER_SIZE) {
+ uint64_t uncompressed_size = UINT64_MAX;
+
+ memcpy(lzma->buffer + MZ_LZMA_ZIP_HEADER_SIZE, &uncompressed_size, sizeof(uncompressed_size));
+
+ read += sizeof(uncompressed_size);
+ bytes_to_read = sizeof(lzma->buffer);
+
+ lzma->total_in -= sizeof(uncompressed_size);
+ lzma->header = 0;
+ }
+ }
+
+ lzma->lstream.next_in = lzma->buffer;
+ lzma->lstream.avail_in = (size_t)read;
+ }
+
+ total_in_before = lzma->lstream.avail_in;
+ total_out_before = lzma->lstream.total_out;
+
+ err = lzma_code(&lzma->lstream, LZMA_RUN);
+
+ total_in_after = lzma->lstream.avail_in;
+ total_out_after = lzma->lstream.total_out;
+ if ((lzma->max_total_out != -1) && (int64_t)total_out_after > lzma->max_total_out)
+ total_out_after = (uint64_t)lzma->max_total_out;
+
+ in_bytes = (int32_t)(total_in_before - total_in_after);
+ out_bytes = (int32_t)(total_out_after - total_out_before);
+
+ total_in += in_bytes;
+ total_out += out_bytes;
+
+ lzma->total_in += in_bytes;
+ lzma->total_out += out_bytes;
+
+ if (err == LZMA_STREAM_END)
+ break;
+ if (err != LZMA_OK) {
+ lzma->error = err;
+ break;
+ }
+ } while (lzma->lstream.avail_out > 0);
+
+ if (lzma->error != 0)
+ return MZ_DATA_ERROR;
+
+ return total_out;
+#endif
+}
+
+#ifndef MZ_ZIP_NO_COMPRESSION
+static int32_t mz_stream_lzma_flush(void *stream) {
+ mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
+ int32_t buffer_len = lzma->buffer_len;
+ uint8_t *buffer = lzma->buffer;
+
+ /* Skip writing lzma_alone header uncompressed size for zip format */
+ if (lzma->header) {
+ uint64_t uncompressed_size = 0;
+
+ if (lzma->buffer_len < MZ_LZMA_ALONE_HEADER_SIZE)
+ return MZ_OK;
+
+ if (mz_stream_write(lzma->stream.base, buffer, MZ_LZMA_ZIP_HEADER_SIZE) != MZ_LZMA_ZIP_HEADER_SIZE)
+ return MZ_WRITE_ERROR;
+
+ buffer += MZ_LZMA_ALONE_HEADER_SIZE;
+ buffer_len -= MZ_LZMA_ALONE_HEADER_SIZE;
+
+ lzma->buffer_len -= sizeof(uncompressed_size);
+ lzma->total_out -= sizeof(uncompressed_size);
+ lzma->header = 0;
+ }
+
+ if (mz_stream_write(lzma->stream.base, buffer, buffer_len) != buffer_len)
+ return MZ_WRITE_ERROR;
+
+ return MZ_OK;
+}
+
+static int32_t mz_stream_lzma_code(void *stream, int32_t flush) {
+ mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
+ uint64_t total_out_before = 0;
+ uint64_t total_out_after = 0;
+ uint32_t out_bytes = 0;
+ int32_t err = LZMA_OK;
+
+
+ do {
+ if (lzma->lstream.avail_out == 0) {
+ err = mz_stream_lzma_flush(lzma);
+ if (err != MZ_OK)
+ return err;
+
+ lzma->lstream.avail_out = sizeof(lzma->buffer);
+ lzma->lstream.next_out = lzma->buffer;
+
+ lzma->buffer_len = 0;
+ }
+
+ total_out_before = lzma->lstream.total_out;
+ err = lzma_code(&lzma->lstream, (lzma_action)flush);
+ total_out_after = lzma->lstream.total_out;
+
+ out_bytes = (uint32_t)(total_out_after - total_out_before);
+
+ if (err != LZMA_OK && err != LZMA_STREAM_END) {
+ lzma->error = err;
+ return MZ_DATA_ERROR;
+ }
+
+ lzma->buffer_len += out_bytes;
+ lzma->total_out += out_bytes;
+ } while ((lzma->lstream.avail_in > 0) || (flush == LZMA_FINISH && err == LZMA_OK));
+
+ return MZ_OK;
+}
+#endif
+
+int32_t mz_stream_lzma_write(void *stream, const void *buf, int32_t size) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ MZ_UNUSED(stream);
+ MZ_UNUSED(buf);
+ MZ_UNUSED(size);
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
+ int32_t err = MZ_OK;
+
+ lzma->lstream.next_in = (uint8_t*)(intptr_t)buf;
+ lzma->lstream.avail_in = (size_t)size;
+
+ err = mz_stream_lzma_code(stream, LZMA_RUN);
+ if (err != MZ_OK) {
+ return err;
+ }
+
+ lzma->total_in += size;
+ return size;
+#endif
+}
+
+int64_t mz_stream_lzma_tell(void *stream) {
+ MZ_UNUSED(stream);
+
+ return MZ_TELL_ERROR;
+}
+
+int32_t mz_stream_lzma_seek(void *stream, int64_t offset, int32_t origin) {
+ MZ_UNUSED(stream);
+ MZ_UNUSED(offset);
+ MZ_UNUSED(origin);
+
+ return MZ_SEEK_ERROR;
+}
+
+int32_t mz_stream_lzma_close(void *stream) {
+ mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
+
+ if (lzma->mode & MZ_OPEN_MODE_WRITE) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_lzma_code(stream, LZMA_FINISH);
+ mz_stream_lzma_flush(stream);
+
+ lzma_end(&lzma->lstream);
+#endif
+ } else if (lzma->mode & MZ_OPEN_MODE_READ) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ lzma_end(&lzma->lstream);
+#endif
+ }
+
+ lzma->initialized = 0;
+
+ if (lzma->error != LZMA_OK)
+ return MZ_CLOSE_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_lzma_error(void *stream) {
+ mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
+ return lzma->error;
+}
+
+int32_t mz_stream_lzma_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
+ mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_IN:
+ *value = lzma->total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ *value = lzma->max_total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_OUT:
+ *value = lzma->total_out;
+ break;
+ case MZ_STREAM_PROP_TOTAL_OUT_MAX:
+ *value = lzma->max_total_out;
+ break;
+ case MZ_STREAM_PROP_HEADER_SIZE:
+ *value = MZ_LZMA_MAGIC_SIZE;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_stream_lzma_set_prop_int64(void *stream, int32_t prop, int64_t value) {
+ mz_stream_lzma *lzma = (mz_stream_lzma *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_COMPRESS_LEVEL:
+ if (value >= 9)
+ lzma->preset = LZMA_PRESET_EXTREME;
+ else
+ lzma->preset = LZMA_PRESET_DEFAULT;
+ break;
+ case MZ_STREAM_PROP_COMPRESS_METHOD:
+ lzma->method = (int16_t)value;
+ break;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ lzma->max_total_in = value;
+ break;
+ case MZ_STREAM_PROP_TOTAL_OUT_MAX:
+ if (value < -1)
+ return MZ_PARAM_ERROR;
+ lzma->max_total_out = value;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+void *mz_stream_lzma_create(void **stream) {
+ mz_stream_lzma *lzma = NULL;
+
+ lzma = (mz_stream_lzma *)MZ_ALLOC(sizeof(mz_stream_lzma));
+ if (lzma != NULL) {
+ memset(lzma, 0, sizeof(mz_stream_lzma));
+ lzma->stream.vtbl = &mz_stream_lzma_vtbl;
+ lzma->method = MZ_COMPRESS_METHOD_LZMA;
+ lzma->preset = LZMA_PRESET_DEFAULT;
+ lzma->max_total_out = -1;
+ }
+ if (stream != NULL)
+ *stream = lzma;
+
+ return lzma;
+}
+
+void mz_stream_lzma_delete(void **stream) {
+ mz_stream_lzma *lzma = NULL;
+ if (stream == NULL)
+ return;
+ lzma = (mz_stream_lzma *)*stream;
+ if (lzma != NULL)
+ MZ_FREE(lzma);
+ *stream = NULL;
+}
+
+void *mz_stream_lzma_get_interface(void) {
+ return (void *)&mz_stream_lzma_vtbl;
+}
diff --git a/Externals/minizip/mz_strm_lzma.h b/Externals/minizip/mz_strm_lzma.h
new file mode 100644
index 0000000000..f447baa65c
--- /dev/null
+++ b/Externals/minizip/mz_strm_lzma.h
@@ -0,0 +1,43 @@
+/* mz_strm_lzma.h -- Stream for lzma inflate/deflate
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as lzma.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_LZMA_H
+#define MZ_STREAM_LZMA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_lzma_open(void *stream, const char *filename, int32_t mode);
+int32_t mz_stream_lzma_is_open(void *stream);
+int32_t mz_stream_lzma_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_lzma_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_lzma_tell(void *stream);
+int32_t mz_stream_lzma_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_lzma_close(void *stream);
+int32_t mz_stream_lzma_error(void *stream);
+
+int32_t mz_stream_lzma_get_prop_int64(void *stream, int32_t prop, int64_t *value);
+int32_t mz_stream_lzma_set_prop_int64(void *stream, int32_t prop, int64_t value);
+
+void* mz_stream_lzma_create(void **stream);
+void mz_stream_lzma_delete(void **stream);
+
+void* mz_stream_lzma_get_interface(void);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_strm_mem.c b/Externals/minizip/mz_strm_mem.c
new file mode 100644
index 0000000000..f4a882d928
--- /dev/null
+++ b/Externals/minizip/mz_strm_mem.c
@@ -0,0 +1,272 @@
+/* mz_strm_mem.c -- Stream for memory access
+ part of the minizip-ng project
+
+ This interface is designed to access memory rather than files.
+ We do use a region of memory to put data in to and take it out of.
+
+ Based on Unzip ioapi.c version 0.22, May 19th, 2003
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Copyright (C) 2003 Justin Fletcher
+ Copyright (C) 1998-2003 Gilles Vollant
+ https://www.winimage.com/zLibDll/minizip.html
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_strm.h"
+#include "mz_strm_mem.h"
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_mem_vtbl = {
+ mz_stream_mem_open,
+ mz_stream_mem_is_open,
+ mz_stream_mem_read,
+ mz_stream_mem_write,
+ mz_stream_mem_tell,
+ mz_stream_mem_seek,
+ mz_stream_mem_close,
+ mz_stream_mem_error,
+ mz_stream_mem_create,
+ mz_stream_mem_delete,
+ NULL,
+ NULL
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_mem_s {
+ mz_stream stream;
+ int32_t mode;
+ uint8_t *buffer; /* Memory buffer pointer */
+ int32_t size; /* Size of the memory buffer */
+ int32_t limit; /* Furthest we've written */
+ int32_t position; /* Current position in the memory */
+ int32_t grow_size; /* Size to grow when full */
+} mz_stream_mem;
+
+/***************************************************************************/
+
+static int32_t mz_stream_mem_set_size(void *stream, int32_t size) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ int32_t new_size = size;
+ uint8_t *new_buf = NULL;
+
+
+ new_buf = (uint8_t *)MZ_ALLOC((uint32_t)new_size);
+ if (new_buf == NULL)
+ return MZ_BUF_ERROR;
+
+ if (mem->buffer) {
+ memcpy(new_buf, mem->buffer, mem->size);
+ MZ_FREE(mem->buffer);
+ }
+
+ mem->buffer = new_buf;
+ mem->size = new_size;
+ return MZ_OK;
+}
+
+int32_t mz_stream_mem_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ int32_t err = MZ_OK;
+
+ MZ_UNUSED(path);
+
+ mem->mode = mode;
+ mem->limit = 0;
+ mem->position = 0;
+
+ if (mem->mode & MZ_OPEN_MODE_CREATE)
+ err = mz_stream_mem_set_size(stream, mem->grow_size);
+ else
+ mem->limit = mem->size;
+
+ return err;
+}
+
+int32_t mz_stream_mem_is_open(void *stream) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ if (mem->buffer == NULL)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_mem_read(void *stream, void *buf, int32_t size) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+
+ if (size > mem->size - mem->position)
+ size = mem->size - mem->position;
+ if (mem->position + size > mem->limit)
+ size = mem->limit - mem->position;
+
+ if (size <= 0)
+ return 0;
+
+ memcpy(buf, mem->buffer + mem->position, size);
+ mem->position += size;
+
+ return size;
+}
+
+int32_t mz_stream_mem_write(void *stream, const void *buf, int32_t size) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ int32_t new_size = 0;
+ int32_t err = MZ_OK;
+
+ if (size == 0)
+ return size;
+
+ if (size > mem->size - mem->position) {
+ if (mem->mode & MZ_OPEN_MODE_CREATE) {
+ new_size = mem->size;
+ if (size < mem->grow_size)
+ new_size += mem->grow_size;
+ else
+ new_size += size;
+
+ err = mz_stream_mem_set_size(stream, new_size);
+ if (err != MZ_OK)
+ return err;
+ } else {
+ size = mem->size - mem->position;
+ }
+ }
+
+ memcpy(mem->buffer + mem->position, buf, size);
+
+ mem->position += size;
+ if (mem->position > mem->limit)
+ mem->limit = mem->position;
+
+ return size;
+}
+
+int64_t mz_stream_mem_tell(void *stream) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ return mem->position;
+}
+
+int32_t mz_stream_mem_seek(void *stream, int64_t offset, int32_t origin) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ int64_t new_pos = 0;
+ int32_t err = MZ_OK;
+
+ switch (origin) {
+ case MZ_SEEK_CUR:
+ new_pos = mem->position + offset;
+ break;
+ case MZ_SEEK_END:
+ new_pos = mem->limit + offset;
+ break;
+ case MZ_SEEK_SET:
+ new_pos = offset;
+ break;
+ default:
+ return MZ_SEEK_ERROR;
+ }
+
+ if (new_pos > mem->size) {
+ if ((mem->mode & MZ_OPEN_MODE_CREATE) == 0)
+ return MZ_SEEK_ERROR;
+
+ err = mz_stream_mem_set_size(stream, (int32_t)new_pos);
+ if (err != MZ_OK)
+ return err;
+ } else if (new_pos < 0) {
+ return MZ_SEEK_ERROR;
+ }
+
+ mem->position = (int32_t)new_pos;
+ return MZ_OK;
+}
+
+int32_t mz_stream_mem_close(void *stream) {
+ MZ_UNUSED(stream);
+
+ /* We never return errors */
+ return MZ_OK;
+}
+
+int32_t mz_stream_mem_error(void *stream) {
+ MZ_UNUSED(stream);
+
+ /* We never return errors */
+ return MZ_OK;
+}
+
+void mz_stream_mem_set_buffer(void *stream, void *buf, int32_t size) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ mem->buffer = (uint8_t *)buf;
+ mem->size = size;
+ mem->limit = size;
+}
+
+int32_t mz_stream_mem_get_buffer(void *stream, const void **buf) {
+ return mz_stream_mem_get_buffer_at(stream, 0, buf);
+}
+
+int32_t mz_stream_mem_get_buffer_at(void *stream, int64_t position, const void **buf) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ if (buf == NULL || position < 0 || mem->size < position || mem->buffer == NULL)
+ return MZ_SEEK_ERROR;
+ *buf = mem->buffer + position;
+ return MZ_OK;
+}
+
+int32_t mz_stream_mem_get_buffer_at_current(void *stream, const void **buf) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ return mz_stream_mem_get_buffer_at(stream, mem->position, buf);
+}
+
+void mz_stream_mem_get_buffer_length(void *stream, int32_t *length) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ *length = mem->limit;
+}
+
+void mz_stream_mem_set_buffer_limit(void *stream, int32_t limit) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ mem->limit = limit;
+}
+
+void mz_stream_mem_set_grow_size(void *stream, int32_t grow_size) {
+ mz_stream_mem *mem = (mz_stream_mem *)stream;
+ mem->grow_size = grow_size;
+}
+
+void *mz_stream_mem_create(void **stream) {
+ mz_stream_mem *mem = NULL;
+
+ mem = (mz_stream_mem *)MZ_ALLOC(sizeof(mz_stream_mem));
+ if (mem != NULL) {
+ memset(mem, 0, sizeof(mz_stream_mem));
+ mem->stream.vtbl = &mz_stream_mem_vtbl;
+ mem->grow_size = 4096;
+ }
+ if (stream != NULL)
+ *stream = mem;
+
+ return mem;
+}
+
+void mz_stream_mem_delete(void **stream) {
+ mz_stream_mem *mem = NULL;
+ if (stream == NULL)
+ return;
+ mem = (mz_stream_mem *)*stream;
+ if (mem != NULL) {
+ if ((mem->mode & MZ_OPEN_MODE_CREATE) && (mem->buffer != NULL))
+ MZ_FREE(mem->buffer);
+ MZ_FREE(mem);
+ }
+ *stream = NULL;
+}
+
+void *mz_stream_mem_get_interface(void) {
+ return (void *)&mz_stream_mem_vtbl;
+}
diff --git a/Externals/minizip/mz_strm_mem.h b/Externals/minizip/mz_strm_mem.h
new file mode 100644
index 0000000000..5bfa13d8a6
--- /dev/null
+++ b/Externals/minizip/mz_strm_mem.h
@@ -0,0 +1,48 @@
+/* mz_strm_mem.h -- Stream for memory access
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_MEM_H
+#define MZ_STREAM_MEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_mem_open(void *stream, const char *filename, int32_t mode);
+int32_t mz_stream_mem_is_open(void *stream);
+int32_t mz_stream_mem_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_mem_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_mem_tell(void *stream);
+int32_t mz_stream_mem_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_mem_close(void *stream);
+int32_t mz_stream_mem_error(void *stream);
+
+void mz_stream_mem_set_buffer(void *stream, void *buf, int32_t size);
+int32_t mz_stream_mem_get_buffer(void *stream, const void **buf);
+int32_t mz_stream_mem_get_buffer_at(void *stream, int64_t position, const void **buf);
+int32_t mz_stream_mem_get_buffer_at_current(void *stream, const void **buf);
+void mz_stream_mem_get_buffer_length(void *stream, int32_t *length);
+void mz_stream_mem_set_buffer_limit(void *stream, int32_t limit);
+void mz_stream_mem_set_grow_size(void *stream, int32_t grow_size);
+
+void* mz_stream_mem_create(void **stream);
+void mz_stream_mem_delete(void **stream);
+
+void* mz_stream_mem_get_interface(void);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_strm_os.h b/Externals/minizip/mz_strm_os.h
new file mode 100644
index 0000000000..614e255207
--- /dev/null
+++ b/Externals/minizip/mz_strm_os.h
@@ -0,0 +1,40 @@
+/* mz_sstrm_os.h -- Stream for filesystem access
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_OS_H
+#define MZ_STREAM_OS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_os_open(void *stream, const char *path, int32_t mode);
+int32_t mz_stream_os_is_open(void *stream);
+int32_t mz_stream_os_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_os_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_os_tell(void *stream);
+int32_t mz_stream_os_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_os_close(void *stream);
+int32_t mz_stream_os_error(void *stream);
+
+void* mz_stream_os_create(void **stream);
+void mz_stream_os_delete(void **stream);
+
+void* mz_stream_os_get_interface(void);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_strm_os_posix.c b/Externals/minizip/mz_strm_os_posix.c
new file mode 100644
index 0000000000..f0b5bd3351
--- /dev/null
+++ b/Externals/minizip/mz_strm_os_posix.c
@@ -0,0 +1,206 @@
+/* mz_strm_posix.c -- Stream for filesystem access for posix/linux
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson
+ http://result42.com
+ Copyright (C) 1998-2010 Gilles Vollant
+ https://www.winimage.com/zLibDll/minizip.html
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_strm.h"
+#include "mz_strm_os.h"
+
+#include <stdio.h> /* fopen, fread.. */
+#include <errno.h>
+
+/***************************************************************************/
+
+#define fopen64 fopen
+#ifndef MZ_FILE32_API
+# ifndef NO_FSEEKO
+# define ftello64 ftello
+# define fseeko64 fseeko
+# elif defined(_MSC_VER) && (_MSC_VER >= 1400)
+# define ftello64 _ftelli64
+# define fseeko64 _fseeki64
+# endif
+#endif
+#ifndef ftello64
+# define ftello64 ftell
+#endif
+#ifndef fseeko64
+# define fseeko64 fseek
+#endif
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_os_vtbl = {
+ mz_stream_os_open,
+ mz_stream_os_is_open,
+ mz_stream_os_read,
+ mz_stream_os_write,
+ mz_stream_os_tell,
+ mz_stream_os_seek,
+ mz_stream_os_close,
+ mz_stream_os_error,
+ mz_stream_os_create,
+ mz_stream_os_delete,
+ NULL,
+ NULL
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_posix_s {
+ mz_stream stream;
+ int32_t error;
+ FILE *handle;
+} mz_stream_posix;
+
+/***************************************************************************/
+
+int32_t mz_stream_os_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_posix *posix = (mz_stream_posix *)stream;
+ const char *mode_fopen = NULL;
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+
+ if ((mode & MZ_OPEN_MODE_READWRITE) == MZ_OPEN_MODE_READ)
+ mode_fopen = "rb";
+ else if (mode & MZ_OPEN_MODE_APPEND)
+ mode_fopen = "r+b";
+ else if (mode & MZ_OPEN_MODE_CREATE)
+ mode_fopen = "wb";
+ else
+ return MZ_OPEN_ERROR;
+
+ posix->handle = fopen64(path, mode_fopen);
+ if (posix->handle == NULL) {
+ posix->error = errno;
+ return MZ_OPEN_ERROR;
+ }
+
+ if (mode & MZ_OPEN_MODE_APPEND)
+ return mz_stream_os_seek(stream, 0, MZ_SEEK_END);
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_os_is_open(void *stream) {
+ mz_stream_posix *posix = (mz_stream_posix*)stream;
+ if (posix->handle == NULL)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_os_read(void *stream, void *buf, int32_t size) {
+ mz_stream_posix *posix = (mz_stream_posix*)stream;
+ int32_t read = (int32_t)fread(buf, 1, (size_t)size, posix->handle);
+ if (read < size && ferror(posix->handle)) {
+ posix->error = errno;
+ return MZ_READ_ERROR;
+ }
+ return read;
+}
+
+int32_t mz_stream_os_write(void *stream, const void *buf, int32_t size) {
+ mz_stream_posix *posix = (mz_stream_posix*)stream;
+ int32_t written = (int32_t)fwrite(buf, 1, (size_t)size, posix->handle);
+ if (written < size && ferror(posix->handle)) {
+ posix->error = errno;
+ return MZ_WRITE_ERROR;
+ }
+ return written;
+}
+
+int64_t mz_stream_os_tell(void *stream) {
+ mz_stream_posix *posix = (mz_stream_posix*)stream;
+ int64_t position = ftello64(posix->handle);
+ if (position == -1) {
+ posix->error = errno;
+ return MZ_TELL_ERROR;
+ }
+ return position;
+}
+
+int32_t mz_stream_os_seek(void *stream, int64_t offset, int32_t origin) {
+ mz_stream_posix *posix = (mz_stream_posix*)stream;
+ int32_t fseek_origin = 0;
+
+ switch (origin) {
+ case MZ_SEEK_CUR:
+ fseek_origin = SEEK_CUR;
+ break;
+ case MZ_SEEK_END:
+ fseek_origin = SEEK_END;
+ break;
+ case MZ_SEEK_SET:
+ fseek_origin = SEEK_SET;
+ break;
+ default:
+ return MZ_SEEK_ERROR;
+ }
+
+ if (fseeko64(posix->handle, offset, fseek_origin) != 0) {
+ posix->error = errno;
+ return MZ_SEEK_ERROR;
+ }
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_os_close(void *stream) {
+ mz_stream_posix *posix = (mz_stream_posix*)stream;
+ int32_t closed = 0;
+ if (posix->handle != NULL) {
+ closed = fclose(posix->handle);
+ posix->handle = NULL;
+ }
+ if (closed != 0) {
+ posix->error = errno;
+ return MZ_CLOSE_ERROR;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_stream_os_error(void *stream) {
+ mz_stream_posix *posix = (mz_stream_posix*)stream;
+ return posix->error;
+}
+
+void *mz_stream_os_create(void **stream) {
+ mz_stream_posix *posix = NULL;
+
+ posix = (mz_stream_posix *)MZ_ALLOC(sizeof(mz_stream_posix));
+ if (posix != NULL) {
+ memset(posix, 0, sizeof(mz_stream_posix));
+ posix->stream.vtbl = &mz_stream_os_vtbl;
+ }
+ if (stream != NULL)
+ *stream = posix;
+
+ return posix;
+}
+
+void mz_stream_os_delete(void **stream) {
+ mz_stream_posix *posix = NULL;
+ if (stream == NULL)
+ return;
+ posix = (mz_stream_posix *)*stream;
+ if (posix != NULL)
+ MZ_FREE(posix);
+ *stream = NULL;
+}
+
+void *mz_stream_os_get_interface(void) {
+ return (void *)&mz_stream_os_vtbl;
+}
diff --git a/Externals/minizip/mz_strm_os_win32.c b/Externals/minizip/mz_strm_os_win32.c
new file mode 100644
index 0000000000..893df54183
--- /dev/null
+++ b/Externals/minizip/mz_strm_os_win32.c
@@ -0,0 +1,296 @@
+/* mz_strm_win32.c -- Stream for filesystem access for windows
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Copyright (C) 2009-2010 Mathias Svensson
+ Modifications for Zip64 support
+ http://result42.com
+ Copyright (C) 1998-2010 Gilles Vollant
+ https://www.winimage.com/zLibDll/minizip.html
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_os.h"
+#include "mz_strm.h"
+#include "mz_strm_os.h"
+
+#include <windows.h>
+
+/***************************************************************************/
+
+#ifndef INVALID_HANDLE_VALUE
+# define INVALID_HANDLE_VALUE (0xFFFFFFFF)
+#endif
+
+#ifndef INVALID_SET_FILE_POINTER
+# define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+
+#if defined(WINAPI_FAMILY_ONE_PARTITION) && !defined(MZ_WINRT_API)
+# if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP)
+# define MZ_WINRT_API 1
+# endif
+#endif
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_os_vtbl = {
+ mz_stream_os_open,
+ mz_stream_os_is_open,
+ mz_stream_os_read,
+ mz_stream_os_write,
+ mz_stream_os_tell,
+ mz_stream_os_seek,
+ mz_stream_os_close,
+ mz_stream_os_error,
+ mz_stream_os_create,
+ mz_stream_os_delete,
+ NULL,
+ NULL
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_win32_s {
+ mz_stream stream;
+ HANDLE handle;
+ int32_t error;
+} mz_stream_win32;
+
+/***************************************************************************/
+
+#if 0
+# define mz_stream_os_print printf
+#else
+# define mz_stream_os_print(fmt,...)
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_os_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+ uint32_t desired_access = 0;
+ uint32_t creation_disposition = 0;
+ uint32_t share_mode = FILE_SHARE_READ;
+ uint32_t flags_attribs = FILE_ATTRIBUTE_NORMAL;
+ wchar_t *path_wide = NULL;
+
+
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+
+ /* Some use cases require write sharing as well */
+ share_mode |= FILE_SHARE_WRITE;
+
+ if ((mode & MZ_OPEN_MODE_READWRITE) == MZ_OPEN_MODE_READ) {
+ desired_access = GENERIC_READ;
+ creation_disposition = OPEN_EXISTING;
+ } else if (mode & MZ_OPEN_MODE_APPEND) {
+ desired_access = GENERIC_WRITE | GENERIC_READ;
+ creation_disposition = OPEN_EXISTING;
+ } else if (mode & MZ_OPEN_MODE_CREATE) {
+ desired_access = GENERIC_WRITE | GENERIC_READ;
+ creation_disposition = CREATE_ALWAYS;
+ } else {
+ return MZ_PARAM_ERROR;
+ }
+
+ mz_stream_os_print("Win32 - Open - %s (mode %" PRId32 ")\n", path);
+
+ path_wide = mz_os_unicode_string_create(path, MZ_ENCODING_UTF8);
+ if (path_wide == NULL)
+ return MZ_PARAM_ERROR;
+
+#ifdef MZ_WINRT_API
+ win32->handle = CreateFile2(path_wide, desired_access, share_mode,
+ creation_disposition, NULL);
+#else
+ win32->handle = CreateFileW(path_wide, desired_access, share_mode, NULL,
+ creation_disposition, flags_attribs, NULL);
+#endif
+
+ mz_os_unicode_string_delete(&path_wide);
+
+ if (mz_stream_os_is_open(stream) != MZ_OK) {
+ win32->error = GetLastError();
+ return MZ_OPEN_ERROR;
+ }
+
+ if (mode & MZ_OPEN_MODE_APPEND)
+ return mz_stream_os_seek(stream, 0, MZ_SEEK_END);
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_os_is_open(void *stream) {
+ mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+ if (win32->handle == NULL || win32->handle == INVALID_HANDLE_VALUE)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_os_read(void *stream, void *buf, int32_t size) {
+ mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+ uint32_t read = 0;
+
+ if (mz_stream_os_is_open(stream) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ if (!ReadFile(win32->handle, buf, size, (DWORD *)&read, NULL)) {
+ win32->error = GetLastError();
+ if (win32->error == ERROR_HANDLE_EOF)
+ win32->error = 0;
+ }
+
+ mz_stream_os_print("Win32 - Read - %" PRId32 "\n", read);
+
+ return read;
+}
+
+int32_t mz_stream_os_write(void *stream, const void *buf, int32_t size) {
+ mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+ int32_t written = 0;
+
+ if (mz_stream_os_is_open(stream) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ if (!WriteFile(win32->handle, buf, size, (DWORD *)&written, NULL)) {
+ win32->error = GetLastError();
+ if (win32->error == ERROR_HANDLE_EOF)
+ win32->error = 0;
+ }
+
+ mz_stream_os_print("Win32 - Write - %" PRId32 "\n", written);
+
+ return written;
+}
+
+static int32_t mz_stream_os_seekinternal(HANDLE handle, LARGE_INTEGER large_pos,
+ LARGE_INTEGER *new_pos, uint32_t move_method) {
+#ifdef MZ_WINRT_API
+ BOOL success = FALSE;
+ success = SetFilePointerEx(handle, large_pos, new_pos, move_method);
+ if ((success == FALSE) && (GetLastError() != NO_ERROR))
+ return MZ_SEEK_ERROR;
+
+ return MZ_OK;
+#else
+ LONG high_part = 0;
+ uint32_t pos = 0;
+
+ high_part = large_pos.HighPart;
+ pos = SetFilePointer(handle, large_pos.LowPart, &high_part, move_method);
+
+ if ((pos == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR))
+ return MZ_SEEK_ERROR;
+
+ if (new_pos != NULL) {
+ new_pos->LowPart = pos;
+ new_pos->HighPart = high_part;
+ }
+
+ return MZ_OK;
+#endif
+}
+
+int64_t mz_stream_os_tell(void *stream) {
+ mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+ LARGE_INTEGER large_pos;
+
+ if (mz_stream_os_is_open(stream) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ large_pos.QuadPart = 0;
+
+ if (mz_stream_os_seekinternal(win32->handle, large_pos, &large_pos, FILE_CURRENT) != MZ_OK)
+ win32->error = GetLastError();
+
+ mz_stream_os_print("Win32 - Tell - %" PRId64 "\n", large_pos.QuadPart);
+
+ return large_pos.QuadPart;
+}
+
+int32_t mz_stream_os_seek(void *stream, int64_t offset, int32_t origin) {
+ mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+ uint32_t move_method = 0xFFFFFFFF;
+ int32_t err = MZ_OK;
+ LARGE_INTEGER large_pos;
+
+
+ if (mz_stream_os_is_open(stream) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ switch (origin) {
+ case MZ_SEEK_CUR:
+ move_method = FILE_CURRENT;
+ break;
+ case MZ_SEEK_END:
+ move_method = FILE_END;
+ break;
+ case MZ_SEEK_SET:
+ move_method = FILE_BEGIN;
+ break;
+ default:
+ return MZ_SEEK_ERROR;
+ }
+
+ mz_stream_os_print("Win32 - Seek - %" PRId64 " (origin %" PRId32 ")\n", offset, origin);
+
+ large_pos.QuadPart = offset;
+
+ err = mz_stream_os_seekinternal(win32->handle, large_pos, NULL, move_method);
+ if (err != MZ_OK) {
+ win32->error = GetLastError();
+ return err;
+ }
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_os_close(void *stream) {
+ mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+
+ if (win32->handle != NULL)
+ CloseHandle(win32->handle);
+ mz_stream_os_print("Win32 - Close\n");
+ win32->handle = NULL;
+ return MZ_OK;
+}
+
+int32_t mz_stream_os_error(void *stream) {
+ mz_stream_win32 *win32 = (mz_stream_win32 *)stream;
+ return win32->error;
+}
+
+void *mz_stream_os_create(void **stream) {
+ mz_stream_win32 *win32 = NULL;
+
+ win32 = (mz_stream_win32 *)MZ_ALLOC(sizeof(mz_stream_win32));
+ if (win32 != NULL) {
+ memset(win32, 0, sizeof(mz_stream_win32));
+ win32->stream.vtbl = &mz_stream_os_vtbl;
+ }
+ if (stream != NULL)
+ *stream = win32;
+
+ return win32;
+}
+
+void mz_stream_os_delete(void **stream) {
+ mz_stream_win32 *win32 = NULL;
+ if (stream == NULL)
+ return;
+ win32 = (mz_stream_win32 *)*stream;
+ if (win32 != NULL)
+ MZ_FREE(win32);
+ *stream = NULL;
+}
+
+void *mz_stream_os_get_interface(void) {
+ return (void *)&mz_stream_os_vtbl;
+}
diff --git a/Externals/minizip/mz_strm_pkcrypt.c b/Externals/minizip/mz_strm_pkcrypt.c
new file mode 100644
index 0000000000..41c762f9c0
--- /dev/null
+++ b/Externals/minizip/mz_strm_pkcrypt.c
@@ -0,0 +1,338 @@
+/* mz_strm_pkcrypt.c -- Code for traditional PKWARE encryption
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Copyright (C) 1998-2005 Gilles Vollant
+ Modifications for Info-ZIP crypting
+ https://www.winimage.com/zLibDll/minizip.html
+ Copyright (C) 2003 Terry Thorsen
+
+ This code is a modified version of crypting code in Info-ZIP distribution
+
+ Copyright (C) 1990-2000 Info-ZIP. All rights reserved.
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+
+ This encryption code is a direct transcription of the algorithm from
+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+ file (appnote.txt) is distributed with the PKZIP program (even in the
+ version without encryption capabilities).
+*/
+
+
+#include "mz.h"
+#include "mz_crypt.h"
+#include "mz_strm.h"
+#include "mz_strm_pkcrypt.h"
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_pkcrypt_vtbl = {
+ mz_stream_pkcrypt_open,
+ mz_stream_pkcrypt_is_open,
+ mz_stream_pkcrypt_read,
+ mz_stream_pkcrypt_write,
+ mz_stream_pkcrypt_tell,
+ mz_stream_pkcrypt_seek,
+ mz_stream_pkcrypt_close,
+ mz_stream_pkcrypt_error,
+ mz_stream_pkcrypt_create,
+ mz_stream_pkcrypt_delete,
+ mz_stream_pkcrypt_get_prop_int64,
+ mz_stream_pkcrypt_set_prop_int64
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_pkcrypt_s {
+ mz_stream stream;
+ int32_t error;
+ int16_t initialized;
+ uint8_t buffer[UINT16_MAX];
+ int64_t total_in;
+ int64_t max_total_in;
+ int64_t total_out;
+ uint32_t keys[3]; /* keys defining the pseudo-random sequence */
+ uint8_t verify1;
+ uint8_t verify2;
+ const char *password;
+} mz_stream_pkcrypt;
+
+/***************************************************************************/
+
+#define mz_stream_pkcrypt_decode(strm, c) \
+ (mz_stream_pkcrypt_update_keys(strm, \
+ c ^= mz_stream_pkcrypt_decrypt_byte(strm)))
+
+#define mz_stream_pkcrypt_encode(strm, c, t) \
+ (t = mz_stream_pkcrypt_decrypt_byte(strm), \
+ mz_stream_pkcrypt_update_keys(strm, (uint8_t)c), (uint8_t)(t^(c)))
+
+/***************************************************************************/
+
+static uint8_t mz_stream_pkcrypt_decrypt_byte(void *stream) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+
+ unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an */
+ /* unpredictable manner on 16-bit systems; not a problem */
+ /* with any known compiler so far, though. */
+
+ temp = pkcrypt->keys[2] | 2;
+ return (uint8_t)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+static uint8_t mz_stream_pkcrypt_update_keys(void *stream, uint8_t c) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ uint8_t buf = c;
+
+ pkcrypt->keys[0] = (uint32_t)~mz_crypt_crc32_update(~pkcrypt->keys[0], &buf, 1);
+
+ pkcrypt->keys[1] += pkcrypt->keys[0] & 0xff;
+ pkcrypt->keys[1] *= 134775813L;
+ pkcrypt->keys[1] += 1;
+
+ buf = (uint8_t)(pkcrypt->keys[1] >> 24);
+ pkcrypt->keys[2] = (uint32_t)~mz_crypt_crc32_update(~pkcrypt->keys[2], &buf, 1);
+
+ return (uint8_t)c;
+}
+
+static void mz_stream_pkcrypt_init_keys(void *stream, const char *password) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+
+ pkcrypt->keys[0] = 305419896L;
+ pkcrypt->keys[1] = 591751049L;
+ pkcrypt->keys[2] = 878082192L;
+
+ while (*password != 0) {
+ mz_stream_pkcrypt_update_keys(stream, (uint8_t)*password);
+ password += 1;
+ }
+}
+
+/***************************************************************************/
+
+int32_t mz_stream_pkcrypt_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ uint16_t t = 0;
+ int16_t i = 0;
+ uint8_t verify1 = 0;
+ uint8_t verify2 = 0;
+ uint8_t header[MZ_PKCRYPT_HEADER_SIZE];
+ const char *password = path;
+
+ pkcrypt->total_in = 0;
+ pkcrypt->total_out = 0;
+ pkcrypt->initialized = 0;
+
+ if (mz_stream_is_open(pkcrypt->stream.base) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ if (password == NULL)
+ password = pkcrypt->password;
+ if (password == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_stream_pkcrypt_init_keys(stream, password);
+
+ if (mode & MZ_OPEN_MODE_WRITE) {
+ /* First generate RAND_HEAD_LEN - 2 random bytes. */
+ mz_crypt_rand(header, MZ_PKCRYPT_HEADER_SIZE - 2);
+
+ /* Encrypt random header (last two bytes is high word of crc) */
+ for (i = 0; i < MZ_PKCRYPT_HEADER_SIZE - 2; i++)
+ header[i] = mz_stream_pkcrypt_encode(stream, header[i], t);
+
+ header[i++] = mz_stream_pkcrypt_encode(stream, pkcrypt->verify1, t);
+ header[i++] = mz_stream_pkcrypt_encode(stream, pkcrypt->verify2, t);
+
+ if (mz_stream_write(pkcrypt->stream.base, header, sizeof(header)) != sizeof(header))
+ return MZ_WRITE_ERROR;
+
+ pkcrypt->total_out += MZ_PKCRYPT_HEADER_SIZE;
+ } else if (mode & MZ_OPEN_MODE_READ) {
+ if (mz_stream_read(pkcrypt->stream.base, header, sizeof(header)) != sizeof(header))
+ return MZ_READ_ERROR;
+
+ for (i = 0; i < MZ_PKCRYPT_HEADER_SIZE - 2; i++)
+ header[i] = mz_stream_pkcrypt_decode(stream, header[i]);
+
+ verify1 = mz_stream_pkcrypt_decode(stream, header[i++]);
+ verify2 = mz_stream_pkcrypt_decode(stream, header[i++]);
+
+ /* Older versions used 2 byte check, newer versions use 1 byte check. */
+ MZ_UNUSED(verify1);
+ if ((verify2 != 0) && (verify2 != pkcrypt->verify2))
+ return MZ_PASSWORD_ERROR;
+
+ pkcrypt->total_in += MZ_PKCRYPT_HEADER_SIZE;
+ }
+
+ pkcrypt->initialized = 1;
+ return MZ_OK;
+}
+
+int32_t mz_stream_pkcrypt_is_open(void *stream) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ if (pkcrypt->initialized == 0)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_pkcrypt_read(void *stream, void *buf, int32_t size) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ uint8_t *buf_ptr = (uint8_t *)buf;
+ int32_t bytes_to_read = size;
+ int32_t read = 0;
+ int32_t i = 0;
+
+
+ if ((int64_t)bytes_to_read > (pkcrypt->max_total_in - pkcrypt->total_in))
+ bytes_to_read = (int32_t)(pkcrypt->max_total_in - pkcrypt->total_in);
+
+ read = mz_stream_read(pkcrypt->stream.base, buf, bytes_to_read);
+
+ for (i = 0; i < read; i++)
+ buf_ptr[i] = mz_stream_pkcrypt_decode(stream, buf_ptr[i]);
+
+ if (read > 0)
+ pkcrypt->total_in += read;
+
+ return read;
+}
+
+int32_t mz_stream_pkcrypt_write(void *stream, const void *buf, int32_t size) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ const uint8_t *buf_ptr = (const uint8_t *)buf;
+ int32_t bytes_to_write = sizeof(pkcrypt->buffer);
+ int32_t total_written = 0;
+ int32_t written = 0;
+ int32_t i = 0;
+ uint16_t t = 0;
+
+ if (size < 0)
+ return MZ_PARAM_ERROR;
+
+ do {
+ if (bytes_to_write > (size - total_written))
+ bytes_to_write = (size - total_written);
+
+ for (i = 0; i < bytes_to_write; i += 1) {
+ pkcrypt->buffer[i] = mz_stream_pkcrypt_encode(stream, *buf_ptr, t);
+ buf_ptr += 1;
+ }
+
+ written = mz_stream_write(pkcrypt->stream.base, pkcrypt->buffer, bytes_to_write);
+ if (written < 0)
+ return written;
+
+ total_written += written;
+ } while (total_written < size && written > 0);
+
+ pkcrypt->total_out += total_written;
+ return total_written;
+}
+
+int64_t mz_stream_pkcrypt_tell(void *stream) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ return mz_stream_tell(pkcrypt->stream.base);
+}
+
+int32_t mz_stream_pkcrypt_seek(void *stream, int64_t offset, int32_t origin) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ return mz_stream_seek(pkcrypt->stream.base, offset, origin);
+}
+
+int32_t mz_stream_pkcrypt_close(void *stream) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ pkcrypt->initialized = 0;
+ return MZ_OK;
+}
+
+int32_t mz_stream_pkcrypt_error(void *stream) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ return pkcrypt->error;
+}
+
+void mz_stream_pkcrypt_set_password(void *stream, const char *password) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ pkcrypt->password = password;
+}
+
+void mz_stream_pkcrypt_set_verify(void *stream, uint8_t verify1, uint8_t verify2) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ pkcrypt->verify1 = verify1;
+ pkcrypt->verify2 = verify2;
+}
+
+void mz_stream_pkcrypt_get_verify(void *stream, uint8_t *verify1, uint8_t *verify2) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ *verify1 = pkcrypt->verify1;
+ *verify2 = pkcrypt->verify2;
+}
+
+int32_t mz_stream_pkcrypt_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_IN:
+ *value = pkcrypt->total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_OUT:
+ *value = pkcrypt->total_out;
+ break;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ *value = pkcrypt->max_total_in;
+ break;
+ case MZ_STREAM_PROP_HEADER_SIZE:
+ *value = MZ_PKCRYPT_HEADER_SIZE;
+ break;
+ case MZ_STREAM_PROP_FOOTER_SIZE:
+ *value = 0;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_stream_pkcrypt_set_prop_int64(void *stream, int32_t prop, int64_t value) {
+ mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ pkcrypt->max_total_in = value;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+void *mz_stream_pkcrypt_create(void **stream) {
+ mz_stream_pkcrypt *pkcrypt = NULL;
+
+ pkcrypt = (mz_stream_pkcrypt *)MZ_ALLOC(sizeof(mz_stream_pkcrypt));
+ if (pkcrypt != NULL) {
+ memset(pkcrypt, 0, sizeof(mz_stream_pkcrypt));
+ pkcrypt->stream.vtbl = &mz_stream_pkcrypt_vtbl;
+ }
+
+ if (stream != NULL)
+ *stream = pkcrypt;
+ return pkcrypt;
+}
+
+void mz_stream_pkcrypt_delete(void **stream) {
+ mz_stream_pkcrypt *pkcrypt = NULL;
+ if (stream == NULL)
+ return;
+ pkcrypt = (mz_stream_pkcrypt *)*stream;
+ if (pkcrypt != NULL)
+ MZ_FREE(pkcrypt);
+ *stream = NULL;
+}
+
+void *mz_stream_pkcrypt_get_interface(void) {
+ return (void *)&mz_stream_pkcrypt_vtbl;
+}
diff --git a/Externals/minizip/mz_strm_pkcrypt.h b/Externals/minizip/mz_strm_pkcrypt.h
new file mode 100644
index 0000000000..453f1f9948
--- /dev/null
+++ b/Externals/minizip/mz_strm_pkcrypt.h
@@ -0,0 +1,46 @@
+/* mz_strm_pkcrypt.h -- Code for traditional PKWARE encryption
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_PKCRYPT_H
+#define MZ_STREAM_PKCRYPT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_pkcrypt_open(void *stream, const char *filename, int32_t mode);
+int32_t mz_stream_pkcrypt_is_open(void *stream);
+int32_t mz_stream_pkcrypt_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_pkcrypt_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_pkcrypt_tell(void *stream);
+int32_t mz_stream_pkcrypt_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_pkcrypt_close(void *stream);
+int32_t mz_stream_pkcrypt_error(void *stream);
+
+void mz_stream_pkcrypt_set_password(void *stream, const char *password);
+void mz_stream_pkcrypt_set_verify(void *stream, uint8_t verify1, uint8_t verify2);
+void mz_stream_pkcrypt_get_verify(void *stream, uint8_t *verify1, uint8_t *verify2);
+int32_t mz_stream_pkcrypt_get_prop_int64(void *stream, int32_t prop, int64_t *value);
+int32_t mz_stream_pkcrypt_set_prop_int64(void *stream, int32_t prop, int64_t value);
+
+void* mz_stream_pkcrypt_create(void **stream);
+void mz_stream_pkcrypt_delete(void **stream);
+
+void* mz_stream_pkcrypt_get_interface(void);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_strm_split.c b/Externals/minizip/mz_strm_split.c
new file mode 100644
index 0000000000..12c8bda303
--- /dev/null
+++ b/Externals/minizip/mz_strm_split.c
@@ -0,0 +1,438 @@
+/* mz_strm_split.c -- Stream for split files
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_os.h"
+#include "mz_strm.h"
+#include "mz_strm_split.h"
+
+#include <stdio.h> /* snprintf */
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+# define snprintf _snprintf
+#endif
+
+/***************************************************************************/
+
+#define MZ_ZIP_MAGIC_DISKHEADER (0x08074b50)
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_split_vtbl = {
+ mz_stream_split_open,
+ mz_stream_split_is_open,
+ mz_stream_split_read,
+ mz_stream_split_write,
+ mz_stream_split_tell,
+ mz_stream_split_seek,
+ mz_stream_split_close,
+ mz_stream_split_error,
+ mz_stream_split_create,
+ mz_stream_split_delete,
+ mz_stream_split_get_prop_int64,
+ mz_stream_split_set_prop_int64
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_split_s {
+ mz_stream stream;
+ int32_t is_open;
+ int64_t disk_size;
+ int64_t total_in;
+ int64_t total_in_disk;
+ int64_t total_out;
+ int64_t total_out_disk;
+ int32_t mode;
+ char *path_cd;
+ uint32_t path_cd_size;
+ char *path_disk;
+ uint32_t path_disk_size;
+ int32_t number_disk;
+ int32_t current_disk;
+ int64_t current_disk_size;
+ int32_t reached_end;
+} mz_stream_split;
+
+/***************************************************************************/
+
+#if 0
+# define mz_stream_split_print printf
+#else
+# define mz_stream_split_print(fmt,...)
+#endif
+
+/***************************************************************************/
+
+static int32_t mz_stream_split_open_disk(void *stream, int32_t number_disk) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ uint32_t magic = 0;
+ int64_t position = 0;
+ int32_t i = 0;
+ int32_t err = MZ_OK;
+ int16_t disk_part = 0;
+
+
+ /* Check if we are reading or writing a disk part or the cd disk */
+ if (number_disk >= 0) {
+ if ((split->mode & MZ_OPEN_MODE_WRITE) == 0)
+ disk_part = MZ_OPEN_MODE_READ;
+ else if (split->disk_size > 0)
+ disk_part = MZ_OPEN_MODE_WRITE;
+ }
+
+ /* Construct disk path */
+ if (disk_part > 0) {
+ for (i = (int32_t)strlen(split->path_disk) - 1; i >= 0; i -= 1) {
+ if (split->path_disk[i] != '.')
+ continue;
+ snprintf(&split->path_disk[i], split->path_disk_size - (uint32_t)i,
+ ".z%02" PRId32, number_disk + 1);
+ break;
+ }
+ } else {
+ strncpy(split->path_disk, split->path_cd, split->path_disk_size - 1);
+ split->path_disk[split->path_disk_size - 1] = 0;
+ }
+
+ mz_stream_split_print("Split - Goto disk - %s (disk %" PRId32 ")\n", split->path_disk, number_disk);
+
+ /* If disk part doesn't exist during reading then return MZ_EXIST_ERROR */
+ if (disk_part == MZ_OPEN_MODE_READ)
+ err = mz_os_file_exists(split->path_disk);
+
+ if (err == MZ_OK)
+ err = mz_stream_open(split->stream.base, split->path_disk, split->mode);
+
+ if (err == MZ_OK) {
+ split->total_in_disk = 0;
+ split->total_out_disk = 0;
+ split->current_disk = number_disk;
+
+ if (split->mode & MZ_OPEN_MODE_WRITE) {
+ if ((split->current_disk == 0) && (split->disk_size > 0)) {
+ err = mz_stream_write_uint32(split->stream.base, MZ_ZIP_MAGIC_DISKHEADER);
+
+ split->total_out_disk += 4;
+ split->total_out += split->total_out_disk;
+ }
+ } else if (split->mode & MZ_OPEN_MODE_READ) {
+ if (split->current_disk == 0) {
+ err = mz_stream_read_uint32(split->stream.base, &magic);
+ if (magic != MZ_ZIP_MAGIC_DISKHEADER)
+ err = MZ_FORMAT_ERROR;
+ }
+ }
+ }
+
+ if (err == MZ_OK) {
+ /* Get the size of the current disk we are on */
+ position = mz_stream_tell(split->stream.base);
+ mz_stream_seek(split->stream.base, 0, MZ_SEEK_END);
+ split->current_disk_size = mz_stream_tell(split->stream.base);
+ mz_stream_seek(split->stream.base, position, MZ_SEEK_SET);
+
+ split->is_open = 1;
+ }
+
+ return err;
+}
+
+static int32_t mz_stream_split_close_disk(void *stream) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+
+ if (mz_stream_is_open(split->stream.base) != MZ_OK)
+ return MZ_OK;
+
+ mz_stream_split_print("Split - Close disk\n");
+ return mz_stream_close(split->stream.base);
+}
+
+static int32_t mz_stream_split_goto_disk(void *stream, int32_t number_disk) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ int32_t err = MZ_OK;
+ int32_t err_is_open = MZ_OK;
+
+ err_is_open = mz_stream_is_open(split->stream.base);
+
+ if ((split->disk_size == 0) && (split->mode & MZ_OPEN_MODE_WRITE)) {
+ if (err_is_open != MZ_OK)
+ err = mz_stream_split_open_disk(stream, number_disk);
+ } else if ((number_disk != split->current_disk) || (err_is_open != MZ_OK)) {
+ err = mz_stream_split_close_disk(stream);
+ if (err == MZ_OK) {
+ err = mz_stream_split_open_disk(stream, number_disk);
+ if (err == MZ_OK)
+ split->number_disk = number_disk;
+ }
+ }
+
+ return err;
+}
+
+int32_t mz_stream_split_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ int32_t number_disk = 0;
+
+ split->mode = mode;
+
+ split->path_cd_size = (uint32_t)strlen(path) + 1;
+ split->path_cd = (char *)MZ_ALLOC(split->path_cd_size);
+
+ if (split->path_cd == NULL)
+ return MZ_MEM_ERROR;
+
+ strncpy(split->path_cd, path, split->path_cd_size - 1);
+ split->path_cd[split->path_cd_size - 1] = 0;
+
+ mz_stream_split_print("Split - Open - %s (disk %" PRId32 ")\n", split->path_cd, number_disk);
+
+ split->path_disk_size = (uint32_t)strlen(path) + 10;
+ split->path_disk = (char *)MZ_ALLOC(split->path_disk_size);
+
+ if (split->path_disk == NULL) {
+ MZ_FREE(split->path_cd);
+ return MZ_MEM_ERROR;
+ }
+
+ strncpy(split->path_disk, path, split->path_disk_size - 1);
+ split->path_disk[split->path_disk_size - 1] = 0;
+
+ if ((mode & MZ_OPEN_MODE_WRITE) && ((mode & MZ_OPEN_MODE_APPEND) == 0)) {
+ number_disk = 0;
+ split->current_disk = -1;
+ } else {
+ number_disk = -1;
+ split->current_disk = 0;
+ }
+
+ return mz_stream_split_goto_disk(stream, number_disk);
+}
+
+int32_t mz_stream_split_is_open(void *stream) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ if (split->is_open != 1)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_split_read(void *stream, void *buf, int32_t size) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ int32_t bytes_left = size;
+ int32_t read = 0;
+ int32_t err = MZ_OK;
+ uint8_t *buf_ptr = (uint8_t *)buf;
+
+ err = mz_stream_split_goto_disk(stream, split->number_disk);
+ if (err != MZ_OK)
+ return err;
+
+ while (bytes_left > 0) {
+ read = mz_stream_read(split->stream.base, buf_ptr, bytes_left);
+
+ mz_stream_split_print("Split - Read disk - %" PRId32 "\n", read);
+
+ if (read < 0)
+ return read;
+ if (read == 0) {
+ if (split->current_disk < 0) /* No more disks to goto */
+ break;
+ err = mz_stream_split_goto_disk(stream, split->current_disk + 1);
+ if (err == MZ_EXIST_ERROR) {
+ split->current_disk = -1;
+ break;
+ }
+ if (err != MZ_OK)
+ return err;
+ }
+
+ bytes_left -= read;
+ buf_ptr += read;
+ split->total_in += read;
+ split->total_in_disk += read;
+ }
+ return size - bytes_left;
+}
+
+int32_t mz_stream_split_write(void *stream, const void *buf, int32_t size) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ int64_t position = 0;
+ int32_t written = 0;
+ int32_t bytes_left = size;
+ int32_t bytes_to_write = 0;
+ int32_t bytes_avail = 0;
+ int32_t number_disk = -1;
+ int32_t err = MZ_OK;
+ const uint8_t *buf_ptr = (const uint8_t *)buf;
+
+ position = mz_stream_tell(split->stream.base);
+
+ while (bytes_left > 0) {
+ bytes_to_write = bytes_left;
+
+ if (split->disk_size > 0) {
+ if ((split->total_out_disk == split->disk_size && split->total_out > 0) ||
+ (split->number_disk == -1 && split->number_disk != split->current_disk)) {
+ if (split->number_disk != -1)
+ number_disk = split->current_disk + 1;
+
+ err = mz_stream_split_goto_disk(stream, number_disk);
+ if (err != MZ_OK)
+ return err;
+ }
+
+ if (split->number_disk != -1) {
+ bytes_avail = (int32_t)(split->disk_size - split->total_out_disk);
+ if (bytes_to_write > bytes_avail)
+ bytes_to_write = bytes_avail;
+ }
+ }
+
+ written = mz_stream_write(split->stream.base, buf_ptr, bytes_to_write);
+ if (written != bytes_to_write)
+ return MZ_WRITE_ERROR;
+
+ mz_stream_split_print("Split - Write disk - %" PRId32 "\n", written);
+
+ bytes_left -= written;
+ buf_ptr += written;
+
+ split->total_out += written;
+ split->total_out_disk += written;
+
+ if (position == split->current_disk_size) {
+ split->current_disk_size += written;
+ position = split->current_disk_size;
+ }
+ }
+
+ return size - bytes_left;
+}
+
+int64_t mz_stream_split_tell(void *stream) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ int32_t err = MZ_OK;
+ err = mz_stream_split_goto_disk(stream, split->number_disk);
+ if (err != MZ_OK)
+ return err;
+ return mz_stream_tell(split->stream.base);
+}
+
+int32_t mz_stream_split_seek(void *stream, int64_t offset, int32_t origin) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ int64_t disk_left = 0;
+ int64_t position = 0;
+ int32_t err = MZ_OK;
+
+ err = mz_stream_split_goto_disk(stream, split->number_disk);
+
+ if (err != MZ_OK)
+ return err;
+
+ mz_stream_split_print("Split - Seek disk - %" PRId64 " (origin %" PRId32 ")\n", offset, origin);
+
+ if ((origin == MZ_SEEK_CUR) && (split->number_disk != -1)) {
+ position = mz_stream_tell(split->stream.base);
+ disk_left = split->current_disk_size - position;
+
+ while (offset > disk_left) {
+ err = mz_stream_split_goto_disk(stream, split->current_disk + 1);
+ if (err != MZ_OK)
+ return err;
+
+ offset -= disk_left;
+ disk_left = split->current_disk_size;
+ }
+ }
+
+ return mz_stream_seek(split->stream.base, offset, origin);
+}
+
+int32_t mz_stream_split_close(void *stream) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ int32_t err = MZ_OK;
+
+ err = mz_stream_split_close_disk(stream);
+ split->is_open = 0;
+ return err;
+}
+
+int32_t mz_stream_split_error(void *stream) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ return mz_stream_error(split->stream.base);
+}
+
+int32_t mz_stream_split_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_OUT:
+ *value = split->total_out;
+ break;
+ case MZ_STREAM_PROP_DISK_NUMBER:
+ *value = split->number_disk;
+ break;
+ case MZ_STREAM_PROP_DISK_SIZE:
+ *value = split->disk_size;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_stream_split_set_prop_int64(void *stream, int32_t prop, int64_t value) {
+ mz_stream_split *split = (mz_stream_split *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_DISK_NUMBER:
+ split->number_disk = (int32_t)value;
+ break;
+ case MZ_STREAM_PROP_DISK_SIZE:
+ split->disk_size = value;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+void *mz_stream_split_create(void **stream) {
+ mz_stream_split *split = NULL;
+
+ split = (mz_stream_split *)MZ_ALLOC(sizeof(mz_stream_split));
+ if (split != NULL) {
+ memset(split, 0, sizeof(mz_stream_split));
+ split->stream.vtbl = &mz_stream_split_vtbl;
+ }
+ if (stream != NULL)
+ *stream = split;
+
+ return split;
+}
+
+void mz_stream_split_delete(void **stream) {
+ mz_stream_split *split = NULL;
+ if (stream == NULL)
+ return;
+ split = (mz_stream_split *)*stream;
+ if (split != NULL) {
+ if (split->path_cd)
+ MZ_FREE(split->path_cd);
+ if (split->path_disk)
+ MZ_FREE(split->path_disk);
+
+ MZ_FREE(split);
+ }
+ *stream = NULL;
+}
+
+void *mz_stream_split_get_interface(void) {
+ return (void *)&mz_stream_split_vtbl;
+}
diff --git a/Externals/minizip/mz_strm_split.h b/Externals/minizip/mz_strm_split.h
new file mode 100644
index 0000000000..da404dae2a
--- /dev/null
+++ b/Externals/minizip/mz_strm_split.h
@@ -0,0 +1,43 @@
+/* mz_strm_split.h -- Stream for split files
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_SPLIT_H
+#define MZ_STREAM_SPLIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_split_open(void *stream, const char *filename, int32_t mode);
+int32_t mz_stream_split_is_open(void *stream);
+int32_t mz_stream_split_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_split_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_split_tell(void *stream);
+int32_t mz_stream_split_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_split_close(void *stream);
+int32_t mz_stream_split_error(void *stream);
+
+int32_t mz_stream_split_get_prop_int64(void *stream, int32_t prop, int64_t *value);
+int32_t mz_stream_split_set_prop_int64(void *stream, int32_t prop, int64_t value);
+
+void* mz_stream_split_create(void **stream);
+void mz_stream_split_delete(void **stream);
+
+void* mz_stream_split_get_interface(void);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_strm_wzaes.c b/Externals/minizip/mz_strm_wzaes.c
new file mode 100644
index 0000000000..fd0119991a
--- /dev/null
+++ b/Externals/minizip/mz_strm_wzaes.c
@@ -0,0 +1,362 @@
+/* mz_strm_wzaes.c -- Stream for WinZip AES encryption
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Copyright (C) 1998-2010 Brian Gladman, Worcester, UK
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_crypt.h"
+#include "mz_strm.h"
+#include "mz_strm_wzaes.h"
+
+/***************************************************************************/
+
+#define MZ_AES_KEYING_ITERATIONS (1000)
+#define MZ_AES_SALT_LENGTH(MODE) (4 * (MODE & 3) + 4)
+#define MZ_AES_SALT_LENGTH_MAX (16)
+#define MZ_AES_PW_LENGTH_MAX (128)
+#define MZ_AES_PW_VERIFY_SIZE (2)
+#define MZ_AES_AUTHCODE_SIZE (10)
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_wzaes_vtbl = {
+ mz_stream_wzaes_open,
+ mz_stream_wzaes_is_open,
+ mz_stream_wzaes_read,
+ mz_stream_wzaes_write,
+ mz_stream_wzaes_tell,
+ mz_stream_wzaes_seek,
+ mz_stream_wzaes_close,
+ mz_stream_wzaes_error,
+ mz_stream_wzaes_create,
+ mz_stream_wzaes_delete,
+ mz_stream_wzaes_get_prop_int64,
+ mz_stream_wzaes_set_prop_int64
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_wzaes_s {
+ mz_stream stream;
+ int32_t mode;
+ int32_t error;
+ int16_t initialized;
+ uint8_t buffer[UINT16_MAX];
+ int64_t total_in;
+ int64_t max_total_in;
+ int64_t total_out;
+ int16_t encryption_mode;
+ const char *password;
+ void *aes;
+ uint32_t crypt_pos;
+ uint8_t crypt_block[MZ_AES_BLOCK_SIZE];
+ void *hmac;
+ uint8_t nonce[MZ_AES_BLOCK_SIZE];
+} mz_stream_wzaes;
+
+/***************************************************************************/
+
+int32_t mz_stream_wzaes_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ uint16_t salt_length = 0;
+ uint16_t password_length = 0;
+ uint16_t key_length = 0;
+ uint8_t kbuf[2 * MZ_AES_KEY_LENGTH_MAX + MZ_AES_PW_VERIFY_SIZE];
+ uint8_t verify[MZ_AES_PW_VERIFY_SIZE];
+ uint8_t verify_expected[MZ_AES_PW_VERIFY_SIZE];
+ uint8_t salt_value[MZ_AES_SALT_LENGTH_MAX];
+ const char *password = path;
+
+ wzaes->total_in = 0;
+ wzaes->total_out = 0;
+ wzaes->initialized = 0;
+
+ if (mz_stream_is_open(wzaes->stream.base) != MZ_OK)
+ return MZ_OPEN_ERROR;
+
+ if (password == NULL)
+ password = wzaes->password;
+ if (password == NULL)
+ return MZ_PARAM_ERROR;
+ password_length = (uint16_t)strlen(password);
+ if (password_length > MZ_AES_PW_LENGTH_MAX)
+ return MZ_PARAM_ERROR;
+
+ if (wzaes->encryption_mode < 1 || wzaes->encryption_mode > 3)
+ return MZ_PARAM_ERROR;
+
+ salt_length = MZ_AES_SALT_LENGTH(wzaes->encryption_mode);
+
+ if (mode & MZ_OPEN_MODE_WRITE) {
+ mz_crypt_rand(salt_value, salt_length);
+ } else if (mode & MZ_OPEN_MODE_READ) {
+ if (mz_stream_read(wzaes->stream.base, salt_value, salt_length) != salt_length)
+ return MZ_READ_ERROR;
+ }
+
+ key_length = MZ_AES_KEY_LENGTH(wzaes->encryption_mode);
+
+ /* Derive the encryption and authentication keys and the password verifier */
+ mz_crypt_pbkdf2((uint8_t *)password, password_length, salt_value, salt_length,
+ MZ_AES_KEYING_ITERATIONS, kbuf, 2 * key_length + MZ_AES_PW_VERIFY_SIZE);
+
+ /* Initialize the encryption nonce and buffer pos */
+ wzaes->crypt_pos = MZ_AES_BLOCK_SIZE;
+ memset(wzaes->nonce, 0, sizeof(wzaes->nonce));
+
+ /* Initialize for encryption using key 1 */
+ mz_crypt_aes_reset(wzaes->aes);
+ mz_crypt_aes_set_mode(wzaes->aes, wzaes->encryption_mode);
+ mz_crypt_aes_set_encrypt_key(wzaes->aes, kbuf, key_length);
+
+ /* Initialize for authentication using key 2 */
+ mz_crypt_hmac_reset(wzaes->hmac);
+ mz_crypt_hmac_set_algorithm(wzaes->hmac, MZ_HASH_SHA1);
+ mz_crypt_hmac_init(wzaes->hmac, kbuf + key_length, key_length);
+
+ memcpy(verify, kbuf + (2 * key_length), MZ_AES_PW_VERIFY_SIZE);
+
+ if (mode & MZ_OPEN_MODE_WRITE) {
+ if (mz_stream_write(wzaes->stream.base, salt_value, salt_length) != salt_length)
+ return MZ_WRITE_ERROR;
+
+ wzaes->total_out += salt_length;
+
+ if (mz_stream_write(wzaes->stream.base, verify, MZ_AES_PW_VERIFY_SIZE) != MZ_AES_PW_VERIFY_SIZE)
+ return MZ_WRITE_ERROR;
+
+ wzaes->total_out += MZ_AES_PW_VERIFY_SIZE;
+ } else if (mode & MZ_OPEN_MODE_READ) {
+ wzaes->total_in += salt_length;
+
+ if (mz_stream_read(wzaes->stream.base, verify_expected, MZ_AES_PW_VERIFY_SIZE) != MZ_AES_PW_VERIFY_SIZE)
+ return MZ_READ_ERROR;
+
+ wzaes->total_in += MZ_AES_PW_VERIFY_SIZE;
+
+ if (memcmp(verify_expected, verify, MZ_AES_PW_VERIFY_SIZE) != 0)
+ return MZ_PASSWORD_ERROR;
+ }
+
+ wzaes->mode = mode;
+ wzaes->initialized = 1;
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_wzaes_is_open(void *stream) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ if (wzaes->initialized == 0)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+static int32_t mz_stream_wzaes_ctr_encrypt(void *stream, uint8_t *buf, int32_t size) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ uint32_t pos = wzaes->crypt_pos;
+ uint32_t i = 0;
+ int32_t err = MZ_OK;
+
+ while (i < (uint32_t)size) {
+ if (pos == MZ_AES_BLOCK_SIZE) {
+ uint32_t j = 0;
+
+ /* Increment encryption nonce */
+ while (j < 8 && !++wzaes->nonce[j])
+ j += 1;
+
+ /* Encrypt the nonce to form next xor buffer */
+ memcpy(wzaes->crypt_block, wzaes->nonce, MZ_AES_BLOCK_SIZE);
+ mz_crypt_aes_encrypt(wzaes->aes, wzaes->crypt_block, sizeof(wzaes->crypt_block));
+ pos = 0;
+ }
+
+ buf[i++] ^= wzaes->crypt_block[pos++];
+ }
+
+ wzaes->crypt_pos = pos;
+ return err;
+}
+
+int32_t mz_stream_wzaes_read(void *stream, void *buf, int32_t size) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ int64_t max_total_in = 0;
+ int32_t bytes_to_read = size;
+ int32_t read = 0;
+
+ max_total_in = wzaes->max_total_in - MZ_AES_FOOTER_SIZE;
+ if ((int64_t)bytes_to_read > (max_total_in - wzaes->total_in))
+ bytes_to_read = (int32_t)(max_total_in - wzaes->total_in);
+
+ read = mz_stream_read(wzaes->stream.base, buf, bytes_to_read);
+
+ if (read > 0) {
+ mz_crypt_hmac_update(wzaes->hmac, (uint8_t *)buf, read);
+ mz_stream_wzaes_ctr_encrypt(stream, (uint8_t *)buf, read);
+
+ wzaes->total_in += read;
+ }
+
+ return read;
+}
+
+int32_t mz_stream_wzaes_write(void *stream, const void *buf, int32_t size) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ const uint8_t *buf_ptr = (const uint8_t *)buf;
+ int32_t bytes_to_write = sizeof(wzaes->buffer);
+ int32_t total_written = 0;
+ int32_t written = 0;
+
+ if (size < 0)
+ return MZ_PARAM_ERROR;
+
+ do {
+ if (bytes_to_write > (size - total_written))
+ bytes_to_write = (size - total_written);
+
+ memcpy(wzaes->buffer, buf_ptr, bytes_to_write);
+ buf_ptr += bytes_to_write;
+
+ mz_stream_wzaes_ctr_encrypt(stream, (uint8_t *)wzaes->buffer, bytes_to_write);
+ mz_crypt_hmac_update(wzaes->hmac, wzaes->buffer, bytes_to_write);
+
+ written = mz_stream_write(wzaes->stream.base, wzaes->buffer, bytes_to_write);
+ if (written < 0)
+ return written;
+
+ total_written += written;
+ } while (total_written < size && written > 0);
+
+ wzaes->total_out += total_written;
+ return total_written;
+}
+
+int64_t mz_stream_wzaes_tell(void *stream) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ return mz_stream_tell(wzaes->stream.base);
+}
+
+int32_t mz_stream_wzaes_seek(void *stream, int64_t offset, int32_t origin) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ return mz_stream_seek(wzaes->stream.base, offset, origin);
+}
+
+int32_t mz_stream_wzaes_close(void *stream) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ uint8_t expected_hash[MZ_AES_AUTHCODE_SIZE];
+ uint8_t computed_hash[MZ_HASH_SHA1_SIZE];
+
+ mz_crypt_hmac_end(wzaes->hmac, computed_hash, sizeof(computed_hash));
+
+ if (wzaes->mode & MZ_OPEN_MODE_WRITE) {
+ if (mz_stream_write(wzaes->stream.base, computed_hash, MZ_AES_AUTHCODE_SIZE) != MZ_AES_AUTHCODE_SIZE)
+ return MZ_WRITE_ERROR;
+
+ wzaes->total_out += MZ_AES_AUTHCODE_SIZE;
+ } else if (wzaes->mode & MZ_OPEN_MODE_READ) {
+ if (mz_stream_read(wzaes->stream.base, expected_hash, MZ_AES_AUTHCODE_SIZE) != MZ_AES_AUTHCODE_SIZE)
+ return MZ_READ_ERROR;
+
+ wzaes->total_in += MZ_AES_AUTHCODE_SIZE;
+
+ /* If entire entry was not read this will fail */
+ if (memcmp(computed_hash, expected_hash, MZ_AES_AUTHCODE_SIZE) != 0)
+ return MZ_CRC_ERROR;
+ }
+
+ wzaes->initialized = 0;
+ return MZ_OK;
+}
+
+int32_t mz_stream_wzaes_error(void *stream) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ return wzaes->error;
+}
+
+void mz_stream_wzaes_set_password(void *stream, const char *password) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ wzaes->password = password;
+}
+
+void mz_stream_wzaes_set_encryption_mode(void *stream, int16_t encryption_mode) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ wzaes->encryption_mode = encryption_mode;
+}
+
+int32_t mz_stream_wzaes_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_IN:
+ *value = wzaes->total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_OUT:
+ *value = wzaes->total_out;
+ break;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ *value = wzaes->max_total_in;
+ break;
+ case MZ_STREAM_PROP_HEADER_SIZE:
+ *value = MZ_AES_SALT_LENGTH((int64_t)wzaes->encryption_mode) + MZ_AES_PW_VERIFY_SIZE;
+ break;
+ case MZ_STREAM_PROP_FOOTER_SIZE:
+ *value = MZ_AES_AUTHCODE_SIZE;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_stream_wzaes_set_prop_int64(void *stream, int32_t prop, int64_t value) {
+ mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ wzaes->max_total_in = value;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+void *mz_stream_wzaes_create(void **stream) {
+ mz_stream_wzaes *wzaes = NULL;
+
+ wzaes = (mz_stream_wzaes *)MZ_ALLOC(sizeof(mz_stream_wzaes));
+ if (wzaes != NULL) {
+ memset(wzaes, 0, sizeof(mz_stream_wzaes));
+ wzaes->stream.vtbl = &mz_stream_wzaes_vtbl;
+ wzaes->encryption_mode = MZ_AES_ENCRYPTION_MODE_256;
+
+ mz_crypt_hmac_create(&wzaes->hmac);
+ mz_crypt_aes_create(&wzaes->aes);
+ }
+ if (stream != NULL)
+ *stream = wzaes;
+
+ return wzaes;
+}
+
+void mz_stream_wzaes_delete(void **stream) {
+ mz_stream_wzaes *wzaes = NULL;
+ if (stream == NULL)
+ return;
+ wzaes = (mz_stream_wzaes *)*stream;
+ if (wzaes != NULL) {
+ mz_crypt_aes_delete(&wzaes->aes);
+ mz_crypt_hmac_delete(&wzaes->hmac);
+ MZ_FREE(wzaes);
+ }
+ *stream = NULL;
+}
+
+void *mz_stream_wzaes_get_interface(void) {
+ return (void *)&mz_stream_wzaes_vtbl;
+}
diff --git a/Externals/minizip/mz_strm_wzaes.h b/Externals/minizip/mz_strm_wzaes.h
new file mode 100644
index 0000000000..e27f11203f
--- /dev/null
+++ b/Externals/minizip/mz_strm_wzaes.h
@@ -0,0 +1,46 @@
+/* mz_strm_wzaes.h -- Stream for WinZIP AES encryption
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_WZAES_SHA1_H
+#define MZ_STREAM_WZAES_SHA1_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_wzaes_open(void *stream, const char *filename, int32_t mode);
+int32_t mz_stream_wzaes_is_open(void *stream);
+int32_t mz_stream_wzaes_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_wzaes_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_wzaes_tell(void *stream);
+int32_t mz_stream_wzaes_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_wzaes_close(void *stream);
+int32_t mz_stream_wzaes_error(void *stream);
+
+void mz_stream_wzaes_set_password(void *stream, const char *password);
+void mz_stream_wzaes_set_encryption_mode(void *stream, int16_t encryption_mode);
+
+int32_t mz_stream_wzaes_get_prop_int64(void *stream, int32_t prop, int64_t *value);
+int32_t mz_stream_wzaes_set_prop_int64(void *stream, int32_t prop, int64_t value);
+
+void* mz_stream_wzaes_create(void **stream);
+void mz_stream_wzaes_delete(void **stream);
+
+void* mz_stream_wzaes_get_interface(void);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_strm_zlib.c b/Externals/minizip/mz_strm_zlib.c
new file mode 100644
index 0000000000..e83bbac91a
--- /dev/null
+++ b/Externals/minizip/mz_strm_zlib.c
@@ -0,0 +1,393 @@
+/* mz_strm_zlib.c -- Stream for zlib inflate/deflate
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_strm.h"
+#include "mz_strm_zlib.h"
+
+#include "zlib.h"
+#if defined(ZLIBNG_VERNUM) && !defined(ZLIB_COMPAT)
+# include "zlib-ng.h"
+#endif
+
+/***************************************************************************/
+
+#if defined(ZLIBNG_VERNUM) && !defined(ZLIB_COMPAT)
+# define ZLIB_PREFIX(x) zng_ ## x
+ typedef zng_stream zlib_stream;
+#else
+# define ZLIB_PREFIX(x) x
+ typedef z_stream zlib_stream;
+#endif
+
+#if !defined(DEF_MEM_LEVEL)
+# if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+# else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+# endif
+#endif
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_zlib_vtbl = {
+ mz_stream_zlib_open,
+ mz_stream_zlib_is_open,
+ mz_stream_zlib_read,
+ mz_stream_zlib_write,
+ mz_stream_zlib_tell,
+ mz_stream_zlib_seek,
+ mz_stream_zlib_close,
+ mz_stream_zlib_error,
+ mz_stream_zlib_create,
+ mz_stream_zlib_delete,
+ mz_stream_zlib_get_prop_int64,
+ mz_stream_zlib_set_prop_int64
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_zlib_s {
+ mz_stream stream;
+ zlib_stream zstream;
+ uint8_t buffer[INT16_MAX];
+ int32_t buffer_len;
+ int64_t total_in;
+ int64_t total_out;
+ int64_t max_total_in;
+ int8_t initialized;
+ int16_t level;
+ int32_t window_bits;
+ int32_t mode;
+ int32_t error;
+} mz_stream_zlib;
+
+/***************************************************************************/
+
+int32_t mz_stream_zlib_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
+
+ MZ_UNUSED(path);
+
+ zlib->zstream.data_type = Z_BINARY;
+ zlib->zstream.zalloc = Z_NULL;
+ zlib->zstream.zfree = Z_NULL;
+ zlib->zstream.opaque = Z_NULL;
+ zlib->zstream.total_in = 0;
+ zlib->zstream.total_out = 0;
+
+ zlib->total_in = 0;
+ zlib->total_out = 0;
+
+ if (mode & MZ_OPEN_MODE_WRITE) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ zlib->zstream.next_out = zlib->buffer;
+ zlib->zstream.avail_out = sizeof(zlib->buffer);
+
+ zlib->error = ZLIB_PREFIX(deflateInit2)(&zlib->zstream, (int8_t)zlib->level, Z_DEFLATED,
+ zlib->window_bits, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+#endif
+ } else if (mode & MZ_OPEN_MODE_READ) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ zlib->zstream.next_in = zlib->buffer;
+ zlib->zstream.avail_in = 0;
+
+ zlib->error = ZLIB_PREFIX(inflateInit2)(&zlib->zstream, zlib->window_bits);
+#endif
+ }
+
+ if (zlib->error != Z_OK)
+ return MZ_OPEN_ERROR;
+
+ zlib->initialized = 1;
+ zlib->mode = mode;
+ return MZ_OK;
+}
+
+int32_t mz_stream_zlib_is_open(void *stream) {
+ mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
+ if (zlib->initialized != 1)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_zlib_read(void *stream, void *buf, int32_t size) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ MZ_UNUSED(stream);
+ MZ_UNUSED(buf);
+ MZ_UNUSED(size);
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
+ uint64_t total_in_before = 0;
+ uint64_t total_in_after = 0;
+ uint64_t total_out_before = 0;
+ uint64_t total_out_after = 0;
+ uint32_t total_in = 0;
+ uint32_t total_out = 0;
+ uint32_t in_bytes = 0;
+ uint32_t out_bytes = 0;
+ int32_t bytes_to_read = sizeof(zlib->buffer);
+ int32_t read = 0;
+ int32_t err = Z_OK;
+
+
+ zlib->zstream.next_out = (Bytef*)buf;
+ zlib->zstream.avail_out = (uInt)size;
+
+ do {
+ if (zlib->zstream.avail_in == 0) {
+ if (zlib->max_total_in > 0) {
+ if ((int64_t)bytes_to_read > (zlib->max_total_in - zlib->total_in))
+ bytes_to_read = (int32_t)(zlib->max_total_in - zlib->total_in);
+ }
+
+ read = mz_stream_read(zlib->stream.base, zlib->buffer, bytes_to_read);
+
+ if (read < 0)
+ return read;
+
+ zlib->zstream.next_in = zlib->buffer;
+ zlib->zstream.avail_in = read;
+ }
+
+ total_in_before = zlib->zstream.avail_in;
+ total_out_before = zlib->zstream.total_out;
+
+ err = ZLIB_PREFIX(inflate)(&zlib->zstream, Z_SYNC_FLUSH);
+ if ((err >= Z_OK) && (zlib->zstream.msg != NULL)) {
+ zlib->error = Z_DATA_ERROR;
+ break;
+ }
+
+ total_in_after = zlib->zstream.avail_in;
+ total_out_after = zlib->zstream.total_out;
+
+ in_bytes = (uint32_t)(total_in_before - total_in_after);
+ out_bytes = (uint32_t)(total_out_after - total_out_before);
+
+ total_in += in_bytes;
+ total_out += out_bytes;
+
+ zlib->total_in += in_bytes;
+ zlib->total_out += out_bytes;
+
+ if (err == Z_STREAM_END)
+ break;
+ if (err != Z_OK) {
+ zlib->error = err;
+ break;
+ }
+ } while (zlib->zstream.avail_out > 0);
+
+ if (zlib->error != 0) {
+ /* Zlib errors are compatible with MZ */
+ return zlib->error;
+ }
+
+ return total_out;
+#endif
+}
+
+#ifndef MZ_ZIP_NO_COMPRESSION
+static int32_t mz_stream_zlib_flush(void *stream) {
+ mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
+ if (mz_stream_write(zlib->stream.base, zlib->buffer, zlib->buffer_len) != zlib->buffer_len)
+ return MZ_WRITE_ERROR;
+ return MZ_OK;
+}
+
+static int32_t mz_stream_zlib_deflate(void *stream, int flush) {
+ mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
+ uint64_t total_out_before = 0;
+ uint64_t total_out_after = 0;
+ int32_t out_bytes = 0;
+ int32_t err = Z_OK;
+
+
+ do {
+ if (zlib->zstream.avail_out == 0) {
+ err = mz_stream_zlib_flush(zlib);
+ if (err != MZ_OK)
+ return err;
+
+ zlib->zstream.avail_out = sizeof(zlib->buffer);
+ zlib->zstream.next_out = zlib->buffer;
+
+ zlib->buffer_len = 0;
+ }
+
+ total_out_before = zlib->zstream.total_out;
+ err = ZLIB_PREFIX(deflate)(&zlib->zstream, flush);
+ total_out_after = zlib->zstream.total_out;
+
+ out_bytes = (uint32_t)(total_out_after - total_out_before);
+
+ zlib->buffer_len += out_bytes;
+ zlib->total_out += out_bytes;
+
+ if (err == Z_STREAM_END)
+ break;
+ if (err != Z_OK) {
+ zlib->error = err;
+ return MZ_DATA_ERROR;
+ }
+ } while ((zlib->zstream.avail_in > 0) || (flush == Z_FINISH && err == Z_OK));
+
+ return MZ_OK;
+}
+#endif
+
+int32_t mz_stream_zlib_write(void *stream, const void *buf, int32_t size) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ MZ_UNUSED(stream);
+ MZ_UNUSED(buf);
+ MZ_UNUSED(size);
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
+ int32_t err = MZ_OK;
+
+ zlib->zstream.next_in = (Bytef*)(intptr_t)buf;
+ zlib->zstream.avail_in = (uInt)size;
+
+ err = mz_stream_zlib_deflate(stream, Z_NO_FLUSH);
+ if (err != MZ_OK) {
+ return err;
+ }
+
+ zlib->total_in += size;
+ return size;
+#endif
+}
+
+int64_t mz_stream_zlib_tell(void *stream) {
+ MZ_UNUSED(stream);
+
+ return MZ_TELL_ERROR;
+}
+
+int32_t mz_stream_zlib_seek(void *stream, int64_t offset, int32_t origin) {
+ MZ_UNUSED(stream);
+ MZ_UNUSED(offset);
+ MZ_UNUSED(origin);
+
+ return MZ_SEEK_ERROR;
+}
+
+int32_t mz_stream_zlib_close(void *stream) {
+ mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
+
+
+ if (zlib->mode & MZ_OPEN_MODE_WRITE) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_zlib_deflate(stream, Z_FINISH);
+ mz_stream_zlib_flush(stream);
+
+ ZLIB_PREFIX(deflateEnd)(&zlib->zstream);
+#endif
+ } else if (zlib->mode & MZ_OPEN_MODE_READ) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ ZLIB_PREFIX(inflateEnd)(&zlib->zstream);
+#endif
+ }
+
+ zlib->initialized = 0;
+
+ if (zlib->error != Z_OK)
+ return MZ_CLOSE_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_zlib_error(void *stream) {
+ mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
+ return zlib->error;
+}
+
+int32_t mz_stream_zlib_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
+ mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_IN:
+ *value = zlib->total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ *value = zlib->max_total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_OUT:
+ *value = zlib->total_out;
+ break;
+ case MZ_STREAM_PROP_HEADER_SIZE:
+ *value = 0;
+ break;
+ case MZ_STREAM_PROP_COMPRESS_WINDOW:
+ *value = zlib->window_bits;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_stream_zlib_set_prop_int64(void *stream, int32_t prop, int64_t value) {
+ mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_COMPRESS_LEVEL:
+ zlib->level = (int16_t)value;
+ break;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ zlib->max_total_in = value;
+ break;
+ case MZ_STREAM_PROP_COMPRESS_WINDOW:
+ zlib->window_bits = (int32_t)value;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+void *mz_stream_zlib_create(void **stream) {
+ mz_stream_zlib *zlib = NULL;
+
+ zlib = (mz_stream_zlib *)MZ_ALLOC(sizeof(mz_stream_zlib));
+ if (zlib != NULL) {
+ memset(zlib, 0, sizeof(mz_stream_zlib));
+ zlib->stream.vtbl = &mz_stream_zlib_vtbl;
+ zlib->level = Z_DEFAULT_COMPRESSION;
+ zlib->window_bits = -MAX_WBITS;
+ }
+ if (stream != NULL)
+ *stream = zlib;
+
+ return zlib;
+}
+
+void mz_stream_zlib_delete(void **stream) {
+ mz_stream_zlib *zlib = NULL;
+ if (stream == NULL)
+ return;
+ zlib = (mz_stream_zlib *)*stream;
+ if (zlib != NULL)
+ MZ_FREE(zlib);
+ *stream = NULL;
+}
+
+void *mz_stream_zlib_get_interface(void) {
+ return (void *)&mz_stream_zlib_vtbl;
+}
diff --git a/Externals/minizip/mz_strm_zlib.h b/Externals/minizip/mz_strm_zlib.h
new file mode 100644
index 0000000000..47f74804fb
--- /dev/null
+++ b/Externals/minizip/mz_strm_zlib.h
@@ -0,0 +1,43 @@
+/* mz_strm_zlib.h -- Stream for zlib inflate/deflate
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_ZLIB_H
+#define MZ_STREAM_ZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_zlib_open(void *stream, const char *filename, int32_t mode);
+int32_t mz_stream_zlib_is_open(void *stream);
+int32_t mz_stream_zlib_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_zlib_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_zlib_tell(void *stream);
+int32_t mz_stream_zlib_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_zlib_close(void *stream);
+int32_t mz_stream_zlib_error(void *stream);
+
+int32_t mz_stream_zlib_get_prop_int64(void *stream, int32_t prop, int64_t *value);
+int32_t mz_stream_zlib_set_prop_int64(void *stream, int32_t prop, int64_t value);
+
+void* mz_stream_zlib_create(void **stream);
+void mz_stream_zlib_delete(void **stream);
+
+void* mz_stream_zlib_get_interface(void);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_strm_zstd.c b/Externals/minizip/mz_strm_zstd.c
new file mode 100644
index 0000000000..4c9c335618
--- /dev/null
+++ b/Externals/minizip/mz_strm_zstd.c
@@ -0,0 +1,351 @@
+/* mz_strm_zstd.c -- Stream for zstd compress/decompress
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Authors: Force Charlie
+ https://github.com/fcharlie
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include "mz.h"
+#include "mz_strm.h"
+#include "mz_strm_zstd.h"
+
+#include <zstd.h>
+
+/***************************************************************************/
+
+static mz_stream_vtbl mz_stream_zstd_vtbl = {
+ mz_stream_zstd_open,
+ mz_stream_zstd_is_open,
+ mz_stream_zstd_read,
+ mz_stream_zstd_write,
+ mz_stream_zstd_tell,
+ mz_stream_zstd_seek,
+ mz_stream_zstd_close,
+ mz_stream_zstd_error,
+ mz_stream_zstd_create,
+ mz_stream_zstd_delete,
+ mz_stream_zstd_get_prop_int64,
+ mz_stream_zstd_set_prop_int64
+};
+
+/***************************************************************************/
+
+typedef struct mz_stream_zstd_s {
+ mz_stream stream;
+ ZSTD_CStream *zcstream;
+ ZSTD_DStream *zdstream;
+ ZSTD_outBuffer out;
+ ZSTD_inBuffer in;
+ int32_t mode;
+ int32_t error;
+ uint8_t buffer[INT16_MAX];
+ int32_t buffer_len;
+ int64_t total_in;
+ int64_t total_out;
+ int64_t max_total_in;
+ int64_t max_total_out;
+ int8_t initialized;
+ uint32_t preset;
+} mz_stream_zstd;
+
+/***************************************************************************/
+
+int32_t mz_stream_zstd_open(void *stream, const char *path, int32_t mode) {
+ mz_stream_zstd *zstd = (mz_stream_zstd *)stream;
+
+ MZ_UNUSED(path);
+
+ if (mode & MZ_OPEN_MODE_WRITE) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ zstd->zcstream = ZSTD_createCStream();
+ zstd->out.dst = zstd->buffer;
+ zstd->out.size = sizeof(zstd->buffer);
+ zstd->out.pos = 0;
+#endif
+ } else if (mode & MZ_OPEN_MODE_READ) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ zstd->zdstream = ZSTD_createDStream();
+ memset(&zstd->out, 0, sizeof(ZSTD_outBuffer));
+#endif
+ }
+
+ memset(&zstd->in, 0, sizeof(ZSTD_inBuffer));
+
+ zstd->initialized = 1;
+ zstd->mode = mode;
+ zstd->error = MZ_OK;
+
+ return MZ_OK;
+}
+
+int32_t mz_stream_zstd_is_open(void *stream) {
+ mz_stream_zstd *zstd = (mz_stream_zstd *)stream;
+ if (zstd->initialized != 1)
+ return MZ_OPEN_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_stream_zstd_read(void *stream, void *buf, int32_t size) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ MZ_UNUSED(stream);
+ MZ_UNUSED(buf);
+ MZ_UNUSED(size);
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_zstd *zstd = (mz_stream_zstd *)stream;
+ uint64_t total_in_before = 0;
+ uint64_t total_in_after = 0;
+ uint64_t total_out_before = 0;
+ uint64_t total_out_after = 0;
+ int32_t total_in = 0;
+ int32_t total_out = 0;
+ int32_t in_bytes = 0;
+ int32_t out_bytes = 0;
+ int32_t bytes_to_read = sizeof(zstd->buffer);
+ int32_t read = 0;
+ size_t result = 0;
+
+ zstd->out.dst = (void*)buf;
+ zstd->out.size = (size_t)size;
+ zstd->out.pos = 0;
+
+ do {
+ if (zstd->in.pos == zstd->in.size) {
+ if (zstd->max_total_in > 0) {
+ if ((int64_t)bytes_to_read > (zstd->max_total_in - zstd->total_in))
+ bytes_to_read = (int32_t)(zstd->max_total_in - zstd->total_in);
+ }
+
+ read = mz_stream_read(zstd->stream.base, zstd->buffer, bytes_to_read);
+
+ if (read < 0)
+ return read;
+
+ zstd->in.src = (const void*)zstd->buffer;
+ zstd->in.pos = 0;
+ zstd->in.size = (size_t)read;
+ }
+
+ total_in_before = zstd->in.pos;
+ total_out_before = zstd->out.pos;
+
+ result = ZSTD_decompressStream(zstd->zdstream, &zstd->out, &zstd->in);
+
+ if (ZSTD_isError(result)) {
+ zstd->error = (int32_t)result;
+ return MZ_DATA_ERROR;
+ }
+
+ total_in_after = zstd->in.pos;
+ total_out_after = zstd->out.pos;
+ if ((zstd->max_total_out != -1) && (int64_t)total_out_after > zstd->max_total_out)
+ total_out_after = (uint64_t)zstd->max_total_out;
+
+ in_bytes = (int32_t)(total_in_after - total_in_before);
+ out_bytes = (int32_t)(total_out_after - total_out_before);
+
+ total_in += in_bytes;
+ total_out += out_bytes;
+
+ zstd->total_in += in_bytes;
+ zstd->total_out += out_bytes;
+
+ } while ((zstd->in.size > 0 || out_bytes > 0) && (zstd->out.pos < zstd->out.size));
+
+ return total_out;
+#endif
+}
+
+#ifndef MZ_ZIP_NO_COMPRESSION
+static int32_t mz_stream_zstd_flush(void *stream) {
+ mz_stream_zstd *zstd = (mz_stream_zstd *)stream;
+ if (mz_stream_write(zstd->stream.base, zstd->buffer, zstd->buffer_len) != zstd->buffer_len)
+ return MZ_WRITE_ERROR;
+ return MZ_OK;
+}
+
+static int32_t mz_stream_zstd_compress(void *stream, ZSTD_EndDirective flush) {
+ mz_stream_zstd *zstd = (mz_stream_zstd *)stream;
+ uint64_t total_out_before = 0;
+ uint64_t total_out_after = 0;
+ int32_t out_bytes = 0;
+ size_t result = 0;
+ int32_t err = 0;
+
+ do {
+ if (zstd->out.pos == zstd->out.size) {
+ err = mz_stream_zstd_flush(zstd);
+ if (err != MZ_OK)
+ return err;
+
+ zstd->out.dst = zstd->buffer;
+ zstd->out.size = sizeof(zstd->buffer);
+ zstd->out.pos = 0;
+
+ zstd->buffer_len = 0;
+ }
+
+ total_out_before = zstd->out.pos;
+
+ result = ZSTD_compressStream2(zstd->zcstream, &zstd->out, &zstd->in, flush);
+
+ total_out_after = zstd->out.pos;
+
+ out_bytes = (uint32_t)(total_out_after - total_out_before);
+
+ zstd->buffer_len += out_bytes;
+ zstd->total_out += out_bytes;
+
+ if (ZSTD_isError(result)) {
+ zstd->error = (int32_t)result;
+ return MZ_DATA_ERROR;
+ }
+ } while ((zstd->in.pos < zstd->in.size) || (flush == ZSTD_e_end && result != 0));
+
+ return MZ_OK;
+}
+#endif
+
+int32_t mz_stream_zstd_write(void *stream, const void *buf, int32_t size) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ MZ_UNUSED(stream);
+ MZ_UNUSED(buf);
+ MZ_UNUSED(size);
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_zstd *zstd = (mz_stream_zstd *)stream;
+ int32_t err = MZ_OK;
+
+ zstd->in.src = buf;
+ zstd->in.pos = 0;
+ zstd->in.size = size;
+
+ err = mz_stream_zstd_compress(stream, ZSTD_e_continue);
+ if (err != MZ_OK) {
+ return err;
+ }
+
+ zstd->total_in += size;
+ return size;
+#endif
+}
+
+int64_t mz_stream_zstd_tell(void *stream) {
+ MZ_UNUSED(stream);
+
+ return MZ_TELL_ERROR;
+}
+
+int32_t mz_stream_zstd_seek(void *stream, int64_t offset, int32_t origin) {
+ MZ_UNUSED(stream);
+ MZ_UNUSED(offset);
+ MZ_UNUSED(origin);
+
+ return MZ_SEEK_ERROR;
+}
+
+int32_t mz_stream_zstd_close(void *stream) {
+ mz_stream_zstd *zstd = (mz_stream_zstd *)stream;
+
+ if (zstd->mode & MZ_OPEN_MODE_WRITE) {
+#ifdef MZ_ZIP_NO_COMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ mz_stream_zstd_compress(stream, ZSTD_e_end);
+ mz_stream_zstd_flush(stream);
+
+ ZSTD_freeCStream(zstd->zcstream);
+ zstd->zcstream = NULL;
+#endif
+ } else if (zstd->mode & MZ_OPEN_MODE_READ) {
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ return MZ_SUPPORT_ERROR;
+#else
+ ZSTD_freeDStream(zstd->zdstream);
+ zstd->zdstream = NULL;
+#endif
+ }
+ zstd->initialized = 0;
+ return MZ_OK;
+}
+
+int32_t mz_stream_zstd_error(void *stream) {
+ mz_stream_zstd *zstd = (mz_stream_zstd *)stream;
+ return zstd->error;
+}
+
+int32_t mz_stream_zstd_get_prop_int64(void *stream, int32_t prop, int64_t *value) {
+ mz_stream_zstd *zstd = (mz_stream_zstd *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_TOTAL_IN:
+ *value = zstd->total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ *value = zstd->max_total_in;
+ break;
+ case MZ_STREAM_PROP_TOTAL_OUT:
+ *value = zstd->total_out;
+ break;
+ case MZ_STREAM_PROP_TOTAL_OUT_MAX:
+ *value = zstd->max_total_out;
+ break;
+ case MZ_STREAM_PROP_HEADER_SIZE:
+ *value = 0;
+ break;
+ default:
+ return MZ_EXIST_ERROR;
+ }
+ return MZ_OK;
+}
+
+int32_t mz_stream_zstd_set_prop_int64(void *stream, int32_t prop, int64_t value) {
+ mz_stream_zstd *zstd = (mz_stream_zstd *)stream;
+ switch (prop) {
+ case MZ_STREAM_PROP_COMPRESS_LEVEL:
+ if (value < 0)
+ zstd->preset = 6;
+ else
+ zstd->preset = (int16_t)value;
+ return MZ_OK;
+ case MZ_STREAM_PROP_TOTAL_IN_MAX:
+ zstd->max_total_in = value;
+ return MZ_OK;
+ }
+ return MZ_EXIST_ERROR;
+}
+
+void *mz_stream_zstd_create(void **stream) {
+ mz_stream_zstd *zstd = NULL;
+ zstd = (mz_stream_zstd *)MZ_ALLOC(sizeof(mz_stream_zstd));
+ if (zstd != NULL) {
+ memset(zstd, 0, sizeof(mz_stream_zstd));
+ zstd->stream.vtbl = &mz_stream_zstd_vtbl;
+ zstd->max_total_out = -1;
+ }
+ if (stream != NULL)
+ *stream = zstd;
+ return zstd;
+}
+
+void mz_stream_zstd_delete(void **stream) {
+ mz_stream_zstd *zstd = NULL;
+ if (stream == NULL)
+ return;
+ zstd = (mz_stream_zstd *)*stream;
+ if (zstd != NULL)
+ MZ_FREE(zstd);
+ *stream = NULL;
+}
+
+void *mz_stream_zstd_get_interface(void) {
+ return (void *)&mz_stream_zstd_vtbl;
+}
diff --git a/Externals/minizip/mz_strm_zstd.h b/Externals/minizip/mz_strm_zstd.h
new file mode 100644
index 0000000000..3587083548
--- /dev/null
+++ b/Externals/minizip/mz_strm_zstd.h
@@ -0,0 +1,44 @@
+/* mz_strm_zlib.h -- Stream for zlib inflate/deflate
+ Version 2.9.2, February 12, 2020
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_STREAM_ZSTD_H
+#define MZ_STREAM_ZSTD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+int32_t mz_stream_zstd_open(void *stream, const char *filename, int32_t mode);
+int32_t mz_stream_zstd_is_open(void *stream);
+int32_t mz_stream_zstd_read(void *stream, void *buf, int32_t size);
+int32_t mz_stream_zstd_write(void *stream, const void *buf, int32_t size);
+int64_t mz_stream_zstd_tell(void *stream);
+int32_t mz_stream_zstd_seek(void *stream, int64_t offset, int32_t origin);
+int32_t mz_stream_zstd_close(void *stream);
+int32_t mz_stream_zstd_error(void *stream);
+
+int32_t mz_stream_zstd_get_prop_int64(void *stream, int32_t prop, int64_t *value);
+int32_t mz_stream_zstd_set_prop_int64(void *stream, int32_t prop, int64_t value);
+
+void* mz_stream_zstd_create(void **stream);
+void mz_stream_zstd_delete(void **stream);
+
+void* mz_stream_zstd_get_interface(void);
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/mz_zip.c b/Externals/minizip/mz_zip.c
new file mode 100644
index 0000000000..cc4f57d0b3
--- /dev/null
+++ b/Externals/minizip/mz_zip.c
@@ -0,0 +1,2771 @@
+/* zip.c -- Zip manipulation
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Copyright (C) 2009-2010 Mathias Svensson
+ Modifications for Zip64 support
+ http://result42.com
+ Copyright (C) 2007-2008 Even Rouault
+ Modifications of Unzip for Zip64
+ Copyright (C) 1998-2010 Gilles Vollant
+ https://www.winimage.com/zLibDll/minizip.html
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+
+#include "mz.h"
+#include "mz_crypt.h"
+#include "mz_strm.h"
+#ifdef HAVE_BZIP2
+# include "mz_strm_bzip.h"
+#endif
+#ifdef HAVE_LIBCOMP
+# include "mz_strm_libcomp.h"
+#endif
+#ifdef HAVE_LZMA
+# include "mz_strm_lzma.h"
+#endif
+#include "mz_strm_mem.h"
+#ifdef HAVE_PKCRYPT
+# include "mz_strm_pkcrypt.h"
+#endif
+#ifdef HAVE_WZAES
+# include "mz_strm_wzaes.h"
+#endif
+#ifdef HAVE_ZLIB
+# include "mz_strm_zlib.h"
+#endif
+#ifdef HAVE_ZSTD
+# include "mz_strm_zstd.h"
+#endif
+
+#include "mz_zip.h"
+
+#include <ctype.h> /* tolower */
+#include <stdio.h> /* snprintf */
+
+#if defined(_MSC_VER) || defined(__MINGW32__)
+# define localtime_r(t1,t2) (localtime_s(t2,t1) == 0 ? t1 : NULL)
+#endif
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+# define snprintf _snprintf
+#endif
+
+/***************************************************************************/
+
+#define MZ_ZIP_MAGIC_LOCALHEADER (0x04034b50)
+#define MZ_ZIP_MAGIC_LOCALHEADERU8 { 0x50, 0x4b, 0x03, 0x04 }
+#define MZ_ZIP_MAGIC_CENTRALHEADER (0x02014b50)
+#define MZ_ZIP_MAGIC_CENTRALHEADERU8 { 0x50, 0x4b, 0x01, 0x02 }
+#define MZ_ZIP_MAGIC_ENDHEADER (0x06054b50)
+#define MZ_ZIP_MAGIC_ENDHEADERU8 { 0x50, 0x4b, 0x05, 0x06 }
+#define MZ_ZIP_MAGIC_ENDHEADER64 (0x06064b50)
+#define MZ_ZIP_MAGIC_ENDLOCHEADER64 (0x07064b50)
+#define MZ_ZIP_MAGIC_DATADESCRIPTOR (0x08074b50)
+#define MZ_ZIP_MAGIC_DATADESCRIPTORU8 { 0x50, 0x4b, 0x07, 0x08 }
+
+#define MZ_ZIP_SIZE_LD_ITEM (30)
+#define MZ_ZIP_SIZE_CD_ITEM (46)
+#define MZ_ZIP_SIZE_CD_LOCATOR64 (20)
+#define MZ_ZIP_SIZE_MAX_DATA_DESCRIPTOR (24)
+
+#define MZ_ZIP_OFFSET_CRC_SIZES (14)
+#define MZ_ZIP_UNCOMPR_SIZE64_CUSHION (2 * 1024 * 1024)
+
+#ifndef MZ_ZIP_EOCD_MAX_BACK
+#define MZ_ZIP_EOCD_MAX_BACK (1 << 20)
+#endif
+
+/***************************************************************************/
+
+typedef struct mz_zip_s {
+ mz_zip_file file_info;
+ mz_zip_file local_file_info;
+
+ void *stream; /* main stream */
+ void *cd_stream; /* pointer to the stream with the cd */
+ void *cd_mem_stream; /* memory stream for central directory */
+ void *compress_stream; /* compression stream */
+ void *crypt_stream; /* encryption stream */
+ void *file_info_stream; /* memory stream for storing file info */
+ void *local_file_info_stream; /* memory stream for storing local file info */
+
+ int32_t open_mode;
+ uint8_t recover;
+ uint8_t data_descriptor;
+
+ uint32_t disk_number_with_cd; /* number of the disk with the central dir */
+ int64_t disk_offset_shift; /* correction for zips that have wrong offset start of cd */
+
+ int64_t cd_start_pos; /* pos of the first file in the central dir stream */
+ int64_t cd_current_pos; /* pos of the current file in the central dir */
+ int64_t cd_offset; /* offset of start of central directory */
+ int64_t cd_size; /* size of the central directory */
+ uint32_t cd_signature; /* signature of central directory */
+
+ uint8_t entry_scanned; /* entry header information read ok */
+ uint8_t entry_opened; /* entry is open for read/write */
+ uint8_t entry_raw; /* entry opened with raw mode */
+ uint32_t entry_crc32; /* entry crc32 */
+
+ uint64_t number_entry;
+
+ uint16_t version_madeby;
+ char *comment;
+} mz_zip;
+
+/***************************************************************************/
+
+#if 0
+# define mz_zip_print printf
+#else
+# define mz_zip_print(fmt,...)
+#endif
+
+/***************************************************************************/
+
+/* Locate the end of central directory */
+static int32_t mz_zip_search_eocd(void *stream, int64_t *central_pos) {
+ int64_t file_size = 0;
+ int64_t max_back = MZ_ZIP_EOCD_MAX_BACK;
+ uint8_t find[4] = MZ_ZIP_MAGIC_ENDHEADERU8;
+ int32_t err = MZ_OK;
+
+ err = mz_stream_seek(stream, 0, MZ_SEEK_END);
+ if (err != MZ_OK)
+ return err;
+
+ file_size = mz_stream_tell(stream);
+
+ if (max_back <= 0 || max_back > file_size)
+ max_back = file_size;
+
+ return mz_stream_find_reverse(stream, (const void *)find, sizeof(find), max_back, central_pos);
+}
+
+/* Locate the end of central directory 64 of a zip file */
+static int32_t mz_zip_search_zip64_eocd(void *stream, const int64_t end_central_offset, int64_t *central_pos) {
+ int64_t offset = 0;
+ uint32_t value32 = 0;
+ int32_t err = MZ_OK;
+
+
+ *central_pos = 0;
+
+ /* Zip64 end of central directory locator */
+ err = mz_stream_seek(stream, end_central_offset - MZ_ZIP_SIZE_CD_LOCATOR64, MZ_SEEK_SET);
+ /* Read locator signature */
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint32(stream, &value32);
+ if (value32 != MZ_ZIP_MAGIC_ENDLOCHEADER64)
+ err = MZ_FORMAT_ERROR;
+ }
+ /* Number of the disk with the start of the zip64 end of central directory */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(stream, &value32);
+ /* Relative offset of the zip64 end of central directory record8 */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint64(stream, (uint64_t *)&offset);
+ /* Total number of disks */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(stream, &value32);
+ /* Goto end of central directory record */
+ if (err == MZ_OK)
+ err = mz_stream_seek(stream, (int64_t)offset, MZ_SEEK_SET);
+ /* The signature */
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint32(stream, &value32);
+ if (value32 != MZ_ZIP_MAGIC_ENDHEADER64)
+ err = MZ_FORMAT_ERROR;
+ }
+
+ if (err == MZ_OK)
+ *central_pos = offset;
+
+ return err;
+}
+
+/* Get PKWARE traditional encryption verifier */
+static uint16_t mz_zip_get_pk_verify(uint32_t dos_date, uint64_t crc, uint16_t flag)
+{
+ /* Info-ZIP modification to ZipCrypto format: if bit 3 of the general
+ * purpose bit flag is set, it uses high byte of 16-bit File Time. */
+ if (flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR)
+ return ((dos_date >> 16) & 0xff) << 8 | ((dos_date >> 8) & 0xff);
+ return ((crc >> 16) & 0xff) << 8 | ((crc >> 24) & 0xff);
+}
+
+/* Get info about the current file in the zip file */
+static int32_t mz_zip_entry_read_header(void *stream, uint8_t local, mz_zip_file *file_info, void *file_extra_stream) {
+ uint64_t ntfs_time = 0;
+ uint32_t reserved = 0;
+ uint32_t magic = 0;
+ uint32_t dos_date = 0;
+ uint32_t field_pos = 0;
+ uint16_t field_type = 0;
+ uint16_t field_length = 0;
+ uint32_t field_length_read = 0;
+ uint16_t ntfs_attrib_id = 0;
+ uint16_t ntfs_attrib_size = 0;
+ uint16_t linkname_size;
+ uint16_t value16 = 0;
+ uint32_t value32 = 0;
+ int64_t extrafield_pos = 0;
+ int64_t comment_pos = 0;
+ int64_t linkname_pos = 0;
+ int64_t saved_pos = 0;
+ int32_t err = MZ_OK;
+ char *linkname = NULL;
+
+
+ memset(file_info, 0, sizeof(mz_zip_file));
+
+ /* Check the magic */
+ err = mz_stream_read_uint32(stream, &magic);
+ if (err == MZ_END_OF_STREAM)
+ err = MZ_END_OF_LIST;
+ else if (magic == MZ_ZIP_MAGIC_ENDHEADER || magic == MZ_ZIP_MAGIC_ENDHEADER64)
+ err = MZ_END_OF_LIST;
+ else if ((local) && (magic != MZ_ZIP_MAGIC_LOCALHEADER))
+ err = MZ_FORMAT_ERROR;
+ else if ((!local) && (magic != MZ_ZIP_MAGIC_CENTRALHEADER))
+ err = MZ_FORMAT_ERROR;
+
+ /* Read header fields */
+ if (err == MZ_OK) {
+ if (!local)
+ err = mz_stream_read_uint16(stream, &file_info->version_madeby);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(stream, &file_info->version_needed);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(stream, &file_info->flag);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(stream, &file_info->compression_method);
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint32(stream, &dos_date);
+ file_info->modified_date = mz_zip_dosdate_to_time_t(dos_date);
+ }
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(stream, &file_info->crc);
+#ifdef HAVE_PKCRYPT
+ if (err == MZ_OK && file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) {
+ /* Use dos_date from header instead of derived from time in zip extensions */
+ file_info->pk_verify = mz_zip_get_pk_verify(dos_date, file_info->crc, file_info->flag);
+ }
+#endif
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint32(stream, &value32);
+ file_info->compressed_size = value32;
+ }
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint32(stream, &value32);
+ file_info->uncompressed_size = value32;
+ }
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(stream, &file_info->filename_size);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(stream, &file_info->extrafield_size);
+ if (!local) {
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(stream, &file_info->comment_size);
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint16(stream, &value16);
+ file_info->disk_number = value16;
+ }
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(stream, &file_info->internal_fa);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(stream, &file_info->external_fa);
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint32(stream, &value32);
+ file_info->disk_offset = value32;
+ }
+ }
+ }
+
+ if (err == MZ_OK)
+ err = mz_stream_seek(file_extra_stream, 0, MZ_SEEK_SET);
+
+ /* Copy variable length data to memory stream for later retrieval */
+ if ((err == MZ_OK) && (file_info->filename_size > 0))
+ err = mz_stream_copy(file_extra_stream, stream, file_info->filename_size);
+ mz_stream_write_uint8(file_extra_stream, 0);
+ extrafield_pos = mz_stream_tell(file_extra_stream);
+
+ if ((err == MZ_OK) && (file_info->extrafield_size > 0))
+ err = mz_stream_copy(file_extra_stream, stream, file_info->extrafield_size);
+ mz_stream_write_uint8(file_extra_stream, 0);
+
+ comment_pos = mz_stream_tell(file_extra_stream);
+ if ((err == MZ_OK) && (file_info->comment_size > 0))
+ err = mz_stream_copy(file_extra_stream, stream, file_info->comment_size);
+ mz_stream_write_uint8(file_extra_stream, 0);
+
+ linkname_pos = mz_stream_tell(file_extra_stream);
+ /* Overwrite if we encounter UNIX1 extra block */
+ mz_stream_write_uint8(file_extra_stream, 0);
+
+ if ((err == MZ_OK) && (file_info->extrafield_size > 0)) {
+ /* Seek to and parse the extra field */
+ err = mz_stream_seek(file_extra_stream, extrafield_pos, MZ_SEEK_SET);
+
+ while ((err == MZ_OK) && (field_pos + 4 <= file_info->extrafield_size)) {
+ err = mz_zip_extrafield_read(file_extra_stream, &field_type, &field_length);
+ if (err != MZ_OK)
+ break;
+ field_pos += 4;
+
+ /* Don't allow field length to exceed size of remaining extrafield */
+ if (field_length > (file_info->extrafield_size - field_pos))
+ field_length = (uint16_t)(file_info->extrafield_size - field_pos);
+
+ /* Read ZIP64 extra field */
+ if ((field_type == MZ_ZIP_EXTENSION_ZIP64) && (field_length >= 8)) {
+ if ((err == MZ_OK) && (file_info->uncompressed_size == UINT32_MAX)) {
+ err = mz_stream_read_int64(file_extra_stream, &file_info->uncompressed_size);
+ if (file_info->uncompressed_size < 0)
+ err = MZ_FORMAT_ERROR;
+ }
+ if ((err == MZ_OK) && (file_info->compressed_size == UINT32_MAX)) {
+ err = mz_stream_read_int64(file_extra_stream, &file_info->compressed_size);
+ if (file_info->compressed_size < 0)
+ err = MZ_FORMAT_ERROR;
+ }
+ if ((err == MZ_OK) && (file_info->disk_offset == UINT32_MAX)) {
+ err = mz_stream_read_int64(file_extra_stream, &file_info->disk_offset);
+ if (file_info->disk_offset < 0)
+ err = MZ_FORMAT_ERROR;
+ }
+ if ((err == MZ_OK) && (file_info->disk_number == UINT16_MAX))
+ err = mz_stream_read_uint32(file_extra_stream, &file_info->disk_number);
+ }
+ /* Read NTFS extra field */
+ else if ((field_type == MZ_ZIP_EXTENSION_NTFS) && (field_length > 4)) {
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(file_extra_stream, &reserved);
+ field_length_read = 4;
+
+ while ((err == MZ_OK) && (field_length_read + 4 <= field_length)) {
+ err = mz_stream_read_uint16(file_extra_stream, &ntfs_attrib_id);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(file_extra_stream, &ntfs_attrib_size);
+ field_length_read += 4;
+
+ if ((err == MZ_OK) && (ntfs_attrib_id == 0x01) && (ntfs_attrib_size == 24)) {
+ err = mz_stream_read_uint64(file_extra_stream, &ntfs_time);
+ mz_zip_ntfs_to_unix_time(ntfs_time, &file_info->modified_date);
+
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint64(file_extra_stream, &ntfs_time);
+ mz_zip_ntfs_to_unix_time(ntfs_time, &file_info->accessed_date);
+ }
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint64(file_extra_stream, &ntfs_time);
+ mz_zip_ntfs_to_unix_time(ntfs_time, &file_info->creation_date);
+ }
+ } else if ((err == MZ_OK) && (field_length_read + ntfs_attrib_size <= field_length)) {
+ err = mz_stream_seek(file_extra_stream, ntfs_attrib_size, MZ_SEEK_CUR);
+ }
+
+ field_length_read += ntfs_attrib_size;
+ }
+ }
+ /* Read UNIX1 extra field */
+ else if ((field_type == MZ_ZIP_EXTENSION_UNIX1) && (field_length >= 12)) {
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint32(file_extra_stream, &value32);
+ if (err == MZ_OK && file_info->accessed_date == 0)
+ file_info->accessed_date = value32;
+ }
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint32(file_extra_stream, &value32);
+ if (err == MZ_OK && file_info->modified_date == 0)
+ file_info->modified_date = value32;
+ }
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(file_extra_stream, &value16); /* User id */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(file_extra_stream, &value16); /* Group id */
+
+ /* Copy linkname to end of file extra stream so we can return null
+ terminated string */
+ linkname_size = field_length - 12;
+ if ((err == MZ_OK) && (linkname_size > 0)) {
+ linkname = (char *)MZ_ALLOC(linkname_size);
+ if (linkname != NULL) {
+ if (mz_stream_read(file_extra_stream, linkname, linkname_size) != linkname_size)
+ err = MZ_READ_ERROR;
+ if (err == MZ_OK) {
+ saved_pos = mz_stream_tell(file_extra_stream);
+
+ mz_stream_seek(file_extra_stream, linkname_pos, MZ_SEEK_SET);
+ mz_stream_write(file_extra_stream, linkname, linkname_size);
+ mz_stream_write_uint8(file_extra_stream, 0);
+
+ mz_stream_seek(file_extra_stream, saved_pos, MZ_SEEK_SET);
+ }
+ MZ_FREE(linkname);
+ }
+ }
+ }
+#ifdef HAVE_WZAES
+ /* Read AES extra field */
+ else if ((field_type == MZ_ZIP_EXTENSION_AES) && (field_length == 7)) {
+ uint8_t value8 = 0;
+ /* Verify version info */
+ err = mz_stream_read_uint16(file_extra_stream, &value16);
+ /* Support AE-1 and AE-2 */
+ if (value16 != 1 && value16 != 2)
+ err = MZ_FORMAT_ERROR;
+ file_info->aes_version = value16;
+ if (err == MZ_OK)
+ err = mz_stream_read_uint8(file_extra_stream, &value8);
+ if ((char)value8 != 'A')
+ err = MZ_FORMAT_ERROR;
+ if (err == MZ_OK)
+ err = mz_stream_read_uint8(file_extra_stream, &value8);
+ if ((char)value8 != 'E')
+ err = MZ_FORMAT_ERROR;
+ /* Get AES encryption strength and actual compression method */
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint8(file_extra_stream, &value8);
+ file_info->aes_encryption_mode = value8;
+ }
+ if (err == MZ_OK) {
+ err = mz_stream_read_uint16(file_extra_stream, &value16);
+ file_info->compression_method = value16;
+ }
+ }
+#endif
+ else if (field_length > 0) {
+ err = mz_stream_seek(file_extra_stream, field_length, MZ_SEEK_CUR);
+ }
+
+ field_pos += field_length;
+ }
+ }
+
+ /* Get pointers to variable length data */
+ mz_stream_mem_get_buffer(file_extra_stream, (const void **)&file_info->filename);
+ mz_stream_mem_get_buffer_at(file_extra_stream, extrafield_pos, (const void **)&file_info->extrafield);
+ mz_stream_mem_get_buffer_at(file_extra_stream, comment_pos, (const void **)&file_info->comment);
+ mz_stream_mem_get_buffer_at(file_extra_stream, linkname_pos, (const void **)&file_info->linkname);
+
+ /* Set to empty string just in-case */
+ if (file_info->filename == NULL)
+ file_info->filename = "";
+ if (file_info->extrafield == NULL)
+ file_info->extrafield_size = 0;
+ if (file_info->comment == NULL)
+ file_info->comment = "";
+ if (file_info->linkname == NULL)
+ file_info->linkname = "";
+
+ if (err == MZ_OK) {
+ mz_zip_print("Zip - Entry - Read header - %s (local %" PRId8 ")\n",
+ file_info->filename, local);
+ mz_zip_print("Zip - Entry - Read header compress (ucs %" PRId64 " cs %" PRId64 " crc 0x%08" PRIx32 ")\n",
+ file_info->uncompressed_size, file_info->compressed_size, file_info->crc);
+ if (!local) {
+ mz_zip_print("Zip - Entry - Read header disk (disk %" PRIu32 " offset %" PRId64 ")\n",
+ file_info->disk_number, file_info->disk_offset);
+ }
+ mz_zip_print("Zip - Entry - Read header variable (fnl %" PRId32 " efs %" PRId32 " cms %" PRId32 ")\n",
+ file_info->filename_size, file_info->extrafield_size, file_info->comment_size);
+ }
+
+ return err;
+}
+
+static int32_t mz_zip_entry_read_descriptor(void *stream, uint8_t zip64, uint32_t *crc32, int64_t *compressed_size, int64_t *uncompressed_size) {
+ uint32_t value32 = 0;
+ int64_t value64 = 0;
+ int32_t err = MZ_OK;
+
+
+ err = mz_stream_read_uint32(stream, &value32);
+ if (value32 != MZ_ZIP_MAGIC_DATADESCRIPTOR)
+ err = MZ_FORMAT_ERROR;
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(stream, &value32);
+ if ((err == MZ_OK) && (crc32 != NULL))
+ *crc32 = value32;
+ if (err == MZ_OK) {
+ /* If zip 64 extension is enabled then read as 8 byte */
+ if (!zip64) {
+ err = mz_stream_read_uint32(stream, &value32);
+ value64 = value32;
+ } else {
+ err = mz_stream_read_int64(stream, &value64);
+ if (value64 < 0)
+ err = MZ_FORMAT_ERROR;
+ }
+ if ((err == MZ_OK) && (compressed_size != NULL))
+ *compressed_size = value64;
+ }
+ if (err == MZ_OK) {
+ if (!zip64) {
+ err = mz_stream_read_uint32(stream, &value32);
+ value64 = value32;
+ } else {
+ err = mz_stream_read_int64(stream, &value64);
+ if (value64 < 0)
+ err = MZ_FORMAT_ERROR;
+ }
+ if ((err == MZ_OK) && (uncompressed_size != NULL))
+ *uncompressed_size = value64;
+ }
+
+ return err;
+}
+
+static int32_t mz_zip_entry_write_crc_sizes(void *stream, uint8_t zip64, uint8_t mask, mz_zip_file *file_info) {
+ int32_t err = MZ_OK;
+
+ if (mask)
+ err = mz_stream_write_uint32(stream, 0);
+ else
+ err = mz_stream_write_uint32(stream, file_info->crc); /* crc */
+
+ /* For backwards-compatibility with older zip applications we set all sizes to UINT32_MAX
+ * when zip64 is needed, instead of only setting sizes larger than UINT32_MAX. */
+
+ if (err == MZ_OK) {
+ if (zip64) /* compr size */
+ err = mz_stream_write_uint32(stream, UINT32_MAX);
+ else
+ err = mz_stream_write_uint32(stream, (uint32_t)file_info->compressed_size);
+ }
+ if (err == MZ_OK) {
+ if (mask) /* uncompr size */
+ err = mz_stream_write_uint32(stream, 0);
+ else if (zip64)
+ err = mz_stream_write_uint32(stream, UINT32_MAX);
+ else
+ err = mz_stream_write_uint32(stream, (uint32_t)file_info->uncompressed_size);
+ }
+ return err;
+}
+
+static int32_t mz_zip_entry_needs_zip64(mz_zip_file *file_info, uint8_t local, uint8_t *zip64) {
+ uint32_t max_uncompressed_size = UINT32_MAX;
+ uint8_t needs_zip64 = 0;
+
+ if (zip64 == NULL)
+ return MZ_PARAM_ERROR;
+
+ *zip64 = 0;
+
+ if (local) {
+ /* At local header we might not know yet whether compressed size will overflow unsigned
+ 32-bit integer which might happen for high entropy data so we give it some cushion */
+
+ max_uncompressed_size -= MZ_ZIP_UNCOMPR_SIZE64_CUSHION;
+ }
+
+ needs_zip64 = (file_info->uncompressed_size >= max_uncompressed_size) ||
+ (file_info->compressed_size >= UINT32_MAX);
+
+ if (!local) {
+ /* Disk offset and number only used in central directory header */
+ needs_zip64 |= (file_info->disk_offset >= UINT32_MAX) ||
+ (file_info->disk_number >= UINT16_MAX);
+ }
+
+ if (file_info->zip64 == MZ_ZIP64_AUTO) {
+ /* If uncompressed size is unknown, assume zip64 for 64-bit data descriptors */
+ if (local && file_info->uncompressed_size == 0) {
+ /* Don't use zip64 for local header directory entries */
+ if (mz_zip_attrib_is_dir(file_info->external_fa, file_info->version_madeby) != MZ_OK) {
+ *zip64 = 1;
+ }
+ }
+ *zip64 |= needs_zip64;
+ } else if (file_info->zip64 == MZ_ZIP64_FORCE) {
+ *zip64 = 1;
+ } else if (file_info->zip64 == MZ_ZIP64_DISABLE) {
+ /* Zip64 extension is required to zip file */
+ if (needs_zip64)
+ return MZ_PARAM_ERROR;
+ }
+
+ return MZ_OK;
+}
+
+static int32_t mz_zip_entry_write_header(void *stream, uint8_t local, mz_zip_file *file_info) {
+ uint64_t ntfs_time = 0;
+ uint32_t reserved = 0;
+ uint32_t dos_date = 0;
+ uint16_t extrafield_size = 0;
+ uint16_t field_type = 0;
+ uint16_t field_length = 0;
+ uint16_t field_length_zip64 = 0;
+ uint16_t field_length_ntfs = 0;
+ uint16_t field_length_aes = 0;
+ uint16_t field_length_unix1 = 0;
+ uint16_t filename_size = 0;
+ uint16_t filename_length = 0;
+ uint16_t linkname_size = 0;
+ uint16_t version_needed = 0;
+ int32_t comment_size = 0;
+ int32_t err = MZ_OK;
+ int32_t err_mem = MZ_OK;
+ uint8_t zip64 = 0;
+ uint8_t skip_aes = 0;
+ uint8_t mask = 0;
+ uint8_t write_end_slash = 0;
+ const char *filename = NULL;
+ char masked_name[64];
+ void *file_extra_stream = NULL;
+
+ if (file_info == NULL)
+ return MZ_PARAM_ERROR;
+
+ if ((local) && (file_info->flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO))
+ mask = 1;
+
+ /* Determine if zip64 extra field is necessary */
+ err = mz_zip_entry_needs_zip64(file_info, local, &zip64);
+ if (err != MZ_OK)
+ return err;
+
+ /* Start calculating extra field sizes */
+ if (zip64) {
+ /* Both compressed and uncompressed sizes must be included (at least in local header) */
+ field_length_zip64 = 8 + 8;
+ if ((!local) && (file_info->disk_offset >= UINT32_MAX))
+ field_length_zip64 += 8;
+
+ extrafield_size += 4;
+ extrafield_size += field_length_zip64;
+ }
+
+ /* Calculate extra field size and check for duplicates */
+ if (file_info->extrafield_size > 0) {
+ mz_stream_mem_create(&file_extra_stream);
+ mz_stream_mem_set_buffer(file_extra_stream, (void *)file_info->extrafield,
+ file_info->extrafield_size);
+
+ do {
+ err_mem = mz_stream_read_uint16(file_extra_stream, &field_type);
+ if (err_mem == MZ_OK)
+ err_mem = mz_stream_read_uint16(file_extra_stream, &field_length);
+ if (err_mem != MZ_OK)
+ break;
+
+ /* Prefer incoming aes extensions over ours */
+ if (field_type == MZ_ZIP_EXTENSION_AES)
+ skip_aes = 1;
+
+ /* Prefer our zip64, ntfs, unix1 extension over incoming */
+ if (field_type != MZ_ZIP_EXTENSION_ZIP64 && field_type != MZ_ZIP_EXTENSION_NTFS &&
+ field_type != MZ_ZIP_EXTENSION_UNIX1)
+ extrafield_size += 4 + field_length;
+
+ if (err_mem == MZ_OK)
+ err_mem = mz_stream_seek(file_extra_stream, field_length, MZ_SEEK_CUR);
+ } while (err_mem == MZ_OK);
+ }
+
+#ifdef HAVE_WZAES
+ if (!skip_aes) {
+ if ((file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version)) {
+ field_length_aes = 1 + 1 + 1 + 2 + 2;
+ extrafield_size += 4 + field_length_aes;
+ }
+ }
+#else
+ MZ_UNUSED(field_length_aes);
+ MZ_UNUSED(skip_aes);
+#endif
+ /* NTFS timestamps */
+ if ((file_info->modified_date != 0) &&
+ (file_info->accessed_date != 0) &&
+ (file_info->creation_date != 0) && (!mask)) {
+ field_length_ntfs = 8 + 8 + 8 + 4 + 2 + 2;
+ extrafield_size += 4 + field_length_ntfs;
+ }
+
+ /* Unix1 symbolic links */
+ if (file_info->linkname != NULL && *file_info->linkname != 0) {
+ linkname_size = (uint16_t)strlen(file_info->linkname);
+ field_length_unix1 = 12 + linkname_size;
+ extrafield_size += 4 + field_length_unix1;
+ }
+
+ if (local)
+ err = mz_stream_write_uint32(stream, MZ_ZIP_MAGIC_LOCALHEADER);
+ else {
+ err = mz_stream_write_uint32(stream, MZ_ZIP_MAGIC_CENTRALHEADER);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, file_info->version_madeby);
+ }
+
+ /* Calculate version needed to extract */
+ if (err == MZ_OK) {
+ version_needed = file_info->version_needed;
+ if (version_needed == 0) {
+ version_needed = 20;
+ if (zip64)
+ version_needed = 45;
+#ifdef HAVE_WZAES
+ if ((file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version))
+ version_needed = 51;
+#endif
+#if defined(HAVE_LZMA) || defined(HAVE_LIBCOMP)
+ if ((file_info->compression_method == MZ_COMPRESS_METHOD_LZMA) ||
+ (file_info->compression_method == MZ_COMPRESS_METHOD_XZ))
+ version_needed = 63;
+#endif
+ }
+ err = mz_stream_write_uint16(stream, version_needed);
+ }
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, file_info->flag);
+ if (err == MZ_OK) {
+#ifdef HAVE_WZAES
+ if ((file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version))
+ err = mz_stream_write_uint16(stream, MZ_COMPRESS_METHOD_AES);
+ else
+#endif
+ err = mz_stream_write_uint16(stream, file_info->compression_method);
+ }
+ if (err == MZ_OK) {
+ if (file_info->modified_date != 0 && !mask)
+ dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date);
+ err = mz_stream_write_uint32(stream, dos_date);
+ }
+
+ if (err == MZ_OK)
+ err = mz_zip_entry_write_crc_sizes(stream, zip64, mask, file_info);
+
+ if (mask) {
+ snprintf(masked_name, sizeof(masked_name), "%" PRIx32 "_%" PRIx64,
+ file_info->disk_number, file_info->disk_offset);
+ filename = masked_name;
+ } else {
+ filename = file_info->filename;
+ }
+
+ filename_length = (uint16_t)strlen(filename);
+ filename_size += filename_length;
+
+ if ((mz_zip_attrib_is_dir(file_info->external_fa, file_info->version_madeby) == MZ_OK) &&
+ ((filename[filename_length - 1] != '/') && (filename[filename_length - 1] != '\\'))) {
+ filename_size += 1;
+ write_end_slash = 1;
+ }
+
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, filename_size);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, extrafield_size);
+
+ if (!local) {
+ if (file_info->comment != NULL) {
+ comment_size = (int32_t)strlen(file_info->comment);
+ if (comment_size > UINT16_MAX)
+ comment_size = UINT16_MAX;
+ }
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, (uint16_t)comment_size);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, (uint16_t)file_info->disk_number);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, file_info->internal_fa);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(stream, file_info->external_fa);
+ if (err == MZ_OK) {
+ if (file_info->disk_offset >= UINT32_MAX)
+ err = mz_stream_write_uint32(stream, UINT32_MAX);
+ else
+ err = mz_stream_write_uint32(stream, (uint32_t)file_info->disk_offset);
+ }
+ }
+
+ if (err == MZ_OK) {
+ if (mz_stream_write(stream, filename, filename_length) != filename_length)
+ err = MZ_WRITE_ERROR;
+
+ /* Ensure that directories have a slash appended to them for compatibility */
+ if (err == MZ_OK && write_end_slash)
+ err = mz_stream_write_uint8(stream, '/');
+ }
+
+ /* Write ZIP64 extra field first so we can update sizes later if data descriptor not used */
+ if ((err == MZ_OK) && (zip64)) {
+ err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_ZIP64, field_length_zip64);
+ if (err == MZ_OK) {
+ if (mask)
+ err = mz_stream_write_int64(stream, 0);
+ else
+ err = mz_stream_write_int64(stream, file_info->uncompressed_size);
+ }
+ if (err == MZ_OK)
+ err = mz_stream_write_int64(stream, file_info->compressed_size);
+ if ((err == MZ_OK) && (!local) && (file_info->disk_offset >= UINT32_MAX))
+ err = mz_stream_write_int64(stream, file_info->disk_offset);
+ if ((err == MZ_OK) && (!local) && (file_info->disk_number >= UINT16_MAX))
+ err = mz_stream_write_uint32(stream, file_info->disk_number);
+ }
+ /* Write NTFS extra field */
+ if ((err == MZ_OK) && (field_length_ntfs > 0)) {
+ err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_NTFS, field_length_ntfs);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(stream, reserved);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, 0x01);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, field_length_ntfs - 8);
+ if (err == MZ_OK) {
+ mz_zip_unix_to_ntfs_time(file_info->modified_date, &ntfs_time);
+ err = mz_stream_write_uint64(stream, ntfs_time);
+ }
+ if (err == MZ_OK) {
+ mz_zip_unix_to_ntfs_time(file_info->accessed_date, &ntfs_time);
+ err = mz_stream_write_uint64(stream, ntfs_time);
+ }
+ if (err == MZ_OK) {
+ mz_zip_unix_to_ntfs_time(file_info->creation_date, &ntfs_time);
+ err = mz_stream_write_uint64(stream, ntfs_time);
+ }
+ }
+ /* Write UNIX extra block extra field */
+ if ((err == MZ_OK) && (field_length_unix1 > 0)) {
+ err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_UNIX1, field_length_unix1);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(stream, (uint32_t)file_info->accessed_date);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(stream, (uint32_t)file_info->modified_date);
+ if (err == MZ_OK) /* User id */
+ err = mz_stream_write_uint16(stream, 0);
+ if (err == MZ_OK) /* Group id */
+ err = mz_stream_write_uint16(stream, 0);
+ if (err == MZ_OK && linkname_size > 0) {
+ if (mz_stream_write(stream, file_info->linkname, linkname_size) != linkname_size)
+ err = MZ_WRITE_ERROR;
+ }
+ }
+#ifdef HAVE_WZAES
+ /* Write AES extra field */
+ if ((err == MZ_OK) && (!skip_aes) && (file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (file_info->aes_version)) {
+ err = mz_zip_extrafield_write(stream, MZ_ZIP_EXTENSION_AES, field_length_aes);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, file_info->aes_version);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint8(stream, 'A');
+ if (err == MZ_OK)
+ err = mz_stream_write_uint8(stream, 'E');
+ if (err == MZ_OK)
+ err = mz_stream_write_uint8(stream, file_info->aes_encryption_mode);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, file_info->compression_method);
+ }
+#endif
+
+ if (file_info->extrafield_size > 0) {
+ err_mem = mz_stream_mem_seek(file_extra_stream, 0, MZ_SEEK_SET);
+ while (err == MZ_OK && err_mem == MZ_OK) {
+ err_mem = mz_stream_read_uint16(file_extra_stream, &field_type);
+ if (err_mem == MZ_OK)
+ err_mem = mz_stream_read_uint16(file_extra_stream, &field_length);
+ if (err_mem != MZ_OK)
+ break;
+
+ /* Prefer our zip 64, ntfs, unix1 extensions over incoming */
+ if (field_type == MZ_ZIP_EXTENSION_ZIP64 || field_type == MZ_ZIP_EXTENSION_NTFS ||
+ field_type == MZ_ZIP_EXTENSION_UNIX1) {
+ err_mem = mz_stream_seek(file_extra_stream, field_length, MZ_SEEK_CUR);
+ continue;
+ }
+
+ err = mz_stream_write_uint16(stream, field_type);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, field_length);
+ if (err == MZ_OK)
+ err = mz_stream_copy(stream, file_extra_stream, field_length);
+ }
+
+ mz_stream_mem_delete(&file_extra_stream);
+ }
+
+ if ((err == MZ_OK) && (!local) && (file_info->comment != NULL)) {
+ if (mz_stream_write(stream, file_info->comment, file_info->comment_size) != file_info->comment_size)
+ err = MZ_WRITE_ERROR;
+ }
+
+ return err;
+}
+
+static int32_t mz_zip_entry_write_descriptor(void *stream, uint8_t zip64, uint32_t crc32, int64_t compressed_size, int64_t uncompressed_size) {
+ int32_t err = MZ_OK;
+
+ err = mz_stream_write_uint32(stream, MZ_ZIP_MAGIC_DATADESCRIPTOR);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(stream, crc32);
+
+ /* Store data descriptor as 8 bytes if zip 64 extension enabled */
+ if (err == MZ_OK) {
+ /* Zip 64 extension is enabled when uncompressed size is > UINT32_MAX */
+ if (!zip64)
+ err = mz_stream_write_uint32(stream, (uint32_t)compressed_size);
+ else
+ err = mz_stream_write_int64(stream, compressed_size);
+ }
+ if (err == MZ_OK) {
+ if (!zip64)
+ err = mz_stream_write_uint32(stream, (uint32_t)uncompressed_size);
+ else
+ err = mz_stream_write_int64(stream, uncompressed_size);
+ }
+
+ return err;
+}
+
+static int32_t mz_zip_read_cd(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+ uint64_t number_entry_cd64 = 0;
+ uint64_t number_entry_cd = 0;
+ int64_t eocd_pos = 0;
+ int64_t eocd_pos64 = 0;
+ int64_t value64i = 0;
+ uint16_t value16 = 0;
+ uint32_t value32 = 0;
+ uint64_t value64 = 0;
+ uint16_t comment_size = 0;
+ int32_t comment_read = 0;
+ int32_t err = MZ_OK;
+
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+
+ /* Read and cache central directory records */
+ err = mz_zip_search_eocd(zip->stream, &eocd_pos);
+ if (err == MZ_OK) {
+ /* The signature, already checked */
+ err = mz_stream_read_uint32(zip->stream, &value32);
+ /* Number of this disk */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(zip->stream, &value16);
+ /* Number of the disk with the start of the central directory */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(zip->stream, &value16);
+ zip->disk_number_with_cd = value16;
+ /* Total number of entries in the central dir on this disk */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(zip->stream, &value16);
+ zip->number_entry = value16;
+ /* Total number of entries in the central dir */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(zip->stream, &value16);
+ number_entry_cd = value16;
+ if (number_entry_cd != zip->number_entry)
+ err = MZ_FORMAT_ERROR;
+ /* Size of the central directory */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(zip->stream, &value32);
+ if (err == MZ_OK)
+ zip->cd_size = value32;
+ /* Offset of start of central directory with respect to the starting disk number */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(zip->stream, &value32);
+ if (err == MZ_OK)
+ zip->cd_offset = value32;
+ /* Zip file global comment length */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(zip->stream, &comment_size);
+ if ((err == MZ_OK) && (comment_size > 0)) {
+ zip->comment = (char *)MZ_ALLOC(comment_size + 1);
+ if (zip->comment != NULL) {
+ comment_read = mz_stream_read(zip->stream, zip->comment, comment_size);
+ /* Don't fail if incorrect comment length read, not critical */
+ if (comment_read < 0)
+ comment_read = 0;
+ zip->comment[comment_read] = 0;
+ }
+ }
+
+ if ((err == MZ_OK) && ((number_entry_cd == UINT16_MAX) || (zip->cd_offset == UINT32_MAX))) {
+ /* Format should be Zip64, as the central directory or file size is too large */
+ if (mz_zip_search_zip64_eocd(zip->stream, eocd_pos, &eocd_pos64) == MZ_OK) {
+ eocd_pos = eocd_pos64;
+
+ err = mz_stream_seek(zip->stream, eocd_pos, MZ_SEEK_SET);
+ /* The signature, already checked */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(zip->stream, &value32);
+ /* Size of zip64 end of central directory record */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint64(zip->stream, &value64);
+ /* Version made by */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(zip->stream, &zip->version_madeby);
+ /* Version needed to extract */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(zip->stream, &value16);
+ /* Number of this disk */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(zip->stream, &value32);
+ /* Number of the disk with the start of the central directory */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(zip->stream, &zip->disk_number_with_cd);
+ /* Total number of entries in the central directory on this disk */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint64(zip->stream, &zip->number_entry);
+ /* Total number of entries in the central directory */
+ if (err == MZ_OK)
+ err = mz_stream_read_uint64(zip->stream, &number_entry_cd64);
+ if (zip->number_entry != number_entry_cd64)
+ err = MZ_FORMAT_ERROR;
+ /* Size of the central directory */
+ if (err == MZ_OK) {
+ err = mz_stream_read_int64(zip->stream, &zip->cd_size);
+ if (zip->cd_size < 0)
+ err = MZ_FORMAT_ERROR;
+ }
+ /* Offset of start of central directory with respect to the starting disk number */
+ if (err == MZ_OK) {
+ err = mz_stream_read_int64(zip->stream, &zip->cd_offset);
+ if (zip->cd_offset < 0)
+ err = MZ_FORMAT_ERROR;
+ }
+ } else if ((zip->number_entry == UINT16_MAX) || (number_entry_cd != zip->number_entry) ||
+ (zip->cd_size == UINT16_MAX) || (zip->cd_offset == UINT32_MAX)) {
+ err = MZ_FORMAT_ERROR;
+ }
+ }
+ }
+
+ if (err == MZ_OK) {
+ mz_zip_print("Zip - Read cd (disk %" PRId32 " entries %" PRId64 " offset %" PRId64 " size %" PRId64 ")\n",
+ zip->disk_number_with_cd, zip->number_entry, zip->cd_offset, zip->cd_size);
+
+ /* Verify central directory signature exists at offset */
+ err = mz_stream_seek(zip->stream, zip->cd_offset, MZ_SEEK_SET);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(zip->stream, &zip->cd_signature);
+ if ((err == MZ_OK) && (zip->cd_signature != MZ_ZIP_MAGIC_CENTRALHEADER)) {
+ /* If cd exists in large file and no zip-64 support, error for recover */
+ if (eocd_pos > UINT32_MAX && eocd_pos64 == 0)
+ err = MZ_FORMAT_ERROR;
+ /* If cd not found attempt to seek backward to find it */
+ if (err == MZ_OK)
+ err = mz_stream_seek(zip->stream, eocd_pos - zip->cd_size, MZ_SEEK_SET);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint32(zip->stream, &zip->cd_signature);
+ if ((err == MZ_OK) && (zip->cd_signature == MZ_ZIP_MAGIC_CENTRALHEADER)) {
+
+ /* If found compensate for incorrect locations */
+ value64i = zip->cd_offset;
+ zip->cd_offset = eocd_pos - zip->cd_size;
+ /* Assume disk has prepended data */
+ zip->disk_offset_shift = zip->cd_offset - value64i;
+ }
+ }
+ }
+
+ if (err == MZ_OK) {
+ if (eocd_pos < zip->cd_offset) {
+ /* End of central dir should always come after central dir */
+ err = MZ_FORMAT_ERROR;
+ } else if ((uint64_t)eocd_pos < (uint64_t)zip->cd_offset + zip->cd_size) {
+ /* Truncate size of cd if incorrect size or offset provided */
+ zip->cd_size = eocd_pos - zip->cd_offset;
+ }
+ }
+
+ return err;
+}
+
+static int32_t mz_zip_write_cd(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+ int64_t zip64_eocd_pos_inzip = 0;
+ int64_t disk_number = 0;
+ int64_t disk_size = 0;
+ int32_t comment_size = 0;
+ int32_t err = MZ_OK;
+
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+
+ if (mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &disk_number) == MZ_OK)
+ zip->disk_number_with_cd = (uint32_t)disk_number;
+ if (mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_SIZE, &disk_size) == MZ_OK && disk_size > 0)
+ zip->disk_number_with_cd += 1;
+ mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, -1);
+ if ((zip->disk_number_with_cd > 0) && (zip->open_mode & MZ_OPEN_MODE_APPEND)) {
+ // Overwrite existing central directory if using split disks
+ mz_stream_seek(zip->stream, 0, MZ_SEEK_SET);
+ }
+
+ zip->cd_offset = mz_stream_tell(zip->stream);
+ mz_stream_seek(zip->cd_mem_stream, 0, MZ_SEEK_END);
+ zip->cd_size = (uint32_t)mz_stream_tell(zip->cd_mem_stream);
+ mz_stream_seek(zip->cd_mem_stream, 0, MZ_SEEK_SET);
+
+ err = mz_stream_copy(zip->stream, zip->cd_mem_stream, (int32_t)zip->cd_size);
+
+ mz_zip_print("Zip - Write cd (disk %" PRId32 " entries %" PRId64 " offset %" PRId64 " size %" PRId64 ")\n",
+ zip->disk_number_with_cd, zip->number_entry, zip->cd_offset, zip->cd_size);
+
+ if (zip->cd_size == 0 && zip->number_entry > 0) {
+ // Zip does not contain central directory, open with recovery option
+ return MZ_FORMAT_ERROR;
+ }
+
+ /* Write the ZIP64 central directory header */
+ if (zip->cd_offset >= UINT32_MAX || zip->number_entry >= UINT16_MAX) {
+ zip64_eocd_pos_inzip = mz_stream_tell(zip->stream);
+
+ err = mz_stream_write_uint32(zip->stream, MZ_ZIP_MAGIC_ENDHEADER64);
+
+ /* Size of this 'zip64 end of central directory' */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint64(zip->stream, (uint64_t)44);
+ /* Version made by */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(zip->stream, zip->version_madeby);
+ /* Version needed */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(zip->stream, (uint16_t)45);
+ /* Number of this disk */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd);
+ /* Number of the disk with the start of the central directory */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd);
+ /* Total number of entries in the central dir on this disk */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint64(zip->stream, zip->number_entry);
+ /* Total number of entries in the central dir */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint64(zip->stream, zip->number_entry);
+ /* Size of the central directory */
+ if (err == MZ_OK)
+ err = mz_stream_write_int64(zip->stream, zip->cd_size);
+ /* Offset of start of central directory with respect to the starting disk number */
+ if (err == MZ_OK)
+ err = mz_stream_write_int64(zip->stream, zip->cd_offset);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(zip->stream, MZ_ZIP_MAGIC_ENDLOCHEADER64);
+
+ /* Number of the disk with the start of the central directory */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd);
+ /* Relative offset to the end of zip64 central directory */
+ if (err == MZ_OK)
+ err = mz_stream_write_int64(zip->stream, zip64_eocd_pos_inzip);
+ /* Number of the disk with the start of the central directory */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(zip->stream, zip->disk_number_with_cd + 1);
+ }
+
+ /* Write the central directory header */
+
+ /* Signature */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(zip->stream, MZ_ZIP_MAGIC_ENDHEADER);
+ /* Number of this disk */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->disk_number_with_cd);
+ /* Number of the disk with the start of the central directory */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->disk_number_with_cd);
+ /* Total number of entries in the central dir on this disk */
+ if (err == MZ_OK) {
+ if (zip->number_entry >= UINT16_MAX)
+ err = mz_stream_write_uint16(zip->stream, UINT16_MAX);
+ else
+ err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->number_entry);
+ }
+ /* Total number of entries in the central dir */
+ if (err == MZ_OK) {
+ if (zip->number_entry >= UINT16_MAX)
+ err = mz_stream_write_uint16(zip->stream, UINT16_MAX);
+ else
+ err = mz_stream_write_uint16(zip->stream, (uint16_t)zip->number_entry);
+ }
+ /* Size of the central directory */
+ if (err == MZ_OK)
+ err = mz_stream_write_uint32(zip->stream, (uint32_t)zip->cd_size);
+ /* Offset of start of central directory with respect to the starting disk number */
+ if (err == MZ_OK) {
+ if (zip->cd_offset >= UINT32_MAX)
+ err = mz_stream_write_uint32(zip->stream, UINT32_MAX);
+ else
+ err = mz_stream_write_uint32(zip->stream, (uint32_t)zip->cd_offset);
+ }
+
+ /* Write global comment */
+ if (zip->comment != NULL) {
+ comment_size = (int32_t)strlen(zip->comment);
+ if (comment_size > UINT16_MAX)
+ comment_size = UINT16_MAX;
+ }
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(zip->stream, (uint16_t)comment_size);
+ if (err == MZ_OK) {
+ if (mz_stream_write(zip->stream, zip->comment, comment_size) != comment_size)
+ err = MZ_READ_ERROR;
+ }
+ return err;
+}
+
+static int32_t mz_zip_recover_cd(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+ mz_zip_file local_file_info;
+ void *local_file_info_stream = NULL;
+ void *cd_mem_stream = NULL;
+ uint64_t number_entry = 0;
+ int64_t descriptor_pos = 0;
+ int64_t next_header_pos = 0;
+ int64_t disk_offset = 0;
+ int64_t disk_number = 0;
+ int64_t compressed_pos = 0;
+ int64_t compressed_end_pos = 0;
+ int64_t compressed_size = 0;
+ int64_t uncompressed_size = 0;
+ uint8_t descriptor_magic[4] = MZ_ZIP_MAGIC_DATADESCRIPTORU8;
+ uint8_t local_header_magic[4] = MZ_ZIP_MAGIC_LOCALHEADERU8;
+ uint8_t central_header_magic[4] = MZ_ZIP_MAGIC_CENTRALHEADERU8;
+ uint32_t crc32 = 0;
+ int32_t disk_number_with_cd = 0;
+ int32_t err = MZ_OK;
+ uint8_t zip64 = 0;
+ uint8_t eof = 0;
+
+
+ mz_zip_print("Zip - Recover - Start\n");
+
+ mz_zip_get_cd_mem_stream(handle, &cd_mem_stream);
+
+ /* Determine if we are on a split disk or not */
+ mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, 0);
+ if (mz_stream_tell(zip->stream) < 0) {
+ mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, -1);
+ mz_stream_seek(zip->stream, 0, MZ_SEEK_SET);
+ } else
+ disk_number_with_cd = 1;
+
+ if (mz_stream_is_open(cd_mem_stream) != MZ_OK)
+ err = mz_stream_mem_open(cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE);
+
+ mz_stream_mem_create(&local_file_info_stream);
+ mz_stream_mem_open(local_file_info_stream, NULL, MZ_OPEN_MODE_CREATE);
+
+ if (err == MZ_OK) {
+ err = mz_stream_find(zip->stream, (const void *)local_header_magic, sizeof(local_header_magic),
+ INT64_MAX, &next_header_pos);
+ }
+
+ while (err == MZ_OK && !eof) {
+ /* Get current offset and disk number for central dir record */
+ disk_offset = mz_stream_tell(zip->stream);
+ mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &disk_number);
+
+ /* Read local headers */
+ memset(&local_file_info, 0, sizeof(local_file_info));
+ err = mz_zip_entry_read_header(zip->stream, 1, &local_file_info, local_file_info_stream);
+ if (err != MZ_OK)
+ break;
+
+ local_file_info.disk_offset = disk_offset;
+ if (disk_number < 0)
+ disk_number = 0;
+ local_file_info.disk_number = (uint32_t)disk_number;
+
+ compressed_pos = mz_stream_tell(zip->stream);
+
+ if ((err == MZ_OK) && (local_file_info.compressed_size > 0)) {
+ mz_stream_seek(zip->stream, local_file_info.compressed_size, MZ_SEEK_CUR);
+ }
+
+ for (;;) {
+ /* Search for the next local header */
+ err = mz_stream_find(zip->stream, (const void *)local_header_magic, sizeof(local_header_magic),
+ INT64_MAX, &next_header_pos);
+
+ if (err == MZ_EXIST_ERROR) {
+ mz_stream_seek(zip->stream, compressed_pos, MZ_SEEK_SET);
+
+ /* Search for central dir if no local header found */
+ err = mz_stream_find(zip->stream, (const void *)central_header_magic, sizeof(central_header_magic),
+ INT64_MAX, &next_header_pos);
+
+ if (err == MZ_EXIST_ERROR) {
+ /* Get end of stream if no central header found */
+ mz_stream_seek(zip->stream, 0, MZ_SEEK_END);
+ next_header_pos = mz_stream_tell(zip->stream);
+ }
+
+ eof = 1;
+ }
+
+ if (local_file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR || local_file_info.compressed_size == 0) {
+ /* Search backwards for the descriptor, seeking too far back will be incorrect if compressed size is small */
+ err = mz_stream_find_reverse(zip->stream, (const void *)descriptor_magic, sizeof(descriptor_magic),
+ MZ_ZIP_SIZE_MAX_DATA_DESCRIPTOR, &descriptor_pos);
+ if (err == MZ_OK) {
+ if (mz_zip_extrafield_contains(local_file_info.extrafield,
+ local_file_info.extrafield_size, MZ_ZIP_EXTENSION_ZIP64, NULL) == MZ_OK)
+ zip64 = 1;
+
+ err = mz_zip_entry_read_descriptor(zip->stream, zip64, &crc32,
+ &compressed_size, &uncompressed_size);
+
+ if (err == MZ_OK) {
+ if (local_file_info.crc == 0)
+ local_file_info.crc = crc32;
+ if (local_file_info.compressed_size == 0)
+ local_file_info.compressed_size = compressed_size;
+ if (local_file_info.uncompressed_size == 0)
+ local_file_info.uncompressed_size = uncompressed_size;
+ }
+
+ compressed_end_pos = descriptor_pos;
+ } else if (eof) {
+ compressed_end_pos = next_header_pos;
+ } else if (local_file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR) {
+ /* Wrong local file entry found, keep searching */
+ next_header_pos += 1;
+ mz_stream_seek(zip->stream, next_header_pos, MZ_SEEK_SET);
+ continue;
+ }
+ } else {
+ compressed_end_pos = next_header_pos;
+ }
+
+ break;
+ }
+
+ compressed_size = compressed_end_pos - compressed_pos;
+
+ if (compressed_size > UINT32_MAX) {
+ /* Update sizes if 4GB file is written with no ZIP64 support */
+ if (local_file_info.uncompressed_size < UINT32_MAX) {
+ local_file_info.compressed_size = compressed_size;
+ local_file_info.uncompressed_size = 0;
+ }
+ }
+
+ mz_zip_print("Zip - Recover - Entry %s (csize %" PRId64 " usize %" PRId64 " flags 0x%" PRIx16 ")\n",
+ local_file_info.filename, local_file_info.compressed_size, local_file_info.uncompressed_size,
+ local_file_info.flag);
+
+ /* Rewrite central dir with local headers and offsets */
+ err = mz_zip_entry_write_header(cd_mem_stream, 0, &local_file_info);
+ if (err == MZ_OK)
+ number_entry += 1;
+
+ err = mz_stream_seek(zip->stream, next_header_pos, MZ_SEEK_SET);
+ }
+
+ mz_stream_mem_delete(&local_file_info_stream);
+
+ mz_zip_print("Zip - Recover - Complete (cddisk %" PRId32 " entries %" PRId64 ")\n",
+ disk_number_with_cd, number_entry);
+
+ if (number_entry == 0)
+ return err;
+
+ /* Set new upper seek boundary for central dir mem stream */
+ disk_offset = mz_stream_tell(cd_mem_stream);
+ mz_stream_mem_set_buffer_limit(cd_mem_stream, (int32_t)disk_offset);
+
+ /* Set new central directory info */
+ mz_zip_set_cd_stream(handle, 0, cd_mem_stream);
+ mz_zip_set_number_entry(handle, number_entry);
+ mz_zip_set_disk_number_with_cd(handle, disk_number_with_cd);
+
+ return MZ_OK;
+}
+
+void *mz_zip_create(void **handle) {
+ mz_zip *zip = NULL;
+
+ zip = (mz_zip *)MZ_ALLOC(sizeof(mz_zip));
+ if (zip != NULL) {
+ memset(zip, 0, sizeof(mz_zip));
+ zip->data_descriptor = 1;
+ }
+ if (handle != NULL)
+ *handle = zip;
+
+ return zip;
+}
+
+void mz_zip_delete(void **handle) {
+ mz_zip *zip = NULL;
+ if (handle == NULL)
+ return;
+ zip = (mz_zip *)*handle;
+ if (zip != NULL) {
+ MZ_FREE(zip);
+ }
+ *handle = NULL;
+}
+
+int32_t mz_zip_open(void *handle, void *stream, int32_t mode) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t err = MZ_OK;
+
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_zip_print("Zip - Open\n");
+
+ zip->stream = stream;
+
+ mz_stream_mem_create(&zip->cd_mem_stream);
+
+ if (mode & MZ_OPEN_MODE_WRITE) {
+ mz_stream_mem_open(zip->cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE);
+ zip->cd_stream = zip->cd_mem_stream;
+ } else {
+ zip->cd_stream = stream;
+ }
+
+ if ((mode & MZ_OPEN_MODE_READ) || (mode & MZ_OPEN_MODE_APPEND)) {
+ if ((mode & MZ_OPEN_MODE_CREATE) == 0) {
+ err = mz_zip_read_cd(zip);
+ if (err != MZ_OK) {
+ mz_zip_print("Zip - Error detected reading cd (%" PRId32 ")\n", err);
+ if (zip->recover && mz_zip_recover_cd(zip) == MZ_OK)
+ err = MZ_OK;
+ }
+ }
+
+ if ((err == MZ_OK) && (mode & MZ_OPEN_MODE_APPEND)) {
+ if (zip->cd_size > 0) {
+ /* Store central directory in memory */
+ err = mz_stream_seek(zip->stream, zip->cd_offset, MZ_SEEK_SET);
+ if (err == MZ_OK)
+ err = mz_stream_copy(zip->cd_mem_stream, zip->stream, (int32_t)zip->cd_size);
+ if (err == MZ_OK)
+ err = mz_stream_seek(zip->stream, zip->cd_offset, MZ_SEEK_SET);
+ } else {
+ if (zip->cd_signature == MZ_ZIP_MAGIC_ENDHEADER) {
+ /* If tiny zip then overwrite end header */
+ err = mz_stream_seek(zip->stream, zip->cd_offset, MZ_SEEK_SET);
+ } else {
+ /* If no central directory, append new zip to end of file */
+ err = mz_stream_seek(zip->stream, 0, MZ_SEEK_END);
+ }
+ }
+
+ if (zip->disk_number_with_cd > 0) {
+ /* Move to last disk to begin appending */
+ mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, zip->disk_number_with_cd - 1);
+ }
+ } else {
+ zip->cd_start_pos = zip->cd_offset;
+ }
+ }
+
+ if (err != MZ_OK) {
+ mz_zip_close(zip);
+ return err;
+ }
+
+ /* Memory streams used to store variable length file info data */
+ mz_stream_mem_create(&zip->file_info_stream);
+ mz_stream_mem_open(zip->file_info_stream, NULL, MZ_OPEN_MODE_CREATE);
+
+ mz_stream_mem_create(&zip->local_file_info_stream);
+ mz_stream_mem_open(zip->local_file_info_stream, NULL, MZ_OPEN_MODE_CREATE);
+
+ zip->open_mode = mode;
+
+ return err;
+}
+
+int32_t mz_zip_close(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t err = MZ_OK;
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_zip_print("Zip - Close\n");
+
+ if (mz_zip_entry_is_open(handle) == MZ_OK)
+ err = mz_zip_entry_close(handle);
+
+ if ((err == MZ_OK) && (zip->open_mode & MZ_OPEN_MODE_WRITE))
+ err = mz_zip_write_cd(handle);
+
+ if (zip->cd_mem_stream != NULL) {
+ mz_stream_close(zip->cd_mem_stream);
+ mz_stream_delete(&zip->cd_mem_stream);
+ }
+
+ if (zip->file_info_stream != NULL) {
+ mz_stream_mem_close(zip->file_info_stream);
+ mz_stream_mem_delete(&zip->file_info_stream);
+ }
+ if (zip->local_file_info_stream != NULL) {
+ mz_stream_mem_close(zip->local_file_info_stream);
+ mz_stream_mem_delete(&zip->local_file_info_stream);
+ }
+
+ if (zip->comment) {
+ MZ_FREE(zip->comment);
+ zip->comment = NULL;
+ }
+
+ zip->stream = NULL;
+ zip->cd_stream = NULL;
+
+ return err;
+}
+
+int32_t mz_zip_get_comment(void *handle, const char **comment) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL || comment == NULL)
+ return MZ_PARAM_ERROR;
+ if (zip->comment == NULL)
+ return MZ_EXIST_ERROR;
+ *comment = zip->comment;
+ return MZ_OK;
+}
+
+int32_t mz_zip_set_comment(void *handle, const char *comment) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t comment_size = 0;
+ if (zip == NULL || comment == NULL)
+ return MZ_PARAM_ERROR;
+ if (zip->comment != NULL)
+ MZ_FREE(zip->comment);
+ comment_size = (int32_t)strlen(comment);
+ if (comment_size > UINT16_MAX)
+ return MZ_PARAM_ERROR;
+ zip->comment = (char *)MZ_ALLOC(comment_size+1);
+ if (zip->comment == NULL)
+ return MZ_MEM_ERROR;
+ memset(zip->comment, 0, comment_size+1);
+ strncpy(zip->comment, comment, comment_size);
+ return MZ_OK;
+}
+
+int32_t mz_zip_get_version_madeby(void *handle, uint16_t *version_madeby) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL || version_madeby == NULL)
+ return MZ_PARAM_ERROR;
+ *version_madeby = zip->version_madeby;
+ return MZ_OK;
+}
+
+int32_t mz_zip_set_version_madeby(void *handle, uint16_t version_madeby) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+ zip->version_madeby = version_madeby;
+ return MZ_OK;
+}
+
+int32_t mz_zip_set_recover(void *handle, uint8_t recover) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+ zip->recover = recover;
+ return MZ_OK;
+}
+
+int32_t mz_zip_set_data_descriptor(void *handle, uint8_t data_descriptor) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+ zip->data_descriptor = data_descriptor;
+ return MZ_OK;
+}
+
+int32_t mz_zip_get_stream(void *handle, void **stream) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL || stream == NULL)
+ return MZ_PARAM_ERROR;
+ *stream = zip->stream;
+ if (*stream == NULL)
+ return MZ_EXIST_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_zip_set_cd_stream(void *handle, int64_t cd_start_pos, void *cd_stream) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL || cd_stream == NULL)
+ return MZ_PARAM_ERROR;
+ zip->cd_offset = 0;
+ zip->cd_stream = cd_stream;
+ zip->cd_start_pos = cd_start_pos;
+ return MZ_OK;
+}
+
+int32_t mz_zip_get_cd_mem_stream(void *handle, void **cd_mem_stream) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL || cd_mem_stream == NULL)
+ return MZ_PARAM_ERROR;
+ *cd_mem_stream = zip->cd_mem_stream;
+ if (*cd_mem_stream == NULL)
+ return MZ_EXIST_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_zip_set_number_entry(void *handle, uint64_t number_entry) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+ zip->number_entry = number_entry;
+ return MZ_OK;
+}
+
+int32_t mz_zip_get_number_entry(void *handle, uint64_t *number_entry) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL || number_entry == NULL)
+ return MZ_PARAM_ERROR;
+ *number_entry = zip->number_entry;
+ return MZ_OK;
+}
+
+int32_t mz_zip_set_disk_number_with_cd(void *handle, uint32_t disk_number_with_cd) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+ zip->disk_number_with_cd = disk_number_with_cd;
+ return MZ_OK;
+}
+
+int32_t mz_zip_get_disk_number_with_cd(void *handle, uint32_t *disk_number_with_cd) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL || disk_number_with_cd == NULL)
+ return MZ_PARAM_ERROR;
+ *disk_number_with_cd = zip->disk_number_with_cd;
+ return MZ_OK;
+}
+
+static int32_t mz_zip_entry_close_int(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+
+ if (zip->crypt_stream != NULL)
+ mz_stream_delete(&zip->crypt_stream);
+ zip->crypt_stream = NULL;
+ if (zip->compress_stream != NULL)
+ mz_stream_delete(&zip->compress_stream);
+ zip->compress_stream = NULL;
+
+ zip->entry_opened = 0;
+
+ return MZ_OK;
+}
+
+static int32_t mz_zip_entry_open_int(void *handle, uint8_t raw, int16_t compress_level, const char *password) {
+ mz_zip *zip = (mz_zip *)handle;
+ int64_t max_total_in = 0;
+ int64_t header_size = 0;
+ int64_t footer_size = 0;
+ int32_t err = MZ_OK;
+ uint8_t use_crypt = 0;
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+
+ switch (zip->file_info.compression_method) {
+ case MZ_COMPRESS_METHOD_STORE:
+ case MZ_COMPRESS_METHOD_DEFLATE:
+#ifdef HAVE_BZIP2
+ case MZ_COMPRESS_METHOD_BZIP2:
+#endif
+#ifdef HAVE_LZMA
+ case MZ_COMPRESS_METHOD_LZMA:
+#endif
+#if defined(HAVE_LZMA) || defined(HAVE_LIBCOMP)
+ case MZ_COMPRESS_METHOD_XZ:
+#endif
+#ifdef HAVE_ZSTD
+ case MZ_COMPRESS_METHOD_ZSTD:
+#endif
+ err = MZ_OK;
+ break;
+ default:
+ return MZ_SUPPORT_ERROR;
+ }
+
+#ifndef HAVE_WZAES
+ if (zip->file_info.aes_version)
+ return MZ_SUPPORT_ERROR;
+#endif
+
+ zip->entry_raw = raw;
+
+ if ((zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && (password != NULL)) {
+ if (zip->open_mode & MZ_OPEN_MODE_WRITE) {
+ /* Encrypt only when we are not trying to write raw and password is supplied. */
+ if (!zip->entry_raw)
+ use_crypt = 1;
+ } else if (zip->open_mode & MZ_OPEN_MODE_READ) {
+ /* Decrypt only when password is supplied. Don't error when password */
+ /* is not supplied as we may want to read the raw encrypted data. */
+ use_crypt = 1;
+ }
+ }
+
+ if ((err == MZ_OK) && (use_crypt)) {
+#ifdef HAVE_WZAES
+ if (zip->file_info.aes_version) {
+ mz_stream_wzaes_create(&zip->crypt_stream);
+ mz_stream_wzaes_set_password(zip->crypt_stream, password);
+ mz_stream_wzaes_set_encryption_mode(zip->crypt_stream, zip->file_info.aes_encryption_mode);
+ } else
+#endif
+ {
+#ifdef HAVE_PKCRYPT
+ uint8_t verify1 = (uint8_t)((zip->file_info.pk_verify >> 8) & 0xff);
+ uint8_t verify2 = (uint8_t)((zip->file_info.pk_verify) & 0xff);
+
+ mz_stream_pkcrypt_create(&zip->crypt_stream);
+ mz_stream_pkcrypt_set_password(zip->crypt_stream, password);
+ mz_stream_pkcrypt_set_verify(zip->crypt_stream, verify1, verify2);
+#endif
+ }
+ }
+
+ if (err == MZ_OK) {
+ if (zip->crypt_stream == NULL)
+ mz_stream_raw_create(&zip->crypt_stream);
+
+ mz_stream_set_base(zip->crypt_stream, zip->stream);
+
+ err = mz_stream_open(zip->crypt_stream, NULL, zip->open_mode);
+ }
+
+ if (err == MZ_OK) {
+ if (zip->entry_raw || zip->file_info.compression_method == MZ_COMPRESS_METHOD_STORE)
+ mz_stream_raw_create(&zip->compress_stream);
+#ifdef HAVE_ZLIB
+ else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_DEFLATE)
+ mz_stream_zlib_create(&zip->compress_stream);
+#endif
+#ifdef HAVE_BZIP2
+ else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_BZIP2)
+ mz_stream_bzip_create(&zip->compress_stream);
+#endif
+#ifdef HAVE_LIBCOMP
+ else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_DEFLATE ||
+ zip->file_info.compression_method == MZ_COMPRESS_METHOD_XZ) {
+ mz_stream_libcomp_create(&zip->compress_stream);
+ mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_COMPRESS_METHOD,
+ zip->file_info.compression_method);
+ }
+#endif
+#ifdef HAVE_LZMA
+ else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_LZMA ||
+ zip->file_info.compression_method == MZ_COMPRESS_METHOD_XZ) {
+ mz_stream_lzma_create(&zip->compress_stream);
+ mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_COMPRESS_METHOD,
+ zip->file_info.compression_method);
+ }
+#endif
+#ifdef HAVE_ZSTD
+ else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_ZSTD)
+ mz_stream_zstd_create(&zip->compress_stream);
+#endif
+ else
+ err = MZ_PARAM_ERROR;
+ }
+
+ if (err == MZ_OK) {
+ if (zip->open_mode & MZ_OPEN_MODE_WRITE) {
+ mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_COMPRESS_LEVEL, compress_level);
+ } else {
+ int32_t set_end_of_stream = 0;
+
+#ifndef HAVE_LIBCOMP
+ if (zip->entry_raw ||
+ zip->file_info.compression_method == MZ_COMPRESS_METHOD_STORE ||
+ zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED)
+#endif
+ {
+ max_total_in = zip->file_info.compressed_size;
+ mz_stream_set_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_TOTAL_IN_MAX, max_total_in);
+
+ if (mz_stream_get_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_HEADER_SIZE, &header_size) == MZ_OK)
+ max_total_in -= header_size;
+ if (mz_stream_get_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_FOOTER_SIZE, &footer_size) == MZ_OK)
+ max_total_in -= footer_size;
+
+ mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN_MAX, max_total_in);
+ }
+
+ switch (zip->file_info.compression_method) {
+ case MZ_COMPRESS_METHOD_LZMA:
+ case MZ_COMPRESS_METHOD_XZ:
+ set_end_of_stream = (zip->file_info.flag & MZ_ZIP_FLAG_LZMA_EOS_MARKER);
+ break;
+ case MZ_COMPRESS_METHOD_ZSTD:
+ set_end_of_stream = 1;
+ break;
+ }
+
+ if (set_end_of_stream) {
+ mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN_MAX, zip->file_info.compressed_size);
+ mz_stream_set_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_OUT_MAX, zip->file_info.uncompressed_size);
+ }
+ }
+
+ mz_stream_set_base(zip->compress_stream, zip->crypt_stream);
+
+ err = mz_stream_open(zip->compress_stream, NULL, zip->open_mode);
+ }
+
+ if (err == MZ_OK) {
+ zip->entry_opened = 1;
+ zip->entry_crc32 = 0;
+ } else {
+ mz_zip_entry_close_int(handle);
+ }
+
+ return err;
+}
+
+int32_t mz_zip_entry_is_open(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+ if (zip->entry_opened == 0)
+ return MZ_EXIST_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_zip_entry_read_open(void *handle, uint8_t raw, const char *password) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t err = MZ_OK;
+ int32_t err_shift = MZ_OK;
+
+#if defined(MZ_ZIP_NO_ENCRYPTION)
+ if (password != NULL)
+ return MZ_SUPPORT_ERROR;
+#endif
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+ if ((zip->open_mode & MZ_OPEN_MODE_READ) == 0)
+ return MZ_PARAM_ERROR;
+ if (zip->entry_scanned == 0)
+ return MZ_PARAM_ERROR;
+
+ mz_zip_print("Zip - Entry - Read open (raw %" PRId32 ")\n", raw);
+
+ err = mz_zip_entry_seek_local_header(handle);
+ if (err == MZ_OK)
+ err = mz_zip_entry_read_header(zip->stream, 1, &zip->local_file_info, zip->local_file_info_stream);
+
+ if (err == MZ_FORMAT_ERROR && zip->disk_offset_shift > 0) {
+ /* Perhaps we didn't compensated correctly for incorrect cd offset */
+ err_shift = mz_stream_seek(zip->stream, zip->file_info.disk_offset, MZ_SEEK_SET);
+ if (err_shift == MZ_OK)
+ err_shift = mz_zip_entry_read_header(zip->stream, 1, &zip->local_file_info, zip->local_file_info_stream);
+ if (err_shift == MZ_OK) {
+ zip->disk_offset_shift = 0;
+ err = err_shift;
+ }
+ }
+
+#ifdef MZ_ZIP_NO_DECOMPRESSION
+ if (!raw && zip->file_info.compression_method != MZ_COMPRESS_METHOD_STORE)
+ err = MZ_SUPPORT_ERROR;
+#endif
+ if (err == MZ_OK)
+ err = mz_zip_entry_open_int(handle, raw, 0, password);
+
+ return err;
+}
+
+int32_t mz_zip_entry_write_open(void *handle, const mz_zip_file *file_info, int16_t compress_level, uint8_t raw, const char *password) {
+ mz_zip *zip = (mz_zip *)handle;
+ int64_t filename_pos = -1;
+ int64_t extrafield_pos = 0;
+ int64_t comment_pos = 0;
+ int64_t linkname_pos = 0;
+ int64_t disk_number = 0;
+ uint8_t is_dir = 0;
+ int32_t err = MZ_OK;
+
+#if defined(MZ_ZIP_NO_ENCRYPTION)
+ if (password != NULL)
+ return MZ_SUPPORT_ERROR;
+#endif
+ if (zip == NULL || file_info == NULL || file_info->filename == NULL)
+ return MZ_PARAM_ERROR;
+
+ if (mz_zip_entry_is_open(handle) == MZ_OK) {
+ err = mz_zip_entry_close(handle);
+ if (err != MZ_OK)
+ return err;
+ }
+
+ memcpy(&zip->file_info, file_info, sizeof(mz_zip_file));
+
+ mz_zip_print("Zip - Entry - Write open - %s (level %" PRId16 " raw %" PRId8 ")\n",
+ zip->file_info.filename, compress_level, raw);
+
+ mz_stream_seek(zip->file_info_stream, 0, MZ_SEEK_SET);
+ mz_stream_write(zip->file_info_stream, file_info, sizeof(mz_zip_file));
+
+ /* Copy filename, extrafield, and comment internally */
+ filename_pos = mz_stream_tell(zip->file_info_stream);
+ if (file_info->filename != NULL)
+ mz_stream_write(zip->file_info_stream, file_info->filename, (int32_t)strlen(file_info->filename));
+ mz_stream_write_uint8(zip->file_info_stream, 0);
+
+ extrafield_pos = mz_stream_tell(zip->file_info_stream);
+ if (file_info->extrafield != NULL)
+ mz_stream_write(zip->file_info_stream, file_info->extrafield, file_info->extrafield_size);
+ mz_stream_write_uint8(zip->file_info_stream, 0);
+
+ comment_pos = mz_stream_tell(zip->file_info_stream);
+ if (file_info->comment != NULL)
+ mz_stream_write(zip->file_info_stream, file_info->comment, file_info->comment_size);
+ mz_stream_write_uint8(zip->file_info_stream, 0);
+
+ linkname_pos = mz_stream_tell(zip->file_info_stream);
+ if (file_info->linkname != NULL)
+ mz_stream_write(zip->file_info_stream, file_info->linkname, (int32_t)strlen(file_info->linkname));
+ mz_stream_write_uint8(zip->file_info_stream, 0);
+
+ mz_stream_mem_get_buffer_at(zip->file_info_stream, filename_pos, (const void **)&zip->file_info.filename);
+ mz_stream_mem_get_buffer_at(zip->file_info_stream, extrafield_pos, (const void **)&zip->file_info.extrafield);
+ mz_stream_mem_get_buffer_at(zip->file_info_stream, comment_pos, (const void **)&zip->file_info.comment);
+ mz_stream_mem_get_buffer_at(zip->file_info_stream, linkname_pos, (const void **)&zip->file_info.linkname);
+
+ if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_DEFLATE) {
+ if ((compress_level == 8) || (compress_level == 9))
+ zip->file_info.flag |= MZ_ZIP_FLAG_DEFLATE_MAX;
+ if (compress_level == 2)
+ zip->file_info.flag |= MZ_ZIP_FLAG_DEFLATE_FAST;
+ if (compress_level == 1)
+ zip->file_info.flag |= MZ_ZIP_FLAG_DEFLATE_SUPER_FAST;
+ }
+#if defined(HAVE_LZMA) || defined(HAVE_LIBCOMP)
+ else if (zip->file_info.compression_method == MZ_COMPRESS_METHOD_LZMA ||
+ zip->file_info.compression_method == MZ_COMPRESS_METHOD_XZ)
+ zip->file_info.flag |= MZ_ZIP_FLAG_LZMA_EOS_MARKER;
+#endif
+
+ if (mz_zip_attrib_is_dir(zip->file_info.external_fa, zip->file_info.version_madeby) == MZ_OK)
+ is_dir = 1;
+
+ if (!is_dir) {
+ if (zip->data_descriptor)
+ zip->file_info.flag |= MZ_ZIP_FLAG_DATA_DESCRIPTOR;
+ if (password != NULL)
+ zip->file_info.flag |= MZ_ZIP_FLAG_ENCRYPTED;
+ }
+
+ mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &disk_number);
+ zip->file_info.disk_number = (uint32_t)disk_number;
+ zip->file_info.disk_offset = mz_stream_tell(zip->stream);
+
+ if (zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) {
+#ifdef HAVE_PKCRYPT
+ /* Pre-calculated CRC value is required for PKWARE traditional encryption */
+ uint32_t dos_date = mz_zip_time_t_to_dos_date(zip->file_info.modified_date);
+ zip->file_info.pk_verify = mz_zip_get_pk_verify(dos_date, zip->file_info.crc, zip->file_info.flag);
+#endif
+#ifdef HAVE_WZAES
+ if (zip->file_info.aes_version && zip->file_info.aes_encryption_mode == 0)
+ zip->file_info.aes_encryption_mode = MZ_AES_ENCRYPTION_MODE_256;
+#endif
+ }
+
+ zip->file_info.crc = 0;
+ zip->file_info.compressed_size = 0;
+
+ if ((compress_level == 0) || (is_dir))
+ zip->file_info.compression_method = MZ_COMPRESS_METHOD_STORE;
+
+#ifdef MZ_ZIP_NO_COMPRESSION
+ if (zip->file_info.compression_method != MZ_COMPRESS_METHOD_STORE)
+ err = MZ_SUPPORT_ERROR;
+#endif
+ if (err == MZ_OK)
+ err = mz_zip_entry_write_header(zip->stream, 1, &zip->file_info);
+ if (err == MZ_OK)
+ err = mz_zip_entry_open_int(handle, raw, compress_level, password);
+
+ return err;
+}
+
+int32_t mz_zip_entry_read(void *handle, void *buf, int32_t len) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t read = 0;
+
+ if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (UINT_MAX == UINT16_MAX && len > UINT16_MAX) /* zlib limitation */
+ return MZ_PARAM_ERROR;
+ if (len == 0)
+ return MZ_PARAM_ERROR;
+
+ if (zip->file_info.compressed_size == 0)
+ return 0;
+
+ /* Read entire entry even if uncompressed_size = 0, otherwise */
+ /* aes encryption validation will fail if compressed_size > 0 */
+ read = mz_stream_read(zip->compress_stream, buf, len);
+ if (read > 0)
+ zip->entry_crc32 = mz_crypt_crc32_update(zip->entry_crc32, buf, read);
+
+ mz_zip_print("Zip - Entry - Read - %" PRId32 " (max %" PRId32 ")\n", read, len);
+
+ return read;
+}
+
+int32_t mz_zip_entry_write(void *handle, const void *buf, int32_t len) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t written = 0;
+
+ if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ written = mz_stream_write(zip->compress_stream, buf, len);
+ if (written > 0)
+ zip->entry_crc32 = mz_crypt_crc32_update(zip->entry_crc32, buf, written);
+
+ mz_zip_print("Zip - Entry - Write - %" PRId32 " (max %" PRId32 ")\n", written, len);
+
+ return written;
+}
+
+int32_t mz_zip_entry_read_close(void *handle, uint32_t *crc32, int64_t *compressed_size,
+ int64_t *uncompressed_size) {
+ mz_zip *zip = (mz_zip *)handle;
+ int64_t total_in = 0;
+ int32_t err = MZ_OK;
+ uint8_t zip64 = 0;
+
+ if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+
+ mz_stream_close(zip->compress_stream);
+
+ mz_zip_print("Zip - Entry - Read Close\n");
+
+ if (crc32 != NULL)
+ *crc32 = zip->file_info.crc;
+ if (compressed_size != NULL)
+ *compressed_size = zip->file_info.compressed_size;
+ if (uncompressed_size != NULL)
+ *uncompressed_size = zip->file_info.uncompressed_size;
+
+ mz_stream_get_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN, &total_in);
+
+ if ((zip->file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR) &&
+ ((zip->file_info.flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO) == 0) &&
+ (crc32 != NULL || compressed_size != NULL || uncompressed_size != NULL)) {
+ /* Check to see if data descriptor is zip64 bit format or not */
+ if (mz_zip_extrafield_contains(zip->local_file_info.extrafield,
+ zip->local_file_info.extrafield_size, MZ_ZIP_EXTENSION_ZIP64, NULL) == MZ_OK)
+ zip64 = 1;
+
+ err = mz_zip_entry_seek_local_header(handle);
+
+ /* Seek to end of compressed stream since we might have over-read during compression */
+ if (err == MZ_OK)
+ err = mz_stream_seek(zip->stream, MZ_ZIP_SIZE_LD_ITEM +
+ (int64_t)zip->local_file_info.filename_size +
+ (int64_t)zip->local_file_info.extrafield_size +
+ total_in, MZ_SEEK_CUR);
+
+ /* Read data descriptor */
+ if (err == MZ_OK)
+ err = mz_zip_entry_read_descriptor(zip->stream, zip64,
+ crc32, compressed_size, uncompressed_size);
+ }
+
+ /* If entire entry was not read verification will fail */
+ if ((err == MZ_OK) && (total_in > 0) && (!zip->entry_raw)) {
+#ifdef HAVE_WZAES
+ /* AES zip version AE-1 will expect a valid crc as well */
+ if (zip->file_info.aes_version <= 0x0001)
+#endif
+ {
+ if (zip->entry_crc32 != zip->file_info.crc) {
+ mz_zip_print("Zip - Entry - Crc failed (actual 0x%08" PRIx32 " expected 0x%08" PRIx32 ")\n",
+ zip->entry_crc32, zip->file_info.crc);
+
+ err = MZ_CRC_ERROR;
+ }
+ }
+ }
+
+ mz_zip_entry_close_int(handle);
+
+ return err;
+}
+
+int32_t mz_zip_entry_write_close(void *handle, uint32_t crc32, int64_t compressed_size,
+ int64_t uncompressed_size) {
+ mz_zip *zip = (mz_zip *)handle;
+ int64_t end_disk_number = 0;
+ int32_t err = MZ_OK;
+ uint8_t zip64 = 0;
+
+ if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+
+ mz_stream_close(zip->compress_stream);
+
+ if (!zip->entry_raw)
+ crc32 = zip->entry_crc32;
+
+ mz_zip_print("Zip - Entry - Write Close (crc 0x%08" PRIx32 " cs %" PRId64 " ucs %" PRId64 ")\n",
+ crc32, compressed_size, uncompressed_size);
+
+ /* If sizes are not set, then read them from the compression stream */
+ if (compressed_size < 0)
+ mz_stream_get_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_OUT, &compressed_size);
+ if (uncompressed_size < 0)
+ mz_stream_get_prop_int64(zip->compress_stream, MZ_STREAM_PROP_TOTAL_IN, &uncompressed_size);
+
+ if (zip->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) {
+ mz_stream_set_base(zip->crypt_stream, zip->stream);
+ err = mz_stream_close(zip->crypt_stream);
+
+ mz_stream_get_prop_int64(zip->crypt_stream, MZ_STREAM_PROP_TOTAL_OUT, &compressed_size);
+ }
+
+ mz_zip_entry_needs_zip64(&zip->file_info, 1, &zip64);
+
+ if ((err == MZ_OK) && (zip->file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR)) {
+ /* Determine if we need to write data descriptor in zip64 format,
+ if local extrafield was saved with zip64 extrafield */
+
+ if (zip->file_info.flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO)
+ err = mz_zip_entry_write_descriptor(zip->stream,
+ zip64, 0, compressed_size, 0);
+ else
+ err = mz_zip_entry_write_descriptor(zip->stream,
+ zip64, crc32, compressed_size, uncompressed_size);
+ }
+
+ /* Write file info to central directory */
+
+ mz_zip_print("Zip - Entry - Write cd (ucs %" PRId64 " cs %" PRId64 " crc 0x%08" PRIx32 ")\n",
+ uncompressed_size, compressed_size, crc32);
+
+ zip->file_info.crc = crc32;
+ zip->file_info.compressed_size = compressed_size;
+ zip->file_info.uncompressed_size = uncompressed_size;
+
+ if (err == MZ_OK)
+ err = mz_zip_entry_write_header(zip->cd_mem_stream, 0, &zip->file_info);
+
+ /* Update local header with crc32 and sizes */
+ if ((err == MZ_OK) && ((zip->file_info.flag & MZ_ZIP_FLAG_DATA_DESCRIPTOR) == 0) &&
+ ((zip->file_info.flag & MZ_ZIP_FLAG_MASK_LOCAL_INFO) == 0)) {
+ /* Save the disk number and position we are to seek back after updating local header */
+ int64_t end_pos = mz_stream_tell(zip->stream);
+ mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &end_disk_number);
+
+ err = mz_zip_entry_seek_local_header(handle);
+
+ if (err == MZ_OK) {
+ /* Seek to crc32 and sizes offset in local header */
+ err = mz_stream_seek(zip->stream, MZ_ZIP_OFFSET_CRC_SIZES, MZ_SEEK_CUR);
+ }
+
+ if (err == MZ_OK)
+ err = mz_zip_entry_write_crc_sizes(zip->stream, zip64, 0, &zip->file_info);
+
+ /* Seek to and update zip64 extension sizes */
+ if ((err == MZ_OK) && (zip64)) {
+ int64_t filename_size = zip->file_info.filename_size;
+
+ if (filename_size == 0)
+ filename_size = strlen(zip->file_info.filename);
+
+ /* Since we write zip64 extension first we know its offset */
+ err = mz_stream_seek(zip->stream, 2 + 2 + filename_size + 4, MZ_SEEK_CUR);
+
+ if (err == MZ_OK)
+ err = mz_stream_write_uint64(zip->stream, zip->file_info.uncompressed_size);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint64(zip->stream, zip->file_info.compressed_size);
+ }
+
+ mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, end_disk_number);
+ mz_stream_seek(zip->stream, end_pos, MZ_SEEK_SET);
+ }
+
+ zip->number_entry += 1;
+
+ mz_zip_entry_close_int(handle);
+
+ return err;
+}
+
+int32_t mz_zip_entry_seek_local_header(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+ int64_t disk_size = 0;
+ uint32_t disk_number = zip->file_info.disk_number;
+
+ if (disk_number == zip->disk_number_with_cd) {
+ mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_SIZE, &disk_size);
+ if ((disk_size == 0) || ((zip->open_mode & MZ_OPEN_MODE_WRITE) == 0))
+ disk_number = (uint32_t)-1;
+ }
+
+ mz_stream_set_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, disk_number);
+
+ mz_zip_print("Zip - Entry - Seek local (disk %" PRId32 " offset %" PRId64 ")\n",
+ disk_number, zip->file_info.disk_offset);
+
+ /* Guard against seek overflows */
+ if ((zip->disk_offset_shift > 0) &&
+ (zip->file_info.disk_offset > (INT64_MAX - zip->disk_offset_shift)))
+ return MZ_FORMAT_ERROR;
+
+ return mz_stream_seek(zip->stream, zip->file_info.disk_offset + zip->disk_offset_shift, MZ_SEEK_SET);
+}
+
+int32_t mz_zip_entry_close(void *handle) {
+ return mz_zip_entry_close_raw(handle, UINT64_MAX, 0);
+}
+
+int32_t mz_zip_entry_close_raw(void *handle, int64_t uncompressed_size, uint32_t crc32) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t err = MZ_OK;
+
+ if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+
+ if (zip->open_mode & MZ_OPEN_MODE_WRITE)
+ err = mz_zip_entry_write_close(handle, crc32, UINT64_MAX, uncompressed_size);
+ else
+ err = mz_zip_entry_read_close(handle, NULL, NULL, NULL);
+
+ return err;
+}
+
+int32_t mz_zip_entry_is_dir(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t filename_length = 0;
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+ if (zip->entry_scanned == 0)
+ return MZ_PARAM_ERROR;
+ if (mz_zip_attrib_is_dir(zip->file_info.external_fa, zip->file_info.version_madeby) == MZ_OK)
+ return MZ_OK;
+
+ filename_length = (int32_t)strlen(zip->file_info.filename);
+ if (filename_length > 0) {
+ if ((zip->file_info.filename[filename_length - 1] == '/') ||
+ (zip->file_info.filename[filename_length - 1] == '\\'))
+ return MZ_OK;
+ }
+ return MZ_EXIST_ERROR;
+}
+
+int32_t mz_zip_entry_is_symlink(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+ if (zip->entry_scanned == 0)
+ return MZ_PARAM_ERROR;
+ if (mz_zip_attrib_is_symlink(zip->file_info.external_fa, zip->file_info.version_madeby) != MZ_OK)
+ return MZ_EXIST_ERROR;
+ if (zip->file_info.linkname == NULL || *zip->file_info.linkname == 0)
+ return MZ_EXIST_ERROR;
+
+ return MZ_OK;
+}
+
+int32_t mz_zip_entry_get_info(void *handle, mz_zip_file **file_info) {
+ mz_zip *zip = (mz_zip *)handle;
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+
+ if ((zip->open_mode & MZ_OPEN_MODE_WRITE) == 0) {
+ if (!zip->entry_scanned)
+ return MZ_PARAM_ERROR;
+ }
+
+ *file_info = &zip->file_info;
+ return MZ_OK;
+}
+
+int32_t mz_zip_entry_get_local_info(void *handle, mz_zip_file **local_file_info) {
+ mz_zip *zip = (mz_zip *)handle;
+ if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ *local_file_info = &zip->local_file_info;
+ return MZ_OK;
+}
+
+int32_t mz_zip_entry_set_extrafield(void *handle, const uint8_t *extrafield, uint16_t extrafield_size) {
+ mz_zip *zip = (mz_zip *)handle;
+
+ if (zip == NULL || mz_zip_entry_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+
+ zip->file_info.extrafield = extrafield;
+ zip->file_info.extrafield_size = extrafield_size;
+ return MZ_OK;
+}
+
+static int32_t mz_zip_goto_next_entry_int(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t err = MZ_OK;
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+
+ zip->entry_scanned = 0;
+
+ mz_stream_set_prop_int64(zip->cd_stream, MZ_STREAM_PROP_DISK_NUMBER, -1);
+
+ err = mz_stream_seek(zip->cd_stream, zip->cd_current_pos, MZ_SEEK_SET);
+ if (err == MZ_OK)
+ err = mz_zip_entry_read_header(zip->cd_stream, 0, &zip->file_info, zip->file_info_stream);
+ if (err == MZ_OK)
+ zip->entry_scanned = 1;
+ return err;
+}
+
+int64_t mz_zip_get_entry(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+
+ return zip->cd_current_pos;
+}
+
+int32_t mz_zip_goto_entry(void *handle, int64_t cd_pos) {
+ mz_zip *zip = (mz_zip *)handle;
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+
+ if (cd_pos < zip->cd_start_pos || cd_pos > zip->cd_start_pos + zip->cd_size)
+ return MZ_PARAM_ERROR;
+
+ zip->cd_current_pos = cd_pos;
+
+ return mz_zip_goto_next_entry_int(handle);
+}
+
+int32_t mz_zip_goto_first_entry(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+
+ zip->cd_current_pos = zip->cd_start_pos;
+
+ return mz_zip_goto_next_entry_int(handle);
+}
+
+int32_t mz_zip_goto_next_entry(void *handle) {
+ mz_zip *zip = (mz_zip *)handle;
+
+ if (zip == NULL)
+ return MZ_PARAM_ERROR;
+
+ zip->cd_current_pos += (int64_t)MZ_ZIP_SIZE_CD_ITEM + zip->file_info.filename_size +
+ zip->file_info.extrafield_size + zip->file_info.comment_size;
+
+ return mz_zip_goto_next_entry_int(handle);
+}
+
+int32_t mz_zip_locate_entry(void *handle, const char *filename, uint8_t ignore_case) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t err = MZ_OK;
+ int32_t result = 0;
+
+ if (zip == NULL || filename == NULL)
+ return MZ_PARAM_ERROR;
+
+ /* If we are already on the current entry, no need to search */
+ if ((zip->entry_scanned) && (zip->file_info.filename != NULL)) {
+ result = mz_zip_path_compare(zip->file_info.filename, filename, ignore_case);
+ if (result == 0)
+ return MZ_OK;
+ }
+
+ /* Search all entries starting at the first */
+ err = mz_zip_goto_first_entry(handle);
+ while (err == MZ_OK) {
+ result = mz_zip_path_compare(zip->file_info.filename, filename, ignore_case);
+ if (result == 0)
+ return MZ_OK;
+
+ err = mz_zip_goto_next_entry(handle);
+ }
+
+ return err;
+}
+
+int32_t mz_zip_locate_first_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t err = MZ_OK;
+ int32_t result = 0;
+
+ /* Search first entry looking for match */
+ err = mz_zip_goto_first_entry(handle);
+ if (err != MZ_OK)
+ return err;
+
+ result = cb(handle, userdata, &zip->file_info);
+ if (result == 0)
+ return MZ_OK;
+
+ return mz_zip_locate_next_entry(handle, userdata, cb);
+}
+
+int32_t mz_zip_locate_next_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb) {
+ mz_zip *zip = (mz_zip *)handle;
+ int32_t err = MZ_OK;
+ int32_t result = 0;
+
+ /* Search next entries looking for match */
+ err = mz_zip_goto_next_entry(handle);
+ while (err == MZ_OK) {
+ result = cb(handle, userdata, &zip->file_info);
+ if (result == 0)
+ return MZ_OK;
+
+ err = mz_zip_goto_next_entry(handle);
+ }
+
+ return err;
+}
+
+/***************************************************************************/
+
+int32_t mz_zip_attrib_is_dir(uint32_t attrib, int32_t version_madeby) {
+ uint32_t posix_attrib = 0;
+ uint8_t system = MZ_HOST_SYSTEM(version_madeby);
+ int32_t err = MZ_OK;
+
+ err = mz_zip_attrib_convert(system, attrib, MZ_HOST_SYSTEM_UNIX, &posix_attrib);
+ if (err == MZ_OK) {
+ if ((posix_attrib & 0170000) == 0040000) /* S_ISDIR */
+ return MZ_OK;
+ }
+
+ return MZ_EXIST_ERROR;
+}
+
+int32_t mz_zip_attrib_is_symlink(uint32_t attrib, int32_t version_madeby) {
+ uint32_t posix_attrib = 0;
+ uint8_t system = MZ_HOST_SYSTEM(version_madeby);
+ int32_t err = MZ_OK;
+
+ err = mz_zip_attrib_convert(system, attrib, MZ_HOST_SYSTEM_UNIX, &posix_attrib);
+ if (err == MZ_OK) {
+ if ((posix_attrib & 0170000) == 0120000) /* S_ISLNK */
+ return MZ_OK;
+ }
+
+ return MZ_EXIST_ERROR;
+}
+
+int32_t mz_zip_attrib_convert(uint8_t src_sys, uint32_t src_attrib, uint8_t target_sys, uint32_t *target_attrib) {
+ if (target_attrib == NULL)
+ return MZ_PARAM_ERROR;
+
+ *target_attrib = 0;
+
+ if ((src_sys == MZ_HOST_SYSTEM_MSDOS) || (src_sys == MZ_HOST_SYSTEM_WINDOWS_NTFS)) {
+ if ((target_sys == MZ_HOST_SYSTEM_MSDOS) || (target_sys == MZ_HOST_SYSTEM_WINDOWS_NTFS)) {
+ *target_attrib = src_attrib;
+ return MZ_OK;
+ }
+ if ((target_sys == MZ_HOST_SYSTEM_UNIX) || (target_sys == MZ_HOST_SYSTEM_OSX_DARWIN) || (target_sys == MZ_HOST_SYSTEM_RISCOS))
+ return mz_zip_attrib_win32_to_posix(src_attrib, target_attrib);
+ } else if ((src_sys == MZ_HOST_SYSTEM_UNIX) || (src_sys == MZ_HOST_SYSTEM_OSX_DARWIN) || (src_sys == MZ_HOST_SYSTEM_RISCOS)) {
+ if ((target_sys == MZ_HOST_SYSTEM_UNIX) || (target_sys == MZ_HOST_SYSTEM_OSX_DARWIN) || (target_sys == MZ_HOST_SYSTEM_RISCOS)) {
+ /* If high bytes are set, it contains unix specific attributes */
+ if ((src_attrib >> 16) != 0)
+ src_attrib >>= 16;
+
+ *target_attrib = src_attrib;
+ return MZ_OK;
+ }
+ if ((target_sys == MZ_HOST_SYSTEM_MSDOS) || (target_sys == MZ_HOST_SYSTEM_WINDOWS_NTFS))
+ return mz_zip_attrib_posix_to_win32(src_attrib, target_attrib);
+ }
+
+ return MZ_SUPPORT_ERROR;
+}
+
+int32_t mz_zip_attrib_posix_to_win32(uint32_t posix_attrib, uint32_t *win32_attrib) {
+ if (win32_attrib == NULL)
+ return MZ_PARAM_ERROR;
+
+ *win32_attrib = 0;
+
+ /* S_IWUSR | S_IWGRP | S_IWOTH | S_IXUSR | S_IXGRP | S_IXOTH */
+ if ((posix_attrib & 0000333) == 0 && (posix_attrib & 0000444) != 0)
+ *win32_attrib |= 0x01; /* FILE_ATTRIBUTE_READONLY */
+ /* S_IFLNK */
+ if ((posix_attrib & 0170000) == 0120000)
+ *win32_attrib |= 0x400; /* FILE_ATTRIBUTE_REPARSE_POINT */
+ /* S_IFDIR */
+ else if ((posix_attrib & 0170000) == 0040000)
+ *win32_attrib |= 0x10; /* FILE_ATTRIBUTE_DIRECTORY */
+ /* S_IFREG */
+ else
+ *win32_attrib |= 0x80; /* FILE_ATTRIBUTE_NORMAL */
+
+ return MZ_OK;
+}
+
+int32_t mz_zip_attrib_win32_to_posix(uint32_t win32_attrib, uint32_t *posix_attrib) {
+ if (posix_attrib == NULL)
+ return MZ_PARAM_ERROR;
+
+ *posix_attrib = 0000444; /* S_IRUSR | S_IRGRP | S_IROTH */
+ /* FILE_ATTRIBUTE_READONLY */
+ if ((win32_attrib & 0x01) == 0)
+ *posix_attrib |= 0000222; /* S_IWUSR | S_IWGRP | S_IWOTH */
+ /* FILE_ATTRIBUTE_REPARSE_POINT */
+ if ((win32_attrib & 0x400) == 0x400)
+ *posix_attrib |= 0120000; /* S_IFLNK */
+ /* FILE_ATTRIBUTE_DIRECTORY */
+ else if ((win32_attrib & 0x10) == 0x10)
+ *posix_attrib |= 0040111; /* S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH */
+ else
+ *posix_attrib |= 0100000; /* S_IFREG */
+
+ return MZ_OK;
+}
+
+/***************************************************************************/
+
+int32_t mz_zip_extrafield_find(void *stream, uint16_t type, int32_t max_seek, uint16_t *length) {
+ int32_t err = MZ_OK;
+ uint16_t field_type = 0;
+ uint16_t field_length = 0;
+
+
+ if (max_seek < 4)
+ return MZ_EXIST_ERROR;
+
+ do {
+ err = mz_stream_read_uint16(stream, &field_type);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(stream, &field_length);
+ if (err != MZ_OK)
+ break;
+
+ if (type == field_type) {
+ if (length != NULL)
+ *length = field_length;
+ return MZ_OK;
+ }
+
+ max_seek -= field_length - 4;
+ if (max_seek < 0)
+ return MZ_EXIST_ERROR;
+
+ err = mz_stream_seek(stream, field_length, MZ_SEEK_CUR);
+ } while (err == MZ_OK);
+
+ return MZ_EXIST_ERROR;
+}
+
+int32_t mz_zip_extrafield_contains(const uint8_t *extrafield, int32_t extrafield_size,
+ uint16_t type, uint16_t *length) {
+ void *file_extra_stream = NULL;
+ int32_t err = MZ_OK;
+
+ if (extrafield == NULL || extrafield_size == 0)
+ return MZ_PARAM_ERROR;
+
+ mz_stream_mem_create(&file_extra_stream);
+ mz_stream_mem_set_buffer(file_extra_stream, (void *)extrafield, extrafield_size);
+
+ err = mz_zip_extrafield_find(file_extra_stream, type, extrafield_size, length);
+
+ mz_stream_mem_delete(&file_extra_stream);
+
+ return err;
+}
+
+int32_t mz_zip_extrafield_read(void *stream, uint16_t *type, uint16_t *length) {
+ int32_t err = MZ_OK;
+ if (type == NULL || length == NULL)
+ return MZ_PARAM_ERROR;
+ err = mz_stream_read_uint16(stream, type);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(stream, length);
+ return err;
+}
+
+int32_t mz_zip_extrafield_write(void *stream, uint16_t type, uint16_t length) {
+ int32_t err = MZ_OK;
+ err = mz_stream_write_uint16(stream, type);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(stream, length);
+ return err;
+}
+
+/***************************************************************************/
+
+static int32_t mz_zip_invalid_date(const struct tm *ptm) {
+#define datevalue_in_range(min, max, value) ((min) <= (value) && (value) <= (max))
+ return (!datevalue_in_range(0, 127 + 80, ptm->tm_year) || /* 1980-based year, allow 80 extra */
+ !datevalue_in_range(0, 11, ptm->tm_mon) ||
+ !datevalue_in_range(1, 31, ptm->tm_mday) ||
+ !datevalue_in_range(0, 23, ptm->tm_hour) ||
+ !datevalue_in_range(0, 59, ptm->tm_min) ||
+ !datevalue_in_range(0, 59, ptm->tm_sec));
+#undef datevalue_in_range
+}
+
+static void mz_zip_dosdate_to_raw_tm(uint64_t dos_date, struct tm *ptm) {
+ uint64_t date = (uint64_t)(dos_date >> 16);
+
+ ptm->tm_mday = (uint16_t)(date & 0x1f);
+ ptm->tm_mon = (uint16_t)(((date & 0x1E0) / 0x20) - 1);
+ ptm->tm_year = (uint16_t)(((date & 0x0FE00) / 0x0200) + 80);
+ ptm->tm_hour = (uint16_t)((dos_date & 0xF800) / 0x800);
+ ptm->tm_min = (uint16_t)((dos_date & 0x7E0) / 0x20);
+ ptm->tm_sec = (uint16_t)(2 * (dos_date & 0x1f));
+ ptm->tm_isdst = -1;
+}
+
+int32_t mz_zip_dosdate_to_tm(uint64_t dos_date, struct tm *ptm) {
+ if (ptm == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_zip_dosdate_to_raw_tm(dos_date, ptm);
+
+ if (mz_zip_invalid_date(ptm)) {
+ /* Invalid date stored, so don't return it */
+ memset(ptm, 0, sizeof(struct tm));
+ return MZ_FORMAT_ERROR;
+ }
+ return MZ_OK;
+}
+
+time_t mz_zip_dosdate_to_time_t(uint64_t dos_date) {
+ struct tm ptm;
+ mz_zip_dosdate_to_raw_tm(dos_date, &ptm);
+ return mktime(&ptm);
+}
+
+int32_t mz_zip_time_t_to_tm(time_t unix_time, struct tm *ptm) {
+ struct tm ltm;
+ if (ptm == NULL)
+ return MZ_PARAM_ERROR;
+ if (localtime_r(&unix_time, &ltm) == NULL) { /* Returns a 1900-based year */
+ /* Invalid date stored, so don't return it */
+ memset(ptm, 0, sizeof(struct tm));
+ return MZ_INTERNAL_ERROR;
+ }
+ memcpy(ptm, &ltm, sizeof(struct tm));
+ return MZ_OK;
+}
+
+uint32_t mz_zip_time_t_to_dos_date(time_t unix_time) {
+ struct tm ptm;
+ mz_zip_time_t_to_tm(unix_time, &ptm);
+ return mz_zip_tm_to_dosdate((const struct tm *)&ptm);
+}
+
+uint32_t mz_zip_tm_to_dosdate(const struct tm *ptm) {
+ struct tm fixed_tm;
+
+ /* Years supported: */
+
+ /* [00, 79] (assumed to be between 2000 and 2079) */
+ /* [80, 207] (assumed to be between 1980 and 2107, typical output of old */
+ /* software that does 'year-1900' to get a double digit year) */
+ /* [1980, 2107] (due to format limitations, only years 1980-2107 can be stored.) */
+
+ memcpy(&fixed_tm, ptm, sizeof(struct tm));
+ if (fixed_tm.tm_year >= 1980) /* range [1980, 2107] */
+ fixed_tm.tm_year -= 1980;
+ else if (fixed_tm.tm_year >= 80) /* range [80, 207] */
+ fixed_tm.tm_year -= 80;
+ else /* range [00, 79] */
+ fixed_tm.tm_year += 20;
+
+ if (mz_zip_invalid_date(&fixed_tm))
+ return 0;
+
+ return (((uint32_t)fixed_tm.tm_mday + (32 * ((uint32_t)fixed_tm.tm_mon + 1)) + (512 * (uint32_t)fixed_tm.tm_year)) << 16) |
+ (((uint32_t)fixed_tm.tm_sec / 2) + (32 * (uint32_t)fixed_tm.tm_min) + (2048 * (uint32_t)fixed_tm.tm_hour));
+}
+
+int32_t mz_zip_ntfs_to_unix_time(uint64_t ntfs_time, time_t *unix_time) {
+ *unix_time = (time_t)((ntfs_time - 116444736000000000LL) / 10000000);
+ return MZ_OK;
+}
+
+int32_t mz_zip_unix_to_ntfs_time(time_t unix_time, uint64_t *ntfs_time) {
+ *ntfs_time = ((uint64_t)unix_time * 10000000) + 116444736000000000LL;
+ return MZ_OK;
+}
+
+/***************************************************************************/
+
+int32_t mz_zip_path_compare(const char *path1, const char *path2, uint8_t ignore_case) {
+ do {
+ if ((*path1 == '\\' && *path2 == '/') ||
+ (*path2 == '\\' && *path1 == '/')) {
+ /* Ignore comparison of path slashes */
+ } else if (ignore_case) {
+ if (tolower(*path1) != tolower(*path2))
+ break;
+ } else if (*path1 != *path2) {
+ break;
+ }
+
+ path1 += 1;
+ path2 += 1;
+ } while (*path1 != 0 && *path2 != 0);
+
+ if (ignore_case)
+ return (int32_t)(tolower(*path1) - tolower(*path2));
+
+ return (int32_t)(*path1 - *path2);
+}
+
+/***************************************************************************/
+
+const char* mz_zip_get_compression_method_string(int32_t compression_method)
+{
+ const char *method = "?";
+ switch (compression_method) {
+ case MZ_COMPRESS_METHOD_STORE:
+ method = "stored";
+ break;
+ case MZ_COMPRESS_METHOD_DEFLATE:
+ method = "deflate";
+ break;
+ case MZ_COMPRESS_METHOD_BZIP2:
+ method = "bzip2";
+ break;
+ case MZ_COMPRESS_METHOD_LZMA:
+ method = "lzma";
+ break;
+ case MZ_COMPRESS_METHOD_XZ:
+ method = "xz";
+ break;
+ case MZ_COMPRESS_METHOD_ZSTD:
+ method = "zstd";
+ break;
+ }
+ return method;
+}
+
+/***************************************************************************/
diff --git a/Externals/minizip/mz_zip.h b/Externals/minizip/mz_zip.h
new file mode 100644
index 0000000000..e3d1fbd523
--- /dev/null
+++ b/Externals/minizip/mz_zip.h
@@ -0,0 +1,259 @@
+/* mz_zip.h -- Zip manipulation
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+ Copyright (C) 2009-2010 Mathias Svensson
+ Modifications for Zip64 support
+ http://result42.com
+ Copyright (C) 1998-2010 Gilles Vollant
+ https://www.winimage.com/zLibDll/minizip.html
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_ZIP_H
+#define MZ_ZIP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+typedef struct mz_zip_file_s {
+ uint16_t version_madeby; /* version made by */
+ uint16_t version_needed; /* version needed to extract */
+ uint16_t flag; /* general purpose bit flag */
+ uint16_t compression_method; /* compression method */
+ time_t modified_date; /* last modified date in unix time */
+ time_t accessed_date; /* last accessed date in unix time */
+ time_t creation_date; /* creation date in unix time */
+ uint32_t crc; /* crc-32 */
+ int64_t compressed_size; /* compressed size */
+ int64_t uncompressed_size; /* uncompressed size */
+ uint16_t filename_size; /* filename length */
+ uint16_t extrafield_size; /* extra field length */
+ uint16_t comment_size; /* file comment length */
+ uint32_t disk_number; /* disk number start */
+ int64_t disk_offset; /* relative offset of local header */
+ uint16_t internal_fa; /* internal file attributes */
+ uint32_t external_fa; /* external file attributes */
+
+ const char *filename; /* filename utf8 null-terminated string */
+ const uint8_t *extrafield; /* extrafield data */
+ const char *comment; /* comment utf8 null-terminated string */
+ const char *linkname; /* sym-link filename utf8 null-terminated string */
+
+ uint16_t zip64; /* zip64 extension mode */
+ uint16_t aes_version; /* winzip aes extension if not 0 */
+ uint8_t aes_encryption_mode; /* winzip aes encryption mode */
+ uint16_t pk_verify; /* pkware encryption verifier */
+
+} mz_zip_file, mz_zip_entry;
+
+/***************************************************************************/
+
+typedef int32_t (*mz_zip_locate_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info);
+
+/***************************************************************************/
+
+void * mz_zip_create(void **handle);
+/* Create zip instance for opening */
+
+void mz_zip_delete(void **handle);
+/* Delete zip object */
+
+int32_t mz_zip_open(void *handle, void *stream, int32_t mode);
+/* Create a zip file, no delete file in zip functionality */
+
+int32_t mz_zip_close(void *handle);
+/* Close the zip file */
+
+int32_t mz_zip_get_comment(void *handle, const char **comment);
+/* Get a pointer to the global comment */
+
+int32_t mz_zip_set_comment(void *handle, const char *comment);
+/* Sets the global comment used for writing zip file */
+
+int32_t mz_zip_get_version_madeby(void *handle, uint16_t *version_madeby);
+/* Get the version made by */
+
+int32_t mz_zip_set_version_madeby(void *handle, uint16_t version_madeby);
+/* Sets the version made by used for writing zip file */
+
+int32_t mz_zip_set_recover(void *handle, uint8_t recover);
+/* Sets the ability to recover the central dir by reading local file headers */
+
+int32_t mz_zip_set_data_descriptor(void *handle, uint8_t data_descriptor);
+/* Sets the use of data descriptor flag when writing zip entries */
+
+int32_t mz_zip_get_stream(void *handle, void **stream);
+/* Get a pointer to the stream used to open */
+
+int32_t mz_zip_set_cd_stream(void *handle, int64_t cd_start_pos, void *cd_stream);
+/* Sets the stream to use for reading the central dir */
+
+int32_t mz_zip_get_cd_mem_stream(void *handle, void **cd_mem_stream);
+/* Get a pointer to the stream used to store the central dir in memory */
+
+int32_t mz_zip_set_number_entry(void *handle, uint64_t number_entry);
+/* Sets the total number of entries */
+
+int32_t mz_zip_get_number_entry(void *handle, uint64_t *number_entry);
+/* Get the total number of entries */
+
+int32_t mz_zip_set_disk_number_with_cd(void *handle, uint32_t disk_number_with_cd);
+/* Sets the disk number containing the central directory record */
+
+int32_t mz_zip_get_disk_number_with_cd(void *handle, uint32_t *disk_number_with_cd);
+/* Get the disk number containing the central directory record */
+
+/***************************************************************************/
+
+int32_t mz_zip_entry_is_open(void *handle);
+/* Check to see if entry is open for read/write */
+
+int32_t mz_zip_entry_read_open(void *handle, uint8_t raw, const char *password);
+/* Open for reading the current file in the zip file */
+
+int32_t mz_zip_entry_read(void *handle, void *buf, int32_t len);
+/* Read bytes from the current file in the zip file */
+
+int32_t mz_zip_entry_read_close(void *handle, uint32_t *crc32, int64_t *compressed_size,
+ int64_t *uncompressed_size);
+/* Close the current file for reading and get data descriptor values */
+
+int32_t mz_zip_entry_write_open(void *handle, const mz_zip_file *file_info,
+ int16_t compress_level, uint8_t raw, const char *password);
+/* Open for writing the current file in the zip file */
+
+int32_t mz_zip_entry_write(void *handle, const void *buf, int32_t len);
+/* Write bytes from the current file in the zip file */
+
+int32_t mz_zip_entry_write_close(void *handle, uint32_t crc32, int64_t compressed_size,
+ int64_t uncompressed_size);
+/* Close the current file for writing and set data descriptor values */
+
+int32_t mz_zip_entry_seek_local_header(void *handle);
+/* Seeks to the local header for the entry */
+
+int32_t mz_zip_entry_close_raw(void *handle, int64_t uncompressed_size, uint32_t crc32);
+/* Close the current file in the zip file where raw is compressed data */
+
+int32_t mz_zip_entry_close(void *handle);
+/* Close the current file in the zip file */
+
+/***************************************************************************/
+
+int32_t mz_zip_entry_is_dir(void *handle);
+/* Checks to see if the entry is a directory */
+
+int32_t mz_zip_entry_is_symlink(void *handle);
+/* Checks to see if the entry is a symbolic link */
+
+int32_t mz_zip_entry_get_info(void *handle, mz_zip_file **file_info);
+/* Get info about the current file, only valid while current entry is open */
+
+int32_t mz_zip_entry_get_local_info(void *handle, mz_zip_file **local_file_info);
+/* Get local info about the current file, only valid while current entry is being read */
+
+int32_t mz_zip_entry_set_extrafield(void *handle, const uint8_t *extrafield, uint16_t extrafield_size);
+/* Sets or updates the extra field for the entry to be used before writing cd */
+
+int64_t mz_zip_get_entry(void *handle);
+/* Return offset of the current entry in the zip file */
+
+int32_t mz_zip_goto_entry(void *handle, int64_t cd_pos);
+/* Go to specified entry in the zip file */
+
+int32_t mz_zip_goto_first_entry(void *handle);
+/* Go to the first entry in the zip file */
+
+int32_t mz_zip_goto_next_entry(void *handle);
+/* Go to the next entry in the zip file or MZ_END_OF_LIST if reaching the end */
+
+int32_t mz_zip_locate_entry(void *handle, const char *filename, uint8_t ignore_case);
+/* Locate the file with the specified name in the zip file or MZ_END_LIST if not found */
+
+int32_t mz_zip_locate_first_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb);
+/* Locate the first matching entry based on a match callback */
+
+int32_t mz_zip_locate_next_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb);
+/* Locate the next matching entry based on a match callback */
+
+/***************************************************************************/
+
+int32_t mz_zip_attrib_is_dir(uint32_t attrib, int32_t version_madeby);
+/* Checks to see if the attribute is a directory based on platform */
+
+int32_t mz_zip_attrib_is_symlink(uint32_t attrib, int32_t version_madeby);
+/* Checks to see if the attribute is a symbolic link based on platform */
+
+int32_t mz_zip_attrib_convert(uint8_t src_sys, uint32_t src_attrib, uint8_t target_sys,
+ uint32_t *target_attrib);
+/* Converts file attributes from one host system to another */
+
+int32_t mz_zip_attrib_posix_to_win32(uint32_t posix_attrib, uint32_t *win32_attrib);
+/* Converts posix file attributes to win32 file attributes */
+
+int32_t mz_zip_attrib_win32_to_posix(uint32_t win32_attrib, uint32_t *posix_attrib);
+/* Converts win32 file attributes to posix file attributes */
+
+/***************************************************************************/
+
+int32_t mz_zip_extrafield_find(void *stream, uint16_t type, int32_t max_seek, uint16_t *length);
+/* Seeks to extra field by its type and returns its length */
+
+int32_t mz_zip_extrafield_contains(const uint8_t *extrafield, int32_t extrafield_size,
+ uint16_t type, uint16_t *length);
+/* Gets whether an extrafield exists and its size */
+
+int32_t mz_zip_extrafield_read(void *stream, uint16_t *type, uint16_t *length);
+/* Reads an extrafield header from a stream */
+
+int32_t mz_zip_extrafield_write(void *stream, uint16_t type, uint16_t length);
+/* Writes an extrafield header to a stream */
+
+/***************************************************************************/
+
+int32_t mz_zip_dosdate_to_tm(uint64_t dos_date, struct tm *ptm);
+/* Convert dos date/time format to struct tm */
+
+time_t mz_zip_dosdate_to_time_t(uint64_t dos_date);
+/* Convert dos date/time format to time_t */
+
+int32_t mz_zip_time_t_to_tm(time_t unix_time, struct tm *ptm);
+/* Convert time_t to time struct */
+
+uint32_t mz_zip_time_t_to_dos_date(time_t unix_time);
+/* Convert time_t to dos date/time format */
+
+uint32_t mz_zip_tm_to_dosdate(const struct tm *ptm);
+/* Convert struct tm to dos date/time format */
+
+int32_t mz_zip_ntfs_to_unix_time(uint64_t ntfs_time, time_t *unix_time);
+/* Convert ntfs time to unix time */
+
+int32_t mz_zip_unix_to_ntfs_time(time_t unix_time, uint64_t *ntfs_time);
+/* Convert unix time to ntfs time */
+
+/***************************************************************************/
+
+int32_t mz_zip_path_compare(const char *path1, const char *path2, uint8_t ignore_case);
+/* Compare two paths without regard to slashes */
+
+/***************************************************************************/
+
+const
+char* mz_zip_get_compression_method_string(int32_t compression_method);
+/* Gets a string representing the compression method */
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZIP_H */
diff --git a/Externals/minizip/mz_zip_rw.c b/Externals/minizip/mz_zip_rw.c
new file mode 100644
index 0000000000..464e559057
--- /dev/null
+++ b/Externals/minizip/mz_zip_rw.c
@@ -0,0 +1,1943 @@
+/* mz_zip_rw.c -- Zip reader/writer
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#include "mz.h"
+#include "mz_crypt.h"
+#include "mz_os.h"
+#include "mz_strm.h"
+#include "mz_strm_buf.h"
+#include "mz_strm_mem.h"
+#include "mz_strm_os.h"
+#include "mz_strm_split.h"
+#include "mz_strm_wzaes.h"
+#include "mz_zip.h"
+
+#include "mz_zip_rw.h"
+
+/***************************************************************************/
+
+#define MZ_DEFAULT_PROGRESS_INTERVAL (1000u)
+
+#define MZ_ZIP_CD_FILENAME ("__cdcd__")
+
+/***************************************************************************/
+
+typedef struct mz_zip_reader_s {
+ void *zip_handle;
+ void *file_stream;
+ void *buffered_stream;
+ void *split_stream;
+ void *mem_stream;
+ void *hash;
+ uint16_t hash_algorithm;
+ uint16_t hash_digest_size;
+ mz_zip_file *file_info;
+ const char *pattern;
+ uint8_t pattern_ignore_case;
+ const char *password;
+ void *overwrite_userdata;
+ mz_zip_reader_overwrite_cb
+ overwrite_cb;
+ void *password_userdata;
+ mz_zip_reader_password_cb
+ password_cb;
+ void *progress_userdata;
+ mz_zip_reader_progress_cb
+ progress_cb;
+ uint32_t progress_cb_interval_ms;
+ void *entry_userdata;
+ mz_zip_reader_entry_cb
+ entry_cb;
+ uint8_t raw;
+ uint8_t buffer[UINT16_MAX];
+ int32_t encoding;
+ uint8_t sign_required;
+ uint8_t cd_verified;
+ uint8_t cd_zipped;
+ uint8_t entry_verified;
+ uint8_t recover;
+} mz_zip_reader;
+
+/***************************************************************************/
+
+int32_t mz_zip_reader_is_open(void *handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ if (reader == NULL)
+ return MZ_PARAM_ERROR;
+ if (reader->zip_handle == NULL)
+ return MZ_PARAM_ERROR;
+ return MZ_OK;
+}
+
+int32_t mz_zip_reader_open(void *handle, void *stream) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+
+ reader->cd_verified = 0;
+ reader->cd_zipped = 0;
+
+ mz_zip_create(&reader->zip_handle);
+ mz_zip_set_recover(reader->zip_handle, reader->recover);
+
+ err = mz_zip_open(reader->zip_handle, stream, MZ_OPEN_MODE_READ);
+
+ if (err != MZ_OK) {
+ mz_zip_reader_close(handle);
+ return err;
+ }
+
+ mz_zip_reader_unzip_cd(reader);
+ return MZ_OK;
+}
+
+int32_t mz_zip_reader_open_file(void *handle, const char *path) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+
+
+ mz_zip_reader_close(handle);
+
+ mz_stream_os_create(&reader->file_stream);
+ mz_stream_buffered_create(&reader->buffered_stream);
+ mz_stream_split_create(&reader->split_stream);
+
+ mz_stream_set_base(reader->buffered_stream, reader->file_stream);
+ mz_stream_set_base(reader->split_stream, reader->buffered_stream);
+
+ err = mz_stream_open(reader->split_stream, path, MZ_OPEN_MODE_READ);
+ if (err == MZ_OK)
+ err = mz_zip_reader_open(handle, reader->split_stream);
+ return err;
+}
+
+int32_t mz_zip_reader_open_file_in_memory(void *handle, const char *path) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ void *file_stream = NULL;
+ int64_t file_size = 0;
+ int32_t err = 0;
+
+
+ mz_zip_reader_close(handle);
+
+ mz_stream_os_create(&file_stream);
+
+ err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_READ);
+
+ if (err != MZ_OK) {
+ mz_stream_os_delete(&file_stream);
+ mz_zip_reader_close(handle);
+ return err;
+ }
+
+ mz_stream_os_seek(file_stream, 0, MZ_SEEK_END);
+ file_size = mz_stream_os_tell(file_stream);
+ mz_stream_os_seek(file_stream, 0, MZ_SEEK_SET);
+
+ if ((file_size <= 0) || (file_size > UINT32_MAX)) {
+ /* Memory size is too large or too small */
+
+ mz_stream_os_close(file_stream);
+ mz_stream_os_delete(&file_stream);
+ mz_zip_reader_close(handle);
+ return MZ_MEM_ERROR;
+ }
+
+ mz_stream_mem_create(&reader->mem_stream);
+ mz_stream_mem_set_grow_size(reader->mem_stream, (int32_t)file_size);
+ mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_CREATE);
+
+ err = mz_stream_copy(reader->mem_stream, file_stream, (int32_t)file_size);
+
+ mz_stream_os_close(file_stream);
+ mz_stream_os_delete(&file_stream);
+
+ if (err == MZ_OK)
+ err = mz_zip_reader_open(handle, reader->mem_stream);
+ if (err != MZ_OK)
+ mz_zip_reader_close(handle);
+
+ return err;
+}
+
+int32_t mz_zip_reader_open_buffer(void *handle, uint8_t *buf, int32_t len, uint8_t copy) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+
+ mz_zip_reader_close(handle);
+
+ mz_stream_mem_create(&reader->mem_stream);
+
+ if (copy) {
+ mz_stream_mem_set_grow_size(reader->mem_stream, len);
+ mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_CREATE);
+ mz_stream_mem_write(reader->mem_stream, buf, len);
+ mz_stream_mem_seek(reader->mem_stream, 0, MZ_SEEK_SET);
+ } else {
+ mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_READ);
+ mz_stream_mem_set_buffer(reader->mem_stream, buf, len);
+ }
+
+ if (err == MZ_OK)
+ err = mz_zip_reader_open(handle, reader->mem_stream);
+
+ return err;
+}
+
+int32_t mz_zip_reader_close(void *handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+
+ if (reader->zip_handle != NULL) {
+ err = mz_zip_close(reader->zip_handle);
+ mz_zip_delete(&reader->zip_handle);
+ }
+
+ if (reader->split_stream != NULL) {
+ mz_stream_split_close(reader->split_stream);
+ mz_stream_split_delete(&reader->split_stream);
+ }
+
+ if (reader->buffered_stream != NULL)
+ mz_stream_buffered_delete(&reader->buffered_stream);
+
+ if (reader->file_stream != NULL)
+ mz_stream_os_delete(&reader->file_stream);
+
+ if (reader->mem_stream != NULL) {
+ mz_stream_mem_close(reader->mem_stream);
+ mz_stream_mem_delete(&reader->mem_stream);
+ }
+
+ return err;
+}
+
+/***************************************************************************/
+
+int32_t mz_zip_reader_unzip_cd(void *handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ mz_zip_file *cd_info = NULL;
+ void *cd_mem_stream = NULL;
+ void *new_cd_stream = NULL;
+ void *file_extra_stream = NULL;
+ uint64_t number_entry = 0;
+ int32_t err = MZ_OK;
+
+
+ err = mz_zip_reader_goto_first_entry(handle);
+ if (err != MZ_OK)
+ return err;
+ err = mz_zip_reader_entry_get_info(handle, &cd_info);
+ if (err != MZ_OK)
+ return err;
+
+ if (strcmp(cd_info->filename, MZ_ZIP_CD_FILENAME) != 0)
+ return mz_zip_reader_goto_first_entry(handle);
+
+ err = mz_zip_reader_entry_open(handle);
+ if (err != MZ_OK)
+ return err;
+
+ mz_stream_mem_create(&file_extra_stream);
+ mz_stream_mem_set_buffer(file_extra_stream, (void *)cd_info->extrafield, cd_info->extrafield_size);
+
+ err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_CDCD, INT32_MAX, NULL);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint64(file_extra_stream, &number_entry);
+
+ mz_stream_mem_delete(&file_extra_stream);
+
+ if (err != MZ_OK)
+ return err;
+
+ mz_zip_get_cd_mem_stream(reader->zip_handle, &cd_mem_stream);
+ if (mz_stream_mem_is_open(cd_mem_stream) != MZ_OK)
+ mz_stream_mem_open(cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE);
+
+ err = mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);
+ if (err == MZ_OK)
+ err = mz_stream_copy_stream(cd_mem_stream, NULL, handle, mz_zip_reader_entry_read,
+ (int32_t)cd_info->uncompressed_size);
+
+ if (err == MZ_OK) {
+ reader->cd_zipped = 1;
+
+ mz_zip_set_cd_stream(reader->zip_handle, 0, cd_mem_stream);
+ mz_zip_set_number_entry(reader->zip_handle, number_entry);
+
+ err = mz_zip_reader_goto_first_entry(handle);
+ }
+
+ reader->cd_verified = reader->entry_verified;
+
+ mz_stream_mem_delete(&new_cd_stream);
+ return err;
+}
+
+/***************************************************************************/
+
+static int32_t mz_zip_reader_locate_entry_cb(void *handle, void *userdata, mz_zip_file *file_info) {
+ mz_zip_reader *reader = (mz_zip_reader *)userdata;
+ int32_t result = 0;
+ MZ_UNUSED(handle);
+ result = mz_path_compare_wc(file_info->filename, reader->pattern, reader->pattern_ignore_case);
+ return result;
+}
+
+int32_t mz_zip_reader_goto_first_entry(void *handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+
+ if (mz_zip_reader_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+
+ if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
+ mz_zip_reader_entry_close(handle);
+
+ if (reader->pattern == NULL)
+ err = mz_zip_goto_first_entry(reader->zip_handle);
+ else
+ err = mz_zip_locate_first_entry(reader->zip_handle, reader, mz_zip_reader_locate_entry_cb);
+
+ reader->file_info = NULL;
+ if (err == MZ_OK)
+ err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);
+
+ return err;
+}
+
+int32_t mz_zip_reader_goto_next_entry(void *handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+
+ if (mz_zip_reader_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+
+ if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
+ mz_zip_reader_entry_close(handle);
+
+ if (reader->pattern == NULL)
+ err = mz_zip_goto_next_entry(reader->zip_handle);
+ else
+ err = mz_zip_locate_next_entry(reader->zip_handle, reader, mz_zip_reader_locate_entry_cb);
+
+ reader->file_info = NULL;
+ if (err == MZ_OK)
+ err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);
+
+ return err;
+}
+
+int32_t mz_zip_reader_locate_entry(void *handle, const char *filename, uint8_t ignore_case) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+
+ if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
+ mz_zip_reader_entry_close(handle);
+
+ err = mz_zip_locate_entry(reader->zip_handle, filename, ignore_case);
+
+ reader->file_info = NULL;
+ if (err == MZ_OK)
+ err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);
+
+ return err;
+}
+
+/***************************************************************************/
+
+int32_t mz_zip_reader_entry_open(void *handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+ const char *password = NULL;
+ char password_buf[120];
+
+
+ reader->entry_verified = 0;
+
+ if (mz_zip_reader_is_open(reader) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (reader->file_info == NULL)
+ return MZ_PARAM_ERROR;
+
+ /* If the entry isn't open for reading, open it */
+ if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
+ return MZ_OK;
+
+ password = reader->password;
+
+ /* Check if we need a password and ask for it if we need to */
+ if ((reader->file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL) &&
+ (reader->password_cb != NULL)) {
+ reader->password_cb(handle, reader->password_userdata, reader->file_info,
+ password_buf, sizeof(password_buf));
+
+ password = password_buf;
+ }
+
+ err = mz_zip_entry_read_open(reader->zip_handle, reader->raw, password);
+#ifndef MZ_ZIP_NO_CRYPTO
+ if (err != MZ_OK)
+ return err;
+
+ if (mz_zip_reader_entry_get_first_hash(handle, &reader->hash_algorithm, &reader->hash_digest_size) == MZ_OK) {
+ mz_crypt_sha_create(&reader->hash);
+ if (reader->hash_algorithm == MZ_HASH_SHA1)
+ mz_crypt_sha_set_algorithm(reader->hash, MZ_HASH_SHA1);
+ else if (reader->hash_algorithm == MZ_HASH_SHA256)
+ mz_crypt_sha_set_algorithm(reader->hash, MZ_HASH_SHA256);
+ else
+ err = MZ_SUPPORT_ERROR;
+
+ if (err == MZ_OK)
+ mz_crypt_sha_begin(reader->hash);
+#ifdef MZ_ZIP_SIGNING
+ if (err == MZ_OK) {
+ if (mz_zip_reader_entry_has_sign(handle) == MZ_OK) {
+ err = mz_zip_reader_entry_sign_verify(handle);
+ if (err == MZ_OK)
+ reader->entry_verified = 1;
+ } else if (reader->sign_required && !reader->cd_verified)
+ err = MZ_SIGN_ERROR;
+ }
+#endif
+ } else if (reader->sign_required && !reader->cd_verified)
+ err = MZ_SIGN_ERROR;
+#endif
+
+ return err;
+}
+
+int32_t mz_zip_reader_entry_close(void *handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+ int32_t err_close = MZ_OK;
+#ifndef MZ_ZIP_NO_CRYPTO
+ int32_t err_hash = MZ_OK;
+ uint8_t computed_hash[MZ_HASH_MAX_SIZE];
+ uint8_t expected_hash[MZ_HASH_MAX_SIZE];
+
+ if (reader->hash != NULL) {
+ mz_crypt_sha_end(reader->hash, computed_hash, sizeof(computed_hash));
+ mz_crypt_sha_delete(&reader->hash);
+
+ err_hash = mz_zip_reader_entry_get_hash(handle, reader->hash_algorithm, expected_hash,
+ reader->hash_digest_size);
+
+ if (err_hash == MZ_OK) {
+ /* Verify expected hash against computed hash */
+ if (memcmp(computed_hash, expected_hash, reader->hash_digest_size) != 0)
+ err = MZ_CRC_ERROR;
+ }
+ }
+#endif
+
+ err_close = mz_zip_entry_close(reader->zip_handle);
+ if (err == MZ_OK)
+ err = err_close;
+ return err;
+}
+
+int32_t mz_zip_reader_entry_read(void *handle, void *buf, int32_t len) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t read = 0;
+ read = mz_zip_entry_read(reader->zip_handle, buf, len);
+#ifndef MZ_ZIP_NO_CRYPTO
+ if ((read > 0) && (reader->hash != NULL))
+ mz_crypt_sha_update(reader->hash, buf, read);
+#endif
+ return read;
+}
+
+int32_t mz_zip_reader_entry_has_sign(void *handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+
+ if (reader == NULL || mz_zip_entry_is_open(reader->zip_handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+
+ return mz_zip_extrafield_contains(reader->file_info->extrafield,
+ reader->file_info->extrafield_size, MZ_ZIP_EXTENSION_SIGN, NULL);
+}
+
+#if !defined(MZ_ZIP_NO_CRYPTO) && defined(MZ_ZIP_SIGNING)
+int32_t mz_zip_reader_entry_sign_verify(void *handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ void *file_extra_stream = NULL;
+ int32_t err = MZ_OK;
+ uint8_t *signature = NULL;
+ uint16_t signature_size = 0;
+ uint8_t hash[MZ_HASH_MAX_SIZE];
+
+ if (reader == NULL || mz_zip_entry_is_open(reader->zip_handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+
+ mz_stream_mem_create(&file_extra_stream);
+ mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,
+ reader->file_info->extrafield_size);
+
+ err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_SIGN, INT32_MAX, &signature_size);
+ if ((err == MZ_OK) && (signature_size > 0)) {
+ signature = (uint8_t *)MZ_ALLOC(signature_size);
+ if (mz_stream_read(file_extra_stream, signature, signature_size) != signature_size)
+ err = MZ_READ_ERROR;
+ }
+
+ mz_stream_mem_delete(&file_extra_stream);
+
+ if (err == MZ_OK) {
+ /* Get most secure hash to verify signature against */
+ err = mz_zip_reader_entry_get_hash(handle, reader->hash_algorithm, hash, reader->hash_digest_size);
+ }
+
+ if (err == MZ_OK) {
+ /* Verify the pkcs signature */
+ err = mz_crypt_sign_verify(hash, reader->hash_digest_size, signature, signature_size);
+ }
+
+ if (signature != NULL)
+ MZ_FREE(signature);
+
+ return err;
+}
+#endif
+
+int32_t mz_zip_reader_entry_get_hash(void *handle, uint16_t algorithm, uint8_t *digest, int32_t digest_size) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ void *file_extra_stream = NULL;
+ int32_t err = MZ_OK;
+ int32_t return_err = MZ_EXIST_ERROR;
+ uint16_t cur_algorithm = 0;
+ uint16_t cur_digest_size = 0;
+
+ mz_stream_mem_create(&file_extra_stream);
+ mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,
+ reader->file_info->extrafield_size);
+
+ do {
+ err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_HASH, INT32_MAX, NULL);
+ if (err != MZ_OK)
+ break;
+
+ err = mz_stream_read_uint16(file_extra_stream, &cur_algorithm);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(file_extra_stream, &cur_digest_size);
+ if ((err == MZ_OK) && (cur_algorithm == algorithm) && (cur_digest_size <= digest_size) &&
+ (cur_digest_size <= MZ_HASH_MAX_SIZE)) {
+ /* Read hash digest */
+ if (mz_stream_read(file_extra_stream, digest, digest_size) == cur_digest_size)
+ return_err = MZ_OK;
+ break;
+ } else {
+ err = mz_stream_seek(file_extra_stream, cur_digest_size, MZ_SEEK_CUR);
+ }
+ } while (err == MZ_OK);
+
+ mz_stream_mem_delete(&file_extra_stream);
+
+ return return_err;
+}
+
+int32_t mz_zip_reader_entry_get_first_hash(void *handle, uint16_t *algorithm, uint16_t *digest_size) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ void *file_extra_stream = NULL;
+ int32_t err = MZ_OK;
+ uint16_t cur_algorithm = 0;
+ uint16_t cur_digest_size = 0;
+
+ if (reader == NULL || algorithm == NULL)
+ return MZ_PARAM_ERROR;
+
+ mz_stream_mem_create(&file_extra_stream);
+ mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,
+ reader->file_info->extrafield_size);
+
+ err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_HASH, INT32_MAX, NULL);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(file_extra_stream, &cur_algorithm);
+ if (err == MZ_OK)
+ err = mz_stream_read_uint16(file_extra_stream, &cur_digest_size);
+
+ if (algorithm != NULL)
+ *algorithm = cur_algorithm;
+ if (digest_size != NULL)
+ *digest_size = cur_digest_size;
+
+ mz_stream_mem_delete(&file_extra_stream);
+
+ return err;
+}
+
+int32_t mz_zip_reader_entry_get_info(void *handle, mz_zip_file **file_info) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+ if (file_info == NULL || mz_zip_reader_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ *file_info = reader->file_info;
+ if (*file_info == NULL)
+ return MZ_EXIST_ERROR;
+ return err;
+}
+
+int32_t mz_zip_reader_entry_is_dir(void *handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ if (mz_zip_reader_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ return mz_zip_entry_is_dir(reader->zip_handle);
+}
+
+int32_t mz_zip_reader_entry_save_process(void *handle, void *stream, mz_stream_write_cb write_cb) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+ int32_t read = 0;
+ int32_t written = 0;
+
+
+ if (mz_zip_reader_is_open(reader) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (reader->file_info == NULL)
+ return MZ_PARAM_ERROR;
+ if (write_cb == NULL)
+ return MZ_PARAM_ERROR;
+
+ /* If the entry isn't open for reading, open it */
+ if (mz_zip_entry_is_open(reader->zip_handle) != MZ_OK)
+ err = mz_zip_reader_entry_open(handle);
+
+ if (err != MZ_OK)
+ return err;
+
+ /* Unzip entry in zip file */
+ read = mz_zip_reader_entry_read(handle, reader->buffer, sizeof(reader->buffer));
+
+ if (read == 0) {
+ /* If we are done close the entry */
+ err = mz_zip_reader_entry_close(handle);
+ if (err != MZ_OK)
+ return err;
+
+ return MZ_END_OF_STREAM;
+ }
+
+ if (read > 0) {
+ /* Write the data to the specified stream */
+ written = write_cb(stream, reader->buffer, read);
+ if (written != read)
+ return MZ_WRITE_ERROR;
+ }
+
+ return read;
+}
+
+int32_t mz_zip_reader_entry_save(void *handle, void *stream, mz_stream_write_cb write_cb) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ uint64_t current_time = 0;
+ uint64_t update_time = 0;
+ int64_t current_pos = 0;
+ int64_t update_pos = 0;
+ int32_t err = MZ_OK;
+ int32_t written = 0;
+
+ if (mz_zip_reader_is_open(reader) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (reader->file_info == NULL)
+ return MZ_PARAM_ERROR;
+
+ /* Update the progress at the beginning */
+ if (reader->progress_cb != NULL)
+ reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);
+
+ /* Write data to stream until done */
+ while (err == MZ_OK) {
+ written = mz_zip_reader_entry_save_process(handle, stream, write_cb);
+ if (written == MZ_END_OF_STREAM)
+ break;
+ if (written > 0)
+ current_pos += written;
+ if (written < 0)
+ err = written;
+
+ /* Update progress if enough time have passed */
+ current_time = mz_os_ms_time();
+ if ((current_time - update_time) > reader->progress_cb_interval_ms) {
+ if (reader->progress_cb != NULL)
+ reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);
+
+ update_pos = current_pos;
+ update_time = current_time;
+ }
+ }
+
+ /* Update the progress at the end */
+ if (reader->progress_cb != NULL && update_pos != current_pos)
+ reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);
+
+ return err;
+}
+
+int32_t mz_zip_reader_entry_save_file(void *handle, const char *path) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ void *stream = NULL;
+ uint32_t target_attrib = 0;
+ int32_t err_attrib = 0;
+ int32_t err = MZ_OK;
+ int32_t err_cb = MZ_OK;
+ char pathwfs[512];
+ char directory[512];
+
+ if (mz_zip_reader_is_open(reader) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (reader->file_info == NULL || path == NULL)
+ return MZ_PARAM_ERROR;
+
+ /* Convert to forward slashes for unix which doesn't like backslashes */
+ strncpy(pathwfs, path, sizeof(pathwfs) - 1);
+ pathwfs[sizeof(pathwfs) - 1] = 0;
+ mz_path_convert_slashes(pathwfs, MZ_PATH_SLASH_UNIX);
+
+ if (reader->entry_cb != NULL)
+ reader->entry_cb(handle, reader->entry_userdata, reader->file_info, pathwfs);
+
+ strncpy(directory, pathwfs, sizeof(directory) - 1);
+ directory[sizeof(directory) - 1] = 0;
+ mz_path_remove_filename(directory);
+
+ /* If it is a directory entry then create a directory instead of writing file */
+ if ((mz_zip_entry_is_dir(reader->zip_handle) == MZ_OK) &&
+ (mz_zip_entry_is_symlink(reader->zip_handle) != MZ_OK)) {
+ err = mz_dir_make(directory);
+ return err;
+ }
+
+ /* Check if file exists and ask if we want to overwrite */
+ if ((mz_os_file_exists(pathwfs) == MZ_OK) && (reader->overwrite_cb != NULL)) {
+ err_cb = reader->overwrite_cb(handle, reader->overwrite_userdata, reader->file_info, pathwfs);
+ if (err_cb != MZ_OK)
+ return err;
+ /* We want to overwrite the file so we delete the existing one */
+ mz_os_unlink(pathwfs);
+ }
+
+ /* If symbolic link then properly construct destination path and link path */
+ if (mz_zip_entry_is_symlink(reader->zip_handle) == MZ_OK) {
+ mz_path_remove_slash(pathwfs);
+ mz_path_remove_filename(directory);
+ }
+
+ /* Create the output directory if it doesn't already exist */
+ if (mz_os_is_dir(directory) != MZ_OK) {
+ err = mz_dir_make(directory);
+ if (err != MZ_OK)
+ return err;
+ }
+
+ /* If it is a symbolic link then create symbolic link instead of writing file */
+ if (mz_zip_entry_is_symlink(reader->zip_handle) == MZ_OK) {
+ mz_os_make_symlink(pathwfs, reader->file_info->linkname);
+ /* Don't check return value because we aren't validating symbolic link target */
+ return err;
+ }
+
+ /* Create the file on disk so we can save to it */
+ mz_stream_os_create(&stream);
+ err = mz_stream_os_open(stream, pathwfs, MZ_OPEN_MODE_CREATE);
+
+ if (err == MZ_OK)
+ err = mz_zip_reader_entry_save(handle, stream, mz_stream_write);
+
+ mz_stream_close(stream);
+ mz_stream_delete(&stream);
+
+ if (err == MZ_OK) {
+ /* Set the time of the file that has been created */
+ mz_os_set_file_date(pathwfs, reader->file_info->modified_date,
+ reader->file_info->accessed_date, reader->file_info->creation_date);
+ }
+
+ if (err == MZ_OK) {
+ /* Set file attributes for the correct system */
+ err_attrib = mz_zip_attrib_convert(MZ_HOST_SYSTEM(reader->file_info->version_madeby),
+ reader->file_info->external_fa, MZ_VERSION_MADEBY_HOST_SYSTEM, &target_attrib);
+
+ if (err_attrib == MZ_OK)
+ mz_os_set_file_attribs(pathwfs, target_attrib);
+ }
+
+ return err;
+}
+
+int32_t mz_zip_reader_entry_save_buffer(void *handle, void *buf, int32_t len) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ void *mem_stream = NULL;
+ int32_t err = MZ_OK;
+
+ if (mz_zip_reader_is_open(reader) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (reader->file_info == NULL)
+ return MZ_PARAM_ERROR;
+ if (reader->file_info->uncompressed_size > INT32_MAX)
+ return MZ_PARAM_ERROR;
+ if (len != (int32_t)reader->file_info->uncompressed_size)
+ return MZ_BUF_ERROR;
+
+ /* Create a memory stream backed by our buffer and save to it */
+ mz_stream_mem_create(&mem_stream);
+ mz_stream_mem_set_buffer(mem_stream, buf, len);
+
+ err = mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_READ);
+ if (err == MZ_OK)
+ err = mz_zip_reader_entry_save(handle, mem_stream, mz_stream_mem_write);
+
+ mz_stream_mem_delete(&mem_stream);
+ return err;
+}
+
+int32_t mz_zip_reader_entry_save_buffer_length(void *handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+
+ if (mz_zip_reader_is_open(reader) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (reader->file_info == NULL)
+ return MZ_PARAM_ERROR;
+ if (reader->file_info->uncompressed_size > INT32_MAX)
+ return MZ_PARAM_ERROR;
+
+ /* Get the maximum size required for the save buffer */
+ return (int32_t)reader->file_info->uncompressed_size;
+}
+
+/***************************************************************************/
+
+int32_t mz_zip_reader_save_all(void *handle, const char *destination_dir) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ int32_t err = MZ_OK;
+ uint8_t *utf8_string = NULL;
+ char path[512];
+ char utf8_name[256];
+ char resolved_name[256];
+
+ err = mz_zip_reader_goto_first_entry(handle);
+
+ if (err == MZ_END_OF_LIST)
+ return err;
+
+ while (err == MZ_OK) {
+ /* Construct output path */
+ path[0] = 0;
+
+ strncpy(utf8_name, reader->file_info->filename, sizeof(utf8_name) - 1);
+ utf8_name[sizeof(utf8_name) - 1] = 0;
+
+ if ((reader->encoding > 0) && (reader->file_info->flag & MZ_ZIP_FLAG_UTF8) == 0) {
+ utf8_string = mz_os_utf8_string_create(reader->file_info->filename, reader->encoding);
+ if (utf8_string) {
+ strncpy(utf8_name, (char *)utf8_string, sizeof(utf8_name) - 1);
+ utf8_name[sizeof(utf8_name) - 1] = 0;
+ mz_os_utf8_string_delete(&utf8_string);
+ }
+ }
+
+ err = mz_path_resolve(utf8_name, resolved_name, sizeof(resolved_name));
+ if (err != MZ_OK)
+ break;
+
+ if (destination_dir != NULL)
+ mz_path_combine(path, destination_dir, sizeof(path));
+
+ mz_path_combine(path, resolved_name, sizeof(path));
+
+ /* Save file to disk */
+ err = mz_zip_reader_entry_save_file(handle, path);
+
+ if (err == MZ_OK)
+ err = mz_zip_reader_goto_next_entry(handle);
+ }
+
+ if (err == MZ_END_OF_LIST)
+ return MZ_OK;
+
+ return err;
+}
+
+/***************************************************************************/
+
+void mz_zip_reader_set_pattern(void *handle, const char *pattern, uint8_t ignore_case) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ reader->pattern = pattern;
+ reader->pattern_ignore_case = ignore_case;
+}
+
+void mz_zip_reader_set_password(void *handle, const char *password) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ reader->password = password;
+}
+
+void mz_zip_reader_set_raw(void *handle, uint8_t raw) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ reader->raw = raw;
+}
+
+int32_t mz_zip_reader_get_raw(void *handle, uint8_t *raw) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ if (raw == NULL)
+ return MZ_PARAM_ERROR;
+ *raw = reader->raw;
+ return MZ_OK;
+}
+
+int32_t mz_zip_reader_get_zip_cd(void *handle, uint8_t *zip_cd) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ if (zip_cd == NULL)
+ return MZ_PARAM_ERROR;
+ *zip_cd = reader->cd_zipped;
+ return MZ_OK;
+}
+
+int32_t mz_zip_reader_get_comment(void *handle, const char **comment) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ if (mz_zip_reader_is_open(reader) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (comment == NULL)
+ return MZ_PARAM_ERROR;
+ return mz_zip_get_comment(reader->zip_handle, comment);
+}
+
+int32_t mz_zip_reader_set_recover(void *handle, uint8_t recover) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ if (reader == NULL)
+ return MZ_PARAM_ERROR;
+ reader->recover = recover;
+ return MZ_OK;
+}
+
+void mz_zip_reader_set_encoding(void *handle, int32_t encoding) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ reader->encoding = encoding;
+}
+
+void mz_zip_reader_set_sign_required(void *handle, uint8_t sign_required) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ reader->sign_required = sign_required;
+}
+
+void mz_zip_reader_set_overwrite_cb(void *handle, void *userdata, mz_zip_reader_overwrite_cb cb) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ reader->overwrite_cb = cb;
+ reader->overwrite_userdata = userdata;
+}
+
+void mz_zip_reader_set_password_cb(void *handle, void *userdata, mz_zip_reader_password_cb cb) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ reader->password_cb = cb;
+ reader->password_userdata = userdata;
+}
+
+void mz_zip_reader_set_progress_cb(void *handle, void *userdata, mz_zip_reader_progress_cb cb) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ reader->progress_cb = cb;
+ reader->progress_userdata = userdata;
+}
+
+void mz_zip_reader_set_progress_interval(void *handle, uint32_t milliseconds) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ reader->progress_cb_interval_ms = milliseconds;
+}
+
+void mz_zip_reader_set_entry_cb(void *handle, void *userdata, mz_zip_reader_entry_cb cb) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ reader->entry_cb = cb;
+ reader->entry_userdata = userdata;
+}
+
+int32_t mz_zip_reader_get_zip_handle(void *handle, void **zip_handle) {
+ mz_zip_reader *reader = (mz_zip_reader *)handle;
+ if (zip_handle == NULL)
+ return MZ_PARAM_ERROR;
+ *zip_handle = reader->zip_handle;
+ if (*zip_handle == NULL)
+ return MZ_EXIST_ERROR;
+ return MZ_OK;
+}
+
+/***************************************************************************/
+
+void *mz_zip_reader_create(void **handle) {
+ mz_zip_reader *reader = NULL;
+
+ reader = (mz_zip_reader *)MZ_ALLOC(sizeof(mz_zip_reader));
+ if (reader != NULL) {
+ memset(reader, 0, sizeof(mz_zip_reader));
+ reader->recover = 1;
+ reader->progress_cb_interval_ms = MZ_DEFAULT_PROGRESS_INTERVAL;
+ }
+ if (handle != NULL)
+ *handle = reader;
+
+ return reader;
+}
+
+void mz_zip_reader_delete(void **handle) {
+ mz_zip_reader *reader = NULL;
+ if (handle == NULL)
+ return;
+ reader = (mz_zip_reader *)*handle;
+ if (reader != NULL) {
+ mz_zip_reader_close(reader);
+ MZ_FREE(reader);
+ }
+ *handle = NULL;
+}
+
+/***************************************************************************/
+
+typedef struct mz_zip_writer_s {
+ void *zip_handle;
+ void *file_stream;
+ void *buffered_stream;
+ void *split_stream;
+ void *sha256;
+ void *mem_stream;
+ void *file_extra_stream;
+ mz_zip_file file_info;
+ void *overwrite_userdata;
+ mz_zip_writer_overwrite_cb
+ overwrite_cb;
+ void *password_userdata;
+ mz_zip_writer_password_cb
+ password_cb;
+ void *progress_userdata;
+ mz_zip_writer_progress_cb
+ progress_cb;
+ uint32_t progress_cb_interval_ms;
+ void *entry_userdata;
+ mz_zip_writer_entry_cb
+ entry_cb;
+ const char *password;
+ const char *comment;
+ uint8_t *cert_data;
+ int32_t cert_data_size;
+ const char *cert_pwd;
+ uint16_t compress_method;
+ int16_t compress_level;
+ uint8_t follow_links;
+ uint8_t store_links;
+ uint8_t zip_cd;
+ uint8_t aes;
+ uint8_t raw;
+ uint8_t buffer[UINT16_MAX];
+} mz_zip_writer;
+
+/***************************************************************************/
+
+int32_t mz_zip_writer_zip_cd(void *handle) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ mz_zip_file cd_file;
+ uint64_t number_entry = 0;
+ int64_t cd_mem_length = 0;
+ int32_t err = MZ_OK;
+ int32_t extrafield_size = 0;
+ void *file_extra_stream = NULL;
+ void *cd_mem_stream = NULL;
+
+
+ memset(&cd_file, 0, sizeof(cd_file));
+
+ mz_zip_get_number_entry(writer->zip_handle, &number_entry);
+ mz_zip_get_cd_mem_stream(writer->zip_handle, &cd_mem_stream);
+ mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_END);
+ cd_mem_length = (uint32_t)mz_stream_tell(cd_mem_stream);
+ mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);
+
+ cd_file.filename = MZ_ZIP_CD_FILENAME;
+ cd_file.modified_date = time(NULL);
+ cd_file.version_madeby = MZ_VERSION_MADEBY;
+ cd_file.compression_method = writer->compress_method;
+ cd_file.uncompressed_size = (int32_t)cd_mem_length;
+ cd_file.flag = MZ_ZIP_FLAG_UTF8;
+
+ if (writer->password != NULL)
+ cd_file.flag |= MZ_ZIP_FLAG_ENCRYPTED;
+
+ mz_stream_mem_create(&file_extra_stream);
+ mz_stream_mem_open(file_extra_stream, NULL, MZ_OPEN_MODE_CREATE);
+
+ mz_zip_extrafield_write(file_extra_stream, MZ_ZIP_EXTENSION_CDCD, 8);
+
+ mz_stream_write_uint64(file_extra_stream, number_entry);
+
+ mz_stream_mem_get_buffer(file_extra_stream, (const void **)&cd_file.extrafield);
+ mz_stream_mem_get_buffer_length(file_extra_stream, &extrafield_size);
+ cd_file.extrafield_size = (uint16_t)extrafield_size;
+
+ err = mz_zip_writer_entry_open(handle, &cd_file);
+ if (err == MZ_OK) {
+ mz_stream_copy_stream(handle, mz_zip_writer_entry_write, cd_mem_stream,
+ NULL, (int32_t)cd_mem_length);
+
+ mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);
+ mz_stream_mem_set_buffer_limit(cd_mem_stream, 0);
+
+ err = mz_zip_writer_entry_close(writer);
+ }
+
+ mz_stream_mem_delete(&file_extra_stream);
+
+ return err;
+}
+
+/***************************************************************************/
+
+int32_t mz_zip_writer_is_open(void *handle) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ if (writer == NULL)
+ return MZ_PARAM_ERROR;
+ if (writer->zip_handle == NULL)
+ return MZ_PARAM_ERROR;
+ return MZ_OK;
+}
+
+static int32_t mz_zip_writer_open_int(void *handle, void *stream, int32_t mode) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ int32_t err = MZ_OK;
+
+ mz_zip_create(&writer->zip_handle);
+ err = mz_zip_open(writer->zip_handle, stream, mode);
+
+ if (err != MZ_OK) {
+ mz_zip_writer_close(handle);
+ return err;
+ }
+
+ return MZ_OK;
+}
+
+int32_t mz_zip_writer_open(void *handle, void *stream, uint8_t append) {
+ int32_t mode = MZ_OPEN_MODE_WRITE;
+
+ if (append) {
+ mode |= MZ_OPEN_MODE_APPEND;
+ } else {
+ mode |= MZ_OPEN_MODE_CREATE;
+ }
+
+ return mz_zip_writer_open_int(handle, stream, mode);
+}
+
+int32_t mz_zip_writer_open_file(void *handle, const char *path, int64_t disk_size, uint8_t append) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ int32_t mode = MZ_OPEN_MODE_READWRITE;
+ int32_t err = MZ_OK;
+ int32_t err_cb = 0;
+ char directory[320];
+
+ mz_zip_writer_close(handle);
+
+ if (mz_os_file_exists(path) != MZ_OK) {
+ /* If the file doesn't exist, we don't append file */
+ mode |= MZ_OPEN_MODE_CREATE;
+
+ /* Create destination directory if it doesn't already exist */
+ if (strchr(path, '/') != NULL || strrchr(path, '\\') != NULL) {
+ strncpy(directory, path, sizeof(directory));
+ mz_path_remove_filename(directory);
+ if (mz_os_file_exists(directory) != MZ_OK)
+ mz_dir_make(directory);
+ }
+ } else if (append) {
+ mode |= MZ_OPEN_MODE_APPEND;
+ } else {
+ if (writer->overwrite_cb != NULL)
+ err_cb = writer->overwrite_cb(handle, writer->overwrite_userdata, path);
+
+ if (err_cb == MZ_INTERNAL_ERROR)
+ return err;
+
+ if (err_cb == MZ_OK)
+ mode |= MZ_OPEN_MODE_CREATE;
+ else
+ mode |= MZ_OPEN_MODE_APPEND;
+ }
+
+ mz_stream_os_create(&writer->file_stream);
+ mz_stream_buffered_create(&writer->buffered_stream);
+ mz_stream_split_create(&writer->split_stream);
+
+ mz_stream_set_base(writer->buffered_stream, writer->file_stream);
+ mz_stream_set_base(writer->split_stream, writer->buffered_stream);
+
+ mz_stream_split_set_prop_int64(writer->split_stream, MZ_STREAM_PROP_DISK_SIZE, disk_size);
+
+ err = mz_stream_open(writer->split_stream, path, mode);
+ if (err == MZ_OK)
+ err = mz_zip_writer_open_int(handle, writer->split_stream, mode);
+
+ return err;
+}
+
+int32_t mz_zip_writer_open_file_in_memory(void *handle, const char *path) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ void *file_stream = NULL;
+ int64_t file_size = 0;
+ int32_t err = 0;
+
+
+ mz_zip_writer_close(handle);
+
+ mz_stream_os_create(&file_stream);
+
+ err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_READ);
+
+ if (err != MZ_OK) {
+ mz_stream_os_delete(&file_stream);
+ mz_zip_writer_close(handle);
+ return err;
+ }
+
+ mz_stream_os_seek(file_stream, 0, MZ_SEEK_END);
+ file_size = mz_stream_os_tell(file_stream);
+ mz_stream_os_seek(file_stream, 0, MZ_SEEK_SET);
+
+ if ((file_size <= 0) || (file_size > UINT32_MAX)) {
+ /* Memory size is too large or too small */
+
+ mz_stream_os_close(file_stream);
+ mz_stream_os_delete(&file_stream);
+ mz_zip_writer_close(handle);
+ return MZ_MEM_ERROR;
+ }
+
+ mz_stream_mem_create(&writer->mem_stream);
+ mz_stream_mem_set_grow_size(writer->mem_stream, (int32_t)file_size);
+ mz_stream_mem_open(writer->mem_stream, NULL, MZ_OPEN_MODE_CREATE);
+
+ err = mz_stream_copy(writer->mem_stream, file_stream, (int32_t)file_size);
+
+ mz_stream_os_close(file_stream);
+ mz_stream_os_delete(&file_stream);
+
+ if (err == MZ_OK)
+ err = mz_zip_writer_open(handle, writer->mem_stream, 1);
+ if (err != MZ_OK)
+ mz_zip_writer_close(handle);
+
+ return err;
+}
+
+int32_t mz_zip_writer_close(void *handle) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ int32_t err = MZ_OK;
+
+
+ if (writer->zip_handle != NULL) {
+ mz_zip_set_version_madeby(writer->zip_handle, MZ_VERSION_MADEBY);
+ if (writer->comment)
+ mz_zip_set_comment(writer->zip_handle, writer->comment);
+ if (writer->zip_cd)
+ mz_zip_writer_zip_cd(writer);
+
+ err = mz_zip_close(writer->zip_handle);
+ mz_zip_delete(&writer->zip_handle);
+ }
+
+ if (writer->split_stream != NULL) {
+ mz_stream_split_close(writer->split_stream);
+ mz_stream_split_delete(&writer->split_stream);
+ }
+
+ if (writer->buffered_stream != NULL)
+ mz_stream_buffered_delete(&writer->buffered_stream);
+
+ if (writer->file_stream != NULL)
+ mz_stream_os_delete(&writer->file_stream);
+
+ if (writer->mem_stream != NULL) {
+ mz_stream_mem_close(writer->mem_stream);
+ mz_stream_mem_delete(&writer->mem_stream);
+ }
+
+ return err;
+}
+
+/***************************************************************************/
+
+int32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ int32_t err = MZ_OK;
+ const char *password = NULL;
+ char password_buf[120];
+
+ /* Copy file info to access data upon close */
+ memcpy(&writer->file_info, file_info, sizeof(mz_zip_file));
+
+ if (writer->entry_cb != NULL)
+ writer->entry_cb(handle, writer->entry_userdata, &writer->file_info);
+
+ password = writer->password;
+
+ /* Check if we need a password and ask for it if we need to */
+ if ((writer->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL) &&
+ (writer->password_cb != NULL)) {
+ writer->password_cb(handle, writer->password_userdata, &writer->file_info,
+ password_buf, sizeof(password_buf));
+ password = password_buf;
+ }
+
+#ifndef MZ_ZIP_NO_CRYPTO
+ if (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK) {
+ /* Start calculating sha256 */
+ mz_crypt_sha_create(&writer->sha256);
+ mz_crypt_sha_set_algorithm(writer->sha256, MZ_HASH_SHA256);
+ mz_crypt_sha_begin(writer->sha256);
+ }
+#endif
+
+ /* Open entry in zip */
+ err = mz_zip_entry_write_open(writer->zip_handle, &writer->file_info, writer->compress_level,
+ writer->raw, password);
+
+ return err;
+}
+
+#if !defined(MZ_ZIP_NO_CRYPTO) && defined(MZ_ZIP_SIGNING)
+int32_t mz_zip_writer_entry_sign(void *handle, uint8_t *message, int32_t message_size,
+ uint8_t *cert_data, int32_t cert_data_size, const char *cert_pwd) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ int32_t err = MZ_OK;
+ int32_t signature_size = 0;
+ uint8_t *signature = NULL;
+
+
+ if (writer == NULL || cert_data == NULL || cert_data_size <= 0)
+ return MZ_PARAM_ERROR;
+ if (mz_zip_entry_is_open(writer->zip_handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+
+ /* Sign message with certificate */
+ err = mz_crypt_sign(message, message_size, cert_data, cert_data_size, cert_pwd,
+ &signature, &signature_size);
+
+ if ((err == MZ_OK) && (signature != NULL)) {
+ /* Write signature zip extra field */
+ err = mz_zip_extrafield_write(writer->file_extra_stream, MZ_ZIP_EXTENSION_SIGN,
+ (uint16_t)signature_size);
+
+ if (err == MZ_OK) {
+ if (mz_stream_write(writer->file_extra_stream, signature, signature_size) != signature_size)
+ err = MZ_WRITE_ERROR;
+ }
+
+ MZ_FREE(signature);
+ }
+
+ return err;
+}
+#endif
+
+int32_t mz_zip_writer_entry_close(void *handle) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ int32_t err = MZ_OK;
+#ifndef MZ_ZIP_NO_CRYPTO
+ const uint8_t *extrafield = NULL;
+ int32_t extrafield_size = 0;
+ int16_t field_length_hash = 0;
+ uint8_t sha256[MZ_HASH_SHA256_SIZE];
+
+
+ if (writer->sha256 != NULL) {
+ mz_crypt_sha_end(writer->sha256, sha256, sizeof(sha256));
+ mz_crypt_sha_delete(&writer->sha256);
+
+ /* Copy extrafield so we can append our own fields before close */
+ mz_stream_mem_create(&writer->file_extra_stream);
+ mz_stream_mem_open(writer->file_extra_stream, NULL, MZ_OPEN_MODE_CREATE);
+
+ /* Write sha256 hash to extrafield */
+ field_length_hash = 4 + MZ_HASH_SHA256_SIZE;
+ err = mz_zip_extrafield_write(writer->file_extra_stream, MZ_ZIP_EXTENSION_HASH, field_length_hash);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(writer->file_extra_stream, MZ_HASH_SHA256);
+ if (err == MZ_OK)
+ err = mz_stream_write_uint16(writer->file_extra_stream, MZ_HASH_SHA256_SIZE);
+ if (err == MZ_OK) {
+ if (mz_stream_write(writer->file_extra_stream, sha256, sizeof(sha256)) != MZ_HASH_SHA256_SIZE)
+ err = MZ_WRITE_ERROR;
+ }
+
+#ifdef MZ_ZIP_SIGNING
+ if ((err == MZ_OK) && (writer->cert_data != NULL) && (writer->cert_data_size > 0)) {
+ /* Sign entry if not zipping cd or if it is cd being zipped */
+ if (!writer->zip_cd || strcmp(writer->file_info.filename, MZ_ZIP_CD_FILENAME) == 0) {
+ err = mz_zip_writer_entry_sign(handle, sha256, sizeof(sha256),
+ writer->cert_data, writer->cert_data_size, writer->cert_pwd);
+ }
+ }
+#endif
+
+ if ((writer->file_info.extrafield != NULL) && (writer->file_info.extrafield_size > 0))
+ mz_stream_mem_write(writer->file_extra_stream, writer->file_info.extrafield,
+ writer->file_info.extrafield_size);
+
+ /* Update extra field for central directory after adding extra fields */
+ mz_stream_mem_get_buffer(writer->file_extra_stream, (const void **)&extrafield);
+ mz_stream_mem_get_buffer_length(writer->file_extra_stream, &extrafield_size);
+
+ mz_zip_entry_set_extrafield(writer->zip_handle, extrafield, (uint16_t)extrafield_size);
+ }
+#endif
+
+ if (err == MZ_OK) {
+ if (writer->raw)
+ err = mz_zip_entry_close_raw(writer->zip_handle, writer->file_info.uncompressed_size,
+ writer->file_info.crc);
+ else
+ err = mz_zip_entry_close(writer->zip_handle);
+ }
+
+ if (writer->file_extra_stream != NULL)
+ mz_stream_mem_delete(&writer->file_extra_stream);
+
+ return err;
+}
+
+int32_t mz_zip_writer_entry_write(void *handle, const void *buf, int32_t len) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ int32_t written = 0;
+ written = mz_zip_entry_write(writer->zip_handle, buf, len);
+#ifndef MZ_ZIP_NO_CRYPTO
+ if ((written > 0) && (writer->sha256 != NULL))
+ mz_crypt_sha_update(writer->sha256, buf, written);
+#endif
+ return written;
+}
+/***************************************************************************/
+
+int32_t mz_zip_writer_add_process(void *handle, void *stream, mz_stream_read_cb read_cb) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ int32_t read = 0;
+ int32_t written = 0;
+ int32_t err = MZ_OK;
+
+ if (mz_zip_writer_is_open(writer) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ /* If the entry isn't open for writing, open it */
+ if (mz_zip_entry_is_open(writer->zip_handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (read_cb == NULL)
+ return MZ_PARAM_ERROR;
+
+ read = read_cb(stream, writer->buffer, sizeof(writer->buffer));
+ if (read == 0)
+ return MZ_END_OF_STREAM;
+ if (read < 0) {
+ err = read;
+ return err;
+ }
+
+ written = mz_zip_writer_entry_write(handle, writer->buffer, read);
+ if (written != read)
+ return MZ_WRITE_ERROR;
+
+ return written;
+}
+
+int32_t mz_zip_writer_add(void *handle, void *stream, mz_stream_read_cb read_cb) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ uint64_t current_time = 0;
+ uint64_t update_time = 0;
+ int64_t current_pos = 0;
+ int64_t update_pos = 0;
+ int32_t err = MZ_OK;
+ int32_t written = 0;
+
+ /* Update the progress at the beginning */
+ if (writer->progress_cb != NULL)
+ writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);
+
+ /* Write data to stream until done */
+ while (err == MZ_OK) {
+ written = mz_zip_writer_add_process(handle, stream, read_cb);
+ if (written == MZ_END_OF_STREAM)
+ break;
+ if (written > 0)
+ current_pos += written;
+ if (written < 0)
+ err = written;
+
+ /* Update progress if enough time have passed */
+ current_time = mz_os_ms_time();
+ if ((current_time - update_time) > writer->progress_cb_interval_ms) {
+ if (writer->progress_cb != NULL)
+ writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);
+
+ update_pos = current_pos;
+ update_time = current_time;
+ }
+ }
+
+ /* Update the progress at the end */
+ if (writer->progress_cb != NULL && update_pos != current_pos)
+ writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);
+
+ return err;
+}
+
+int32_t mz_zip_writer_add_info(void *handle, void *stream, mz_stream_read_cb read_cb, mz_zip_file *file_info) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ int32_t err = MZ_OK;
+
+
+ if (mz_zip_writer_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (file_info == NULL)
+ return MZ_PARAM_ERROR;
+
+ /* Add to zip */
+ err = mz_zip_writer_entry_open(handle, file_info);
+ if (err != MZ_OK)
+ return err;
+
+ if (stream != NULL) {
+ if (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK) {
+ err = mz_zip_writer_add(handle, stream, read_cb);
+ if (err != MZ_OK)
+ return err;
+ }
+ }
+
+ err = mz_zip_writer_entry_close(handle);
+
+ return err;
+}
+
+int32_t mz_zip_writer_add_buffer(void *handle, void *buf, int32_t len, mz_zip_file *file_info) {
+ void *mem_stream = NULL;
+ int32_t err = MZ_OK;
+
+ if (mz_zip_writer_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (buf == NULL)
+ return MZ_PARAM_ERROR;
+
+ /* Create a memory stream backed by our buffer and add from it */
+ mz_stream_mem_create(&mem_stream);
+ mz_stream_mem_set_buffer(mem_stream, buf, len);
+
+ err = mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_READ);
+ if (err == MZ_OK)
+ err = mz_zip_writer_add_info(handle, mem_stream, mz_stream_mem_read, file_info);
+
+ mz_stream_mem_delete(&mem_stream);
+ return err;
+}
+
+int32_t mz_zip_writer_add_file(void *handle, const char *path, const char *filename_in_zip) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ mz_zip_file file_info;
+ uint32_t target_attrib = 0;
+ uint32_t src_attrib = 0;
+ int32_t err = MZ_OK;
+ uint8_t src_sys = 0;
+ void *stream = NULL;
+ char link_path[1024];
+ const char *filename = filename_in_zip;
+
+
+ if (mz_zip_writer_is_open(handle) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (path == NULL)
+ return MZ_PARAM_ERROR;
+
+ if (filename == NULL) {
+ err = mz_path_get_filename(path, &filename);
+ if (err != MZ_OK)
+ return err;
+ }
+
+ memset(&file_info, 0, sizeof(file_info));
+
+ /* The path name saved, should not include a leading slash. */
+ /* If it did, windows/xp and dynazip couldn't read the zip file. */
+
+ while (filename[0] == '\\' || filename[0] == '/')
+ filename += 1;
+
+ /* Get information about the file on disk so we can store it in zip */
+
+ file_info.version_madeby = MZ_VERSION_MADEBY;
+ file_info.compression_method = writer->compress_method;
+ file_info.filename = filename;
+ file_info.uncompressed_size = mz_os_get_file_size(path);
+ file_info.flag = MZ_ZIP_FLAG_UTF8;
+
+ if (writer->zip_cd)
+ file_info.flag |= MZ_ZIP_FLAG_MASK_LOCAL_INFO;
+ if (writer->aes)
+ file_info.aes_version = MZ_AES_VERSION;
+
+ mz_os_get_file_date(path, &file_info.modified_date, &file_info.accessed_date,
+ &file_info.creation_date);
+ mz_os_get_file_attribs(path, &src_attrib);
+
+ src_sys = MZ_HOST_SYSTEM(file_info.version_madeby);
+
+ if ((src_sys != MZ_HOST_SYSTEM_MSDOS) && (src_sys != MZ_HOST_SYSTEM_WINDOWS_NTFS)) {
+ /* High bytes are OS specific attributes, low byte is always DOS attributes */
+ if (mz_zip_attrib_convert(src_sys, src_attrib, MZ_HOST_SYSTEM_MSDOS, &target_attrib) == MZ_OK)
+ file_info.external_fa = target_attrib;
+ file_info.external_fa |= (src_attrib << 16);
+ } else {
+ file_info.external_fa = src_attrib;
+ }
+
+ if (writer->store_links && mz_os_is_symlink(path) == MZ_OK) {
+ err = mz_os_read_symlink(path, link_path, sizeof(link_path));
+ if (err == MZ_OK)
+ file_info.linkname = link_path;
+ } else if (mz_os_is_dir(path) != MZ_OK) {
+ mz_stream_os_create(&stream);
+ err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ);
+ }
+
+ if (err == MZ_OK)
+ err = mz_zip_writer_add_info(handle, stream, mz_stream_read, &file_info);
+
+ if (stream != NULL) {
+ mz_stream_close(stream);
+ mz_stream_delete(&stream);
+ }
+
+ return err;
+}
+
+int32_t mz_zip_writer_add_path(void *handle, const char *path, const char *root_path,
+ uint8_t include_path, uint8_t recursive) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ DIR *dir = NULL;
+ struct dirent *entry = NULL;
+ int32_t err = MZ_OK;
+ int16_t is_dir = 0;
+ const char *filename = NULL;
+ const char *filenameinzip = path;
+ char *wildcard_ptr = NULL;
+ char full_path[1024];
+ char path_dir[1024];
+
+
+ if (strrchr(path, '*') != NULL) {
+ strncpy(path_dir, path, sizeof(path_dir) - 1);
+ path_dir[sizeof(path_dir) - 1] = 0;
+ mz_path_remove_filename(path_dir);
+ wildcard_ptr = path_dir + strlen(path_dir) + 1;
+ root_path = path = path_dir;
+ } else {
+ if (mz_os_is_dir(path) == MZ_OK)
+ is_dir = 1;
+
+ /* Construct the filename that our file will be stored in the zip as */
+ if (root_path == NULL)
+ root_path = path;
+
+ /* Should the file be stored with any path info at all? */
+ if (!include_path) {
+ if (!is_dir && root_path == path) {
+ if (mz_path_get_filename(filenameinzip, &filename) == MZ_OK)
+ filenameinzip = filename;
+ } else {
+ filenameinzip += strlen(root_path);
+ }
+ }
+
+ if (!writer->store_links && !writer->follow_links) {
+ if (mz_os_is_symlink(path) == MZ_OK)
+ return err;
+ }
+
+ if (*filenameinzip != 0)
+ err = mz_zip_writer_add_file(handle, path, filenameinzip);
+
+ if (!is_dir)
+ return err;
+
+ if (writer->store_links) {
+ if (mz_os_is_symlink(path) == MZ_OK)
+ return err;
+ }
+ }
+
+ dir = mz_os_open_dir(path);
+
+ if (dir == NULL)
+ return MZ_EXIST_ERROR;
+
+ while ((entry = mz_os_read_dir(dir)) != NULL) {
+ if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+ continue;
+
+ full_path[0] = 0;
+ mz_path_combine(full_path, path, sizeof(full_path));
+ mz_path_combine(full_path, entry->d_name, sizeof(full_path));
+
+ if (!recursive && mz_os_is_dir(full_path) == MZ_OK)
+ continue;
+
+ if ((wildcard_ptr != NULL) && (mz_path_compare_wc(entry->d_name, wildcard_ptr, 1) != MZ_OK))
+ continue;
+
+ err = mz_zip_writer_add_path(handle, full_path, root_path, include_path, recursive);
+ if (err != MZ_OK)
+ break;
+ }
+
+ mz_os_close_dir(dir);
+ return err;
+}
+
+int32_t mz_zip_writer_copy_from_reader(void *handle, void *reader) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ mz_zip_file *file_info = NULL;
+ int64_t compressed_size = 0;
+ int64_t uncompressed_size = 0;
+ uint32_t crc32 = 0;
+ int32_t err = MZ_OK;
+ uint8_t original_raw = 0;
+ void *reader_zip_handle = NULL;
+ void *writer_zip_handle = NULL;
+
+
+ if (mz_zip_reader_is_open(reader) != MZ_OK)
+ return MZ_PARAM_ERROR;
+ if (mz_zip_writer_is_open(writer) != MZ_OK)
+ return MZ_PARAM_ERROR;
+
+ err = mz_zip_reader_entry_get_info(reader, &file_info);
+
+ if (err != MZ_OK)
+ return err;
+
+ mz_zip_reader_get_zip_handle(reader, &reader_zip_handle);
+ mz_zip_writer_get_zip_handle(writer, &writer_zip_handle);
+
+ /* Open entry for raw reading */
+ err = mz_zip_entry_read_open(reader_zip_handle, 1, NULL);
+
+ if (err == MZ_OK) {
+ /* Write entry raw, save original raw value */
+ original_raw = writer->raw;
+ writer->raw = 1;
+
+ err = mz_zip_writer_entry_open(writer, file_info);
+
+ if ((err == MZ_OK) &&
+ (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK)) {
+ err = mz_zip_writer_add(writer, reader_zip_handle, mz_zip_entry_read);
+ }
+
+ if (err == MZ_OK) {
+ err = mz_zip_entry_read_close(reader_zip_handle, &crc32, &compressed_size, &uncompressed_size);
+ if (err == MZ_OK)
+ err = mz_zip_entry_write_close(writer_zip_handle, crc32, compressed_size, uncompressed_size);
+ }
+
+ if (mz_zip_entry_is_open(reader_zip_handle) == MZ_OK)
+ mz_zip_entry_close(reader_zip_handle);
+
+ if (mz_zip_entry_is_open(writer_zip_handle) == MZ_OK)
+ mz_zip_entry_close(writer_zip_handle);
+
+ writer->raw = original_raw;
+ }
+
+ return err;
+}
+
+/***************************************************************************/
+
+void mz_zip_writer_set_password(void *handle, const char *password) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->password = password;
+}
+
+void mz_zip_writer_set_comment(void *handle, const char *comment) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->comment = comment;
+}
+
+void mz_zip_writer_set_raw(void *handle, uint8_t raw) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->raw = raw;
+}
+
+int32_t mz_zip_writer_get_raw(void *handle, uint8_t *raw) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ if (raw == NULL)
+ return MZ_PARAM_ERROR;
+ *raw = writer->raw;
+ return MZ_OK;
+}
+
+void mz_zip_writer_set_aes(void *handle, uint8_t aes) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->aes = aes;
+}
+
+void mz_zip_writer_set_compress_method(void *handle, uint16_t compress_method) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->compress_method = compress_method;
+}
+
+void mz_zip_writer_set_compress_level(void *handle, int16_t compress_level) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->compress_level = compress_level;
+}
+
+void mz_zip_writer_set_follow_links(void *handle, uint8_t follow_links) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->follow_links = follow_links;
+}
+
+void mz_zip_writer_set_store_links(void *handle, uint8_t store_links) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->store_links = store_links;
+}
+
+void mz_zip_writer_set_zip_cd(void *handle, uint8_t zip_cd) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->zip_cd = zip_cd;
+}
+
+int32_t mz_zip_writer_set_certificate(void *handle, const char *cert_path, const char *cert_pwd) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ void *cert_stream = NULL;
+ uint8_t *cert_data = NULL;
+ int32_t cert_data_size = 0;
+ int32_t err = MZ_OK;
+
+ if (cert_path == NULL)
+ return MZ_PARAM_ERROR;
+
+ cert_data_size = (int32_t)mz_os_get_file_size(cert_path);
+
+ if (cert_data_size == 0)
+ return MZ_PARAM_ERROR;
+
+ if (writer->cert_data != NULL) {
+ MZ_FREE(writer->cert_data);
+ writer->cert_data = NULL;
+ }
+
+ cert_data = (uint8_t *)MZ_ALLOC(cert_data_size);
+
+ /* Read pkcs12 certificate from disk */
+ mz_stream_os_create(&cert_stream);
+ err = mz_stream_os_open(cert_stream, cert_path, MZ_OPEN_MODE_READ);
+ if (err == MZ_OK) {
+ if (mz_stream_os_read(cert_stream, cert_data, cert_data_size) != cert_data_size)
+ err = MZ_READ_ERROR;
+ mz_stream_os_close(cert_stream);
+ }
+ mz_stream_os_delete(&cert_stream);
+
+ if (err == MZ_OK) {
+ writer->cert_data = cert_data;
+ writer->cert_data_size = cert_data_size;
+ writer->cert_pwd = cert_pwd;
+ } else {
+ MZ_FREE(cert_data);
+ }
+
+ return err;
+}
+
+void mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->overwrite_cb = cb;
+ writer->overwrite_userdata = userdata;
+}
+
+void mz_zip_writer_set_password_cb(void *handle, void *userdata, mz_zip_writer_password_cb cb) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->password_cb = cb;
+ writer->password_userdata = userdata;
+}
+
+void mz_zip_writer_set_progress_cb(void *handle, void *userdata, mz_zip_writer_progress_cb cb) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->progress_cb = cb;
+ writer->progress_userdata = userdata;
+}
+
+void mz_zip_writer_set_progress_interval(void *handle, uint32_t milliseconds) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->progress_cb_interval_ms = milliseconds;
+}
+
+void mz_zip_writer_set_entry_cb(void *handle, void *userdata, mz_zip_writer_entry_cb cb) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ writer->entry_cb = cb;
+ writer->entry_userdata = userdata;
+}
+
+int32_t mz_zip_writer_get_zip_handle(void *handle, void **zip_handle) {
+ mz_zip_writer *writer = (mz_zip_writer *)handle;
+ if (zip_handle == NULL)
+ return MZ_PARAM_ERROR;
+ *zip_handle = writer->zip_handle;
+ if (*zip_handle == NULL)
+ return MZ_EXIST_ERROR;
+ return MZ_OK;
+}
+
+/***************************************************************************/
+
+void *mz_zip_writer_create(void **handle) {
+ mz_zip_writer *writer = NULL;
+
+ writer = (mz_zip_writer *)MZ_ALLOC(sizeof(mz_zip_writer));
+ if (writer != NULL) {
+ memset(writer, 0, sizeof(mz_zip_writer));
+#if defined(HAVE_WZAES)
+ writer->aes = 1;
+#endif
+#if defined(HAVE_ZLIB) || defined(HAVE_LIBCOMP)
+ writer->compress_method = MZ_COMPRESS_METHOD_DEFLATE;
+#elif defined(HAVE_BZIP2)
+ writer->compress_method = MZ_COMPRESS_METHOD_BZIP2;
+#elif defined(HAVE_LZMA)
+ writer->compress_method = MZ_COMPRESS_METHOD_LZMA;
+#else
+ writer->compress_method = MZ_COMPRESS_METHOD_STORE;
+#endif
+ writer->compress_level = MZ_COMPRESS_LEVEL_BEST;
+ writer->progress_cb_interval_ms = MZ_DEFAULT_PROGRESS_INTERVAL;
+ }
+ if (handle != NULL)
+ *handle = writer;
+
+ return writer;
+}
+
+void mz_zip_writer_delete(void **handle) {
+ mz_zip_writer *writer = NULL;
+ if (handle == NULL)
+ return;
+ writer = (mz_zip_writer *)*handle;
+ if (writer != NULL) {
+ mz_zip_writer_close(writer);
+
+ if (writer->cert_data != NULL)
+ MZ_FREE(writer->cert_data);
+
+ writer->cert_data = NULL;
+ writer->cert_data_size = 0;
+
+ MZ_FREE(writer);
+ }
+ *handle = NULL;
+}
+
+/***************************************************************************/
diff --git a/Externals/minizip/mz_zip_rw.h b/Externals/minizip/mz_zip_rw.h
new file mode 100644
index 0000000000..e507f94a5a
--- /dev/null
+++ b/Externals/minizip/mz_zip_rw.h
@@ -0,0 +1,285 @@
+/* mz_zip_rw.h -- Zip reader/writer
+ part of the minizip-ng project
+
+ Copyright (C) 2010-2021 Nathan Moinvaziri
+ https://github.com/zlib-ng/minizip-ng
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_ZIP_RW_H
+#define MZ_ZIP_RW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/***************************************************************************/
+
+typedef int32_t (*mz_zip_reader_overwrite_cb)(void *handle, void *userdata, mz_zip_file *file_info, const char *path);
+typedef int32_t (*mz_zip_reader_password_cb)(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password);
+typedef int32_t (*mz_zip_reader_progress_cb)(void *handle, void *userdata, mz_zip_file *file_info, int64_t position);
+typedef int32_t (*mz_zip_reader_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info, const char *path);
+
+/***************************************************************************/
+
+int32_t mz_zip_reader_is_open(void *handle);
+/* Checks to see if the zip file is open */
+
+int32_t mz_zip_reader_open(void *handle, void *stream);
+/* Opens zip file from stream */
+
+int32_t mz_zip_reader_open_file(void *handle, const char *path);
+/* Opens zip file from a file path */
+
+int32_t mz_zip_reader_open_file_in_memory(void *handle, const char *path);
+/* Opens zip file from a file path into memory for faster access */
+
+int32_t mz_zip_reader_open_buffer(void *handle, uint8_t *buf, int32_t len, uint8_t copy);
+/* Opens zip file from memory buffer */
+
+int32_t mz_zip_reader_close(void *handle);
+/* Closes the zip file */
+
+/***************************************************************************/
+
+int32_t mz_zip_reader_unzip_cd(void *handle);
+/* Unzip the central directory */
+
+/***************************************************************************/
+
+int32_t mz_zip_reader_goto_first_entry(void *handle);
+/* Goto the first entry in the zip file that matches the pattern */
+
+int32_t mz_zip_reader_goto_next_entry(void *handle);
+/* Goto the next entry in the zip file that matches the pattern */
+
+int32_t mz_zip_reader_locate_entry(void *handle, const char *filename, uint8_t ignore_case);
+/* Locates an entry by filename */
+
+int32_t mz_zip_reader_entry_open(void *handle);
+/* Opens an entry for reading */
+
+int32_t mz_zip_reader_entry_close(void *handle);
+/* Closes an entry */
+
+int32_t mz_zip_reader_entry_read(void *handle, void *buf, int32_t len);
+/* Reads and entry after being opened */
+
+int32_t mz_zip_reader_entry_has_sign(void *handle);
+/* Checks to see if the entry has a signature */
+
+int32_t mz_zip_reader_entry_sign_verify(void *handle);
+/* Verifies a signature stored with the entry */
+
+int32_t mz_zip_reader_entry_get_hash(void *handle, uint16_t algorithm, uint8_t *digest, int32_t digest_size);
+/* Gets a hash algorithm from the entry's extra field */
+
+int32_t mz_zip_reader_entry_get_first_hash(void *handle, uint16_t *algorithm, uint16_t *digest_size);
+/* Gets the most secure hash algorithm from the entry's extra field */
+
+int32_t mz_zip_reader_entry_get_info(void *handle, mz_zip_file **file_info);
+/* Gets the current entry file info */
+
+int32_t mz_zip_reader_entry_is_dir(void *handle);
+/* Gets the current entry is a directory */
+
+int32_t mz_zip_reader_entry_save(void *handle, void *stream, mz_stream_write_cb write_cb);
+/* Save the current entry to a stream */
+
+int32_t mz_zip_reader_entry_save_process(void *handle, void *stream, mz_stream_write_cb write_cb);
+/* Saves a portion of the current entry to a stream callback */
+
+int32_t mz_zip_reader_entry_save_file(void *handle, const char *path);
+/* Save the current entry to a file */
+
+int32_t mz_zip_reader_entry_save_buffer(void *handle, void *buf, int32_t len);
+/* Save the current entry to a memory buffer */
+
+int32_t mz_zip_reader_entry_save_buffer_length(void *handle);
+/* Gets the length of the buffer required to save */
+
+/***************************************************************************/
+
+int32_t mz_zip_reader_save_all(void *handle, const char *destination_dir);
+/* Save all files into a directory */
+
+/***************************************************************************/
+
+void mz_zip_reader_set_pattern(void *handle, const char *pattern, uint8_t ignore_case);
+/* Sets the match pattern for entries in the zip file, if null all entries are matched */
+
+void mz_zip_reader_set_password(void *handle, const char *password);
+/* Sets the password required for extraction */
+
+void mz_zip_reader_set_raw(void *handle, uint8_t raw);
+/* Sets whether or not it should save the entry raw */
+
+int32_t mz_zip_reader_get_raw(void *handle, uint8_t *raw);
+/* Gets whether or not it should save the entry raw */
+
+int32_t mz_zip_reader_get_zip_cd(void *handle, uint8_t *zip_cd);
+/* Gets whether or not the archive has a zipped central directory */
+
+int32_t mz_zip_reader_get_comment(void *handle, const char **comment);
+/* Gets the comment for the central directory */
+
+int32_t mz_zip_reader_set_recover(void *handle, uint8_t recover);
+/* Sets the ability to recover the central dir by reading local file headers */
+
+void mz_zip_reader_set_encoding(void *handle, int32_t encoding);
+/* Sets whether or not it should support a special character encoding in zip file names. */
+
+void mz_zip_reader_set_sign_required(void *handle, uint8_t sign_required);
+/* Sets whether or not it a signature is required */
+
+void mz_zip_reader_set_overwrite_cb(void *handle, void *userdata, mz_zip_reader_overwrite_cb cb);
+/* Callback for what to do when a file is being overwritten */
+
+void mz_zip_reader_set_password_cb(void *handle, void *userdata, mz_zip_reader_password_cb cb);
+/* Callback for when a password is required and hasn't been set */
+
+void mz_zip_reader_set_progress_cb(void *handle, void *userdata, mz_zip_reader_progress_cb cb);
+/* Callback for extraction progress */
+
+void mz_zip_reader_set_progress_interval(void *handle, uint32_t milliseconds);
+/* Let at least milliseconds pass between calls to progress callback */
+
+void mz_zip_reader_set_entry_cb(void *handle, void *userdata, mz_zip_reader_entry_cb cb);
+/* Callback for zip file entries */
+
+int32_t mz_zip_reader_get_zip_handle(void *handle, void **zip_handle);
+/* Gets the underlying zip instance handle */
+
+void* mz_zip_reader_create(void **handle);
+/* Create new instance of zip reader */
+
+void mz_zip_reader_delete(void **handle);
+/* Delete instance of zip reader */
+
+/***************************************************************************/
+
+typedef int32_t (*mz_zip_writer_overwrite_cb)(void *handle, void *userdata, const char *path);
+typedef int32_t (*mz_zip_writer_password_cb)(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password);
+typedef int32_t (*mz_zip_writer_progress_cb)(void *handle, void *userdata, mz_zip_file *file_info, int64_t position);
+typedef int32_t (*mz_zip_writer_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info);
+
+/***************************************************************************/
+
+int32_t mz_zip_writer_is_open(void *handle);
+/* Checks to see if the zip file is open */
+
+int32_t mz_zip_writer_open(void *handle, void *stream, uint8_t append);
+/* Opens zip file from stream */
+
+int32_t mz_zip_writer_open_file(void *handle, const char *path, int64_t disk_size, uint8_t append);
+/* Opens zip file from a file path */
+
+int32_t mz_zip_writer_open_file_in_memory(void *handle, const char *path);
+/* Opens zip file from a file path into memory for faster access */
+
+int32_t mz_zip_writer_close(void *handle);
+/* Closes the zip file */
+
+/***************************************************************************/
+
+int32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info);
+/* Opens an entry in the zip file for writing */
+
+int32_t mz_zip_writer_entry_close(void *handle);
+/* Closes entry in zip file */
+
+int32_t mz_zip_writer_entry_write(void *handle, const void *buf, int32_t len);
+/* Writes data into entry for zip */
+
+/***************************************************************************/
+
+int32_t mz_zip_writer_add(void *handle, void *stream, mz_stream_read_cb read_cb);
+/* Writes all data to the currently open entry in the zip */
+
+int32_t mz_zip_writer_add_process(void *handle, void *stream, mz_stream_read_cb read_cb);
+/* Writes a portion of data to the currently open entry in the zip */
+
+int32_t mz_zip_writer_add_info(void *handle, void *stream, mz_stream_read_cb read_cb, mz_zip_file *file_info);
+/* Adds an entry to the zip based on the info */
+
+int32_t mz_zip_writer_add_buffer(void *handle, void *buf, int32_t len, mz_zip_file *file_info);
+/* Adds an entry to the zip with a memory buffer */
+
+int32_t mz_zip_writer_add_file(void *handle, const char *path, const char *filename_in_zip);
+/* Adds an entry to the zip from a file */
+
+int32_t mz_zip_writer_add_path(void *handle, const char *path, const char *root_path, uint8_t include_path,
+ uint8_t recursive);
+/* Enumerates a directory or pattern and adds entries to the zip */
+
+int32_t mz_zip_writer_copy_from_reader(void *handle, void *reader);
+/* Adds an entry from a zip reader instance */
+
+/***************************************************************************/
+
+void mz_zip_writer_set_password(void *handle, const char *password);
+/* Password to use for encrypting files in the zip */
+
+void mz_zip_writer_set_comment(void *handle, const char *comment);
+/* Comment to use for the archive */
+
+void mz_zip_writer_set_raw(void *handle, uint8_t raw);
+/* Sets whether or not we should write the entry raw */
+
+int32_t mz_zip_writer_get_raw(void *handle, uint8_t *raw);
+/* Gets whether or not we should write the entry raw */
+
+void mz_zip_writer_set_aes(void *handle, uint8_t aes);
+/* Use aes encryption when adding files in zip */
+
+void mz_zip_writer_set_compress_method(void *handle, uint16_t compress_method);
+/* Sets the compression method when adding files in zip */
+
+void mz_zip_writer_set_compress_level(void *handle, int16_t compress_level);
+/* Sets the compression level when adding files in zip */
+
+void mz_zip_writer_set_follow_links(void *handle, uint8_t follow_links);
+/* Follow symbolic links when traversing directories and files to add */
+
+void mz_zip_writer_set_store_links(void *handle, uint8_t store_links);
+/* Store symbolic links in zip file */
+
+void mz_zip_writer_set_zip_cd(void *handle, uint8_t zip_cd);
+/* Sets whether or not central directory should be zipped */
+
+int32_t mz_zip_writer_set_certificate(void *handle, const char *cert_path, const char *cert_pwd);
+/* Sets the certificate and timestamp url to use for signing when adding files in zip */
+
+void mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb);
+/* Callback for what to do when zip file already exists */
+
+void mz_zip_writer_set_password_cb(void *handle, void *userdata, mz_zip_writer_password_cb cb);
+/* Callback for ask if a password is required for adding */
+
+void mz_zip_writer_set_progress_cb(void *handle, void *userdata, mz_zip_writer_progress_cb cb);
+/* Callback for compression progress */
+
+void mz_zip_writer_set_progress_interval(void *handle, uint32_t milliseconds);
+/* Let at least milliseconds pass between calls to progress callback */
+
+void mz_zip_writer_set_entry_cb(void *handle, void *userdata, mz_zip_writer_entry_cb cb);
+/* Callback for zip file entries */
+
+int32_t mz_zip_writer_get_zip_handle(void *handle, void **zip_handle);
+/* Gets the underlying zip handle */
+
+void* mz_zip_writer_create(void **handle);
+/* Create new instance of zip writer */
+
+void mz_zip_writer_delete(void **handle);
+/* Delete instance of zip writer */
+
+/***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Externals/minizip/unzip.c b/Externals/minizip/unzip.c
deleted file mode 100644
index 145fe5fbf8..0000000000
--- a/Externals/minizip/unzip.c
+++ /dev/null
@@ -1,1991 +0,0 @@
-/* unzip.c -- IO for uncompress .zip files using zlib
- Version 1.1, February 14h, 2010
- part of the MiniZip project
-
- Copyright (C) 1998-2010 Gilles Vollant
- http://www.winimage.com/zLibDll/minizip.html
- Modifications of Unzip for Zip64
- Copyright (C) 2007-2008 Even Rouault
- Modifications for Zip64 support on both zip and unzip
- Copyright (C) 2009-2010 Mathias Svensson
- http://result42.com
- Modifications for AES, PKWARE disk spanning
- Copyright (C) 2010-2014 Nathan Moinvaziri
-
- This program is distributed under the terms of the same license as zlib.
- See the accompanying LICENSE file for the full text of the license.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <errno.h>
-
-#include "zlib.h"
-#include "unzip.h"
-
-#ifdef HAVE_AES
-# define AES_METHOD (99)
-# define AES_PWVERIFYSIZE (2)
-# define AES_MAXSALTLENGTH (16)
-# define AES_AUTHCODESIZE (10)
-# define AES_HEADERSIZE (11)
-# define AES_KEYSIZE(mode) (64 + (mode * 64))
-
-# include "aes/aes.h"
-# include "aes/fileenc.h"
-#endif
-#ifdef HAVE_APPLE_COMPRESSION
-# include <compression.h>
-#endif
-
-#ifndef NOUNCRYPT
-# include "crypt.h"
-#endif
-
-#define DISKHEADERMAGIC (0x08074b50)
-#define LOCALHEADERMAGIC (0x04034b50)
-#define CENTRALHEADERMAGIC (0x02014b50)
-#define ENDHEADERMAGIC (0x06054b50)
-#define ZIP64ENDHEADERMAGIC (0x06064b50)
-#define ZIP64ENDLOCHEADERMAGIC (0x07064b50)
-
-#define SIZECENTRALDIRITEM (0x2e)
-#define SIZECENTRALHEADERLOCATOR (0x14)
-#define SIZEZIPLOCALHEADER (0x1e)
-
-#ifndef BUFREADCOMMENT
-# define BUFREADCOMMENT (0x400)
-#endif
-
-#ifndef UNZ_BUFSIZE
-# define UNZ_BUFSIZE (UINT16_MAX)
-#endif
-#ifndef UNZ_MAXFILENAMEINZIP
-# define UNZ_MAXFILENAMEINZIP (256)
-#endif
-
-#ifndef ALLOC
-# define ALLOC(size) (malloc(size))
-#endif
-#ifndef TRYFREE
-# define TRYFREE(p) {if (p) free(p);}
-#endif
-
-const char unz_copyright[] =
- " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
-
-/* unz_file_info_internal contain internal info about a file in zipfile*/
-typedef struct unz_file_info64_internal_s
-{
- uint64_t offset_curfile; /* relative offset of local header 8 bytes */
- uint64_t byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */
-#ifdef HAVE_AES
- uint8_t aes_encryption_mode;
- uint16_t aes_compression_method;
- uint16_t aes_version;
-#endif
-} unz_file_info64_internal;
-
-/* file_in_zip_read_info_s contain internal information about a file in zipfile */
-typedef struct
-{
- uint8_t *read_buffer; /* internal buffer for compressed data */
- z_stream stream; /* zLib stream structure for inflate */
-#ifdef HAVE_BZIP2
- bz_stream bstream; /* bzLib stream structure for bziped */
-#endif
-#ifdef HAVE_APPLE_COMPRESSION
- compression_stream astream; /* libcompression stream structure */
-#endif
-#ifdef HAVE_AES
- fcrypt_ctx aes_ctx;
-#endif
- uint64_t pos_in_zipfile; /* position in byte on the zipfile, for fseek */
- uint8_t stream_initialised; /* flag set if stream structure is initialised */
-
- uint64_t offset_local_extrafield; /* offset of the local extra field */
- uint16_t size_local_extrafield; /* size of the local extra field */
- uint64_t pos_local_extrafield; /* position in the local extra field in read */
- uint64_t total_out_64;
-
- uint32_t crc32; /* crc32 of all data uncompressed */
- uint32_t crc32_wait; /* crc32 we must obtain after decompress all */
- uint64_t rest_read_compressed; /* number of byte to be decompressed */
- uint64_t rest_read_uncompressed; /* number of byte to be obtained after decomp */
-
- zlib_filefunc64_32_def z_filefunc;
-
- voidpf filestream; /* io structore of the zipfile */
- uint16_t compression_method; /* compression method (0==store) */
- uint64_t byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */
- int raw;
-} file_in_zip64_read_info_s;
-
-/* unz64_s contain internal information about the zipfile */
-typedef struct
-{
- zlib_filefunc64_32_def z_filefunc;
-
- voidpf filestream; /* io structure of the current zipfile */
- voidpf filestream_with_CD; /* io structure of the disk with the central directory */
-
- unz_global_info64 gi; /* public global information */
-
- uint64_t byte_before_the_zipfile; /* byte before the zipfile, (>0 for sfx) */
- uint64_t num_file; /* number of the current file in the zipfile */
- uint64_t pos_in_central_dir; /* pos of the current file in the central dir */
- uint64_t current_file_ok; /* flag about the usability of the current file */
- uint64_t central_pos; /* position of the beginning of the central dir */
- uint32_t number_disk; /* number of the current disk, used for spanning ZIP */
- uint64_t size_central_dir; /* size of the central directory */
- uint64_t offset_central_dir; /* offset of start of central directory with
- respect to the starting disk number */
-
- unz_file_info64 cur_file_info; /* public info about the current file in zip*/
- unz_file_info64_internal cur_file_info_internal;
- /* private info about it*/
- file_in_zip64_read_info_s *pfile_in_zip_read;
- /* structure about the current file if we are decompressing it */
- int is_zip64; /* is the current file zip64 */
-#ifndef NOUNCRYPT
- uint32_t keys[3]; /* keys defining the pseudo-random sequence */
- const z_crc_t *pcrc_32_tab;
-#endif
-} unz64_s;
-
-/* Read a byte from a gz_stream; Return EOF for end of file. */
-static int unzReadUInt8(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint8_t *value)
-{
- uint8_t c = 0;
- if (ZREAD64(*pzlib_filefunc_def, filestream, &c, 1) == 1)
- {
- *value = (uint8_t)c;
- return UNZ_OK;
- }
- *value = 0;
- if (ZERROR64(*pzlib_filefunc_def, filestream))
- return UNZ_ERRNO;
- return UNZ_EOF;
-}
-
-static int unzReadUInt16(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint16_t *value)
-{
- uint16_t x;
- uint8_t c = 0;
- int err = UNZ_OK;
-
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
- x = (uint16_t)c;
- if (err == UNZ_OK)
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
- x |= ((uint16_t)c) << 8;
-
- if (err == UNZ_OK)
- *value = x;
- else
- *value = 0;
- return err;
-}
-
-static int unzReadUInt32(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint32_t *value)
-{
- uint32_t x = 0;
- uint8_t c = 0;
- int err = UNZ_OK;
-
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
- x = (uint32_t)c;
- if (err == UNZ_OK)
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
- x |= ((uint32_t)c) << 8;
- if (err == UNZ_OK)
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
- x |= ((uint32_t)c) << 16;
- if (err == UNZ_OK)
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &c);
- x += ((uint32_t)c) << 24;
-
- if (err == UNZ_OK)
- *value = x;
- else
- *value = 0;
- return err;
-}
-
-static int unzReadUInt64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream, uint64_t *value)
-{
- uint64_t x = 0;
- uint8_t i = 0;
- int err = UNZ_OK;
-
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
- x = (uint64_t)i;
- if (err == UNZ_OK)
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
- x |= ((uint64_t)i) << 8;
- if (err == UNZ_OK)
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
- x |= ((uint64_t)i) << 16;
- if (err == UNZ_OK)
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
- x |= ((uint64_t)i) << 24;
- if (err == UNZ_OK)
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
- x |= ((uint64_t)i) << 32;
- if (err == UNZ_OK)
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
- x |= ((uint64_t)i) << 40;
- if (err == UNZ_OK)
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
- x |= ((uint64_t)i) << 48;
- if (err == UNZ_OK)
- err = unzReadUInt8(pzlib_filefunc_def, filestream, &i);
- x |= ((uint64_t)i) << 56;
-
- if (err == UNZ_OK)
- *value = x;
- else
- *value = 0;
- return err;
-}
-
-/* Locate the Central directory of a zip file (at the end, just before the global comment) */
-static uint64_t unzSearchCentralDir(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream)
-{
- uint8_t buf[BUFREADCOMMENT + 4];
- uint64_t file_size = 0;
- uint64_t back_read = 4;
- uint64_t max_back = UINT16_MAX; /* maximum size of global comment */
- uint64_t pos_found = 0;
- uint32_t read_size = 0;
- uint64_t read_pos = 0;
- uint32_t i = 0;
-
- if (ZSEEK64(*pzlib_filefunc_def, filestream, 0, ZLIB_FILEFUNC_SEEK_END) != 0)
- return 0;
-
- file_size = ZTELL64(*pzlib_filefunc_def, filestream);
-
- if (max_back > file_size)
- max_back = file_size;
-
- while (back_read < max_back)
- {
- if (back_read + BUFREADCOMMENT > max_back)
- back_read = max_back;
- else
- back_read += BUFREADCOMMENT;
-
- read_pos = file_size - back_read;
- read_size = ((BUFREADCOMMENT + 4) < (file_size - read_pos)) ?
- (BUFREADCOMMENT + 4) : (uint32_t)(file_size - read_pos);
-
- if (ZSEEK64(*pzlib_filefunc_def, filestream, read_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
- break;
- if (ZREAD64(*pzlib_filefunc_def, filestream, buf, read_size) != read_size)
- break;
-
- for (i = read_size - 3; (i--) > 0;)
- if (((*(buf+i)) == (ENDHEADERMAGIC & 0xff)) &&
- ((*(buf+i+1)) == (ENDHEADERMAGIC >> 8 & 0xff)) &&
- ((*(buf+i+2)) == (ENDHEADERMAGIC >> 16 & 0xff)) &&
- ((*(buf+i+3)) == (ENDHEADERMAGIC >> 24 & 0xff)))
- {
- pos_found = read_pos+i;
- break;
- }
-
- if (pos_found != 0)
- break;
- }
-
- return pos_found;
-}
-
-/* Locate the Central directory 64 of a zipfile (at the end, just before the global comment) */
-static uint64_t unzSearchCentralDir64(const zlib_filefunc64_32_def *pzlib_filefunc_def, voidpf filestream,
- const uint64_t endcentraloffset)
-{
- uint64_t offset = 0;
- uint32_t value32 = 0;
-
- /* Zip64 end of central directory locator */
- if (ZSEEK64(*pzlib_filefunc_def, filestream, endcentraloffset - SIZECENTRALHEADERLOCATOR, ZLIB_FILEFUNC_SEEK_SET) != 0)
- return 0;
-
- /* Read locator signature */
- if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
- return 0;
- if (value32 != ZIP64ENDLOCHEADERMAGIC)
- return 0;
- /* Number of the disk with the start of the zip64 end of central directory */
- if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
- return 0;
- /* Relative offset of the zip64 end of central directory record */
- if (unzReadUInt64(pzlib_filefunc_def, filestream, &offset) != UNZ_OK)
- return 0;
- /* Total number of disks */
- if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
- return 0;
- /* Goto end of central directory record */
- if (ZSEEK64(*pzlib_filefunc_def, filestream, offset, ZLIB_FILEFUNC_SEEK_SET) != 0)
- return 0;
- /* The signature */
- if (unzReadUInt32(pzlib_filefunc_def, filestream, &value32) != UNZ_OK)
- return 0;
- if (value32 != ZIP64ENDHEADERMAGIC)
- return 0;
-
- return offset;
-}
-
-static unzFile unzOpenInternal(const void *path, zlib_filefunc64_32_def *pzlib_filefunc64_32_def)
-{
- unz64_s us;
- unz64_s *s = NULL;
- uint64_t central_pos = 0;
- uint64_t central_pos64 = 0;
- uint64_t number_entry_CD = 0;
- uint16_t value16 = 0;
- uint32_t value32 = 0;
- uint64_t value64 = 0;
- voidpf filestream = NULL;
- int err = UNZ_OK;
-
- if (unz_copyright[0] != ' ')
- return NULL;
-
- us.filestream = NULL;
- us.filestream_with_CD = NULL;
- us.z_filefunc.zseek32_file = NULL;
- us.z_filefunc.ztell32_file = NULL;
-
- if (pzlib_filefunc64_32_def == NULL)
- fill_fopen64_filefunc(&us.z_filefunc.zfile_func64);
- else
- us.z_filefunc = *pzlib_filefunc64_32_def;
-
- us.filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
-
- if (us.filestream == NULL)
- return NULL;
-
- us.filestream_with_CD = us.filestream;
- us.is_zip64 = 0;
-
- /* Search for end of central directory header */
- central_pos = unzSearchCentralDir(&us.z_filefunc, us.filestream);
- if (central_pos)
- {
- if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
- err = UNZ_ERRNO;
-
- /* The signature, already checked */
- if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
- err = UNZ_ERRNO;
- /* Number of this disk */
- if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- us.number_disk = value16;
- /* Number of the disk with the start of the central directory */
- if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- us.gi.number_disk_with_CD = value16;
- /* Total number of entries in the central directory on this disk */
- if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- us.gi.number_entry = value16;
- /* Total number of entries in the central directory */
- if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- number_entry_CD = value16;
- if (number_entry_CD != us.gi.number_entry)
- err = UNZ_BADZIPFILE;
- /* Size of the central directory */
- if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
- err = UNZ_ERRNO;
- us.size_central_dir = value32;
- /* Offset of start of central directory with respect to the starting disk number */
- if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
- err = UNZ_ERRNO;
- us.offset_central_dir = value32;
- /* Zipfile comment length */
- if (unzReadUInt16(&us.z_filefunc, us.filestream, &us.gi.size_comment) != UNZ_OK)
- err = UNZ_ERRNO;
-
- if (err == UNZ_OK)
- {
- /* Search for Zip64 end of central directory header */
- central_pos64 = unzSearchCentralDir64(&us.z_filefunc, us.filestream, central_pos);
- if (central_pos64)
- {
- central_pos = central_pos64;
- us.is_zip64 = 1;
-
- if (ZSEEK64(us.z_filefunc, us.filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
- err = UNZ_ERRNO;
-
- /* the signature, already checked */
- if (unzReadUInt32(&us.z_filefunc, us.filestream, &value32) != UNZ_OK)
- err = UNZ_ERRNO;
- /* size of zip64 end of central directory record */
- if (unzReadUInt64(&us.z_filefunc, us.filestream, &value64) != UNZ_OK)
- err = UNZ_ERRNO;
- /* version made by */
- if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- /* version needed to extract */
- if (unzReadUInt16(&us.z_filefunc, us.filestream, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- /* number of this disk */
- if (unzReadUInt32(&us.z_filefunc, us.filestream, &us.number_disk) != UNZ_OK)
- err = UNZ_ERRNO;
- /* number of the disk with the start of the central directory */
- if (unzReadUInt32(&us.z_filefunc, us.filestream, &us.gi.number_disk_with_CD) != UNZ_OK)
- err = UNZ_ERRNO;
- /* total number of entries in the central directory on this disk */
- if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.gi.number_entry) != UNZ_OK)
- err = UNZ_ERRNO;
- /* total number of entries in the central directory */
- if (unzReadUInt64(&us.z_filefunc, us.filestream, &number_entry_CD) != UNZ_OK)
- err = UNZ_ERRNO;
- if (number_entry_CD != us.gi.number_entry)
- err = UNZ_BADZIPFILE;
- /* size of the central directory */
- if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.size_central_dir) != UNZ_OK)
- err = UNZ_ERRNO;
- /* offset of start of central directory with respect to the starting disk number */
- if (unzReadUInt64(&us.z_filefunc, us.filestream, &us.offset_central_dir) != UNZ_OK)
- err = UNZ_ERRNO;
- }
- else if ((us.gi.number_entry == UINT16_MAX) || (us.size_central_dir == UINT16_MAX) || (us.offset_central_dir == UINT32_MAX))
- err = UNZ_BADZIPFILE;
- }
- }
- else
- err = UNZ_ERRNO;
-
- if ((err == UNZ_OK) && (central_pos < us.offset_central_dir + us.size_central_dir))
- err = UNZ_BADZIPFILE;
-
- if (err != UNZ_OK)
- {
- ZCLOSE64(us.z_filefunc, us.filestream);
- return NULL;
- }
-
- if (us.gi.number_disk_with_CD == 0)
- {
- /* If there is only one disk open another stream so we don't have to seek between the CD
- and the file headers constantly */
- filestream = ZOPEN64(us.z_filefunc, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
- if (filestream != NULL)
- us.filestream = filestream;
- }
-
- /* Hack for zip files that have no respect for zip64
- if ((central_pos > 0xffffffff) && (us.offset_central_dir < 0xffffffff))
- us.offset_central_dir = central_pos - us.size_central_dir;*/
-
- us.byte_before_the_zipfile = central_pos - (us.offset_central_dir + us.size_central_dir);
- us.central_pos = central_pos;
- us.pfile_in_zip_read = NULL;
-
- s = (unz64_s*)ALLOC(sizeof(unz64_s));
- if (s != NULL)
- {
- *s = us;
- unzGoToFirstFile((unzFile)s);
- }
- return (unzFile)s;
-}
-
-extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc32_def)
-{
- if (pzlib_filefunc32_def != NULL)
- {
- zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
- fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill, pzlib_filefunc32_def);
- return unzOpenInternal(path, &zlib_filefunc64_32_def_fill);
- }
- return unzOpenInternal(path, NULL);
-}
-
-extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def)
-{
- if (pzlib_filefunc_def != NULL)
- {
- zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
- zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
- zlib_filefunc64_32_def_fill.ztell32_file = NULL;
- zlib_filefunc64_32_def_fill.zseek32_file = NULL;
- return unzOpenInternal(path, &zlib_filefunc64_32_def_fill);
- }
- return unzOpenInternal(path, NULL);
-}
-
-extern unzFile ZEXPORT unzOpen(const char *path)
-{
- return unzOpenInternal(path, NULL);
-}
-
-extern unzFile ZEXPORT unzOpen64(const void *path)
-{
- return unzOpenInternal(path, NULL);
-}
-
-extern int ZEXPORT unzClose(unzFile file)
-{
- unz64_s *s;
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
-
- if (s->pfile_in_zip_read != NULL)
- unzCloseCurrentFile(file);
-
- if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD))
- ZCLOSE64(s->z_filefunc, s->filestream);
- if (s->filestream_with_CD != NULL)
- ZCLOSE64(s->z_filefunc, s->filestream_with_CD);
-
- s->filestream = NULL;
- s->filestream_with_CD = NULL;
- TRYFREE(s);
- return UNZ_OK;
-}
-
-/* Goto to the next available disk for spanned archives */
-static int unzGoToNextDisk(unzFile file)
-{
- unz64_s *s;
- uint32_t number_disk_next = 0;
-
- s = (unz64_s*)file;
- if (s == NULL)
- return UNZ_PARAMERROR;
- number_disk_next = s->number_disk;
-
- if ((s->pfile_in_zip_read != NULL) && (s->pfile_in_zip_read->rest_read_uncompressed > 0))
- /* We are currently reading a file and we need the next sequential disk */
- number_disk_next += 1;
- else
- /* Goto the disk for the current file */
- number_disk_next = s->cur_file_info.disk_num_start;
-
- if (number_disk_next != s->number_disk)
- {
- /* Switch disks */
- if ((s->filestream != NULL) && (s->filestream != s->filestream_with_CD))
- ZCLOSE64(s->z_filefunc, s->filestream);
-
- if (number_disk_next == s->gi.number_disk_with_CD)
- {
- s->filestream = s->filestream_with_CD;
- }
- else
- {
- s->filestream = ZOPENDISK64(s->z_filefunc, s->filestream_with_CD, number_disk_next,
- ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING);
- }
-
- if (s->filestream == NULL)
- return UNZ_ERRNO;
-
- s->number_disk = number_disk_next;
- }
-
- return UNZ_OK;
-}
-
-extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32)
-{
- unz64_s *s = NULL;
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
-
- pglobal_info32->number_entry = (uint32_t)s->gi.number_entry;
- pglobal_info32->size_comment = s->gi.size_comment;
- pglobal_info32->number_disk_with_CD = s->gi.number_disk_with_CD;
- return UNZ_OK;
-}
-
-extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info)
-{
- unz64_s *s = NULL;
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
- *pglobal_info = s->gi;
- return UNZ_OK;
-}
-
-extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size)
-{
- unz64_s *s = NULL;
- uint16_t bytes_to_read = comment_size;
- if (file == NULL)
- return (int)UNZ_PARAMERROR;
- s = (unz64_s*)file;
-
- if (bytes_to_read > s->gi.size_comment)
- bytes_to_read = s->gi.size_comment;
-
- if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, s->central_pos + 22, ZLIB_FILEFUNC_SEEK_SET) != 0)
- return UNZ_ERRNO;
-
- if (bytes_to_read > 0)
- {
- *comment = 0;
- if (ZREAD64(s->z_filefunc, s->filestream_with_CD, comment, bytes_to_read) != bytes_to_read)
- return UNZ_ERRNO;
- }
-
- if ((comment != NULL) && (comment_size > s->gi.size_comment))
- *(comment + s->gi.size_comment) = 0;
-
- return (int)bytes_to_read;
-}
-
-static int unzGetCurrentFileInfoField(unzFile file, uint32_t *seek, void *field, uint16_t field_size, uint16_t size_file_field, int null_terminated_field)
-{
- unz64_s *s = NULL;
- uint32_t bytes_to_read = 0;
- int err = UNZ_OK;
-
- if (file == NULL)
- return (int)UNZ_PARAMERROR;
- s = (unz64_s*)file;
-
- /* Read field */
- if (field != NULL)
- {
- if (size_file_field < field_size)
- {
- if (null_terminated_field)
- *((char *)field+size_file_field) = 0;
-
- bytes_to_read = size_file_field;
- }
- else
- bytes_to_read = field_size;
-
- if (*seek != 0)
- {
- if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, *seek, ZLIB_FILEFUNC_SEEK_CUR) == 0)
- *seek = 0;
- else
- err = UNZ_ERRNO;
- }
-
- if ((size_file_field > 0) && (field_size > 0))
- {
- if (ZREAD64(s->z_filefunc, s->filestream_with_CD, field, bytes_to_read) != bytes_to_read)
- err = UNZ_ERRNO;
- }
- *seek += size_file_field - bytes_to_read;
- }
- else
- {
- *seek += size_file_field;
- }
-
- return err;
-}
-
-/* Get info about the current file in the zipfile, with internal only info */
-static int unzGetCurrentFileInfoInternal(unzFile file, unz_file_info64 *pfile_info,
- unz_file_info64_internal *pfile_info_internal, char *filename, uint16_t filename_size, void *extrafield,
- uint16_t extrafield_size, char *comment, uint16_t comment_size)
-{
- unz64_s *s = NULL;
- unz_file_info64 file_info;
- unz_file_info64_internal file_info_internal;
- uint32_t magic = 0;
- uint64_t current_pos = 0;
- uint32_t seek = 0;
- uint32_t extra_pos = 0;
- uint16_t extra_header_id = 0;
- uint16_t extra_data_size = 0;
- uint16_t value16 = 0;
- uint32_t value32 = 0;
- uint64_t value64 = 0;
- int err = UNZ_OK;
-
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
-
- if (ZSEEK64(s->z_filefunc, s->filestream_with_CD,
- s->pos_in_central_dir + s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
- err = UNZ_ERRNO;
-
- /* Check the magic */
- if (err == UNZ_OK)
- {
- if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &magic) != UNZ_OK)
- err = UNZ_ERRNO;
- else if (magic != CENTRALHEADERMAGIC)
- err = UNZ_BADZIPFILE;
- }
-
- /* Read central directory header */
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.version) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.version_needed) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.flag) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.compression_method) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.dos_date) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.crc) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
- err = UNZ_ERRNO;
- file_info.compressed_size = value32;
- if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
- err = UNZ_ERRNO;
- file_info.uncompressed_size = value32;
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_filename) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_extra) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.size_file_comment) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- file_info.disk_num_start = value16;
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &file_info.internal_fa) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.external_fa) != UNZ_OK)
- err = UNZ_ERRNO;
- /* Relative offset of local header */
- if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &value32) != UNZ_OK)
- err = UNZ_ERRNO;
-
- file_info.size_file_extra_internal = 0;
- file_info.disk_offset = value32;
- file_info_internal.offset_curfile = value32;
-#ifdef HAVE_AES
- file_info_internal.aes_compression_method = 0;
- file_info_internal.aes_encryption_mode = 0;
- file_info_internal.aes_version = 0;
-#endif
-
- if (err == UNZ_OK)
- err = unzGetCurrentFileInfoField(file, &seek, filename, filename_size, file_info.size_filename, 1);
-
- /* Read extrafield */
- if (err == UNZ_OK)
- err = unzGetCurrentFileInfoField(file, &seek, extrafield, extrafield_size, file_info.size_file_extra, 0);
-
- if ((err == UNZ_OK) && (file_info.size_file_extra != 0))
- {
- if (seek != 0)
- {
- if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, seek, ZLIB_FILEFUNC_SEEK_CUR) == 0)
- seek = 0;
- else
- err = UNZ_ERRNO;
- }
-
- /* We are going to parse the extra field so we need to move back */
- current_pos = ZTELL64(s->z_filefunc, s->filestream_with_CD);
- if (current_pos < file_info.size_file_extra)
- err = UNZ_ERRNO;
- current_pos -= file_info.size_file_extra;
- if (ZSEEK64(s->z_filefunc, s->filestream_with_CD, current_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
- err = UNZ_ERRNO;
-
- while ((err != UNZ_ERRNO) && (extra_pos < file_info.size_file_extra))
- {
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &extra_header_id) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &extra_data_size) != UNZ_OK)
- err = UNZ_ERRNO;
-
- /* ZIP64 extra fields */
- if (extra_header_id == 0x0001)
- {
- /* Subtract size of ZIP64 field, since ZIP64 is handled internally */
- file_info.size_file_extra_internal += 2 + 2 + extra_data_size;
-
- if (file_info.uncompressed_size == UINT32_MAX)
- {
- if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &file_info.uncompressed_size) != UNZ_OK)
- err = UNZ_ERRNO;
- }
- if (file_info.compressed_size == UINT32_MAX)
- {
- if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &file_info.compressed_size) != UNZ_OK)
- err = UNZ_ERRNO;
- }
- if (file_info_internal.offset_curfile == UINT32_MAX)
- {
- /* Relative Header offset */
- if (unzReadUInt64(&s->z_filefunc, s->filestream_with_CD, &value64) != UNZ_OK)
- err = UNZ_ERRNO;
- file_info_internal.offset_curfile = value64;
- file_info.disk_offset = value64;
- }
- if (file_info.disk_num_start == UINT32_MAX)
- {
- /* Disk Start Number */
- if (unzReadUInt32(&s->z_filefunc, s->filestream_with_CD, &file_info.disk_num_start) != UNZ_OK)
- err = UNZ_ERRNO;
- }
- }
-#ifdef HAVE_AES
- /* AES header */
- else if (extra_header_id == 0x9901)
- {
- uint8_t value8 = 0;
-
- /* Subtract size of AES field, since AES is handled internally */
- file_info.size_file_extra_internal += 2 + 2 + extra_data_size;
-
- /* Verify version info */
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- /* Support AE-1 and AE-2 */
- if (value16 != 1 && value16 != 2)
- err = UNZ_ERRNO;
- file_info_internal.aes_version = value16;
- if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
- err = UNZ_ERRNO;
- if ((char)value8 != 'A')
- err = UNZ_ERRNO;
- if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
- err = UNZ_ERRNO;
- if ((char)value8 != 'E')
- err = UNZ_ERRNO;
- /* Get AES encryption strength and actual compression method */
- if (unzReadUInt8(&s->z_filefunc, s->filestream_with_CD, &value8) != UNZ_OK)
- err = UNZ_ERRNO;
- file_info_internal.aes_encryption_mode = value8;
- if (unzReadUInt16(&s->z_filefunc, s->filestream_with_CD, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- file_info_internal.aes_compression_method = value16;
- }
-#endif
- else
- {
- if (ZSEEK64(s->z_filefunc, s->filestream_with_CD,extra_data_size, ZLIB_FILEFUNC_SEEK_CUR) != 0)
- err = UNZ_ERRNO;
- }
-
- extra_pos += 2 + 2 + extra_data_size;
- }
- }
-
- if (file_info.disk_num_start == s->gi.number_disk_with_CD)
- file_info_internal.byte_before_the_zipfile = s->byte_before_the_zipfile;
- else
- file_info_internal.byte_before_the_zipfile = 0;
-
- if (err == UNZ_OK)
- err = unzGetCurrentFileInfoField(file, &seek, comment, comment_size, file_info.size_file_comment, 1);
-
- if ((err == UNZ_OK) && (pfile_info != NULL))
- *pfile_info = file_info;
- if ((err == UNZ_OK) && (pfile_info_internal != NULL))
- *pfile_info_internal = file_info_internal;
-
- return err;
-}
-
-extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,
- uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
-{
- unz_file_info64 file_info64;
- int err = UNZ_OK;
-
- err = unzGetCurrentFileInfoInternal(file, &file_info64, NULL, filename, filename_size,
- extrafield, extrafield_size, comment, comment_size);
-
- if ((err == UNZ_OK) && (pfile_info != NULL))
- {
- pfile_info->version = file_info64.version;
- pfile_info->version_needed = file_info64.version_needed;
- pfile_info->flag = file_info64.flag;
- pfile_info->compression_method = file_info64.compression_method;
- pfile_info->dos_date = file_info64.dos_date;
- pfile_info->crc = file_info64.crc;
-
- pfile_info->size_filename = file_info64.size_filename;
- pfile_info->size_file_extra = file_info64.size_file_extra - file_info64.size_file_extra_internal;
- pfile_info->size_file_comment = file_info64.size_file_comment;
-
- pfile_info->disk_num_start = (uint16_t)file_info64.disk_num_start;
- pfile_info->internal_fa = file_info64.internal_fa;
- pfile_info->external_fa = file_info64.external_fa;
-
- pfile_info->compressed_size = (uint32_t)file_info64.compressed_size;
- pfile_info->uncompressed_size = (uint32_t)file_info64.uncompressed_size;
- }
- return err;
-}
-
-extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename,
- uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
-{
- return unzGetCurrentFileInfoInternal(file, pfile_info, NULL, filename, filename_size,
- extrafield, extrafield_size, comment,comment_size);
-}
-
-/* Read the local header of the current zipfile. Check the coherency of the local header and info in the
- end of central directory about this file store in *piSizeVar the size of extra info in local header
- (filename and size of extra field data) */
-static int unzCheckCurrentFileCoherencyHeader(unz64_s *s, uint32_t *psize_variable, uint64_t *poffset_local_extrafield,
- uint16_t *psize_local_extrafield)
-{
- uint32_t magic = 0;
- uint16_t value16 = 0;
- uint32_t value32 = 0;
- uint32_t flags = 0;
- uint16_t size_filename = 0;
- uint16_t size_extra_field = 0;
- uint16_t compression_method = 0;
- int err = UNZ_OK;
-
- if (psize_variable == NULL)
- return UNZ_PARAMERROR;
- *psize_variable = 0;
- if (poffset_local_extrafield == NULL)
- return UNZ_PARAMERROR;
- *poffset_local_extrafield = 0;
- if (psize_local_extrafield == NULL)
- return UNZ_PARAMERROR;
- *psize_local_extrafield = 0;
-
- err = unzGoToNextDisk((unzFile)s);
- if (err != UNZ_OK)
- return err;
-
- if (ZSEEK64(s->z_filefunc, s->filestream, s->cur_file_info_internal.offset_curfile +
- s->cur_file_info_internal.byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
- return UNZ_ERRNO;
-
- if (err == UNZ_OK)
- {
- if (unzReadUInt32(&s->z_filefunc, s->filestream, &magic) != UNZ_OK)
- err = UNZ_ERRNO;
- else if (magic != LOCALHEADERMAGIC)
- err = UNZ_BADZIPFILE;
- }
-
- if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- flags = value16;
- if (unzReadUInt16(&s->z_filefunc, s->filestream, &value16) != UNZ_OK)
- err = UNZ_ERRNO;
- else if ((err == UNZ_OK) && (value16 != s->cur_file_info.compression_method))
- err = UNZ_BADZIPFILE;
-
- compression_method = s->cur_file_info.compression_method;
-#ifdef HAVE_AES
- if (compression_method == AES_METHOD)
- compression_method = s->cur_file_info_internal.aes_compression_method;
-#endif
-
- if ((err == UNZ_OK) && (compression_method != 0) && (compression_method != Z_DEFLATED))
- {
-#ifdef HAVE_BZIP2
- if (compression_method != Z_BZIP2ED)
-#endif
- err = UNZ_BADZIPFILE;
- }
-
- if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* date/time */
- err = UNZ_ERRNO;
- if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* crc */
- err = UNZ_ERRNO;
- else if ((err == UNZ_OK) && (value32 != s->cur_file_info.crc) && ((flags & 8) == 0))
- err = UNZ_BADZIPFILE;
- if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* size compr */
- err = UNZ_ERRNO;
- else if ((value32 != UINT32_MAX) && (err == UNZ_OK) && (value32 != s->cur_file_info.compressed_size) && ((flags & 8) == 0))
- err = UNZ_BADZIPFILE;
- if (unzReadUInt32(&s->z_filefunc, s->filestream, &value32) != UNZ_OK) /* size uncompr */
- err = UNZ_ERRNO;
- else if ((value32 != UINT32_MAX) && (err == UNZ_OK) && (value32 != s->cur_file_info.uncompressed_size) && ((flags & 8) == 0))
- err = UNZ_BADZIPFILE;
- if (unzReadUInt16(&s->z_filefunc, s->filestream, &size_filename) != UNZ_OK)
- err = UNZ_ERRNO;
- else if ((err == UNZ_OK) && (size_filename != s->cur_file_info.size_filename))
- err = UNZ_BADZIPFILE;
-
- *psize_variable += size_filename;
-
- if (unzReadUInt16(&s->z_filefunc, s->filestream, &size_extra_field) != UNZ_OK)
- err = UNZ_ERRNO;
-
- *poffset_local_extrafield = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename;
- *psize_local_extrafield = size_extra_field;
- *psize_variable += size_extra_field;
-
- return err;
-}
-
-/*
- Open for reading data the current file in the zipfile.
- If there is no error and the file is opened, the return value is UNZ_OK.
-*/
-extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password)
-{
- unz64_s *s = NULL;
- file_in_zip64_read_info_s *pfile_in_zip_read_info = NULL;
- uint16_t compression_method = 0;
- uint64_t offset_local_extrafield = 0;
- uint16_t size_local_extrafield = 0;
- uint32_t size_variable = 0;
- int err = UNZ_OK;
-#ifndef NOUNCRYPT
- char source[12];
-#else
- if (password != NULL)
- return UNZ_PARAMERROR;
-#endif
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
- if (!s->current_file_ok)
- return UNZ_PARAMERROR;
-
- if (s->pfile_in_zip_read != NULL)
- unzCloseCurrentFile(file);
-
- if (unzCheckCurrentFileCoherencyHeader(s, &size_variable, &offset_local_extrafield, &size_local_extrafield) != UNZ_OK)
- return UNZ_BADZIPFILE;
-
- pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));
- if (pfile_in_zip_read_info == NULL)
- return UNZ_INTERNALERROR;
-
- pfile_in_zip_read_info->read_buffer = (uint8_t*)ALLOC(UNZ_BUFSIZE);
- pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
- pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
- pfile_in_zip_read_info->pos_local_extrafield = 0;
- pfile_in_zip_read_info->raw = raw;
-
- if (pfile_in_zip_read_info->read_buffer == NULL)
- {
- TRYFREE(pfile_in_zip_read_info);
- return UNZ_INTERNALERROR;
- }
-
- pfile_in_zip_read_info->stream_initialised = 0;
-
- compression_method = s->cur_file_info.compression_method;
-#ifdef HAVE_AES
- if (compression_method == AES_METHOD)
- {
- compression_method = s->cur_file_info_internal.aes_compression_method;
- if (password == NULL)
- {
- TRYFREE(pfile_in_zip_read_info);
- return UNZ_PARAMERROR;
- }
- }
-#endif
-
- if (method != NULL)
- *method = compression_method;
-
- if (level != NULL)
- {
- *level = 6;
- switch (s->cur_file_info.flag & 0x06)
- {
- case 6 : *level = 1; break;
- case 4 : *level = 2; break;
- case 2 : *level = 9; break;
- }
- }
-
- if ((compression_method != 0) && (compression_method != Z_DEFLATED))
- {
-#ifdef HAVE_BZIP2
- if (compression_method != Z_BZIP2ED)
-#endif
- {
- TRYFREE(pfile_in_zip_read_info);
- return UNZ_BADZIPFILE;
- }
- }
-
- pfile_in_zip_read_info->crc32_wait = s->cur_file_info.crc;
- pfile_in_zip_read_info->crc32 = 0;
- pfile_in_zip_read_info->total_out_64 = 0;
- pfile_in_zip_read_info->compression_method = compression_method;
- pfile_in_zip_read_info->filestream = s->filestream;
- pfile_in_zip_read_info->z_filefunc = s->z_filefunc;
- if (s->number_disk == s->gi.number_disk_with_CD)
- pfile_in_zip_read_info->byte_before_the_zipfile = s->byte_before_the_zipfile;
- else
- pfile_in_zip_read_info->byte_before_the_zipfile = 0;
- pfile_in_zip_read_info->stream.total_out = 0;
- pfile_in_zip_read_info->stream.total_in = 0;
- pfile_in_zip_read_info->stream.next_in = NULL;
-
- if (!raw)
- {
- if (compression_method == Z_BZIP2ED)
- {
-#ifdef HAVE_BZIP2
- pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
- pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
- pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
- pfile_in_zip_read_info->bstream.state = (voidpf)0;
-
- pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
- pfile_in_zip_read_info->stream.zfree = (free_func)0;
- pfile_in_zip_read_info->stream.opaque = (voidpf)0;
- pfile_in_zip_read_info->stream.next_in = (voidpf)0;
- pfile_in_zip_read_info->stream.avail_in = 0;
-
- err = BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
- if (err == Z_OK)
- {
- pfile_in_zip_read_info->stream_initialised = Z_BZIP2ED;
- }
- else
- {
- TRYFREE(pfile_in_zip_read_info);
- return err;
- }
-#else
- pfile_in_zip_read_info->raw = 1;
-#endif
- }
- else if (compression_method == Z_DEFLATED)
- {
- pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
- pfile_in_zip_read_info->stream.zfree = (free_func)0;
- pfile_in_zip_read_info->stream.opaque = (voidpf)s;
- pfile_in_zip_read_info->stream.next_in = 0;
- pfile_in_zip_read_info->stream.avail_in = 0;
-
-#ifdef HAVE_APPLE_COMPRESSION
- err = compression_stream_init(&pfile_in_zip_read_info->astream, COMPRESSION_STREAM_DECODE, COMPRESSION_ZLIB);
- if (err == COMPRESSION_STATUS_ERROR)
- err = UNZ_INTERNALERROR;
- else
- err = Z_OK;
-#else
- err = inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
-#endif
- if (err == Z_OK)
- {
- pfile_in_zip_read_info->stream_initialised = Z_DEFLATED;
- }
- else
- {
- TRYFREE(pfile_in_zip_read_info);
- return err;
- }
- /* windowBits is passed < 0 to tell that there is no zlib header.
- * Note that in this case inflate *requires* an extra "dummy" byte
- * after the compressed stream in order to complete decompression and
- * return Z_STREAM_END.
- * In unzip, i don't wait absolutely Z_STREAM_END because I known the
- * size of both compressed and uncompressed data
- */
- }
- }
-
- pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size;
- pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size;
- pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_variable;
- pfile_in_zip_read_info->stream.avail_in = 0;
-
- s->pfile_in_zip_read = pfile_in_zip_read_info;
-
-#ifndef NOUNCRYPT
- s->pcrc_32_tab = NULL;
-
- if ((password != NULL) && ((s->cur_file_info.flag & 1) != 0))
- {
- if (ZSEEK64(s->z_filefunc, s->filestream,
- s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile,
- ZLIB_FILEFUNC_SEEK_SET) != 0)
- return UNZ_INTERNALERROR;
-#ifdef HAVE_AES
- if (s->cur_file_info.compression_method == AES_METHOD)
- {
- unsigned char passverify_archive[AES_PWVERIFYSIZE];
- unsigned char passverify_password[AES_PWVERIFYSIZE];
- unsigned char salt_value[AES_MAXSALTLENGTH];
- uint32_t salt_length = 0;
-
- if ((s->cur_file_info_internal.aes_encryption_mode < 1) ||
- (s->cur_file_info_internal.aes_encryption_mode > 3))
- return UNZ_INTERNALERROR;
-
- salt_length = SALT_LENGTH(s->cur_file_info_internal.aes_encryption_mode);
-
- if (ZREAD64(s->z_filefunc, s->filestream, salt_value, salt_length) != salt_length)
- return UNZ_INTERNALERROR;
- if (ZREAD64(s->z_filefunc, s->filestream, passverify_archive, AES_PWVERIFYSIZE) != AES_PWVERIFYSIZE)
- return UNZ_INTERNALERROR;
-
- fcrypt_init(s->cur_file_info_internal.aes_encryption_mode, (uint8_t *)password,
- (uint32_t)strlen(password), salt_value, passverify_password, &s->pfile_in_zip_read->aes_ctx);
-
- if (memcmp(passverify_archive, passverify_password, AES_PWVERIFYSIZE) != 0)
- return UNZ_BADPASSWORD;
-
- s->pfile_in_zip_read->rest_read_compressed -= salt_length + AES_PWVERIFYSIZE;
- s->pfile_in_zip_read->rest_read_compressed -= AES_AUTHCODESIZE;
-
- s->pfile_in_zip_read->pos_in_zipfile += salt_length + AES_PWVERIFYSIZE;
- }
- else
-#endif
- {
- int i;
- s->pcrc_32_tab = (const z_crc_t*)get_crc_table();
- init_keys(password, s->keys, s->pcrc_32_tab);
-
- if (ZREAD64(s->z_filefunc, s->filestream, source, 12) < 12)
- return UNZ_INTERNALERROR;
-
- for (i = 0; i < 12; i++)
- zdecode(s->keys, s->pcrc_32_tab, source[i]);
-
- s->pfile_in_zip_read->rest_read_compressed -= 12;
- s->pfile_in_zip_read->pos_in_zipfile += 12;
- }
- }
-#endif
-
- return UNZ_OK;
-}
-
-extern int ZEXPORT unzOpenCurrentFile(unzFile file)
-{
- return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
-}
-
-extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char *password)
-{
- return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
-}
-
-extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw)
-{
- return unzOpenCurrentFile3(file, method, level, raw, NULL);
-}
-
-/* Read bytes from the current file.
- buf contain buffer where data must be copied
- len the size of buf.
-
- return the number of byte copied if some bytes are copied
- return 0 if the end of file was reached
- return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */
-extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, uint32_t len)
-{
- unz64_s *s = NULL;
- uint32_t read = 0;
- int err = UNZ_OK;
-
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
-
- if (s->pfile_in_zip_read == NULL)
- return UNZ_PARAMERROR;
- if (s->pfile_in_zip_read->read_buffer == NULL)
- return UNZ_END_OF_LIST_OF_FILE;
- if (len == 0)
- return 0;
- if (len > UINT16_MAX)
- return UNZ_PARAMERROR;
-
- s->pfile_in_zip_read->stream.next_out = (uint8_t*)buf;
- s->pfile_in_zip_read->stream.avail_out = (uint16_t)len;
-
- if (s->pfile_in_zip_read->raw)
- {
- if (len > s->pfile_in_zip_read->rest_read_compressed + s->pfile_in_zip_read->stream.avail_in)
- s->pfile_in_zip_read->stream.avail_out = (uint16_t)s->pfile_in_zip_read->rest_read_compressed +
- s->pfile_in_zip_read->stream.avail_in;
- }
- else
- {
- if (len > s->pfile_in_zip_read->rest_read_uncompressed)
- s->pfile_in_zip_read->stream.avail_out = (uint16_t)s->pfile_in_zip_read->rest_read_uncompressed;
- }
-
- while (s->pfile_in_zip_read->stream.avail_out > 0)
- {
- if (s->pfile_in_zip_read->stream.avail_in == 0)
- {
- uint32_t bytes_to_read = UNZ_BUFSIZE;
- uint32_t bytes_not_read = 0;
- uint32_t bytes_read = 0;
- uint32_t total_bytes_read = 0;
-
- if (s->pfile_in_zip_read->stream.next_in != NULL)
- bytes_not_read = (uint32_t)(s->pfile_in_zip_read->read_buffer + UNZ_BUFSIZE -
- s->pfile_in_zip_read->stream.next_in);
- bytes_to_read -= bytes_not_read;
- if (bytes_not_read > 0)
- memcpy(s->pfile_in_zip_read->read_buffer, s->pfile_in_zip_read->stream.next_in, bytes_not_read);
- if (s->pfile_in_zip_read->rest_read_compressed < bytes_to_read)
- bytes_to_read = (uint16_t)s->pfile_in_zip_read->rest_read_compressed;
-
- while (total_bytes_read != bytes_to_read)
- {
- if (ZSEEK64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
- s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile,
- ZLIB_FILEFUNC_SEEK_SET) != 0)
- return UNZ_ERRNO;
-
- bytes_read = ZREAD64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
- s->pfile_in_zip_read->read_buffer + bytes_not_read + total_bytes_read,
- bytes_to_read - total_bytes_read);
-
- total_bytes_read += bytes_read;
- s->pfile_in_zip_read->pos_in_zipfile += bytes_read;
-
- if (bytes_read == 0)
- {
- if (ZERROR64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream))
- return UNZ_ERRNO;
-
- err = unzGoToNextDisk(file);
- if (err != UNZ_OK)
- return err;
-
- s->pfile_in_zip_read->pos_in_zipfile = 0;
- s->pfile_in_zip_read->filestream = s->filestream;
- }
- }
-
-#ifndef NOUNCRYPT
- if ((s->cur_file_info.flag & 1) != 0)
- {
-#ifdef HAVE_AES
- if (s->cur_file_info.compression_method == AES_METHOD)
- {
- fcrypt_decrypt(s->pfile_in_zip_read->read_buffer, bytes_to_read, &s->pfile_in_zip_read->aes_ctx);
- }
- else
-#endif
- if (s->pcrc_32_tab != NULL)
- {
- uint32_t i = 0;
-
- for (i = 0; i < total_bytes_read; i++)
- s->pfile_in_zip_read->read_buffer[i] =
- zdecode(s->keys, s->pcrc_32_tab, s->pfile_in_zip_read->read_buffer[i]);
- }
- }
-#endif
-
- s->pfile_in_zip_read->rest_read_compressed -= total_bytes_read;
- s->pfile_in_zip_read->stream.next_in = (uint8_t*)s->pfile_in_zip_read->read_buffer;
- s->pfile_in_zip_read->stream.avail_in = (uint16_t)(bytes_not_read + total_bytes_read);
- }
-
- if ((s->pfile_in_zip_read->compression_method == 0) || (s->pfile_in_zip_read->raw))
- {
- uint32_t i = 0;
- uint32_t copy = 0;
-
- if ((s->pfile_in_zip_read->stream.avail_in == 0) &&
- (s->pfile_in_zip_read->rest_read_compressed == 0))
- return (read == 0) ? UNZ_EOF : read;
-
- if (s->pfile_in_zip_read->stream.avail_out < s->pfile_in_zip_read->stream.avail_in)
- copy = s->pfile_in_zip_read->stream.avail_out;
- else
- copy = s->pfile_in_zip_read->stream.avail_in;
-
- for (i = 0; i < copy; i++)
- *(s->pfile_in_zip_read->stream.next_out + i) =
- *(s->pfile_in_zip_read->stream.next_in + i);
-
- s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + copy;
- s->pfile_in_zip_read->rest_read_uncompressed -= copy;
- s->pfile_in_zip_read->crc32 = (uint32_t)crc32(s->pfile_in_zip_read->crc32,
- s->pfile_in_zip_read->stream.next_out, copy);
-
- s->pfile_in_zip_read->stream.avail_in -= copy;
- s->pfile_in_zip_read->stream.avail_out -= copy;
- s->pfile_in_zip_read->stream.next_out += copy;
- s->pfile_in_zip_read->stream.next_in += copy;
- s->pfile_in_zip_read->stream.total_out += copy;
-
- read += copy;
- }
- else if (s->pfile_in_zip_read->compression_method == Z_BZIP2ED)
- {
-#ifdef HAVE_BZIP2
- uint64_t total_out_before = 0;
- uint64_t total_out_after = 0;
- uint64_t out_bytes = 0;
- const uint8_t *buf_before = NULL;
-
- s->pfile_in_zip_read->bstream.next_in = (char*)s->pfile_in_zip_read->stream.next_in;
- s->pfile_in_zip_read->bstream.avail_in = s->pfile_in_zip_read->stream.avail_in;
- s->pfile_in_zip_read->bstream.total_in_lo32 = (uint32_t)s->pfile_in_zip_read->stream.total_in;
- s->pfile_in_zip_read->bstream.total_in_hi32 = s->pfile_in_zip_read->stream.total_in >> 32;
-
- s->pfile_in_zip_read->bstream.next_out = (char*)s->pfile_in_zip_read->stream.next_out;
- s->pfile_in_zip_read->bstream.avail_out = s->pfile_in_zip_read->stream.avail_out;
- s->pfile_in_zip_read->bstream.total_out_lo32 = (uint32_t)s->pfile_in_zip_read->stream.total_out;
- s->pfile_in_zip_read->bstream.total_out_hi32 = s->pfile_in_zip_read->stream.total_out >> 32;
-
- total_out_before = s->pfile_in_zip_read->bstream.total_out_lo32 +
- (((uint32_t)s->pfile_in_zip_read->bstream.total_out_hi32) << 32);
- buf_before = (const uint8_t*)s->pfile_in_zip_read->bstream.next_out;
-
- err = BZ2_bzDecompress(&s->pfile_in_zip_read->bstream);
-
- total_out_after = s->pfile_in_zip_read->bstream.total_out_lo32 +
- (((uint32_t)s->pfile_in_zip_read->bstream.total_out_hi32) << 32);
-
- out_bytes = total_out_after - total_out_before;
-
- s->pfile_in_zip_read->total_out_64 = s->pfile_in_zip_read->total_out_64 + out_bytes;
- s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
- s->pfile_in_zip_read->crc32 = crc32(s->pfile_in_zip_read->crc32, buf_before, (uint32_t)out_bytes);
-
- read += (uint32_t)out_bytes;
-
- s->pfile_in_zip_read->stream.next_in = (uint8_t*)s->pfile_in_zip_read->bstream.next_in;
- s->pfile_in_zip_read->stream.avail_in = s->pfile_in_zip_read->bstream.avail_in;
- s->pfile_in_zip_read->stream.total_in = s->pfile_in_zip_read->bstream.total_in_lo32;
- s->pfile_in_zip_read->stream.next_out = (uint8_t*)s->pfile_in_zip_read->bstream.next_out;
- s->pfile_in_zip_read->stream.avail_out = s->pfile_in_zip_read->bstream.avail_out;
- s->pfile_in_zip_read->stream.total_out = s->pfile_in_zip_read->bstream.total_out_lo32;
-
- if (err == BZ_STREAM_END)
- return (read == 0) ? UNZ_EOF : read;
- if (err != BZ_OK)
- break;
-#endif
- }
-#ifdef HAVE_APPLE_COMPRESSION
- else
- {
- uint64_t total_out_before = 0;
- uint64_t total_out_after = 0;
- uint64_t out_bytes = 0;
- const uint8_t *buf_before = NULL;
-
- s->pfile_in_zip_read->astream.src_ptr = s->pfile_in_zip_read->stream.next_in;
- s->pfile_in_zip_read->astream.src_size = s->pfile_in_zip_read->stream.avail_in;
- s->pfile_in_zip_read->astream.dst_ptr = s->pfile_in_zip_read->stream.next_out;
- s->pfile_in_zip_read->astream.dst_size = len;
-
- total_out_before = s->pfile_in_zip_read->stream.total_out;
- buf_before = s->pfile_in_zip_read->stream.next_out;
-
- compression_status status;
- compression_stream_flags flags;
-
- if (s->pfile_in_zip_read->stream.avail_in == 0)
- {
- flags = COMPRESSION_STREAM_FINALIZE;
- }
-
- status = compression_stream_process(&s->pfile_in_zip_read->astream, flags);
-
- total_out_after = len - s->pfile_in_zip_read->astream.dst_size;
- out_bytes = total_out_after - total_out_before;
-
- s->pfile_in_zip_read->total_out_64 += out_bytes;
- s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
- s->pfile_in_zip_read->crc32 =
- crc32(s->pfile_in_zip_read->crc32, buf_before, (uint32_t)out_bytes);
-
- read += (uint32_t)out_bytes;
-
- s->pfile_in_zip_read->stream.next_in = s->pfile_in_zip_read->astream.src_ptr;
- s->pfile_in_zip_read->stream.avail_in = s->pfile_in_zip_read->astream.src_size;
- s->pfile_in_zip_read->stream.next_out = s->pfile_in_zip_read->astream.dst_ptr;
- s->pfile_in_zip_read->stream.avail_out = s->pfile_in_zip_read->astream.dst_size;
-
- if (status == COMPRESSION_STATUS_END)
- return (read == 0) ? UNZ_EOF : read;
- if (status == COMPRESSION_STATUS_ERROR)
- return Z_DATA_ERROR;
- return read;
- }
-#else
- else
- {
-
- uint64_t total_out_before = 0;
- uint64_t total_out_after = 0;
- uint64_t out_bytes = 0;
- const uint8_t *buf_before = NULL;
- int flush = Z_SYNC_FLUSH;
-
- total_out_before = s->pfile_in_zip_read->stream.total_out;
- buf_before = s->pfile_in_zip_read->stream.next_out;
-
- /*
- if ((pfile_in_zip_read_info->rest_read_uncompressed ==
- pfile_in_zip_read_info->stream.avail_out) &&
- (pfile_in_zip_read_info->rest_read_compressed == 0))
- flush = Z_FINISH;
- */
- err = inflate(&s->pfile_in_zip_read->stream, flush);
-
- if ((err >= 0) && (s->pfile_in_zip_read->stream.msg != NULL))
- err = Z_DATA_ERROR;
-
- total_out_after = s->pfile_in_zip_read->stream.total_out;
- out_bytes = total_out_after - total_out_before;
-
- s->pfile_in_zip_read->total_out_64 += out_bytes;
- s->pfile_in_zip_read->rest_read_uncompressed -= out_bytes;
- s->pfile_in_zip_read->crc32 =
- (uint32_t)crc32(s->pfile_in_zip_read->crc32,buf_before, (uint32_t)out_bytes);
-
- read += (uint32_t)out_bytes;
-
- if (err == Z_STREAM_END)
- return (read == 0) ? UNZ_EOF : read;
- if (err != Z_OK)
- break;
- }
-#endif
- }
-
- if (err == Z_OK)
- return read;
- return err;
-}
-
-extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, uint32_t len)
-{
- unz64_s *s = NULL;
- uint64_t size_to_read = 0;
- uint32_t read_now = 0;
-
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
- if (s->pfile_in_zip_read == NULL)
- return UNZ_PARAMERROR;
-
- size_to_read = s->pfile_in_zip_read->size_local_extrafield - s->pfile_in_zip_read->pos_local_extrafield;
-
- if (buf == NULL)
- return (int)size_to_read;
-
- if (len > size_to_read)
- read_now = (uint32_t)size_to_read;
- else
- read_now = len;
-
- if (read_now == 0)
- return 0;
-
- if (ZSEEK64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream,
- s->pfile_in_zip_read->offset_local_extrafield + s->pfile_in_zip_read->pos_local_extrafield,
- ZLIB_FILEFUNC_SEEK_SET) != 0)
- return UNZ_ERRNO;
-
- if (ZREAD64(s->pfile_in_zip_read->z_filefunc, s->pfile_in_zip_read->filestream, buf, read_now) != read_now)
- return UNZ_ERRNO;
-
- return (int)read_now;
-}
-
-extern int ZEXPORT unzCloseCurrentFile(unzFile file)
-{
- unz64_s *s = NULL;
- file_in_zip64_read_info_s *pfile_in_zip_read_info = NULL;
- int err = UNZ_OK;
-
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
- pfile_in_zip_read_info = s->pfile_in_zip_read;
- if (pfile_in_zip_read_info == NULL)
- return UNZ_PARAMERROR;
-
-#ifdef HAVE_AES
- if (s->cur_file_info.compression_method == AES_METHOD)
- {
- unsigned char authcode[AES_AUTHCODESIZE];
- unsigned char rauthcode[AES_AUTHCODESIZE];
-
- if (ZREAD64(s->z_filefunc, s->filestream, authcode, AES_AUTHCODESIZE) != AES_AUTHCODESIZE)
- return UNZ_ERRNO;
-
- if (fcrypt_end(rauthcode, &s->pfile_in_zip_read->aes_ctx) != AES_AUTHCODESIZE)
- err = UNZ_CRCERROR;
- if (memcmp(authcode, rauthcode, AES_AUTHCODESIZE) != 0)
- err = UNZ_CRCERROR;
- }
- /* AES zip version AE-1 will expect a valid crc as well */
- if ((s->cur_file_info.compression_method != AES_METHOD) ||
- (s->cur_file_info_internal.aes_version == 0x0001))
-#endif
- {
- if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
- (!pfile_in_zip_read_info->raw))
- {
- if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
- err = UNZ_CRCERROR;
- }
- }
-
- TRYFREE(pfile_in_zip_read_info->read_buffer);
- pfile_in_zip_read_info->read_buffer = NULL;
- if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
- {
-#ifdef HAVE_APPLE_COMPRESSION
- if (compression_stream_destroy)
- compression_stream_destroy(&pfile_in_zip_read_info->astream);
-#else
- inflateEnd(&pfile_in_zip_read_info->stream);
-#endif
-
- }
-#ifdef HAVE_BZIP2
- else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
- BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
-#endif
-
- pfile_in_zip_read_info->stream_initialised = 0;
- TRYFREE(pfile_in_zip_read_info);
-
- s->pfile_in_zip_read = NULL;
-
- return err;
-}
-
-extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
- uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
-{
- unz64_s *s = NULL;
- int err = UNZ_OK;
-
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
-
- s->pos_in_central_dir = s->offset_central_dir;
- s->num_file = 0;
-
- err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal,
- filename, filename_size, extrafield, extrafield_size, comment,comment_size);
-
- s->current_file_ok = (err == UNZ_OK);
- if ((err == UNZ_OK) && (pfile_info != NULL))
- memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64));
-
- return err;
-}
-
-extern int ZEXPORT unzGoToFirstFile(unzFile file)
-{
- return unzGoToFirstFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0);
-}
-
-extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
- uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
-{
- unz64_s *s = NULL;
- int err = UNZ_OK;
-
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
-
- if (!s->current_file_ok)
- return UNZ_END_OF_LIST_OF_FILE;
- if (s->gi.number_entry != UINT16_MAX) /* 2^16 files overflow hack */
- {
- if (s->num_file+1 == s->gi.number_entry)
- return UNZ_END_OF_LIST_OF_FILE;
- }
-
- s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
- s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment;
- s->num_file += 1;
-
- err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal,
- filename, filename_size, extrafield,extrafield_size, comment, comment_size);
-
- s->current_file_ok = (err == UNZ_OK);
- if ((err == UNZ_OK) && (pfile_info != NULL))
- memcpy(pfile_info, &s->cur_file_info, sizeof(unz_file_info64));
-
- return err;
-}
-
-extern int ZEXPORT unzGoToNextFile(unzFile file)
-{
- return unzGoToNextFile2(file, NULL, NULL, 0, NULL, 0, NULL, 0);
-}
-
-extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func)
-{
- unz64_s *s = NULL;
- unz_file_info64 cur_file_info_saved;
- unz_file_info64_internal cur_file_info_internal_saved;
- uint64_t num_file_saved = 0;
- uint64_t pos_in_central_dir_saved = 0;
- char current_filename[UNZ_MAXFILENAMEINZIP+1];
- int err = UNZ_OK;
-
- if (file == NULL)
- return UNZ_PARAMERROR;
- if (strlen(filename) >= UNZ_MAXFILENAMEINZIP)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
- if (!s->current_file_ok)
- return UNZ_END_OF_LIST_OF_FILE;
-
- /* Save the current state */
- num_file_saved = s->num_file;
- pos_in_central_dir_saved = s->pos_in_central_dir;
- cur_file_info_saved = s->cur_file_info;
- cur_file_info_internal_saved = s->cur_file_info_internal;
-
- err = unzGoToFirstFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0);
-
- while (err == UNZ_OK)
- {
- if (filename_compare_func != NULL)
- err = filename_compare_func(file, current_filename, filename);
- else
- err = strcmp(current_filename, filename);
- if (err == 0)
- return UNZ_OK;
- err = unzGoToNextFile2(file, NULL, current_filename, sizeof(current_filename)-1, NULL, 0, NULL, 0);
- }
-
- /* We failed, so restore the state of the 'current file' to where we were. */
- s->num_file = num_file_saved;
- s->pos_in_central_dir = pos_in_central_dir_saved;
- s->cur_file_info = cur_file_info_saved;
- s->cur_file_info_internal = cur_file_info_internal_saved;
- return err;
-}
-
-extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos *file_pos)
-{
- unz64_file_pos file_pos64;
- int err = unzGetFilePos64(file, &file_pos64);
- if (err == UNZ_OK)
- {
- file_pos->pos_in_zip_directory = (uint32_t)file_pos64.pos_in_zip_directory;
- file_pos->num_of_file = (uint32_t)file_pos64.num_of_file;
- }
- return err;
-}
-
-extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos *file_pos)
-{
- unz64_file_pos file_pos64;
- if (file_pos == NULL)
- return UNZ_PARAMERROR;
- file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
- file_pos64.num_of_file = file_pos->num_of_file;
- return unzGoToFilePos64(file, &file_pos64);
-}
-
-extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos *file_pos)
-{
- unz64_s *s = NULL;
-
- if (file == NULL || file_pos == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
- if (!s->current_file_ok)
- return UNZ_END_OF_LIST_OF_FILE;
-
- file_pos->pos_in_zip_directory = s->pos_in_central_dir;
- file_pos->num_of_file = s->num_file;
- return UNZ_OK;
-}
-
-extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos)
-{
- unz64_s *s = NULL;
- int err = UNZ_OK;
-
- if (file == NULL || file_pos == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
-
- /* Jump to the right spot */
- s->pos_in_central_dir = file_pos->pos_in_zip_directory;
- s->num_file = file_pos->num_of_file;
-
- /* Set the current file */
- err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0);
- /* Return results */
- s->current_file_ok = (err == UNZ_OK);
- return err;
-}
-
-extern int32_t ZEXPORT unzGetOffset(unzFile file)
-{
- uint64_t offset64 = 0;
-
- if (file == NULL)
- return UNZ_PARAMERROR;
- offset64 = unzGetOffset64(file);
- return (int32_t)offset64;
-}
-
-extern int64_t ZEXPORT unzGetOffset64(unzFile file)
-{
- unz64_s *s = NULL;
-
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
- if (!s->current_file_ok)
- return 0;
- if (s->gi.number_entry != 0 && s->gi.number_entry != UINT16_MAX)
- {
- if (s->num_file == s->gi.number_entry)
- return 0;
- }
- return s->pos_in_central_dir;
-}
-
-extern int ZEXPORT unzSetOffset(unzFile file, uint32_t pos)
-{
- return unzSetOffset64(file, pos);
-}
-
-extern int ZEXPORT unzSetOffset64(unzFile file, uint64_t pos)
-{
- unz64_s *s = NULL;
- int err = UNZ_OK;
-
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
- s->pos_in_central_dir = pos;
- s->num_file = s->gi.number_entry; /* hack */
-
- err = unzGetCurrentFileInfoInternal(file, &s->cur_file_info, &s->cur_file_info_internal, NULL, 0, NULL, 0, NULL, 0);
-
- s->current_file_ok = (err == UNZ_OK);
- return err;
-}
-
-extern int32_t ZEXPORT unzTell(unzFile file)
-{
- unz64_s *s = NULL;
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
- if (s->pfile_in_zip_read == NULL)
- return UNZ_PARAMERROR;
- return (int32_t)s->pfile_in_zip_read->stream.total_out;
-}
-
-extern int64_t ZEXPORT unzTell64(unzFile file)
-{
- unz64_s *s = NULL;
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
- if (s->pfile_in_zip_read == NULL)
- return UNZ_PARAMERROR;
- return s->pfile_in_zip_read->total_out_64;
-}
-
-extern int ZEXPORT unzSeek(unzFile file, uint32_t offset, int origin)
-{
- return unzSeek64(file, offset, origin);
-}
-
-extern int ZEXPORT unzSeek64(unzFile file, uint64_t offset, int origin)
-{
- unz64_s *s = NULL;
- uint64_t stream_pos_begin = 0;
- uint64_t stream_pos_end = 0;
- uint64_t position = 0;
- int is_within_buffer = 0;
-
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
-
- if (s->pfile_in_zip_read == NULL)
- return UNZ_ERRNO;
- if (s->pfile_in_zip_read->compression_method != 0)
- return UNZ_ERRNO;
-
- if (origin == SEEK_SET)
- position = offset;
- else if (origin == SEEK_CUR)
- position = s->pfile_in_zip_read->total_out_64 + offset;
- else if (origin == SEEK_END)
- position = s->cur_file_info.compressed_size + offset;
- else
- return UNZ_PARAMERROR;
-
- if (position > s->cur_file_info.compressed_size)
- return UNZ_PARAMERROR;
-
- stream_pos_end = s->pfile_in_zip_read->pos_in_zipfile;
- stream_pos_begin = stream_pos_end;
-
- if (stream_pos_begin > UNZ_BUFSIZE)
- stream_pos_begin -= UNZ_BUFSIZE;
- else
- stream_pos_begin = 0;
-
- is_within_buffer =
- (s->pfile_in_zip_read->stream.avail_in != 0) &&
- (s->pfile_in_zip_read->rest_read_compressed != 0 || s->cur_file_info.compressed_size < UNZ_BUFSIZE) &&
- (position >= stream_pos_begin && position < stream_pos_end);
-
- if (is_within_buffer)
- {
- s->pfile_in_zip_read->stream.next_in += position - s->pfile_in_zip_read->total_out_64;
- s->pfile_in_zip_read->stream.avail_in = (uInt)(stream_pos_end - position);
- }
- else
- {
- s->pfile_in_zip_read->stream.avail_in = 0;
- s->pfile_in_zip_read->stream.next_in = 0;
-
- s->pfile_in_zip_read->pos_in_zipfile = s->pfile_in_zip_read->offset_local_extrafield + position;
- s->pfile_in_zip_read->rest_read_compressed = s->cur_file_info.compressed_size - position;
- }
-
- s->pfile_in_zip_read->rest_read_uncompressed -= (position - s->pfile_in_zip_read->total_out_64);
- s->pfile_in_zip_read->stream.total_out = (uint32_t)position;
- s->pfile_in_zip_read->total_out_64 = position;
-
- return UNZ_OK;
-}
-
-extern int ZEXPORT unzEndOfFile(unzFile file)
-{
- unz64_s *s = NULL;
- if (file == NULL)
- return UNZ_PARAMERROR;
- s = (unz64_s*)file;
- if (s->pfile_in_zip_read == NULL)
- return UNZ_PARAMERROR;
- if (s->pfile_in_zip_read->rest_read_uncompressed == 0)
- return 1;
- return 0;
-}
diff --git a/Externals/minizip/unzip.h b/Externals/minizip/unzip.h
index ea4c90a4dd..61cbd974e3 100644
--- a/Externals/minizip/unzip.h
+++ b/Externals/minizip/unzip.h
@@ -1,306 +1,13 @@
-/* unzip.h -- IO for uncompress .zip files using zlib
- Version 1.1, February 14h, 2010
- part of the MiniZip project
-
- Copyright (C) 1998-2010 Gilles Vollant
- http://www.winimage.com/zLibDll/minizip.html
- Modifications of Unzip for Zip64
- Copyright (C) 2007-2008 Even Rouault
- Modifications for Zip64 support on both zip and unzip
- Copyright (C) 2009-2010 Mathias Svensson
- http://result42.com
+/* unzip.h -- Compatibility layer shim
+ part of the minizip-ng project
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
-#ifndef _UNZ_H
-#define _UNZ_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef _ZLIB_H
-#include "zlib.h"
-#endif
-
-#ifndef _ZLIBIOAPI_H
-#include "ioapi.h"
-#endif
+#ifndef MZ_COMPAT_UNZIP
+#define MZ_COMPAT_UNZIP
-#ifdef HAVE_BZIP2
-#include "bzlib.h"
-#endif
+#include "mz_compat.h"
-#define Z_BZIP2ED 12
-
-#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
-/* like the STRICT of WIN32, we define a pointer that cannot be converted
- from (void*) without cast */
-typedef struct TagunzFile__ { int unused; } unz_file__;
-typedef unz_file__ *unzFile;
-#else
-typedef voidp unzFile;
#endif
-
-#define UNZ_OK (0)
-#define UNZ_END_OF_LIST_OF_FILE (-100)
-#define UNZ_ERRNO (Z_ERRNO)
-#define UNZ_EOF (0)
-#define UNZ_PARAMERROR (-102)
-#define UNZ_BADZIPFILE (-103)
-#define UNZ_INTERNALERROR (-104)
-#define UNZ_CRCERROR (-105)
-#define UNZ_BADPASSWORD (-106)
-
-/* unz_global_info structure contain global data about the ZIPfile
- These data comes from the end of central dir */
-typedef struct unz_global_info64_s
-{
- uint64_t number_entry; /* total number of entries in the central dir on this disk */
- uint32_t number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/
- uint16_t size_comment; /* size of the global comment of the zipfile */
-} unz_global_info64;
-
-typedef struct unz_global_info_s
-{
- uint32_t number_entry; /* total number of entries in the central dir on this disk */
- uint32_t number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP*/
- uint16_t size_comment; /* size of the global comment of the zipfile */
-} unz_global_info;
-
-/* unz_file_info contain information about a file in the zipfile */
-typedef struct unz_file_info64_s
-{
- uint16_t version; /* version made by 2 bytes */
- uint16_t version_needed; /* version needed to extract 2 bytes */
- uint16_t flag; /* general purpose bit flag 2 bytes */
- uint16_t compression_method; /* compression method 2 bytes */
- uint32_t dos_date; /* last mod file date in Dos fmt 4 bytes */
- uint32_t crc; /* crc-32 4 bytes */
- uint64_t compressed_size; /* compressed size 8 bytes */
- uint64_t uncompressed_size; /* uncompressed size 8 bytes */
- uint16_t size_filename; /* filename length 2 bytes */
- uint16_t size_file_extra; /* extra field length 2 bytes */
- uint16_t size_file_comment; /* file comment length 2 bytes */
-
- uint32_t disk_num_start; /* disk number start 4 bytes */
- uint16_t internal_fa; /* internal file attributes 2 bytes */
- uint32_t external_fa; /* external file attributes 4 bytes */
-
- uint64_t disk_offset;
-
- uint16_t size_file_extra_internal;
-} unz_file_info64;
-
-typedef struct unz_file_info_s
-{
- uint16_t version; /* version made by 2 bytes */
- uint16_t version_needed; /* version needed to extract 2 bytes */
- uint16_t flag; /* general purpose bit flag 2 bytes */
- uint16_t compression_method; /* compression method 2 bytes */
- uint32_t dos_date; /* last mod file date in Dos fmt 4 bytes */
- uint32_t crc; /* crc-32 4 bytes */
- uint32_t compressed_size; /* compressed size 4 bytes */
- uint32_t uncompressed_size; /* uncompressed size 4 bytes */
- uint16_t size_filename; /* filename length 2 bytes */
- uint16_t size_file_extra; /* extra field length 2 bytes */
- uint16_t size_file_comment; /* file comment length 2 bytes */
-
- uint16_t disk_num_start; /* disk number start 2 bytes */
- uint16_t internal_fa; /* internal file attributes 2 bytes */
- uint32_t external_fa; /* external file attributes 4 bytes */
-
- uint64_t disk_offset;
-} unz_file_info;
-
-/***************************************************************************/
-/* Opening and close a zip file */
-
-extern unzFile ZEXPORT unzOpen(const char *path);
-extern unzFile ZEXPORT unzOpen64(const void *path);
-/* Open a Zip file.
-
- path should contain the full path (by example, on a Windows XP computer
- "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip".
- return NULL if zipfile cannot be opened or doesn't exist
- return unzFile handle if no error
-
- NOTE: The "64" function take a const void *pointer, because the path is just the value passed to the
- open64_file_func callback. Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
- is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char *does not describe the reality */
-
-extern unzFile ZEXPORT unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def);
-/* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write operations */
-extern unzFile ZEXPORT unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def);
-/* Open a Zip file, like unz64Open, but provide a set of file low level API for read/write 64-bit operations */
-
-extern int ZEXPORT unzClose(unzFile file);
-/* Close a ZipFile opened with unzOpen. If there is files inside the .Zip opened with unzOpenCurrentFile,
- these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
-
- return UNZ_OK if there is no error */
-
-extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info);
-extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info);
-/* Write info about the ZipFile in the *pglobal_info structure.
-
- return UNZ_OK if no error */
-
-extern int ZEXPORT unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size);
-/* Get the global comment string of the ZipFile, in the comment buffer.
-
- uSizeBuf is the size of the szComment buffer.
- return the number of byte copied or an error code <0 */
-
-/***************************************************************************/
-/* Reading the content of the current zipfile, you can open it, read data from it, and close it
- (you can close it before reading all the file) */
-
-extern int ZEXPORT unzOpenCurrentFile(unzFile file);
-/* Open for reading data the current file in the zipfile.
-
- return UNZ_OK if no error */
-
-extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char *password);
-/* Open for reading data the current file in the zipfile.
- password is a crypting password
-
- return UNZ_OK if no error */
-
-extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw);
-/* Same as unzOpenCurrentFile, but open for read raw the file (not uncompress)
- if raw==1 *method will receive method of compression, *level will receive level of compression
-
- NOTE: you can set level parameter as NULL (if you did not want known level,
- but you CANNOT set method parameter as NULL */
-
-extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password);
-/* Same as unzOpenCurrentFile, but takes extra parameter password for encrypted files */
-
-extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, uint32_t len);
-/* Read bytes from the current file (opened by unzOpenCurrentFile)
- buf contain buffer where data must be copied
- len the size of buf.
-
- return the number of byte copied if somes bytes are copied
- return 0 if the end of file was reached
- return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */
-
-extern int ZEXPORT unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,
- uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
-extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file, unz_file_info64 *pfile_info, char *filename,
- uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
-/* Get Info about the current file
-
- pfile_info if != NULL, the *pfile_info structure will contain somes info about the current file
- filename if != NULL, the file name string will be copied in filename
- filename_size is the size of the filename buffer
- extrafield if != NULL, the extra field information from the central header will be copied in to
- extrafield_size is the size of the extraField buffer
- comment if != NULL, the comment string of the file will be copied in to
- comment_size is the size of the comment buffer */
-
-extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, uint32_t len);
-/* Read extra field from the current file (opened by unzOpenCurrentFile)
- This is the local-header version of the extra field (sometimes, there is
- more info in the local-header version than in the central-header)
-
- if buf == NULL, it return the size of the local extra field
- if buf != NULL, len is the size of the buffer, the extra header is copied in buf.
-
- return number of bytes copied in buf, or (if <0) the error code */
-
-extern int ZEXPORT unzCloseCurrentFile(unzFile file);
-/* Close the file in zip opened with unzOpenCurrentFile
-
- return UNZ_CRCERROR if all the file was read but the CRC is not good */
-
-/***************************************************************************/
-/* Browse the directory of the zipfile */
-
-typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2);
-typedef int (*unzIteratorFunction)(unzFile file);
-typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename,
- uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
-
-extern int ZEXPORT unzGoToFirstFile(unzFile file);
-/* Set the current file of the zipfile to the first file.
-
- return UNZ_OK if no error */
-
-extern int ZEXPORT unzGoToFirstFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
- uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
-/* Set the current file of the zipfile to the first file and retrieves the current info on success.
- Not as seek intensive as unzGoToFirstFile + unzGetCurrentFileInfo.
-
- return UNZ_OK if no error */
-
-extern int ZEXPORT unzGoToNextFile(unzFile file);
-/* Set the current file of the zipfile to the next file.
-
- return UNZ_OK if no error
- return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */
-
-extern int ZEXPORT unzGoToNextFile2(unzFile file, unz_file_info64 *pfile_info, char *filename,
- uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size);
-/* Set the current file of the zipfile to the next file and retrieves the current
- info on success. Does less seeking around than unzGotoNextFile + unzGetCurrentFileInfo.
-
- return UNZ_OK if no error
- return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest */
-
-extern int ZEXPORT unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func);
-/* Try locate the file szFileName in the zipfile. For custom filename comparison pass in comparison function.
-
- return UNZ_OK if the file is found (it becomes the current file)
- return UNZ_END_OF_LIST_OF_FILE if the file is not found */
-
-/***************************************************************************/
-/* Raw access to zip file */
-
-typedef struct unz_file_pos_s
-{
- uint32_t pos_in_zip_directory; /* offset in zip file directory */
- uint32_t num_of_file; /* # of file */
-} unz_file_pos;
-
-extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos *file_pos);
-extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos *file_pos);
-
-typedef struct unz64_file_pos_s
-{
- uint64_t pos_in_zip_directory; /* offset in zip file directory */
- uint64_t num_of_file; /* # of file */
-} unz64_file_pos;
-
-extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos *file_pos);
-extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos);
-
-extern int32_t ZEXPORT unzGetOffset(unzFile file);
-extern int64_t ZEXPORT unzGetOffset64(unzFile file);
-/* Get the current file offset */
-
-extern int ZEXPORT unzSetOffset(unzFile file, uint32_t pos);
-extern int ZEXPORT unzSetOffset64(unzFile file, uint64_t pos);
-/* Set the current file offset */
-
-extern int32_t ZEXPORT unzTell(unzFile file);
-extern int64_t ZEXPORT unzTell64(unzFile file);
-/* return current position in uncompressed data */
-
-extern int ZEXPORT unzSeek(unzFile file, uint32_t offset, int origin);
-extern int ZEXPORT unzSeek64(unzFile file, uint64_t offset, int origin);
-/* Seek within the uncompressed data if compression method is storage */
-
-extern int ZEXPORT unzEndOfFile(unzFile file);
-/* return 1 if the end of file was reached, 0 elsewhere */
-
-/***************************************************************************/
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _UNZ_H */
diff --git a/Externals/minizip/zip.h b/Externals/minizip/zip.h
new file mode 100644
index 0000000000..cf38ac91a0
--- /dev/null
+++ b/Externals/minizip/zip.h
@@ -0,0 +1,13 @@
+/* zip.h -- Compatibility layer shim
+ part of the minizip-ng project
+
+ This program is distributed under the terms of the same license as zlib.
+ See the accompanying LICENSE file for the full text of the license.
+*/
+
+#ifndef MZ_COMPAT_ZIP
+#define MZ_COMPAT_ZIP
+
+#include "mz_compat.h"
+
+#endif