From 9fc435a59e7b609ad0b541d236a01d5aac874908 Mon Sep 17 00:00:00 2001 From: Rye Mutt Date: Fri, 9 Aug 2024 15:27:07 -0400 Subject: [PATCH] Update to minizip-ng 4.0.7 and zlib-ng 2.2.1-r2 (#5) * Update to minizip-ng 4.0.7 submodule * Update to zlib-ng 2.2.1-r2 * Update build scripts for new library version Fix windows symbol generation Rework cmake builds --- .github/workflows/build.yaml | 23 +- .gitmodules | 3 + autobuild.xml | 20 +- build-cmd.sh | 127 +- minizip-ng | 1 + minizip-ng/.github/FUNDING.yml | 1 - .../.github/workflows/codeql-analysis.yml | 51 - minizip-ng/.github/workflows/fuzz.yml | 23 - minizip-ng/.github/workflows/main.yml | 275 -- minizip-ng/CMakeLists.txt | 1015 ----- minizip-ng/INDEX.md | 24 - minizip-ng/LICENSE | 17 - minizip-ng/README.md | 113 - minizip-ng/doc/README.md | 138 - minizip-ng/doc/mz_compress_level.md | 10 - minizip-ng/doc/mz_compress_method.md | 14 - minizip-ng/doc/mz_encoding.md | 11 - minizip-ng/doc/mz_error.md | 31 - minizip-ng/doc/mz_extrafield.md | 35 - minizip-ng/doc/mz_hash.md | 12 - minizip-ng/doc/mz_host_system.md | 24 - minizip-ng/doc/mz_open_mode.md | 12 - minizip-ng/doc/mz_os.md | 859 ---- minizip-ng/doc/mz_seek.md | 9 - minizip-ng/doc/mz_zip.md | 1597 ------- minizip-ng/doc/mz_zip64.md | 9 - minizip-ng/doc/mz_zip_file.md | 79 - minizip-ng/doc/mz_zip_rw.md | 2076 ---------- minizip-ng/doc/zip/appnote.iz.txt | 3686 ----------------- minizip-ng/doc/zip/appnote.txt | 3497 ---------------- minizip-ng/doc/zip/extra.fld.txt | 1243 ------ minizip-ng/doc/zip/winzip_aes.md | 261 -- minizip-ng/minigzip.c | 182 - minizip-ng/minizip.c | 671 --- minizip-ng/minizip.pc.cmakein | 14 - minizip-ng/mz.h | 274 -- minizip-ng/mz_compat.c | 1303 ------ minizip-ng/mz_compat.h | 396 -- minizip-ng/mz_crypt.c | 196 - minizip-ng/mz_crypt.h | 65 - minizip-ng/mz_crypt_apple.c | 487 --- minizip-ng/mz_crypt_openssl.c | 629 --- minizip-ng/mz_crypt_win32.c | 739 ---- minizip-ng/mz_os.c | 354 -- minizip-ng/mz_os.h | 175 - minizip-ng/mz_os_posix.c | 367 -- minizip-ng/mz_os_win32.c | 658 --- minizip-ng/mz_strm.c | 560 --- minizip-ng/mz_strm.h | 132 - minizip-ng/mz_strm_buf.c | 385 -- minizip-ng/mz_strm_buf.h | 42 - minizip-ng/mz_strm_bzip.c | 374 -- minizip-ng/mz_strm_bzip.h | 45 - minizip-ng/mz_strm_libcomp.c | 356 -- minizip-ng/mz_strm_libcomp.h | 45 - minizip-ng/mz_strm_lzma.c | 470 --- minizip-ng/mz_strm_lzma.h | 43 - minizip-ng/mz_strm_mem.c | 272 -- minizip-ng/mz_strm_mem.h | 48 - minizip-ng/mz_strm_os.h | 40 - minizip-ng/mz_strm_os_posix.c | 206 - minizip-ng/mz_strm_os_win32.c | 296 -- minizip-ng/mz_strm_pkcrypt.c | 338 -- minizip-ng/mz_strm_pkcrypt.h | 46 - minizip-ng/mz_strm_split.c | 438 -- minizip-ng/mz_strm_split.h | 43 - minizip-ng/mz_strm_wzaes.c | 362 -- minizip-ng/mz_strm_wzaes.h | 46 - minizip-ng/mz_strm_zlib.c | 393 -- minizip-ng/mz_strm_zlib.h | 43 - minizip-ng/mz_strm_zstd.c | 351 -- minizip-ng/mz_strm_zstd.h | 44 - minizip-ng/mz_zip.c | 2771 ------------- minizip-ng/mz_zip.h | 259 -- minizip-ng/mz_zip_rw.c | 1943 --------- minizip-ng/mz_zip_rw.h | 285 -- minizip-ng/test/empty.txt | 0 minizip-ng/test/fuzz/standalone.c | 100 - minizip-ng/test/fuzz/unzip_fuzzer.c | 119 - minizip-ng/test/fuzz/unzip_fuzzer.dict | 9 - .../test/fuzz/unzip_fuzzer_seed_corpus/as.zip | Bin 233 -> 0 bytes .../fuzz/unzip_fuzzer_seed_corpus/bzip2.zip | Bin 163941 -> 0 bytes .../unzip_fuzzer_seed_corpus/comments.zip | Bin 220 -> 0 bytes .../fuzz/unzip_fuzzer_seed_corpus/corpus.zip | Bin 71444 -> 0 bytes .../encrypted_pkcrypt.zip | Bin 198 -> 0 bytes .../encrypted_wzaes.zip | Bin 204 -> 0 bytes .../test/fuzz/unzip_fuzzer_seed_corpus/gh.zip | Bin 246 -> 0 bytes .../infozip_symlinks.zip | Bin 328 -> 0 bytes .../large_cd_comment.zip | Bin 65785 -> 0 bytes .../unzip_fuzzer_seed_corpus/license_zstd.zip | Bin 734 -> 0 bytes .../fuzz/unzip_fuzzer_seed_corpus/lzma.zip | Bin 28864 -> 0 bytes .../unzip_fuzzer_seed_corpus/permissions.zip | Bin 634 -> 0 bytes .../fuzz/unzip_fuzzer_seed_corpus/signed.zip | Bin 36122 -> 0 bytes .../unzip_fuzzer_seed_corpus/storeonly.zip | Bin 68373 -> 0 bytes .../fuzz/unzip_fuzzer_seed_corpus/tiny.zip | Bin 22 -> 0 bytes .../unsupported_permissions.zip | Bin 287 -> 0 bytes .../test/fuzz/unzip_fuzzer_seed_corpus/xz.zip | Bin 48740 -> 0 bytes .../fuzz/unzip_fuzzer_seed_corpus/zip64.zip | Bin 215 -> 0 bytes minizip-ng/test/fuzz/zip_fuzzer.c | 114 - minizip-ng/test/random.bin | Bin 131072 -> 0 bytes minizip-ng/test/single.txt | 1 - minizip-ng/test/test.c | 1248 ------ minizip-ng/test/test.h | 28 - minizip-ng/test/test.p12 | Bin 2603 -> 0 bytes minizip-ng/test/test.pem | 61 - minizip-ng/test/uniform.bin | 1 - 106 files changed, 73 insertions(+), 34090 deletions(-) create mode 100644 .gitmodules create mode 160000 minizip-ng delete mode 100644 minizip-ng/.github/FUNDING.yml delete mode 100644 minizip-ng/.github/workflows/codeql-analysis.yml delete mode 100644 minizip-ng/.github/workflows/fuzz.yml delete mode 100644 minizip-ng/.github/workflows/main.yml delete mode 100644 minizip-ng/CMakeLists.txt delete mode 100644 minizip-ng/INDEX.md delete mode 100644 minizip-ng/LICENSE delete mode 100644 minizip-ng/README.md delete mode 100644 minizip-ng/doc/README.md delete mode 100644 minizip-ng/doc/mz_compress_level.md delete mode 100644 minizip-ng/doc/mz_compress_method.md delete mode 100644 minizip-ng/doc/mz_encoding.md delete mode 100644 minizip-ng/doc/mz_error.md delete mode 100644 minizip-ng/doc/mz_extrafield.md delete mode 100644 minizip-ng/doc/mz_hash.md delete mode 100644 minizip-ng/doc/mz_host_system.md delete mode 100644 minizip-ng/doc/mz_open_mode.md delete mode 100644 minizip-ng/doc/mz_os.md delete mode 100644 minizip-ng/doc/mz_seek.md delete mode 100644 minizip-ng/doc/mz_zip.md delete mode 100644 minizip-ng/doc/mz_zip64.md delete mode 100644 minizip-ng/doc/mz_zip_file.md delete mode 100644 minizip-ng/doc/mz_zip_rw.md delete mode 100644 minizip-ng/doc/zip/appnote.iz.txt delete mode 100644 minizip-ng/doc/zip/appnote.txt delete mode 100644 minizip-ng/doc/zip/extra.fld.txt delete mode 100644 minizip-ng/doc/zip/winzip_aes.md delete mode 100644 minizip-ng/minigzip.c delete mode 100644 minizip-ng/minizip.c delete mode 100644 minizip-ng/minizip.pc.cmakein delete mode 100644 minizip-ng/mz.h delete mode 100644 minizip-ng/mz_compat.c delete mode 100644 minizip-ng/mz_compat.h delete mode 100644 minizip-ng/mz_crypt.c delete mode 100644 minizip-ng/mz_crypt.h delete mode 100644 minizip-ng/mz_crypt_apple.c delete mode 100644 minizip-ng/mz_crypt_openssl.c delete mode 100644 minizip-ng/mz_crypt_win32.c delete mode 100644 minizip-ng/mz_os.c delete mode 100644 minizip-ng/mz_os.h delete mode 100644 minizip-ng/mz_os_posix.c delete mode 100644 minizip-ng/mz_os_win32.c delete mode 100644 minizip-ng/mz_strm.c delete mode 100644 minizip-ng/mz_strm.h delete mode 100644 minizip-ng/mz_strm_buf.c delete mode 100644 minizip-ng/mz_strm_buf.h delete mode 100644 minizip-ng/mz_strm_bzip.c delete mode 100644 minizip-ng/mz_strm_bzip.h delete mode 100644 minizip-ng/mz_strm_libcomp.c delete mode 100644 minizip-ng/mz_strm_libcomp.h delete mode 100644 minizip-ng/mz_strm_lzma.c delete mode 100644 minizip-ng/mz_strm_lzma.h delete mode 100644 minizip-ng/mz_strm_mem.c delete mode 100644 minizip-ng/mz_strm_mem.h delete mode 100644 minizip-ng/mz_strm_os.h delete mode 100644 minizip-ng/mz_strm_os_posix.c delete mode 100644 minizip-ng/mz_strm_os_win32.c delete mode 100644 minizip-ng/mz_strm_pkcrypt.c delete mode 100644 minizip-ng/mz_strm_pkcrypt.h delete mode 100644 minizip-ng/mz_strm_split.c delete mode 100644 minizip-ng/mz_strm_split.h delete mode 100644 minizip-ng/mz_strm_wzaes.c delete mode 100644 minizip-ng/mz_strm_wzaes.h delete mode 100644 minizip-ng/mz_strm_zlib.c delete mode 100644 minizip-ng/mz_strm_zlib.h delete mode 100644 minizip-ng/mz_strm_zstd.c delete mode 100644 minizip-ng/mz_strm_zstd.h delete mode 100644 minizip-ng/mz_zip.c delete mode 100644 minizip-ng/mz_zip.h delete mode 100644 minizip-ng/mz_zip_rw.c delete mode 100644 minizip-ng/mz_zip_rw.h delete mode 100644 minizip-ng/test/empty.txt delete mode 100644 minizip-ng/test/fuzz/standalone.c delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer.c delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer.dict delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/as.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/bzip2.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/comments.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/corpus.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/encrypted_pkcrypt.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/encrypted_wzaes.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/gh.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/infozip_symlinks.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/large_cd_comment.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/license_zstd.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/lzma.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/permissions.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/signed.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/storeonly.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/tiny.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/unsupported_permissions.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/xz.zip delete mode 100644 minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/zip64.zip delete mode 100644 minizip-ng/test/fuzz/zip_fuzzer.c delete mode 100644 minizip-ng/test/random.bin delete mode 100644 minizip-ng/test/single.txt delete mode 100644 minizip-ng/test/test.c delete mode 100644 minizip-ng/test/test.h delete mode 100644 minizip-ng/test/test.p12 delete mode 100644 minizip-ng/test/test.pem delete mode 100644 minizip-ng/test/uniform.bin diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 129ed02..6dafbf7 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -1,16 +1,27 @@ name: Build -on: [push] +on: + pull_request: + push: + branches: [main] + tags: [v*] jobs: build: strategy: matrix: - os: [windows-2022, macos-11, ubuntu-22.04] + os: [windows-2022, macos-12, ubuntu-22.04] addrsize: ["64"] - include: - - os: windows-2022 - addrsize: "32" runs-on: ${{ matrix.os }} steps: + - name: Setup Homebrew Packages + if: ${{ runner.os == 'macOS' }} + shell: bash + run: brew install ninja + - name: Setup Apt Packages + if: ${{ runner.os == 'Linux' }} + shell: bash + run: | + sudo apt-get update + sudo apt-get -y install ninja-build - uses: secondlife/action-autobuild@v4 with: addrsize: ${{ matrix.addrsize }} @@ -20,5 +31,3 @@ jobs: if: startsWith(github.ref, 'refs/tags/v') steps: - uses: secondlife/action-autobuild-release@v3 - with: - public: true diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0d3e669 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "minizip-ng"] + path = minizip-ng + url = https://github.com/zlib-ng/minizip-ng.git diff --git a/autobuild.xml b/autobuild.xml index b76b069..135e6b8 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -23,11 +23,11 @@ archive hash - dacc5f3fb307c4d1292ed1ffb1d595d83599062d + 3a6593c71c59ace76d1349483759fcde4b719a76 hash_algorithm sha1 url - https://github.com/secondlife/3p-zlib-ng/releases/download/v1.2.11.zlib-ng.32fd361/zlib_ng-1.2.11.zlib-ng.32fd361-darwin64-32fd361.tar.zst + https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.1-r2/zlib_ng-2.2.1-r2-darwin64-10324415171.tar.zst name darwin64 @@ -37,11 +37,11 @@ archive hash - fba88375e12454ae19f4528e11ffc7ddf7d879ec + fbadeb0b8c771cb06c0055c9fab6d40c6764dacd hash_algorithm sha1 url - https://github.com/secondlife/3p-zlib-ng/releases/download/v1.2.11.zlib-ng.32fd361/zlib_ng-1.2.11.zlib-ng.32fd361-linux64-32fd361.tar.zst + https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.1-r2/zlib_ng-2.2.1-r2-linux64-10324415171.tar.zst name linux64 @@ -65,18 +65,18 @@ archive hash - ccfca9451063e2d0e95baa73b1ad2054d3e38907 + 0094031715662be626f5106ff6c814f4fc3dacfa hash_algorithm sha1 url - https://github.com/secondlife/3p-zlib-ng/releases/download/v1.2.11.zlib-ng.32fd361/zlib_ng-1.2.11.zlib-ng.32fd361-windows64-32fd361.tar.zst + https://github.com/secondlife/3p-zlib-ng/releases/download/v2.2.1-r2/zlib_ng-2.2.1-r2-windows64-10324415171.tar.zst name windows64 version - 1.2.11.zlib-ng.32fd361 + 2.2.1-r2 package_description @@ -93,6 +93,8 @@ LICENSES/minizip-ng.txt name minizip-ng + use_scm_version + true platforms common @@ -187,14 +189,12 @@ manifest - lib/release/libminizip.lib + lib/release/minizip.lib name windows - version_file - VERSION.txt type autobuild diff --git a/build-cmd.sh b/build-cmd.sh index f845cce..9b06688 100755 --- a/build-cmd.sh +++ b/build-cmd.sh @@ -33,25 +33,21 @@ source_environment_tempfile="$stage/source_environment.sh" # remove_cxxstd source "$(dirname "$AUTOBUILD_VARIABLES_FILE")/functions" -VERSION_HEADER_FILE="$MINIZLIB_SOURCE_DIR/mz.h" -version=$(sed -n -E 's/#define MZ_VERSION[ ]+[(]"([0-9.]+)"[)]/\1/p' "${VERSION_HEADER_FILE}") -build=${AUTOBUILD_BUILD_ID:=0} -echo "${version}.${build}" > "${stage}/VERSION.txt" - # CMake configuration options for all platforms config=( \ -DBUILD_SHARED_LIBS=OFF \ -DMZ_BUILD_TESTS=ON \ + -DMZ_BUILD_UNIT_TESTS=ON \ -DMZ_BZIP2=OFF \ -DMZ_COMPAT=ON \ -DMZ_FETCH_LIBS=OFF \ + -DMZ_FORCE_FETCH_LIBS=OFF \ -DMZ_ICONV=OFF \ -DMZ_LIBBSD=OFF \ -DMZ_LIBCOMP=OFF \ -DMZ_LZMA=OFF \ -DMZ_OPENSSL=OFF \ -DMZ_PKCRYPT=OFF \ - -DMZ_SIGNING=OFF \ -DMZ_WZAES=OFF \ -DMZ_ZSTD=OFF \ ) @@ -63,13 +59,19 @@ pushd "$MINIZLIB_SOURCE_DIR" windows*) load_vsvars - cmake -G "$AUTOBUILD_WIN_CMAKE_GEN" -A "$AUTOBUILD_WIN_VSPLATFORM" . \ - -DCMAKE_C_FLAGS:STRING="$LL_BUILD_RELEASE" \ - -DCMAKE_CXX_FLAGS:STRING="$LL_BUILD_RELEASE" \ - "${config[@]}" \ - -DZLIB_INCLUDE_DIRS="$(cygpath -m $stage)/packages/include/zlib-ng/" \ - -DZLIB_LIBRARIES="$(cygpath -m $stage)/packages/lib/release/zlib.lib" + opts="$(replace_switch /Zi /Z7 $LL_BUILD_RELEASE)" + plainopts="$(remove_switch /GR $(remove_cxxstd $opts))" + mkdir -p "build" + pushd "build" + cmake $(cygpath -m ${top}/${MINIZLIB_SOURCE_DIR}) -G "Ninja Multi-Config" \ + -DCMAKE_C_FLAGS:STRING="$plainopts" \ + -DCMAKE_CXX_FLAGS:STRING="$opts" \ + "${config[@]}" \ + -DCMAKE_INSTALL_PREFIX=$(cygpath -m $stage) \ + -DCMAKE_INSTALL_LIBDIR="$(cygpath -m "$stage/lib/release")" \ + -DZLIB_INCLUDE_DIR="$(cygpath -m "$stage/packages/include/zlib-ng/")" \ + -DZLIB_LIBRARY="$(cygpath -m "$stage/packages/lib/release/zlib.lib")" cmake --build . --config Release @@ -78,42 +80,32 @@ pushd "$MINIZLIB_SOURCE_DIR" ctest -C Release fi - mkdir -p "$stage/lib/release" - cp -a "Release/libminizip.lib" "$stage/lib/release/" + cmake --install . --config Release - mkdir -p "$stage/include/minizip-ng" - cp -a *.h "$stage/include/minizip-ng" + mkdir -p $stage/include/minizip-ng + mv $stage/include/minizip/*.h "$stage/include/minizip-ng/" + popd ;; # ------------------------- darwin, darwin64 ------------------------- darwin*) + mkdir -p "build" + pushd "build" - opts="${TARGET_OPTS:--arch $AUTOBUILD_CONFIGURE_ARCH $LL_BUILD_RELEASE}" - - # As of version 3.0.2 (2023-05-18), we get: - # clang: warning: overriding '-mmacosx-version-min=10.13' option - # with '-target x86_64-apple-macos11.7' [-Woverriding-t-option] - # We didn't specify -target explicitly before; try setting it. - # (_find and _test_re from build-variables/functions script) - if idx=$(_find _test_re "-mmacosx-version-min=.*" $opts) - then - optarray=($opts) - versw="${optarray[$idx]}" - minver="${versw#*=}" - optarray+=(-target "x86_64-apple-macos$minver") - opts="${optarray[*]}" - fi + export MACOSX_DEPLOYMENT_TARGET="$LL_BUILD_DARWIN_DEPLOY_TARGET" - mkdir -p "$stage/lib/release" - rm -rf Resources/ ../Resources tests/Resources/ + opts="${TARGET_OPTS:--arch $AUTOBUILD_CONFIGURE_ARCH $LL_BUILD_RELEASE}" - cmake ../${MINIZLIB_SOURCE_DIR} -GXcode \ + cmake ${top}/${MINIZLIB_SOURCE_DIR} -G "Ninja Multi-Config" \ -DCMAKE_C_FLAGS:STRING="$(remove_cxxstd $opts)" \ -DCMAKE_CXX_FLAGS:STRING="$opts" \ "${config[@]}" \ -DCMAKE_INSTALL_PREFIX=$stage \ - -DZLIB_INCLUDE_DIRS="$stage/packages/include/zlib-ng/" \ - -DZLIB_LIBRARIES="$stage/packages/lib/release/libz.a" + -DCMAKE_INSTALL_LIBDIR="$stage/lib/release" \ + -DZLIB_INCLUDE_DIR="${stage}/packages/include/zlib-ng/" \ + -DZLIB_LIBRARY="${stage}/packages/lib/release/libz.a" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} \ + -DCMAKE_OSX_ARCHITECTURES="x86_64" cmake --build . --config Release @@ -122,81 +114,48 @@ pushd "$MINIZLIB_SOURCE_DIR" ctest -C Release fi - mkdir -p "$stage/lib/release" - cp -a Release/libminizip*.a* "${stage}/lib/release/" + cmake --install . --config Release - mkdir -p "$stage/include/minizip-ng" - cp -a *.h "$stage/include/minizip-ng" + mkdir -p $stage/include/minizip-ng + mv $stage/include/minizip/*.h "$stage/include/minizip-ng/" + popd ;; # -------------------------- linux, linux64 -------------------------- linux*) - - # Linux build environment at Linden comes pre-polluted with stuff that can - # seriously damage 3rd-party builds. Environmental garbage you can expect - # includes: - # - # DISTCC_POTENTIAL_HOSTS arch root CXXFLAGS - # DISTCC_LOCATION top branch CC - # DISTCC_HOSTS build_name suffix CXX - # LSDISTCC_ARGS repo prefix CFLAGS - # cxx_version AUTOBUILD SIGN CPPFLAGS - # - # So, clear out bits that shouldn't affect our configure-directed build - # but which do nonetheless. - # - unset DISTCC_HOSTS CC CXX CFLAGS CPPFLAGS CXXFLAGS - - # Prefer gcc-4.6 if available. - if [[ -x /usr/bin/gcc-4.6 && -x /usr/bin/g++-4.6 ]]; then - export CC=/usr/bin/gcc-4.6 - export CXX=/usr/bin/g++-4.6 - fi - # Prefer out of source builds - rm -rf build mkdir -p build - pushd build + pushd "build" # Default target per autobuild build --address-size opts="${TARGET_OPTS:--m$AUTOBUILD_ADDRSIZE $LL_BUILD_RELEASE}" - # Handle any deliberate platform targeting - if [ ! "${TARGET_CPPFLAGS:-}" ]; then - # Remove sysroot contamination from build environment - unset CPPFLAGS - else - # Incorporate special pre-processing flags - export CPPFLAGS="$TARGET_CPPFLAGS" - fi - - cmake ${top}/${MINIZLIB_SOURCE_DIR} -G"Unix Makefiles" \ + cmake ${top}/${MINIZLIB_SOURCE_DIR} -G"Ninja" \ -DCMAKE_C_FLAGS:STRING="$(remove_cxxstd $opts)" \ -DCMAKE_CXX_FLAGS:STRING="$opts" \ "${config[@]}" \ -DCMAKE_INSTALL_PREFIX=$stage \ - -DZLIB_INCLUDE_DIRS="$stage/packages/include/zlib-ng/" \ - -DZLIB_LIBRARIES="$stage/packages/lib/release/libz.a" + -DCMAKE_INSTALL_LIBDIR="$stage/lib/release" \ + -DZLIB_INCLUDE_DIR="${stage}/packages/include/zlib-ng/" \ + -DZLIB_LIBRARY="${stage}/packages/lib/release/libz.a" - cmake --build . --parallel 8 --config Release + cmake --build . --config Release # conditionally run unit tests if [ "${DISABLE_UNIT_TESTS:-0}" -eq 0 ]; then ctest -C Release fi - mkdir -p "$stage/lib/release" - cp -a libminizip*.a* "${stage}/lib/release/" - - mkdir -p "$stage/include/minizip-ng" - cp -a ${top}/${MINIZLIB_SOURCE_DIR}/*.h "$stage/include/minizip-ng" + cmake --install . --config Release - popd + mkdir -p $stage/include/minizip-ng + mv $stage/include/minizip/*.h "$stage/include/minizip-ng/" + popd ;; esac mkdir -p "$stage/LICENSES" - cp LICENSE "$stage/LICENSES/minizip-ng.txt" + cp ${top}/${MINIZLIB_SOURCE_DIR}/LICENSE "$stage/LICENSES/minizip-ng.txt" popd mkdir -p "$stage"/docs/minizip-ng/ diff --git a/minizip-ng b/minizip-ng new file mode 160000 index 0000000..fe5fedc --- /dev/null +++ b/minizip-ng @@ -0,0 +1 @@ +Subproject commit fe5fedc365f7824ada0cf9a84fb79b30d5fc97a8 diff --git a/minizip-ng/.github/FUNDING.yml b/minizip-ng/.github/FUNDING.yml deleted file mode 100644 index 262d117..0000000 --- a/minizip-ng/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: nmoinvaz diff --git a/minizip-ng/.github/workflows/codeql-analysis.yml b/minizip-ng/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 0f3c475..0000000 --- a/minizip-ng/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: CodeQL Analysis - -on: - push: - pull_request: - schedule: - - cron: '0 1 * * 4' - -jobs: - CodeQL-Build: - - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - # Override language selection by uncommenting this and choosing your languages - # with: - # languages: go, javascript, csharp, python, cpp, java - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/minizip-ng/.github/workflows/fuzz.yml b/minizip-ng/.github/workflows/fuzz.yml deleted file mode 100644 index da3ecca..0000000 --- a/minizip-ng/.github/workflows/fuzz.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: OSS-Fuzz -on: [pull_request] -jobs: - Fuzzing: - runs-on: ubuntu-latest - steps: - - name: Build Fuzzers - uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master - with: - oss-fuzz-project-name: 'minizip' - dry-run: true - - name: Run Fuzzers - uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master - with: - oss-fuzz-project-name: 'minizip' - fuzz-seconds: 600 - dry-run: true - - name: Upload Crash - uses: actions/upload-artifact@v1 - if: failure() - with: - name: artifacts - path: ./out/artifacts diff --git a/minizip-ng/.github/workflows/main.yml b/minizip-ng/.github/workflows/main.yml deleted file mode 100644 index f986db3..0000000 --- a/minizip-ng/.github/workflows/main.yml +++ /dev/null @@ -1,275 +0,0 @@ -name: CMake - -on: [push, pull_request] - -jobs: - ci: - name: ${{ matrix.name }} - runs-on: ${{ matrix.os }} - - strategy: - fail-fast: false - matrix: - include: - - name: Ubuntu 16 GCC 4.8 - os: ubuntu-16.04 - compiler: gcc - cmake-args: -DMZ_CODE_COVERAGE=ON - version: "4.8" - codecov: ubuntu_16_gcc_48 - - - name: Ubuntu 16 GCC - os: ubuntu-16.04 - compiler: gcc - cmake-args: -DMZ_CODE_COVERAGE=ON - codecov: ubuntu_16_gcc - - - name: Ubuntu 16 Clang 3.5 - os: ubuntu-16.04 - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON - codecov: ubuntu_16_clang_35 - version: "3.5" - packages: llvm-3.5 - gcov-exec: llvm-cov-3.5 gcov - - # No code coverage on release builds - - name: Ubuntu 16 Clang - os: ubuntu-16.04 - compiler: clang - deploy: true - deploy-name: linux - - - name: Ubuntu GCC - os: ubuntu-latest - compiler: gcc - cmake-args: -DMZ_CODE_COVERAGE=ON - codecov: ubuntu_gcc - - - name: Ubuntu GCC OSB - os: ubuntu-latest - compiler: gcc - build-dir: ../build - build-src-dir: ../minizip-ng - cmake-args: -DMZ_CODE_COVERAGE=ON - codecov: ubuntu_gcc_osb - - - name: Ubuntu Clang - os: ubuntu-latest - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON - codecov: ubuntu_clang - packages: llvm-6.0 - gcov-exec: llvm-cov-6.0 gcov - - - name: Ubuntu Clang No Zlib - os: ubuntu-latest - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_ZLIB=OFF - codecov: ubuntu_clang_no_zlib - packages: llvm-6.0 - gcov-exec: llvm-cov-6.0 gcov - - - name: Ubuntu Clang No Bzip2 - os: ubuntu-latest - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_BZIP=OFF - codecov: ubuntu_clang_no_bzip2 - packages: llvm-6.0 - gcov-exec: llvm-cov-6.0 gcov - - - name: Ubuntu Clang No LZMA - os: ubuntu-latest - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_LZMA=OFF - codecov: ubuntu_clang_no_lzma - packages: llvm-6.0 - gcov-exec: llvm-cov-6.0 gcov - - - name: Ubuntu Clang No Zstd - os: ubuntu-latest - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_ZSTD=OFF - codecov: ubuntu_clang_no_zstd - packages: llvm-6.0 - gcov-exec: llvm-cov-6.0 gcov - - - name: Ubuntu Clang No Pkcrypt - os: ubuntu-latest - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_PKCRYPT=OFF - codecov: ubuntu_clang_no_pkcrypt - packages: llvm-6.0 - gcov-exec: llvm-cov-6.0 gcov - - - name: Ubuntu Clang No Winzip AES - os: ubuntu-latest - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_WZAES=OFF - codecov: ubuntu_clang_no_winzip_aes - packages: llvm-6.0 - gcov-exec: llvm-cov-6.0 gcov - - - name: Ubuntu Clang No Encryption - os: ubuntu-latest - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_PKCRYPT=OFF -DMZ_WZAES=OFF - codecov: ubuntu_clang_no_encryption - packages: llvm-6.0 - gcov-exec: llvm-cov-6.0 gcov - - - name: Ubuntu Clang Compress Only - os: ubuntu-latest - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_COMPRESS_ONLY=ON - codecov: ubuntu_clang_compress_only - packages: llvm-6.0 - gcov-exec: llvm-cov-6.0 gcov - - - name: Ubuntu Clang Decompress Only - os: ubuntu-latest - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_DECOMPRESS_ONLY=ON - codecov: ubuntu_clang_decompress_only - packages: llvm-6.0 - gcov-exec: llvm-cov-6.0 gcov - - - name: Ubuntu Clang OpenSSL - os: ubuntu-latest - compiler: clang - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_OPENSSL=ON - codecov: ubuntu_clang_openssl - packages: llvm-6.0 - gcov-exec: llvm-cov-6.0 gcov - - # No code coverage supported - - name: Windows MSVC - os: windows-latest - compiler: cl - # Don't use find_package for 3rd party libraries which are installed incorrectly on GitHub CI instances - cmake-args: -DMZ_FORCE_FETCH_LIBS=ON - deploy: true - deploy-name: windows - - - name: Windows GCC - os: windows-latest - compiler: gcc - # Don't use find_package for 3rd party libraries which are installed incorrectly on GitHub CI instances - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_FORCE_FETCH_LIBS=ON -G Ninja - codecov: windows_gcc - - # No code coverage on release builds - - name: macOS Xcode 9.4.1 - os: macOS-latest - version: "9.4.1" - deploy: true - deploy-name: macos - - - name: macOS Xcode - os: macOS-latest - cmake-args: -DMZ_CODE_COVERAGE=ON - codecov: macos_xcode - - - name: macOS Xcode LibCompression - os: macOS-latest - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_LIBCOMP=ON - codecov: macos_xcode_libcompression - - - name: macOS Xcode OpenSSL - os: macOS-latest - cmake-args: -DMZ_CODE_COVERAGE=ON -DMZ_OPENSSL=ON -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DOPENSSL_INCLUDE_DIRS=/usr/local/opt/openssl/include -DOPENSSL_CRYPTO_LIBRARY=/usr/local/opt/openssl/lib/libcrypto.dylib -DOPENSSL_SSL_LIBRARY=/usr/local/opt/openssl/lib/libssl.dylib - codecov: macos_xcode_openssl - - steps: - - name: Checkout repository - uses: actions/checkout@v1 - - - name: Install packages (macOS) - if: runner.os == 'macOS' - run: brew install pkgconfig ${{ matrix.packages }} - - - name: Install packages (Ubuntu) - if: runner.os == 'Linux' && matrix.packages - run: | - sudo apt-get update - sudo apt-get install ${{ matrix.packages }} - - - name: Install packages (Windows) - if: runner.os == 'Windows' && matrix.codecov - run: choco install ninja --no-progress - - - name: Install codecov.io tools - if: matrix.codecov - run: python -u -m pip install codecov - - - name: Generate project files - run: | - mkdir ${{ matrix.build-dir || '.not-used' }} - cd ${{ matrix.build-dir || '.' }} - cmake ${{ matrix.build-src-dir || '.' }} -DMZ_BUILD_TESTS=ON -DMZ_BUILD_UNIT_TESTS=ON -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake-args }} - env: - CC: ${{ matrix.compiler }} - CFLAGS: ${{ matrix.cflags }} - LDFLAGS: ${{ matrix.ldflags }} - - - name: Compile source code - run: | - cd ${{ matrix.build-dir || '.' }} - cmake --build . --config ${{ matrix.build-config || 'Release' }} - - - name: Install test certificate (macOS) - if: runner.os == 'macOS' - run: sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain test/test.pem || true - - - name: Install test certificate (Windows) - if: runner.os == 'Windows' - run: certutil -addstore -enterprise Root test/test.pem - - - name: Run test cases - run: | - cd ${{ matrix.build-dir || '.' }} - ctest --output-on-failure -C ${{ matrix.build-config || 'Release' }} - # Specify test certificate for OpenSSL tests - env: - SSL_CERT_FILE: test.pem - - - name: Upload coverage report - if: matrix.codecov && env.CODECOV_TOKEN != '' - run: | - cd ${{ matrix.build-dir || '.' }} - python -m codecov -F "${{ matrix.codecov }}" --name "${{ matrix.name }}" --no-gcov-out --gcov-exec="${{ matrix.gcov-exec || 'gcov' }}" - env: - # Codecov integration does not yet support GitHub Actions - CODECOV_TOKEN: "${{secrets.CODECOV_TOKEN}}" - - - name: Package release (Ubuntu/macOS) - if: (runner.os == 'Linux' || runner.os == 'macOS') && matrix.deploy && startsWith(github.ref, 'refs/tags/') - run: ls -R mini*zip | tar -czvf minizip-ng-${{ matrix.deploy-name }}.tar.gz -T - - - - name: Upload release (Ubuntu/macOS) - uses: svenstaro/upload-release-action@v1-release - if: (runner.os == 'Linux' || runner.os == 'macOS') && matrix.deploy && startsWith(github.ref, 'refs/tags/') && env.GITHUB_TOKEN != '' - with: - asset_name: minizip-ng-${{ matrix.deploy-name }}.tar.gz - file: ${{ matrix.build-dir || '.' }}/minizip-ng-${{ matrix.deploy-name }}.tar.gz - tag: ${{ github.ref }} - repo_token: ${{ secrets.GITHUB_TOKEN }} - overwrite: true - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - - - name: Package release (Windows) - if: runner.os == 'Windows' && matrix.deploy && startsWith(github.ref, 'refs/tags/') - run: 7z a -tzip minizip-ng-${{ matrix.deploy-name }}.zip ./Release/mini*zip.exe - - - name: Upload release (Windows) - uses: svenstaro/upload-release-action@v1-release - if: runner.os == 'Windows' && matrix.deploy && startsWith(github.ref, 'refs/tags/') && env.GITHUB_TOKEN != '' - with: - asset_name: minizip-ng-${{ matrix.deploy-name }}.zip - file: ${{ matrix.build-dir || '.' }}/minizip-ng-${{ matrix.deploy-name }}.zip - tag: ${{ github.ref }} - repo_token: ${{ secrets.GITHUB_TOKEN }} - overwrite: true - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/minizip-ng/CMakeLists.txt b/minizip-ng/CMakeLists.txt deleted file mode 100644 index 4478b36..0000000 --- a/minizip-ng/CMakeLists.txt +++ /dev/null @@ -1,1015 +0,0 @@ -#*************************************************************************** -# 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.2") - -# API version -set(SOVERSION "3.0") - -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( - $<$:/Zi> - $<$:/Od> - $<$:/W3> - $<$:/Ox> - $<$:/Os>) - else() - add_compile_options( - $<$:-g> - $<$:-Wall> - $<$:-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 - $ - $) - -# 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 STREQUAL "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/minizip-ng/INDEX.md b/minizip-ng/INDEX.md deleted file mode 100644 index 86af188..0000000 --- a/minizip-ng/INDEX.md +++ /dev/null @@ -1,24 +0,0 @@ - -## Contents - -| File(s) | Description | -|:-------------------|:------------------------------------------------| -| minizip.c | Sample application | -| mz_compat.\* | Minizip 1.x compatibility layer | -| mz.h | Error codes and flags | -| mz_os\* | Platform specific file/utility functions | -| mz_crypt\* | Configuration specific crypto/hashing functions | -| mz_strm.\* | Stream interface | -| mz_strm_buf.\* | Buffered stream | -| mz_strm_bzip.\* | BZIP2 stream using libbzip2 | -| mz_strm_libcomp.\* | Apple compression stream | -| mz_strm_lzma.\* | LZMA stream using liblzma | -| mz_strm_mem.\* | Memory stream | -| mz_strm_split.\* | Disk splitting stream | -| mz_strm_pkcrypt.\* | PKWARE traditional encryption stream | -| mz_strm_os\* | Platform specific file stream | -| mz_strm_wzaes.\* | WinZIP AES stream | -| mz_strm_zlib.\* | Deflate stream using zlib | -| mz_strm_zstd.\* | ZSTD stream | -| mz_zip.\* | Zip format | -| mz_zip_rw.\* | Zip reader/writer | diff --git a/minizip-ng/LICENSE b/minizip-ng/LICENSE deleted file mode 100644 index 3b6c4e1..0000000 --- a/minizip-ng/LICENSE +++ /dev/null @@ -1,17 +0,0 @@ -Condition of use and distribution are the same as zlib: - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgement in the product documentation would be - 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. diff --git a/minizip-ng/README.md b/minizip-ng/README.md deleted file mode 100644 index 9114efc..0000000 --- a/minizip-ng/README.md +++ /dev/null @@ -1,113 +0,0 @@ -# minizip-ng 3.0.2 - -minizip-ng is a zip manipulation library written in C that is supported on Windows, macOS, and Linux. - -[![Master Branch Status](https://github.com/zlib-ng/minizip-ng/workflows/CI/badge.svg)](https://github.com/zlib-ng/minizip-ng/actions) -[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/minizip.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:minizip) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/53d48ca8fec549f4a8b39cf95cba6ad6)](https://www.codacy.com/manual/nmoinvaz/minizip?utm_source=github.com&utm_medium=referral&utm_content=nmoinvaz/minizip&utm_campaign=Badge_Grade) -[![License: Zlib](https://img.shields.io/badge/license-zlib-lightgrey.svg)](https://github.com/zlib-ng/minizip-ng/blob/master/LICENSE) -[![codecov.io](https://codecov.io/github/nmoinvaz/minizip/coverage.svg?branch=dev)](https://codecov.io/github/nmoinvaz/minizip/) - -Developed and maintained by Nathan Moinvaziri. - -## Branches - -|Name|Description| -|:-|:-| -|[master](https://github.com/zlib-ng/minizip-ng/tree/master)|Most recent release.| -|[dev](https://github.com/zlib-ng/minizip-ng/tree/dev)|Latest development code.| -|[1.2](https://github.com/zlib-ng/minizip-ng/tree/1.2)|Old changes to original minizip that includes WinZip AES encryption, disk splitting, I/O buffering and some additional fixes. Not ABI compatible with original minizip.| -|[1.1](https://github.com/zlib-ng/minizip-ng/tree/1.1)|Original minizip as of zlib 1.2.11.| - -## History - -Minizip was originally developed by [Gilles Vollant](https://www.winimage.com/zLibDll/minizip.html) in 1998. It was first included in the zlib distribution as an additional code contribution starting in zlib 1.1.2. Since that time, it has been continually improved upon and contributed to by many people. The original [project](https://github.com/madler/zlib/tree/master/contrib/minizip) can still be found in the zlib distribution that is maintained by Mark Adler. - -The motivation behind this repository has been the need for new features and bug fixes to the original library which had -not been maintained for a long period of time. The code has been largely refactored and rewritten in order to help improve maintainability and readability. A compatibility layer has been provided for consumers of the original minizip library. - -## Features - -+ Creating and extracting zip archives. -+ Adding and removing entries from zip archives. -+ Read and write raw zip entry data. -+ Reading and writing zip archives from memory. -+ Zlib, BZIP2, LZMA, XZ, and ZSTD compression methods. -+ Password protection through Traditional PKWARE and [WinZIP AES](https://www.winzip.com/aes_info.htm) encryption. -+ Buffered streaming for improved I/O performance. -+ NTFS timestamp support for UTC last modified, last accessed, and creation dates. -+ Disk split support for splitting zip archives into multiple files. -+ Preservation of file attributes across file systems. -+ Follow and store symbolic links. -+ Unicode filename support through UTF-8 encoding. -+ Legacy character encoding support CP437, CP932, CP936, CP950. -+ Turn off compilation of compression, decompression, or encryption. -+ Windows (Win32 & WinRT), macOS and Linux platform support. -+ Streaming interface for easy implementation of additional platforms. -+ Support for Apple's compression library ZLIB and XZ implementations. -+ Zero out local file header information. -+ Zip/unzip of central directory to reduce size. -+ Ability to generate and verify CMS signature for each entry. -+ Recover the central directory if it is corrupt or missing. -+ Example minizip command line tool. - -## Build - -To generate project files for your platform: - -1. [Download and install](https://cmake.org/install/) cmake (version 3.11 or later recommended). -2. Run cmake in the minizip directory. - -``` -cmake . -DMZ_BUILD_TEST=ON -cmake --build . -``` - -## Build Options - -| Name | Description | Default Value | -|:--------------------|:----------------------------------------------------|:-------------:| -| MZ_COMPAT | Enables compatibility layer | ON | -| MZ_ZLIB | Enables ZLIB compression | ON | -| MZ_BZIP2 | Enables BZIP2 compression | ON | -| MZ_LZMA | Enables LZMA & XZ compression | ON | -| MZ_ZSTD | Enables ZSTD compression | ON | -| MZ_LIBCOMP | Enables Apple compression | APPLE | -| MZ_FETCH_LIBS | Enables fetching third-party libraries if not found | WIN32 | -| MZ_FORCE_FETCH_LIBS | Enables fetching third-party libraries always | OFF | -| MZ_PKCRYPT | Enables PKWARE traditional encryption | ON | -| MZ_WZAES | Enables WinZIP AES encryption | ON | -| MZ_OPENSSL | Enables OpenSSL encryption | UNIX | -| MZ_LIBBSD | Builds with libbsd crypto random | UNIX | -| MZ_SIGNING | Enables zip signing support | ON | -| MZ_ICONV | Enables iconv encoding conversion | ON | -| MZ_COMPRESS_ONLY | Only support compression | OFF | -| MZ_DECOMPRESS_ONLY | Only support decompression | OFF | -| MZ_FILE32_API | Builds using posix 32-bit file api | OFF | -| MZ_BUILD_TESTS | Builds minizip test executable | OFF | -| MZ_BUILD_UNIT_TESTS | Builds minizip unit test project | OFF | -| MZ_BUILD_FUZZ_TESTS | Builds minizip fuzz executables | OFF | -| MZ_CODE_COVERAGE | Build with code coverage flags | OFF | -| MZ_PROJECT_SUFFIX | Project name suffix for packaging | | - -## Third-Party Libraries - -Third-party libraries may be required based on the CMake options selected. If the system already has the library -installed then it will be used, otherwise CMake will retrieve the source code for the library from its official git repository and compile it in when the `MZ_FETCH_LIBS` option is enabled. - -|Project|License|CMake Option|Comments| -|-|-|-|-| -[bzip2](https://www.sourceware.org/bzip2/)|[license](https://github.com/zlib-ng/minizip-ng/blob/dev/lib/bzip2/LICENSE)|`MZ_BZIP2`|Written by Julian Seward.| -|[liblzma](https://tukaani.org/xz/)|Public domain|`MZ_LZMA`|Written by Igor Pavlov and Lasse Collin.| -|[zlib](https://zlib.net/)|zlib|`MZ_ZLIB`|Written by Mark Adler and Jean-loup Gailly. Or alternatively, [zlib-ng](https://github.com/zlib-ng/zlib-ng) by Hans Kristian Rosbach.| -|[zstd](https://github.com/facebook/zstd)|[BSD](https://github.com/facebook/zstd/blob/dev/LICENSE)|`MZ_ZSTD`|Written by Facebook.| - -This project uses the zlib [license](LICENSE). - -## Acknowledgments - -Thanks go out to all the people who have taken the time to contribute code reviews, testing and/or patches. This project would not have been as good without you. - -Thanks to [Gilles Vollant](https://www.winimage.com/zLibDll/minizip.html) on which this work is originally based on. - -The [ZIP format](https://github.com/zlib-ng/minizip-ng/blob/master/doc/zip/appnote.txt) was defined by Phil Katz of PKWARE. diff --git a/minizip-ng/doc/README.md b/minizip-ng/doc/README.md deleted file mode 100644 index 807c3c1..0000000 --- a/minizip-ng/doc/README.md +++ /dev/null @@ -1,138 +0,0 @@ -# minizip-ng Documentation - -### Table of Contents - -- [API](#api) -- [Limitations](#limitations) -- [Xcode Instructions](#xcode-instructions) -- [Zlib Configuration](#zlib-configuration) -- [Upgrading from 1.x](#upgrading-from-1x) -- [Security Considerations](#security-considerations) - -## API - -### Constants - -|Prefix|Description| -|-|-| -|[MZ_COMPRESS_LEVEL](mz_compress_level.md)|Compression level enumeration| -|[MZ_COMPRESS_METHOD](mz_compress_method.md)|Compression method enumeration| -|[MZ_ENCODING](mz_encoding.md)|Character encoding enumeration| -|[MZ_ERROR](mz_error.md)|Error constants| -|[MZ_HASH](mz_hash.md)|Hash algorithms and digest sizes -|[MZ_HOST_SYSTEM](mz_host_system.md)|System identifiers| -|[MZ_OPEN_MODE](mz_open_mode.md)|Stream open modes| -|[MZ_SEEK](mz_seek.md)|Stream seek origins| -|[MZ_ZIP64](mz_zip64.md)|Zip64 extrafield options| - -### Interfaces - -|Name|Description| -|-|-| -|MZ_COMPAT|Old minizip 1.x compatibility layer| -|[MZ_OS](mz_os.md)|Operating system level file system operations| -|[MZ_ZIP](mz_zip.md)|Zip archive and entry interface | -|[MZ_ZIP_RW](mz_zip_rw.md)|Easy zip file extraction and creation| - -### Structures - -|Name|Description| -|-|-| -|[MZ_ZIP_FILE](mz_zip_file.md)|Zip entry information| - -### Extrafield Proposals - -The zip reader and writer interface provides support for extended hash algorithms for zip entries, compression of the central directory, and the adding and verifying of CMS signatures for each entry. In order to add support for these features, extrafields were added and are described in the [minizip extrafield documentation](mz_extrafield.md). - -## Limitations - -+ Archives are required to have a central directory unless recovery mode is enabled. -+ Central directory header values should be correct and it is necessary for the compressed size to be accurate for encryption. -+ Central directory is the only data stored on the last disk of a split-disk archive and doesn't follow disk size restrictions. - -### Third-Party Limitations - -* Windows Explorer zip extraction utility does not support disk splitting. [1](https://stackoverflow.com/questions/31286707/the-same-volume-can-not-be-used-as-both-the-source-and-destination) -* macOS archive utility does not properly support ZIP files over 4GB. [1](http://web.archive.org/web/20140331005235/http://www.springyarchiver.com/blog/topic/topic/203) [2](https://bitinn.net/10716/) - -## Xcode Instructions - -To create an Xcode project with CMake use: -``` -cmake -G Xcode . -``` - -## Zlib Configuration - -By default, if zlib is not found, it will be pulled as an external project and installed. This requires [Git](https://git-scm.com/) to be installed and available to your command interpreter. - -* To specify your own zlib repository use `ZLIB_REPOSITORY` and/or `ZLIB_TAG`. -* To specify your own zlib installation use `ZLIB_LIBRARY` and `ZLIB_INCLUDE_DIR`. - -**Compiling with Zlib-ng** - -To compile using zlib-ng use the following cmake args: - -``` --DZLIB_REPOSITORY=https://github.com/zlib-ng/zlib-ng -DZLIB_TAG=develop -``` -**Compiling and Installing Zlib (Windows)** - -To compile and install zlib to the Program Files directory with an Administrator command prompt: - -``` -cmake -DCMAKE_INSTALL_PREFIX="C:\Program Files (x86)\zlib" . -cmake --build . --config Release --target INSTALL -``` -**Configure Existing Zlib Installation (Windows)** - -To configure cmake with an existing zlib installation point cmake to your install directories: - -``` -cmake -DZLIB_LIBRARY:FILEPATH="C:\Program Files (x86)\zlib\lib\zlibstaticd.lib" . -cmake -DZLIB_INCLUDE_DIR:PATH="C:\Program Files (x86)\zlib\include" . -``` - -## Upgrading from 1.x - -If you are using CMAKE it will automatically include all the files and define all the #defines -required based on your configuration and it will also build the project files necessary for your platform. - -However, for some projects it may be necessary to drop in the new files into an existing project. In that -instance, some #defines will have to be set as they have changed. - -|1.x|2.x|Description| -|-|-|:-| -||HAVE_ZLIB|Compile with ZLIB library. Older versions of Minizip required ZLIB. It is now possible to alternatively compile only using liblzma library.| -||HAVE_LZMA|Compile with LZMA support.| -|HAVE_BZIP2|HAVE_BZIP2|Compile with BZIP2 library support.| -|HAVE_APPLE_COMPRESSION|HAVE_LIBCOMP|Compile using Apple Compression library.| -|HAVE_AES|HAVE_WZAES|Compile using AES encryption support.| -||HAVE_PKCRYPT|Compile using PKWARE traditional encryption support. Previously this was automatically assumed.| -|NOUNCRYPT|Nearest to MZ_ZIP_NO_ENCRYPTION|Previously turn off all decryption support.| -|NOCRYPT|Nearest to MZ_ZIP_NO_ENCRYPTION|Previously turned off all encryption support.| -||MZ_ZIP_NO_ENCRYPTION|Turns off all encryption/decryption support.| -|NO_ADDFILEINEXISTINGZIP||Not currently supported.| -|IOWIN32_USING_WINRT_API|MZ_WINRT_API|Enable WinRT API support in Win32 file I/O stream.| -||MZ_ZIP_NO_COMPRESSION|Intended to reduce compilation size if not using zipping functionality.| -||MZ_ZIP_NO_COMPRESSION|Intended to reduce compilation size if not using zipping functionality.| - -At a minimum HAVE_ZLIB and HAVE_PKCRYPT will be necessary to be defined for drop-in replacement. To determine which files to drop in, see the Contents section of the [README](https://github.com/zlib-ng/minizip-ng/blob/master/README.md). - -## Security Considerations - -### WinZip AES - -When compressing an archive with WinZIP AES enabled, by default it uses 256 bit encryption. During decompression whatever bit encryption was specified when the entry was added to the archive will be used. - -WinZip AES encryption uses CTR on top of ECB which prevents identical ciphertext blocks that might occur when using ECB by itself. More details about the WinZIP AES format can be found in the [winzip documentation](zip/winzip_aes.md). - -### How to Create a Secure Zip - -In order to create a secure zip file you must: - -* Use WinZIP AES encryption -* Zip the central directory -* Sign the zip file using a certificate - -The combination of using AES encryption and zipping the central directory prevents data leakage through filename exposure. diff --git a/minizip-ng/doc/mz_compress_level.md b/minizip-ng/doc/mz_compress_level.md deleted file mode 100644 index 9a859b2..0000000 --- a/minizip-ng/doc/mz_compress_level.md +++ /dev/null @@ -1,10 +0,0 @@ -# MZ_COMPRESS_LEVEL - -Compression level enumeration. - -|Name|Code|Description| -|-|-|-| -|MZ_COMPRESS_LEVEL_DEFAULT|-1|Default compression level (6)| -|MZ_COMPRESS_LEVEL_FAST|2|Fast compression level| -|MZ_COMPRESS_LEVEL_NORMAL|6|Mid compression level| -|MZ_COMPRESS_LEVEL_BEST|9|Slow compression level| \ No newline at end of file diff --git a/minizip-ng/doc/mz_compress_method.md b/minizip-ng/doc/mz_compress_method.md deleted file mode 100644 index 9dae2c1..0000000 --- a/minizip-ng/doc/mz_compress_method.md +++ /dev/null @@ -1,14 +0,0 @@ -# MZ_COMPRESS_METHOD - -Compression method enumeration. - -|Name|Code|Description| -|-|-|-| -|MZ_COMPRESS_METHOD_STORE|0|No compression| -|MZ_COMPRESS_METHOD_DEFLATE|8|Deflate compression| -|MZ_COMPRESS_METHOD_BZIP2|12|Bzip2 compression| -|MZ_COMPRESS_METHOD_LZMA|14|LZMA1 compression| -|MZ_COMPRESS_METHOD_ZSTD|93|ZSTD compression| -|MZ_COMPRESS_METHOD_XZ|95|XZ compression| - -_MZ_COMPRESS_METHOD_AES_ is only for internal use. diff --git a/minizip-ng/doc/mz_encoding.md b/minizip-ng/doc/mz_encoding.md deleted file mode 100644 index 8513fb8..0000000 --- a/minizip-ng/doc/mz_encoding.md +++ /dev/null @@ -1,11 +0,0 @@ -# MZ_ENCODING - -Character encoding enumeration. Older zip files may store the filename in a different character encoding. - -|Name|Code|Description| -|-|-|-| -|MZ_ENCODING_CODEPAGE_437|437|[Code page 437](https://en.wikipedia.org/wiki/Code_page_437)| -|MZ_ENCODING_CODEPAGE_932|932|[Code page 932](https://en.wikipedia.org/wiki/Code_page_932)| -|MZ_ENCODING_CODEPAGE_936|936|[Code page 936](https://en.wikipedia.org/wiki/Code_page_936)| -|MZ_ENCODING_CODEPAGE_950|950|[Code page 950](https://en.wikipedia.org/wiki/Code_page_950)| -|MZ_ENCODING_CODEPAGE_UTF8|65001|[UTF-8](https://en.wikipedia.org/wiki/UTF-8)| diff --git a/minizip-ng/doc/mz_error.md b/minizip-ng/doc/mz_error.md deleted file mode 100644 index 5ce5258..0000000 --- a/minizip-ng/doc/mz_error.md +++ /dev/null @@ -1,31 +0,0 @@ -# MZ_ERROR - -Error code enumeration. These errors codes are compatible with and extend zlib error codes. - -|Name|Code|Description| -|-|-|-| -|MZ_OK|0|OK error (zlib)| -|MZ_STREAM_ERROR|-1|Stream error (zlib)| -|MZ_DATA_ERROR|-3|Data error (zlib)| -|MZ_MEM_ERROR|-4|Memory allocation error (zlib)| -|MZ_BUF_ERROR|-5|Buffer error (zlib)| -|MZ_VERSION_ERROR|-6|Version error (zlib)| -|MZ_END_OF_LIST|-100|End of list error| -|MZ_END_OF_STREAM|-101|End of stream error| -|MZ_PARAM_ERROR|-102|Invalid parameter error| -|MZ_FORMAT_ERROR|-103|File format error| -|MZ_INTERNAL_ERROR|-104|Library internal error| -|MZ_CRC_ERROR|-105|CRC error| -|MZ_CRYPT_ERROR|-106|Cryptography error| -|MZ_EXIST_ERROR|-107|Does not exist error| -|MZ_PASSWORD_ERROR|-108|Invalid password error| -|MZ_SUPPORT_ERROR|-109|Library support error| -|MZ_HASH_ERROR|-110|Hash error| -|MZ_OPEN_ERROR|-111|Stream open error| -|MZ_CLOSE_ERROR|-112|Stream close error| -|MZ_SEEK_ERROR|-113|Stream seek error| -|MZ_TELL_ERROR|-114|Stream tell error| -|MZ_READ_ERROR|-115|Stream read error| -|MZ_WRITE_ERROR|-116|Stream write error| -|MZ_SIGN_ERROR|-117|Signing error| -|MZ_SYMLINK_ERROR|-118|Symbolic link error| diff --git a/minizip-ng/doc/mz_extrafield.md b/minizip-ng/doc/mz_extrafield.md deleted file mode 100644 index 4f5c7e2..0000000 --- a/minizip-ng/doc/mz_extrafield.md +++ /dev/null @@ -1,35 +0,0 @@ -# Extrafields - -These are proposals for additional extrafields that are not in the ZIP specification. - -## Hash (0x1a51) - -|Size|Type|Description| -|-|-|:-| -|2|uint16_t|Algorithm| -|2|uint16_t|Digest size| -|*|uint8_t*|Digest| - -|Value|Description| -|-|:-| -|10|MD5| -|20|SHA1| -|23|SHA256| - -By default, the ZIP specification only includes a CRC hash of the uncompressed content. The Hash extrafield allows additional hash digests of the uncompressed content to be stored with the central directory or local file headers. If there are multiple Hash extrafields stored for an entry, they should be sorted in order of most secure to least secure. So that the first Hash extrafield that appears for the entry is always the one considered the most secure and the one used for signing. - -## CMS Signature (0x10c5) - -|Size|Type|Description| -|-|-|:-| -|*|uint8_t*|Variable-length signature| - -Stores a CMS signature whose message is a hash of the uncompressed content of the entry. The hash must correspond to the first Hash (0x1a51) extrafield stored in the entry's extrafield list. - -## Central Directory (0xcdcd) - -|Size|Type|Description| -|-|-|:-| -|8|uint64_t|Number of entries| - -If the zip entry is the central directory for the archive, then this record contains information about that central directory. diff --git a/minizip-ng/doc/mz_hash.md b/minizip-ng/doc/mz_hash.md deleted file mode 100644 index fa1cb6f..0000000 --- a/minizip-ng/doc/mz_hash.md +++ /dev/null @@ -1,12 +0,0 @@ -# MZ_HASH - -Hash algorithm enumeration. The _mz_zip_reader_ and _mz_zip_writer_ instances support storing more secure hash algorithms for each zip entry. - -|Name|Code|Description| -|-|-|-| -|MZ_HASH_MD5|10|MD5 algorithm identifier| -|MZ_HASH_MD5_SIZE|16|MD5 digest size| -|MZ_HASH_SHA1|20|SHA1 algorithm identifier| -|MZ_HASH_SHA1_SIZE|20|SHA1 digest size| -|MZ_HASH_SHA256|23|SHA256 algorithm identifer| -|MZ_HASH_SHA256_SIZE|32|SHA256 digest size| diff --git a/minizip-ng/doc/mz_host_system.md b/minizip-ng/doc/mz_host_system.md deleted file mode 100644 index f9c828e..0000000 --- a/minizip-ng/doc/mz_host_system.md +++ /dev/null @@ -1,24 +0,0 @@ -# MZ_HOST_SYSTEM - -Host system enumeration. These values correspond to section 4.4.2.2 of the [PKWARE zip app note](zip/appnote.txt). - -|Name|Code|Description| -|-|-|-| -|MZ_HOST_SYSTEM_MSDOS|0|MS-DOS| -|MZ_HOST_SYSTEM_UNIX|3|UNIX| -|MZ_HOST_SYSTEM_WINDOWS_NTFS|10|Windows NTFS| -|MZ_HOST_SYSTEM_RISCOS|13|RISC OS| -|MZ_HOST_SYSTEM_OSX_DARWIN|19|Darwin| - - The host system information is available in the _version_madeby_ field in _mz_zip_file_. - -**Example** - ``` - mz_zip_file *file_info = NULL; - mz_zip_entry_get_info(zip_handle, &file_info); - int32_t host_sys = MZ_HOST_SYSTEM(file_info->version_madeby); - printf("Host system value: %d\n", host_sys); - if (host_sys == MZ_HOST_SYSTEM_MSDOS) { - printf("Zip entry attributes are MS-DOS compatible\n"); - } - ``` \ No newline at end of file diff --git a/minizip-ng/doc/mz_open_mode.md b/minizip-ng/doc/mz_open_mode.md deleted file mode 100644 index b1d01fb..0000000 --- a/minizip-ng/doc/mz_open_mode.md +++ /dev/null @@ -1,12 +0,0 @@ -# MZ_OPEN - -Stream open flag enumeration. - -|Name|Code|Description| -|-|-|-| -|MZ_OPEN_MODE_READ|0x01|Open for reading| -|MZ_OPEN_MODE_WRITE|0x02|Open for writing| -|MZ_OPEN_MODE_READWRITE|0x03|Open for reading and writing| -|MZ_OPEN_MODE_APPEND|0x04|Open for appending| -|MZ_OPEN_MODE_CREATE|0x08|Open for creating| -|MZ_OPEN_MODE_EXISTING|0x10|Open existing| \ No newline at end of file diff --git a/minizip-ng/doc/mz_os.md b/minizip-ng/doc/mz_os.md deleted file mode 100644 index b63cc60..0000000 --- a/minizip-ng/doc/mz_os.md +++ /dev/null @@ -1,859 +0,0 @@ -# MZ_OS - -These functions provide support for handling common file system operations. - -- [Path](#path) - - [mz_path_combine](#mz_path_combine) - - [mz_path_append_slash](#mz_path_append_slash) - - [mz_path_remove_slash](#mz_path_remove_slash) - - [mz_path_has_slash](#mz_path_has_slash) - - [mz_path_convert_slashes](#mz_path_convert_slashes) - - [mz_path_compare_wc](#mz_path_compare_wc) - - [mz_path_resolve](#mz_path_resolve) - - [mz_path_remove_filename](#mz_path_remove_filename) - - [mz_path_remove_extension](#mz_path_remove_extension) - - [mz_path_get_filename](#mz_path_get_filename) -- [Directory](#directory) - - [mz_dir_make](#mz_dir_make) -- [File](#file) - - [mz_file_get_crc](#mz_file_get_crc) -- [Operating System](#operating-system) - - [mz_os_unicode_string_create](#mz_os_unicode_string_create) - - [mz_os_unicode_string_delete](#mz_os_unicode_string_delete) - - [mz_os_utf8_string_create](#mz_os_utf8_string_create) - - [mz_os_utf8_string_delete](#mz_os_utf8_string_delete) - - [mz_os_rand](#mz_os_rand) - - [mz_os_rename](#mz_os_rename) - - [mz_os_unlink](#mz_os_unlink) - - [mz_os_file_exists](#mz_os_file_exists) - - [mz_os_get_file_size](#mz_os_get_file_size) - - [mz_os_get_file_date](#mz_os_get_file_date) - - [mz_os_set_file_date](#mz_os_set_file_date) - - [mz_os_get_file_attribs](#mz_os_get_file_attribs) - - [mz_os_set_file_attribs](#mz_os_set_file_attribs) - - [mz_os_make_dir](#mz_os_make_dir) - - [mz_os_open_dir](#mz_os_open_dir) - - [mz_os_read_dir](#mz_os_read_dir) - - [mz_os_close_dir](#mz_os_close_dir) - - [mz_os_is_dir](#mz_os_is_dir) - - [mz_os_is_symlink](#mz_os_is_symlink) - - [mz_os_make_symlink](#mz_os_make_symlink) - - [mz_os_read_symlink](#mz_os_read_symlink) - - [mz_os_ms_time](#mz_os_ms_time) - -## Path - -The _mz_path_ family of functions are helper functions used when constructing file system paths. - -### mz_path_combine - -Combines two paths. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|char *|path|Base path| -|const char *|join|Path to append| -|int32_t|max_path|Maximum path buffer size| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -char path[120]; -strncat(path, "c:\\windows\\", sizeof(path)); -mz_path_combine(path, "temp", sizeof(path)); -printf("Combined path: %s\n", path); -``` - -### mz_path_append_slash - -Appends a path slash on to the end of the path. To get the path slash character for the compiler platform use _MZ_PATH_SLASH_PLATFORM_ preprocessor define. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|char *|path|Path| -|int32_t|max_path|Maximum bytes to store path| -|char|slash|Path slash character| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -char path[120]; -strncat(path, "c:\\windows", sizeof(path)); -mz_path_append_slash(path, sizeof(path), MZ_PATH_SLASH_PLATFORM); -printf("Path with end slash: %s\n", path); -``` - -### mz_path_remove_slash - -Removes a path slash from the end of the path. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|char *|path|Path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -char path[120]; -strncat(path, "c:\\windows\\", sizeof(path)); -mz_path_remove_slash(path); -printf("Path with no slash: %s\n", path); -``` - -### mz_path_has_slash - -Returns whether or not the path ends with slash. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|Path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if has slash.| - -**Example** -``` -const char *path = "c:\\windows\\"; -if (mz_path_has_slash(path) == MZ_OK) - printf("Path ends with a slash\n"); -else - printf("Path does not end with a slash\n"); -``` - -### mz_path_convert_slashes - -Converts the slashes in a path. This can be used to convert all unix path slashes to windows path slashes or conver all windows path slashes to unix path slashes. If there are mixed slashes in the path, it can unify them to all one format. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|char *|path|Path| -|char|slash|Path slash character| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if has slash.| - -**Example** -``` -char path[120]; -strncat(path, "c:\\windows\\", sizeof(path)); -if (mz_path_convert_slashes(path, MZ_PATH_SLASH_UNIX) == MZ_OK) - printf("Path converted to unix slashes: %s\n", path); -``` - -### mz_path_compare_wc - -Compares two paths with a wildcard. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|Path| -|const char *|wildcard|Wildcard pattern| -|uint8_t|ignore_case|Ignore case during comparison if 1.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if matched, MZ_EXIST_ERROR if not matched.| - -**Example** -``` -const char *path = "test.txt"; -if (mz_path_compare_wc(path, "*.txt", 0) == MZ_OK) - printf("%s is a text file\n", path); -else - printf("%s is not a text file\n", path); -``` - -### mz_path_resolve - -Resolves a path. Path parts that only contain dots will be resolved. If a path part contains a single dot, it will be remoed. If a path part contains two dots, it will remove the last path part. This function can be used to prevent the _zipslip_ vulnerability and ensure that files are not written outside of their intended target. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|Path| -|char *|target|Resolved path character array| -|int32_t|max_target|Maximum size of resolved path array| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *path = "c:\\windows\\..\\"; -char target[120]; -mz_path_resolve(path, target, sizeof(target)); -printf("Resolved path: %s\n", target); -``` - -### mz_path_remove_filename - -Removes the filename from a path. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|char *|path|Path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -char path[120]; -strncpy(path, "c:\\windows\\test.txt", sizeof(path)); -printf("Path: %s\n", path); -mz_path_remove_filename(path); -printf("Path with no filename: %s\n", path); -``` - -### mz_path_remove_extension - -Remove the extension from a path. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|char *|path|Path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -char path[120]; -strncpy(path, "c:\\windows\\test.txt", sizeof(path)); -printf("Path: %s\n", path); -mz_path_remove_extension(path); -printf("Path with no file extension: %s\n", path); -``` - -### mz_path_get_filename - -Get the filename from a path. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|Path| -|const char **|filename|Pointer to filename string| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *path = "c:\\windows\\test.txt"; -const char *filename = NULL; -printf("Path: %s\n", path); -if (mz_path_get_filename(path, &filename) == MZ_OK) - printf("Filename: %s\n", filename); -else - printf("Path has no filename\n"); -``` - -## Directory - -### mz_dir_make - -Creates a directory recursively. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|Path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *path = "c:\\temp\\x\\y\\z\\"; -if (mz_dir_make(path) == MZ_OK) - printf("Dir was created: %s\n", path); -else - printf("Dir was not created: %s\n", path); -``` - -## File - -### mz_file_get_crc - -Gets the crc32 hash of a file. This function helps provide functional backwards compatibility. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|Path to calculate CRC value for| -|uint32_t *|result_crc|Pointer to store the calculated CRC value| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *path = "c:\\temp\\test.txt"; -uint32_t crc = 0; -if (mz_file_get_crc(path, &crc) == MZ_OK) - printf("File %s CRC: %08x\n", path, crc); -else - printf("Failed to calculate CRC: %s\n", path); -``` - -## Operating System - -The _mz_os_ family of functions wrap all platform specific code necessary to zip and unzip files. - -### mz_os_unicode_string_create - -Create unicode string from a string with another encoding. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|string|String to convert| -|int32_t|encoding|String encoding (See [MZ_ENCODING](mz_encoding.md))| - -**Return** -|Type|Description| -|-|-| -|wchar_t *|Returns pointer to unicode string if successful, otherwise NULL.| - -**Example** -``` -char *test = "test"; -wchar_t *test_unicode = mz_os_unicode_string_create(test, MZ_ENCODING_UTF8); -if (test_unicode != NULL) { - printf("Unicode test string created\n"); - mz_os_unicode_string_delete(&test_unicode); -} -``` - -### mz_os_unicode_string_delete - -Delete a unicode string that was created with _mz_os_unicode_string_create_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|wchar_t **|string|Pointer to unicode string| - -**Example** -``` -char *test = "test"; -wchar_t *test_unicode = mz_os_unicode_string_create(test, MZ_ENCODING_UTF8); -if (test_unicode != NULL) { - printf("Unicode test string created\n"); - mz_os_unicode_string_delete(&test_unicode); -} -``` - -### mz_os_utf8_string_create - -Create a utf8 string from a string with another encoding. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|string|String to convert| -|int32_t|encoding|String encoding (See [MZ_ENCODING](mz_encoding.md))| - -**Return** -|Type|Description| -|-|-| -|uint8_t *|Returns pointer to UTF-8 encoded string if successful, otherwise NULL.| - -**Example** -``` -char *test = "test"; -wchar_t *test_utf8 = mz_os_utf8_string_create(test, MZ_ENCODING_CODEPAGE_437); -if (test_utf8 != NULL) { - printf("UTF-8 test string created\n"); - mz_os_utf8_string_create(&test_utf8); -} -``` - -### mz_os_utf8_string_delete - -Delete a utf8 string that was created with _mz_os_utf8_string_create_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|uint8_t **|string|Pointer to utf8 encoded string| - -**Example** -``` -char *test = "test"; -wchar_t *test_utf8 = mz_os_utf8_string_create(test, MZ_ENCODING_CODEPAGE_437); -if (test_utf8 != NULL) { - printf("UTF-8 test string created\n"); - mz_os_utf8_string_create(&test_utf8); -} -``` - -### mz_os_rand - -Random number generator (not cryptographically secure). For a cryptographically secure random number generator use _mz_crypt_rand_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|uint8_t *|buf|Buffer to fill with random data| -|int32_t|size|Maximum size of buffer array| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -uint8_t buf[120]; -if (mz_os_rand(buf, sizeof(buf)) == MZ_OK) - printf("%d bytes of random data generated\n", sizeof(buf)); -``` - -### mz_os_rename - -Rename a file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|source_path|Original path| -|const char *|target_path|New path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -if (mz_os_rename("c:\\test1.txt", "c:\\test2.txt") == MZ_OK) - printf("File was renamed successfully\n"); -``` - -### mz_os_unlink - -Delete an existing file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|File path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -if (mz_os_unlink("c:\\test2.txt") == MZ_OK) - printf("File was deleted successfully\n"); -``` - -### mz_os_file_exists - -Check to see if a file exists. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|File path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *path = "c:\\test2.txt"; -if (mz_os_file_exists(path) == MZ_OK) - printf("File %s exists\n", path); -else - printf("File %s does not exist\n", path); -``` - -### mz_os_get_file_size - -Gets the length of a file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|File path| - -**Return** -|Type|Description| -|-|-| -|int64_t|Size of file, does not check for existence of file.| - -**Example** -``` -const char *path = "c:\\test3.txt"; -if (mz_os_file_exists(path) == MZ_OK) { - int64_t file_size = mz_os_get_file_size(path); - printf("File %s size %lld\n", path, file_size); -} else { - printf("File %s does not exist\n", path); -} -``` - -### mz_os_get_file_date - -Gets a file's modified, access, and creation dates if supported. Creation date is not supported on Linux based systems and zero is returned for _creation_date_ on those systems. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|File path| -|time_t *|modified_date|Pointer to store file's modified unix timestamp| -|time_t *|accessed_date|Pointer to store file's accessed unix timestamp| -|time_t *|creation_date|Pointer to store file's creation unix timestamp| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *path = "c:\\test4.txt"; -time_t modified_date, accessed_date, creation_date; -if (mz_os_get_file_date(path, &modified_date, &accessed_date, &creation_date) == MZ_OK) - printf("File %s modified %lld accessed %lld creation %lld\n", path, modified_date, accessed_date, creation_date); -``` - -### mz_os_set_file_date - -Sets a file's modified, access, and creation dates if supported. Creation date is not supported on Linux based systems. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|File path| -|time_t|modified_date|File's modified unix timestamp| -|time_t|accessed_date|File's accessed unix timestamp| -|time_t|creation_date|File's creation unix timestamp| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *src_path = "c:\\test4.txt"; -const char *target_path = "c:\\test5.txt"; -time_t modified_date, accessed_date, creation_date; -if (mz_os_get_file_date(src_path, &modified_date, &accessed_date, &creation_date) == MZ_OK) { - printf("Source file %s modified %lld accessed %lld creation %lld\n", path, modified_date, accessed_date, creation_date); - if (mz_os_set_file_date(target_path, modified_date, accessed_date, creation_date) == MZ_OK) { - printf("Target file dates changed successfully\n"); - } -} -``` - -### mz_os_get_file_attribs - -Gets a file's attributes. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|File path| -|uint32_t *|attributes|Pointer to store file attributes value| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *path = "c:\\test6.txt"; -uint32_t attributes = 0; -if (mz_os_get_file_attribs(path, &attributes) == MZ_OK) - printf("File %s attributes %08x\n", attributes); -``` - -### mz_os_set_file_attribs - -Sets a file's attributes. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|File path| -|uint32_t|attributes|File attributes value| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *path = "c:\\test6.txt"; -uint32_t attributes = 0; -if (mz_os_get_file_attribs(path, &attributes) == MZ_OK) { - printf("File %s attributes %08x\n", attributes); - attributes |= FILE_ATTRIBUTE_READONLY; - if (mz_os_set_file_attribs(path, attributes) == MZ_OK) { - printf("File changed to readonly\n"); - } -} -``` - -### mz_os_make_dir - -Creates a directory. To recursively create a directory use _mz_dir_make_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|Directory path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -if (mz_os_make_dir("c:\\testdir\\") == MZ_OK) - printf("Test directory created\n"); -``` - -### mz_os_open_dir - -Opens a directory for listing. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|Directory path| - -**Return** -|Type|Description| -|-|-| -|DIR *|Directory enumeration handle, returns NULL if error.| - -**Example** -``` -const char *search_dir = "c:\\test1\\"; -DIR *dir = mz_open_dir(search_dir); -if (dir != NULL) { - printf("Dir %s was opened\n", search_dir); - mz_os_close_dir(dir); -} -``` - -### mz_os_read_dir - -Reads a directory listing entry. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|DIR *|dir|Directory enumeration handle| - -**Return** -|Type|Description| -|-|-| -|struct dirent *|Pointer to directory entry information structure. To get the name of the directory use the _d_name_ structure field.| - -**Example** -``` -const char *search_dir = "c:\\test2\\"; -DIR *dir = mz_open_dir(search_dir); -if (dir != NULL) { - struct dirent *entry = NULL; - printf("Dir %s was opened\n", search_dir); - while ((entry = mz_os_read_dir(dir)) != NULL) { - printf("Dir entry: %s was opened\n", entry->d_name); - } - mz_os_close_dir(dir); -} -``` - -### mz_os_close_dir - -Closes a directory that has been opened for listing. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|DIR *|dir|Directory enumeration handle| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *search_dir = "c:\\test3\\"; -DIR *dir = mz_open_dir(search_dir); -if (dir != NULL) { - struct dirent *entry = NULL; - printf("Dir %s was opened\n", search_dir); - while ((entry = mz_os_read_dir(dir)) != NULL) { - printf("Dir entry: %s was opened\n", entry->d_name); - } - mz_os_close_dir(dir); -} -``` - -### mz_os_is_dir - -Checks to see if path is a directory. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|File system path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if it is a directory.| - -**Example** -``` -const char *path = "c:\\test7.txt"; -if (mz_os_is_dir(path) == MZ_OK) - printf("Path %s is a directory\n", path); -else - printf("Path %s is not a directory\n", path); -``` - -### mz_os_is_symlink - -Checks to see if path is a symbolic link. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|File system path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if it is a symbolic link.| - -**Example** -``` -const char *path = "c:\\test7.txt"; -if (mz_os_is_symlink(path) == MZ_OK) - printf("Path %s is a symbolic link\n", path); -else - printf("Path %s is not a symbolic link\n", path); -``` - -### mz_os_make_symlink - -Creates a symbolic link pointing to a target. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|Link path| -|const char *|target_path|Actual path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *path = "c:\\test7.txt"; -const char *target_path = "c:\\test8.txt"; -if (mz_os_make_symlink(path, target_path) == MZ_OK) - printf("Symbolic link created at %s pointing to %s\n", path, target_path); -``` - -### mz_os_read_symlink - -Gets the target path for a symbolic link. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path|Link path| -|char *|target_path|Actual path| -|int32_t|max_path|Maximum bytes to store actual path| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *path = "c:\\test7.txt"; -const char *target_path = "c:\\test8.txt"; -if (mz_os_make_symlink(path, target_path) == MZ_OK) { - char actual_path[120]; - printf("Symbolic link created at %s pointing to %s\n", path, target_path); - if (mz_os_read_symlink(path, actual_path, sizeof(actual_path)) == MZ_OK) { - if (strcmp(target_path, actual_path) == 0) { - printf("Confirmed symbolic link created\n"); - } - } -} -``` - -### mz_os_ms_time - -Gets the time in milliseconds. - -**Return** -|Type|Description| -|-|-| -|uint64_t|Current time in milliseconds| - -**Example** -``` -uint64_t current_time = mz_os_ms_time(); -printf("Current time in %lldms\n", current_time); -``` diff --git a/minizip-ng/doc/mz_seek.md b/minizip-ng/doc/mz_seek.md deleted file mode 100644 index 8071c25..0000000 --- a/minizip-ng/doc/mz_seek.md +++ /dev/null @@ -1,9 +0,0 @@ -# MZ_SEEK - -Stream seek origin enumeration. - -|Name|Code|Description| -|-|-|-| -|MZ_SEEK_SET|0|Seek from beginning| -|MZ_SEEK_CUR|1|Seek from current position| -|MZ_SEEK_END|2|Seek from end| \ No newline at end of file diff --git a/minizip-ng/doc/mz_zip.md b/minizip-ng/doc/mz_zip.md deleted file mode 100644 index 388ba86..0000000 --- a/minizip-ng/doc/mz_zip.md +++ /dev/null @@ -1,1597 +0,0 @@ -# MZ_ZIP - -The _mz_zip_ object allows for the reading and writing of the a zip file and its entries. - -- [Archive](#archive) - - [mz_zip_create](#mz_zip_create) - - [mz_zip_delete](#mz_zip_delete) - - [mz_zip_open](#mz_zip_open) - - [mz_zip_close](#mz_zip_close) - - [mz_zip_get_comment](#mz_zip_get_comment) - - [mz_zip_set_comment](#mz_zip_set_comment) - - [mz_zip_get_version_madeby](#mz_zip_get_version_madeby) - - [mz_zip_set_version_madeby](#mz_zip_set_version_madeby) - - [mz_zip_set_recover](#mz_zip_set_recover) - - [mz_zip_set_data_descriptor](#mz_zip_set_data_descriptor) - - [mz_zip_get_stream](#mz_zip_get_stream) - - [mz_zip_set_cd_stream](#mz_zip_set_cd_stream) - - [mz_zip_get_cd_mem_stream](#mz_zip_get_cd_mem_stream) - - [mz_zip_set_number_entry](#mz_zip_set_number_entry) - - [mz_zip_get_number_entry](#mz_zip_get_number_entry) - - [mz_zip_set_disk_number_with_cd](#mz_zip_set_disk_number_with_cd) - - [mz_zip_get_disk_number_with_cd](#mz_zip_get_disk_number_with_cd) -- [Entry I/O](#entry-io) - - [mz_zip_entry_is_open](#mz_zip_entry_is_open) - - [mz_zip_entry_read_open](#mz_zip_entry_read_open) - - [mz_zip_entry_read](#mz_zip_entry_read) - - [mz_zip_entry_read_close](#mz_zip_entry_read_close) - - [mz_zip_entry_write_open](#mz_zip_entry_write_open) - - [mz_zip_entry_write](#mz_zip_entry_write) - - [mz_zip_entry_write_close](#mz_zip_entry_write_close) - - [mz_zip_entry_seek_local_header](#mz_zip_entry_seek_local_header) - - [mz_zip_entry_close_raw](#mz_zip_entry_close_raw) - - [mz_zip_entry_close](#mz_zip_entry_close) -- [Entry Enumeration](#entry-enumeration) - - [mz_zip_entry_is_dir](#mz_zip_entry_is_dir) - - [mz_zip_entry_is_symlink](#mz_zip_entry_is_symlink) - - [mz_zip_entry_get_info](#mz_zip_entry_get_info) - - [mz_zip_entry_get_local_info](#mz_zip_entry_get_local_info) - - [mz_zip_get_entry](#mz_zip_get_entry) - - [mz_zip_goto_entry](#mz_zip_goto_entry) - - [mz_zip_goto_first_entry](#mz_zip_goto_first_entry) - - [mz_zip_goto_next_entry](#mz_zip_goto_next_entry) - - [mz_zip_locate_entry](#mz_zip_locate_entry) - - [mz_zip_locate_first_entry](#mz_zip_locate_first_entry) - - [mz_zip_locate_next_entry](#mz_zip_locate_next_entry) -- [System Attributes](#system-attributes) - - [mz_zip_attrib_is_dir](#mz_zip_attrib_is_dir) - - [mz_zip_attrib_is_symlink](#mz_zip_attrib_is_symlink) - - [mz_zip_attrib_convert](#mz_zip_attrib_convert) - - [mz_zip_attrib_posix_to_win32](#mz_zip_attrib_posix_to_win32) - - [mz_zip_attrib_win32_to_posix](#mz_zip_attrib_win32_to_posix) -- [Extrafield](#extrafield) - - [mz_zip_extrafield_find](#mz_zip_extrafield_find) - - [mz_zip_extrafield_contains](#mz_zip_extrafield_contains) - - [mz_zip_extrafield_read](#mz_zip_extrafield_read) - - [mz_zip_extrafield_write](#mz_zip_extrafield_write) -- [Time/Date](#timedate) - - [mz_zip_dosdate_to_tm](#mz_zip_dosdate_to_tm) - - [mz_zip_dosdate_to_time_t](#mz_zip_dosdate_to_time_t) - - [mz_zip_time_t_to_tm](#mz_zip_time_t_to_tm) - - [mz_zip_time_t_to_dos_date](#mz_zip_time_t_to_dos_date) - - [mz_zip_tm_to_dosdate](#mz_zip_tm_to_dosdate) - - [mz_zip_ntfs_to_unix_time](#mz_zip_ntfs_to_unix_time) - - [mz_zip_unix_to_ntfs_time](#mz_zip_unix_to_ntfs_time) -- [Path](#path) - - [mz_zip_path_compare](#mz_zip_path_compare) -- [String](#string) - - [mz_zip_get_compression_method_string](#mz_zip_get_compression_method_string) - -## Archive - -### mz_zip_create - -Creates a _mz_zip_ instance and returns its pointer. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void **|handle|Pointer to store the _mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|void *|Pointer to the _mz_zip_ instance| - -**Example** -``` -void *zip_handle = NULL; -mz_zip_create(&zip_handle); -``` - -### mz_zip_delete - -Deletes a _mz_zip_ instance and resets its pointer to zero. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void **|handle|Pointer to the _mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -void *zip_handle = NULL; -mz_zip_create(&zip_handle); -mz_zip_delete(&zip_handle); -``` - -### mz_zip_open - -Opens a zip file given a stream. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|void *|stream|_mz_stream_ instance| -|int32_t|mode|Open mode (See [MZ_OPEN_MODE](mz_open_mode.md))| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -void *zip_handle = NULL; - -// TODO: Create stream - -mz_zip_create(&zip_handle); -err = mz_zip_open(zip_handle, stream, MZ_OPEN_MODE_READ); -if (err != MZ_OK) - printf("Error opening zip file for reading\n"); -else - mz_zip_close(zip_handle); -mz_zip_delete(&zip_handle); - -// TODO: Delete stream -``` - -### mz_zip_close - -Close a zip file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -// TODO: Create and open mz_zip instance -mz_zip_close(zip_handle); -mz_zip_delete(&zip_handle); -``` - -### mz_zip_get_comment - -Gets the zip file's global comment string. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|const char **|comment|Pointer to null-terminated comment character array| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *global_comment = NULL; -if (mz_zip_get_comment(zip_handle, &global_comment) == MZ_OK) - printf("Zip file global comment: %s\n", global_comment); -else - printf("Zip file does not contain a global comment\n"); -``` - -### mz_zip_set_comment - -Sets the zip file's global comment string when the zip file is opened for writing. According to the zip file specification, each zip file can store a global comment with a maximum length of _UINT16_MAX_ or 65535 characters. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|const char *|comment|Null-terminated comment character array| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *global_comment = "Hi! This is my zip file."; -if (mz_zip_set_comment(zip_handle, global_comment) == MZ_OK) - printf("Successfully set the zip file's global comment\n"); -``` - -### mz_zip_get_version_madeby - -Gets the zip file's version information. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|uint16_t *|version_madeby|Pointer to version value (See [PKWARE zip app note](zip/appnote.txt) 4.4.2)| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -uint16_t version_madeby = 0; -if (mz_zip_get_version_madeby(zip_handle, &version_madeby) == MZ_OK) { - printf("Zip eocd version made by: %04x\n", version_madeby); - printf("Zip eocd host system: %d\n", MZ_HOST_SYSTEM(version_madeby)); - printf("Zip eocd app note version: %d\n", (version_madeby & 0xFF)); -} -``` - -### mz_zip_set_version_madeby - -Sets the zip file's version information. The application that original wrote the zip file would have set this value to indicate what operating system and version of the zip specification that was used when making it. This version is stored in the end of central directory record; there is another similar _version_madeby_ stored for each zip entry. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|uint16_t|version_madeby|Version value (See [PKWARE zip app note](zip/appnote.txt) 4.4.2)| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -mz_zip_set_version_madeby(zip_handle, MZ_VERSION_MADEBY); -// MZ_VERSION_MADEBY is the macro use to represent the version made by for the host system -uint16_t custom_version_madeby = ((MZ_HOST_SYSTEM_WINDOWS_NTFS << 8) | 45) -mz_zip_set_version_madeby(zip_handle, custom_version_madeby); -``` - -### mz_zip_set_recover - -Sets the ability to recover/repair the central directory. When the central directory is damaged or incorrectly written, it may be possible to recover it by reading the local file headers. Reading all of the local file headers can be a disk intensive operation and take significant time for large files. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|uint8_t|recover|Set to 1 to enable central directory recover, set to 0 otherwise.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -void *zip_handle = NULL; -mz_zip_create(&zip_handle); -// Enable central directory recover/repair -if (mz_zip_set_recover(zip_handle, 1) == MZ_OK) - printf("Central directory recovery enabled if necessary\n"); -``` - -### mz_zip_set_data_descriptor - -Sets wehther or not zip file entries will be written with a data descriptor. When data descriptor writing is enabled it will zero out the crc32, compressed size, and uncompressed size in the local header. By default data descriptor writing is enabled and disabling it will cause zip file entry writing to seek backwards to fill in these values after writing the compressed data. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|uint8_t|data_descriptor|Set to 1 to enable data descriptor writing, set to 0 otherwise.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -void *zip_handle = NULL; -mz_zip_create(&zip_handle); -// Enable data descriptor writing for zip entries -if (mz_zip_set_data_descriptor(zip_handle, 0) == MZ_OK) - printf("Local file header entries will be written with crc32 and sizes\n"); -``` - -### mz_zip_get_stream - -Gets the _mz_stream_ handle used in the call to _mz_zip_open_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|void **|stream|Pointer to _mz_stream_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -void *zip_handle = NULL; -mz_zip_create(&zip_handle); -if (mz_zip_open(zip_handle, stream_handle, MZ_OPEN_MODE_READ) == MZ_OK) { - void *stream2_handle = NULL; - mz_zip_get_stream(zip_handle, &stream2_handle); - assert(stream_handle == stream2_handle); -} -``` - -### mz_zip_set_cd_stream - -Sets the stream to use for reading the central directory. - -The central directory stream might not be the same as the stream used for reading local file entries. In the case of split disks, they are different and handles to both are open at the same time to keep from opening and closing streams while reading entries. - -This function is used when encrypting the central directory, it is decrypted and extracted into a memory stream, and that memory stream is set as the central directory stream. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|int64_t|cd_start_pos|Start position of central directory in the stream| -|void *|cd_stream|_mz_stream_ instance to use for reading central directory. The cd_stream must be valid as long as it is being used by _mz_zip_.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -void *cd_mem_stream = NULL; -mz_stream_mem_create(&cd_mem_stream); -// TODO: Write central directory to memory stream -mz_zip_set_cd_stream(zip_handle, 0, cd_mem_stream); -``` - -### mz_zip_get_cd_mem_stream - -Gets the stream used to store the central directory in memory for writing. - -When writing to a zip file the central directory is written to this memory stream and written after all entries are written. When a zip file is opened for appending, the central directory is stored in memory while the appending new zip entries. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|void *|cd_stream|Pointer to _mz_stream_ instance that is used for writing the central directory.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -// TODO: Open zip file for writing and write at least one entry -void *cd_mem_stream = NULL; -if (mz_zip_get_cd_mem_stream(zip_handle, &cd_mem_stream) == MZ_OK) { - int64_t org_position = mz_stream_tell(cd_mem_stream); - mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_END); - int64_t cd_length = mz_stream_tell(cd_mem_stream); - mz_stream_seek(cd_mem_stream, org_position, MZ_SEEK_SET); - printf("Length of central directory to write: %d\n", cd_length); -} -``` - -### mz_zip_set_number_entry - -Sets the total number of entries in the zip file. Useful when loading central directory manually via _mz_zip_set_cd_stream_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|uint64_t|number_entry|Total number of entries in central directory| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -// TODO: Load central directory into memory stream -mz_zip_set_cd_stream(zip_handle, 0, cd_mem_stream); -mz_zip_set_number_entry(zip_handle, 10); -``` - -### mz_zip_get_number_entry - -Gets the total number of entries in the zip file after it has been opened. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|uint64_t|number_entry|Pointer to store total number of entries in central directory| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -uint64_t number_entry = 0; - -// TODO: Open zip file - -if (mz_zip_get_number_entry(zip_handle, &number_entry) == MZ_OK) - printf("Total number of entries in zip file %d\n", number_entry); -``` - -### mz_zip_set_disk_number_with_cd - -Sets the disk number containing the central directory record. Useful for when loading the central directory manually using _mz_zip_set_cd_stream_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|uint32_t|disk_number_with_cd|Disk number containing the central directory| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -// TODO: Load central directory into memory stream -mz_zip_set_cd_stream(zip_handle, 0, cd_mem_stream); -mz_zip_set_number_entry(zip_handle, 10); -mz_zip_set_disk_number_with_cd(zip_handle, 0); -``` -### mz_zip_get_disk_number_with_cd - -Gets the disk number containing the central directory. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|uint32_t *|disk_number_with_cd|Pointer to store disk number containing the central directory| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -uint32_t disk_number_with_cd = 0; -// TODO: Open zip file -if (mz_zip_get_disk_number_with_cd(zip_handle, &disk_number_with_cd) == MZ_OK) - printf("Disk number containing cd: %d\n", disk_number_with_cd); -``` - -## Entry I/O - -### mz_zip_entry_is_open - -Gets whether or not a zip entry is open for reading or writing. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if open| - -**Example** -``` -// TODO: Open zip file -if (mz_zip_entry_is_open(zip_handle) == MZ_OK) - printf("Zip entry is open for reading or writing\n"); -``` - -### mz_zip_entry_read_open - -Opens for reading the current entry in the zip file. To navigate to an entry use _mz_zip_goto_first_entry_, _mz_zip_goto_next_entry_, or _mz_zip_locate_entry_. - -Normally, when reading from a zip entry, the data will be automatically decrypted and decompressed. To read the raw zip entry data, set the raw parameter to 1. This is useful if you want access to the raw gzip data (assuming the entry is gzip compressed). - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|uint8_t|raw|Open for raw reading if 1.| -|const char *|password|Null-terminated password character array, or NULL if no password needed for reading.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if entry opened for reading.| - -**Example** -``` -err = mz_zip_goto_first_entry(zip_handle); -if (err == MZ_OK) - err = mz_zip_entry_read_open(zip_handle, 0, NULL); -if (err == MZ_OK) - printf("Zip entry open for reading\n"); -``` - -### mz_zip_entry_read - -Reads bytes from the current entry in the zip file. The data returned in the buffer will be the decrypted and decompressed bytes unless the entry is opened for raw data reading. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|void *|buf|Read buffer array| -|int32_t|len|Maximum bytes to read.| - -**Return** -|Type|Description| -|-|-| -|int32_t|If < 0 then [MZ_ERROR](mz_error.md) code, otherwise number of bytes read. When there are no more bytes left to read then 0 is returned.| - -**Example** -``` -int32_t bytes_read; -int32_t err = MZ_OK; -char buf[4096]; -do { - bytes_read = mz_zip_entry_read(zip_handle, buf, sizeof(buf)); - if (bytes_read < 0) { - err = bytes_read; - } - // TODO: Do something with buf bytes -} while (err == MZ_OK && bytes_read > 0); -``` - -### mz_zip_entry_read_close - -Closes the current entry in the zip file for reading and returns the data descriptor values if the zip entry has the data descriptor flag set. If the data descriptor values are not necessary, _mz_zip_entry_close_ can be used instead. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|uint32_t *|crc32|Pointer to store crc32 value from data descriptor. Use NULL if not needed.| -|int64_t *|compressed_size|Pointer to store compressed size from data descriptor. Use NULL if not needed.| -|int64_t *|uncompressed_size|Pointer to store uncompressed size from data descriptor. Use NULL if not needed.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -uint32_t crc32 = 0; -int64_t compressed_size = 0; -int64_t uncompressed_size = 0; -int32_t err = mz_zip_entry_read_close(zip_handle, &crc32, &compressed_size, &uncompressed_size); -if (err == MZ_OK) { - printf("Zip entry crc32: %08x\n", crc32); - printf("Zip entry compressed size: %lld\n", compressed_size); - printf("Zip entry uncompressed size: %lld\n", uncompressed_size); -} else { - printf("Unknown error closing zip entry for reading (%d)\n", err); -} -``` - -### mz_zip_entry_write_open - -Opens for a new entry in the zip file for writing. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|const mz_zip_file *|file_info|Pointer to [_mz_zip_file_](mz_zip_file.md) structure containing information about entry being added.| -|int16_t|compress_level|Compression level 0-9. Higher is better compression. (See [MZ_COMPRESS_LEVEL](mz_compress_level.md))| -|uint8_t|raw|Write raw data if 1, otherwise the data will be compressed and encrypted based on supplied parameters.| -|const char *|password|Null-terminated password character array. Use NULL if encryption not required.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if entry opened for writing.| - -**Example** - -See _mz_zip_writer_add_file_ for a full example on how to populate the [mz_zip_file](mz_zip_file.md) structure. -``` -mz_zip_file file_info; - -memset(&file_info, 0, sizeof(file_info)); - -file_info.version_madeby = MZ_VERSION_MADEBY; -file_info.compression_method = MZ_COMPRESS_METHOD_DEFLATE; -file_info.filename = "myfile.txt"; -file_info.flag = MZ_ZIP_FLAG_UTF8; -... - -err = mz_zip_entry_write_open(zip_handle, &file_info, 0, NULL); -if (err == MZ_OK) - printf("Zip entry open for writing\n"); -``` - -### mz_zip_entry_write - -Write data to the current entry in the zip file that was opened for writing. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|void *|buf|Write buffer array| -|int32_t|len|Maximum bytes to write.| - -**Return** -|Type|Description| -|-|-| -|int32_t|If < 0 then [MZ_ERROR](mz_error.md) code, otherwise number of bytes written.| - -**Example** -``` -char buf[4096]; -int32_t bytes_to_write = sizeof(buf); -int32_t bytes_written = 0; -int32_t total_bytes_written = 0; -int32_t err = MZ_OK; -// Fill buf with x'es -memset(buf, 'x', sizeof(buf)); -do { - bytes_written = mz_zip_entry_write(zip_handle, buf + total_bytes_written, - bytes_to_write); - if (bytes_written < 0) { - err = bytes_written; - } else { - total_bytes_written += bytes_written; - bytes_to_write -= bytes_written; - } -} while (err == MZ_OK && bytes_to_write > 0); -``` - -### mz_zip_entry_write_close - -Closes the current entry in the zip file for writing and allows setting the data descriptor values if the zip entry has the data descriptor flag set. If the data descriptor values are not necessary, _mz_zip_entry_close_ can be used instead. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|uint32_t|crc32|Crc32 value to store in the data descriptor.| -|int64_t|compressed_size|Compressed size to store in the data descriptor.| -|int64_t|uncompressed_size|Uncompressed size to store in the data descriptor.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -uint32_t crc32 = 0; -int64_t compressed_size = 0; -int64_t uncompressed size = 0; -// TODO: Calculate crc32, compressed size, and uncompressed size -int32_t err = mz_zip_entry_write_close(zip_handle, crc32, compressed_size, uncompressed_size); -if (err == MZ_OK) - printf("Zip file entry closed for writing\n"); -``` - -### mz_zip_entry_seek_local_header -Seeks to the local header for the entry. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -int32_t err = mz_zip_goto_first_entry(zip_handle); -if (err == MZ_OK) - err = mz_zip_entry_seek_local_header(zip_handle); -if (err == MZ_OK) { - void *stream = NULL; - mz_zip_get_stream(zip_handle, &stream); - int64_t position = mz_stream_tell(stream); - printf("Position of local header of first entry: %lld\n", position); -} -``` - -### mz_zip_entry_close_raw - -Closes the current entry in the zip file. To be used to close an entry that has been opened for reading or writing in raw mode. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|int64_t|uncompressed_size|Uncompressed size to store in the data descriptor. Only used when entry was opened for writing.| -|uint32_t|crc32|Crc32 value to store in the data descriptor. Only used when entry was opened for writing.| - -Compressed size is already known through calls to _mz_zip_entry_write_. - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -#include -int32_t err = mz_zip_entry_read_write(zip_handle, &file_info, 1, NULL); -if (err == MZ_OK) { - z_stream zs; - int32_t my_string_crc32; - int32_t my_string_size; - char buf[4096]; - char *my_string = "mystring"; - - my_string_size = strlen(my_string); - my_string_crc32 = crc32(0, my_string, my_string_size); - - memset(&zs, 0, sizeof(zs)); - - zs.zalloc = Z_NULL; - zs.zfree = Z_NULL; - zs.opaque = Z_NULL; - zs.avail_in = my_string_size; - zs.next_in = my_string; - zs.avail_out = sizeof(buf); - zs.next_out = buf; - - deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY); - err = deflate(&zs, Z_FINISH); - deflateEnd(&zs); - - mz_zip_entry_write(zip_handle, buf, zs.total_out); - mz_zip_entry_close_raw(zip_handle, my_string_size, my_string_crc32); -} -``` - -### mz_zip_entry_close - -Closes the current entry in the zip file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -int32_t err = mz_zip_entry_close(zip_handle); -if (err == MZ_OK) - printf("Zip entry closed\n"); -``` - -## Entry Enumeration - -### mz_zip_entry_is_dir - -When enumerating zip entries, returns whether or not the current entry is a directory. This function accounts for the various directory attribute values on each OS. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if entry is a directory.| - -**Example** -``` -int32_t err = mz_zip_goto_first_entry(zip_handle); -if (err == MZ_OK) { - if (mz_zip_entry_is_dir(zip_handle) == MZ_OK) { - printf("First entry in zip file is a directory\n"); - } -} -``` - -### mz_zip_entry_is_symlink - -When enumerating zip entries, returns whether or not the current entry is a symbolic link. This function accounts for the various symbolic link attribute values on each OS. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if entry is a symbolic link.| - -**Example** -``` -int32_t err = mz_zip_goto_first_entry(zip_handle); -if (err == MZ_OK) { - if (mz_zip_entry_is_symlink(zip_handle) == MZ_OK) { - printf("First entry in zip file is a symbolic link\n"); - } -} -``` - -### mz_zip_entry_get_info - -Gets central directory file information about the current entry in the zip file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|mz_zip_file **|file_info|Pointer to _mz_zip_file_ structure. Pointer is only valid for the while the entry is the current entry.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -int32_t err = mz_zip_goto_first_entry(zip_handle); -if (err == MZ_OK) { - mz_zip_file *file_info = NULL; - err = mz_zip_entry_get_info(zip_handle, &file_info); - if (err == MZ_OK) { - printf("Central directory entry filename: %s\n", file_info->filename); - } -} -``` - -### mz_zip_entry_get_local_info - -Gets local file header file information about the current entry in the zip file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|mz_zip_file **|file_info|Pointer to _mz_zip_file_ structure. Pointer is only valid for the while the entry is the current entry.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -int32_t err = mz_zip_goto_first_entry(zip_handle); -if (err == MZ_OK) { - mz_zip_file *local_file_info = NULL; - err = mz_zip_entry_get_info(zip_handle, &local_file_info); - if (err == MZ_OK) { - printf("Local header entry filename: %s\n", local_file_info->filename); - } -} -``` - -### mz_zip_get_entry - -Returns the offset of the current entry in the zip file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|int64_t|Byte position in zip file, if < 0, then [MZ_ERROR](mz_error.md).| - -**Example** -``` -int32_t err = mz_zip_goto_first_entry(zip_handle); -if (err == MZ_OK) { - int64_t entry_offset = mz_zip_get_entry(zip_handle); - if (entry_offset >= 0) { - printf("Entry offset %lld\n", entry_offset); - } -} -``` - -### mz_zip_goto_entry - -Manually set the central directory stream position for and read entry. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|int64_t|cd_pos|Position in the central directory stream| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -// Read the entry at position 0 in central directory stream -mz_zip_goto_entry(zip_handle, 0); -``` - -### mz_zip_goto_first_entry - -Go to the first entry in the zip file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful, MZ_END_OF_LIST if no more entries.| - -**Example** -``` -int32_t err = mz_zip_goto_first_entry(zip_handle); -if (err == MZ_OK) { - mz_zip_file *file_info = NULL; - err = mz_zip_entry_get_info(zip_handle, &file_info); - if (err == MZ_OK) { - printf("First entry is %s\n", file_info->filename); - } -} -``` - -### mz_zip_goto_next_entry - -Go to the next entry in the zip file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful, MZ_END_OF_LIST if no more entries.| - -**Example** -``` -int32_t i = 0; -int32_t err = mz_zip_goto_first_entry(zip_handle); -while (err == MZ_OK) { - mz_zip_file *file_info = NULL; - err = mz_zip_entry_get_info(zip_handle, &file_info); - if (err != MZ_OK) { - printf("Failed to get entry %d info\n", i); - break; - } - printf("Entry %d is %s\n", i, file_info->filename); - err = mz_zip_goto_next_entry(zip_handle); -} -``` - -### mz_zip_locate_entry - -Locate the entry with the specified name in the zip file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|const char *|filename|Filename character array| -|uint8_t|ignore_case|Ignore case during lookup if 1.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful, MZ_END_OF_LIST if not found.| - -**Example** -``` -const char *search_path = "test.txt"; -int32_t err = mz_zip_locate_entry(zip_handle, search_path, 0); -if (err == MZ_OK) { - printf("%s was found\n", search_path); -else - printf("%s was not found\n", search_path); -``` - -### mz_zip_locate_first_entry - -Locate the first matching entry based on a match callback. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|void *|userdata|User pointer| -|mz_zip_locate_entry_cb|cb|Callback to locate filter function| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful, MZ_END_OF_LIST if not found.| - -**Example** -``` -static int32_t locate_a_entries_cb(void *handle, void *userdata, mz_zip_file *file_info) { - if (file_info->filename[0] == 'a') { - return MZ_OK; - } - return MZ_EXIST_ERROR; -} -int32_t err = mz_zip_locate_first_entry(zip_handle, NULL, locate_a_entries_cb); -if (err == MZ_OK) { - mz_zip_file *file_info = NULL; - err = mz_zip_entry_get_info(zip_handle, &file_info); - if (err == MZ_OK) { - printf("First entry beginning with a is %s\n", file_info->filename); - } -} else { - printf("No entries beginning with a found\n"); -} -``` - -### mz_zip_locate_next_entry - -Locate the next matching entry based on a match callback. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_ instance| -|void *|userdata|User pointer| -|mz_zip_locate_entry_cb|cb|Callback to locate filter function| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful, MZ_END_OF_LIST if not found.| - -**Example** -``` -static int32_t locate_a_entries_cb(void *handle, void *userdata, mz_zip_file *file_info) { - if (file_info->filename[0] == 'a') { - return MZ_OK; - } - return MZ_EXIST_ERROR; -} -int32_t err = mz_zip_locate_first_entry(zip_handle, NULL, locate_a_entries_cb); -if (err == MZ_END_OF_LIST) { - printf("No entries beginning with a found\n"); - return; -} -while (err == MZ_OK) { - mz_zip_file *file_info = NULL; - err = mz_zip_entry_get_info(zip_handle, &file_info); - if (err != MZ_OK) { - printf("Error getting entry info\n"); - break; - } - printf("Entry beginning with a is %s\n", file_info->filename); - err = mz_zip_locate_next_entry(zip_handle, 0, locate_a_entries_cb); -} -``` - -## System Attributes - -### mz_zip_attrib_is_dir - -Checks to see if the attribute is a directory based on platform. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|uint32_t|attrib|External file attributes| -|int32_t|version_madeby|Version made by value| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if is a directory.| - -**Example** -``` -mz_zip_file *file_info = NULL; -if (mz_zip_entry_get_info(zip_handle, &file_info) == MZ_OK) { - if (mz_zip_attrib_is_dir(file_info->external_fa, file_info->version_madeby) == MZ_OK) { - printf("Entry is a directory\n"); - } else { - printf("Entry is not a directory\n"); - } -} -``` - -### mz_zip_attrib_is_symlink - -Checks to see if the attribute is a symbolic link based on platform. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|uint32_t|attrib|External file attributes| -|int32_t|version_madeby|Version made by value| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if is a directory.| - -**Example** -``` -mz_zip_file *file_info = NULL; -if (mz_zip_entry_get_info(zip_handle, &file_info) == MZ_OK) { - if (mz_zip_attrib_is_symlink(file_info->external_fa, file_info->version_madeby) == MZ_OK) { - printf("Entry is a symbolic link\n"); - } else { - printf("Entry is not a symbolic link\n"); - } -} -``` - -### mz_zip_attrib_convert - -Converts file attributes from one host system to another. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|uint8_t|src_sys|Source system (See [MZ_HOST_SYSTEM](mz_host_system.md))| -|uint32_t|src_attrib|Source system attribute value| -|uint8_t|target_sys|Target system (See [MZ_HOST_SYSTEM](mz_host_system.md))| -|uint32_t *|target_attrib|Pointer to store target system attribute value| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if converted successfully.| - -**Example** -``` -uint32_t target_attrib = 0; -// Windows FILE_ATTRIBUTE_DIRECTORY (0x10) -if (mz_zip_attrib_convert(MZ_HOST_SYSTEM_WINDOWS_NTFS, 0x10, MZ_HOST_SYSTEM_UNIX, &target_attrib) == MZ_OK) { - printf("Unix file attributes: %08x\n", target_attrib); - if (S_ISDIR(target_attribute)) { - printf("Unix attribute is a directory\n"); - } -} -``` - -### mz_zip_attrib_posix_to_win32 - -Converts posix file attributes to win32 file attributes. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|uint32_t|posix_attrib|Posix attributes value| -|uint32_t *|win32_attrib|Pointer to store windows attributes value| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if converted successfully.| - -**Example** -``` -uint32_t posix_attrib = 0x00008124; -uint32_t win32_attrib = 0; -if (mz_zip_attrib_posix_to_win32(posix_attrib, &win32_attrib) == MZ_OK) { - printf("Win32 file system attributes: %08x\n", win32_attrib); - // Windows FILE_ATTRIBUTE_READONLY (0x01) - if ((win32_attrib & 0x01) != 0) { - printf("Win32 attribute is readonly\n"); - } -} -``` - -### mz_zip_attrib_win32_to_posix - -Converts win32 file attributes to posix file attributes. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|uint32_t|win32_attrib|Windows attributes value| -|uint32_t *|posix_attrib|Pointer to store posix attributes value| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if converted successfully.| - -**Example** -``` -uint32_t posix_attrib = 0; // Read only -uint32_t win32_attrib = 0x01; // FILE_ATTRIBUTE_READONLY; -if (mz_zip_attrib_win32_to_posix(win32_attrib), &posix_attrib) == MZ_OK) { - printf("Posix file system attributes: %08x\n", posix_attrib); - if ((posix_attrib & 0000222) == 0) { - printf("Posix attribute is readonly\n"); - } -} -``` - -## Extrafield - -### mz_zip_extrafield_find - -Seeks using a _mz_stream_ to an extra field by its type and returns its length. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|stream|_mz_stream_ instance| -|uint16_t|type|Extra field type indentifier (See [PKWARE zip app note](zip/appnote.iz.txt) section 4.5.2)| -|int32_t|max_seek|Maximum length to search for extrafield| -|uint16_t *|length|Pointer to extra field length| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if found, MZ_EXIST_ERROR if not found.| - -**Example** -``` -void *file_extra_stream = NULL; -mz_zip_file *file_info = NULL; -uint16_t extrafield_length = 0; - -mz_zip_entry_get_info(zip_handle, &file_info); - -mz_stream_mem_create(&file_extra_stream); -mz_stream_mem_set_buffer(file_extra_stream, (void *)file_info->extrafield, - file_info->extrafield_size); - -if (mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_AES, INT32_MAX, &extrafield_length) == MZ_OK) - printf("Found AES extra field, length %d\n", extrafield_length); -else - printf("Unable to find AES extra field in zip entry\n"); - -mz_stream_mem_delete(&file_extra_stream); -``` - -### mz_zip_extrafield_contains - -Searchs a buffer to determine whether an extrafield exists and returns its length if found. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const uint8_t *|extrafield|Extra field buffer array| -|int32_t|extrafield_size|Maximim buffer bytes| -|uint16_t|type|Extrafield type identifier (See [PKWARE zip app note](zip/appnote.iz.txt) section 4.5.2)| -|uint16_t *|length|Pointer to store extrafield length| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if found, MZ_EXIST_ERROR if not found.| - -**Example** -``` -mz_zip_file *file_info = NULL; -uint16_t extrafield_length = 0; - -mz_zip_entry_get_info(zip_handle, &file_info); -if (mz_zip_extrafield_contains(file_info->extrafield, file_info->extrafield_size, MZ_ZIP_EXTENSION_AES, &extrafield_length) == MZ_OK) - printf("Found AES extra field, length %d\n", extrafield_length); -else - printf("Unable to find AES extra field in zip entry\n"); - -``` - -### mz_zip_extrafield_read - -Reads an extrafield header from a stream. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|stream|_mz_stream_ instance| -|uint16_t *|type|Pointer to store extrafield type identifier (See [PKWARE zip app note](zip/appnote.iz.txt) section 4.5.2)| -|uint16_t *|length|Pointer to store extrafield length| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if extrafield read.| - -**Example** -``` -void *file_extra_stream = NULL; -mz_zip_file *file_info = NULL; -uint16_t extrafield_type = 0; -uint16_t extrafield_length = 0; - -mz_stream_mem_create(&file_extra_stream); -mz_stream_mem_set_buffer(file_extra_stream, (void *)file_info->extrafield, - file_info->extrafield_size); - -while (mz_zip_extrafield_read(field_extra_stream, &extrafield_type, &extrafield_length) == MZ_OK) { - printf("Extra field type: %04x\n", extrafield_type); - printf("Extra field length: %d\n", extrafield_length); -} - -mz_stream_mem_delete(&file_extra_stream); -``` - -### mz_zip_extrafield_write - -Writes an extrafield header to a stream. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|stream|_mz_stream_ instance| -|uint16_t|type|Extrafield type identifier (See [PKWARE zip app note](zip/appnote.iz.txt) section 4.5.2)| -|uint16_t|length|Extrafield length| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -#define MY_CUSTOM_FIELD_TYPE (0x8080) -#define MY_CUSTOM_FIELD_LENGTH (sizeof(uint32_t)) -#define MY_CUSTOM_FIELD_VALUE (1) - -if (mz_zip_extrafield_write(field_extra_stream, MY_CUSTOM_FIELD_TYPE, MY_CUSTOM_FIELD_LENGTH) == MZ_OK) - mz_stream_write_uint32(field_extra_stream, MY_CUSTOM_FIELD_VALUE); -``` - -## Time/Date - -### mz_zip_dosdate_to_tm - -Convert dos date/time format to struct tm. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|uint64_t|dos_date|Dos date/time timestamp| -|struct tm *|ptm|Pointer to tm structure| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -struct tm tmu_date = { 0 }; -uint32_t dos_date = 0x50454839; -mz_zip_dosdate_to_tm(dos_date, &tmu_date); -printf("Time: %02d/%02d/%d %02d:%02d:%02d\n", - (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, - (uint32_t)tmu_date.tm_sec); -``` - -### mz_zip_dosdate_to_time_t - -Convert dos date/time format to unix timestamp. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|uint64_t|dos_date|Dos date/time timestamp| - -**Return** -|Type|Description| -|-|-| -|time_t|Unix timestamp, 0 if not converted.| - -**Example** -``` -uint32_t dos_date = 0x50454839; -time_t unix_time = mz_zip_dosdate_to_time_t(unix_time); -// Unix date/time = 1580922110 -printf("Unix date/time: %lld\n", unix_time); -``` - -### mz_zip_time_t_to_tm - -Convert unix timestamp to time struct. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|time_t|unix_time|Unix timestamp| -|struct tm *|ptm|Pointer to tm structure| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -struct tm tmu_date = { 0 }; -time_t unix_time = 1580922110; -mz_zip_time_t_to_tm(unix_time, &tmu_date); -printf("Time: %02d/%02d/%d %02d:%02d:%02d\n", - (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, - (uint32_t)tmu_date.tm_sec); -``` - -### mz_zip_time_t_to_dos_date - -Convert unix timestamp to dos date/time format. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|time_t|unix_time|Unix timestamp| - -**Return** -|Type|Description| -|-|-| -|uint32_t|Dos/date timestamp, 0 if not converted.| - -**Example** -``` -time_t unix_time = 1580922110; -uint32_t dos_date = mz_zip_time_t_to_dos_date(unix_time); -// Dos date/time = 0x50454839 -printf("Dos date/time: %08x\n", dos_date); -``` - -### mz_zip_tm_to_dosdate - -Convert struct tm to dos date/time format. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const struct tm *|ptm|Pointer to tm structure| - -**Return** -|Type|Description| -|-|-| -|uint32_t|Dos/date timestamp, 0 if not converted.| - -**Example** -``` -struct tm tmu_date = { 50, 1, 9, 5, 1, 120, 3, 35, 0 }; -uint32_t dos_date = mz_zip_tm_to_dosdate(&tmu_date); -printf("Dos date/time: %08x\n", dos_date); -``` - -### mz_zip_ntfs_to_unix_time - -Convert ntfs time to unix time. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|uint64_t|ntfs_time|Windows NTFS timestamp| -|time_t *|unix_time|Pointer to store Unix timestamp| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -time_t unix_time = 0; -uint64_t ntfs_time = 132253957100000000LL; -if (mz_zip_ntfs_to_unix_time(ntfs_time, &unix_time) == MZ_OK) { - // Unix time = 1580922110 - printf("NTFS -> Unix: %lld -> %lld\n", ntfs_time, unix_time); -} -``` - -### mz_zip_unix_to_ntfs_time - -Convert unix time to ntfs time. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|time_t|unix_time|Unix timestamp| -|uint64_t *|ntfs_time|Pointer to store Windows NTFS timestamp| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -time_t unix_time = 1580922110; -uint64_t ntfs_time = 0; -if (mz_zip_unix_to_ntfs_time(unix_time, &ntfs_time) == MZ_OK) { - // NTFS time = 132253957100000000 - printf("Unix -> NTFS: %lld -> %lld\n", unix_time, ntfs_time); -} -``` - -## Path - -### mz_zip_path_compare - -Compare two paths without regard to slashes. Some zip files have paths with unix slashes and some zip files have paths containing windows slashes. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|const char *|path1|First path to compare| -|const char *|path2|Second path to compare| -|uint8_t|ignore_case|Ignore case if 1.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -const char *search_path = "folder1/test1.txt"; -mz_zip_file *file_info = NULL; -if (mz_zip_entry_get_info(zip_handle, &file_info) == MZ_OK) { - if (mz_zip_path_compare(file_info->filename, search_path, 0) == MZ_OK) - printf("Found %s\n", search_path); - else - printf("Not found %s\n", search_path); -} -``` - -## String - -### mz_zip_get_compression_method_string - -Gets a string representing the compression method. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|int32_t|compression_method|Compression method index| - -**Return** -|Type|Description| -|-|-| -|const char *|String representing compression method or "?" if not found| - -**Example** -``` -const char *method = mz_zip_get_compression_method_string(MZ_ZIP_COMPRESS_METHOD_LZMA); -printf("Compression method %s\n", method); -``` diff --git a/minizip-ng/doc/mz_zip64.md b/minizip-ng/doc/mz_zip64.md deleted file mode 100644 index adb39b5..0000000 --- a/minizip-ng/doc/mz_zip64.md +++ /dev/null @@ -1,9 +0,0 @@ -# MZ_ZIP64 - -Zip64 mode enumeration. The zip64 extension is documented in [PKWARE zip app note](zip/appnote.txt) section 4.5.3 and provides support for zip files and entries greater than 4GB. These modes are only supported while writing a zip entry. - -|Name|Code|Description| -|-|-|-| -|MZ_ZIP64_AUTO|0|Only store and use zip64 extrafield if compressed size, uncompressed size, or disk offset is greater than -UINT32_MAX_.| -|MZ_ZIP64_FORCE|1|Always use and store zip64 extrafield even if it is not necessary.| -|MZ_ZIP64_DISABLE|2|Never use or store zip64 extrafield. If zip64 is required to write the entry it will result in MZ_PARAM_ERROR.| diff --git a/minizip-ng/doc/mz_zip_file.md b/minizip-ng/doc/mz_zip_file.md deleted file mode 100644 index d0b83d5..0000000 --- a/minizip-ng/doc/mz_zip_file.md +++ /dev/null @@ -1,79 +0,0 @@ -# MZ_ZIP_FILE - -Zip entry information structure. The _mz_zip_file_ structure is populated when reading zip entry information and can be used to populate zip entry information when writing zip entries. - -|Type|Name|Description|[PKWARE zip app note](zip/appnote.txt) section| -|-|-|-|-| -|uint16_t|version_madeby|Version made by field|4.4.2| -|uint16_t|version_needed|Version needed to extract|4.4.3| -|uint16_t|flag|General purpose bit flag|4.4.4| -|uint16_t|compression_method|Compression method|4.4.5 [MZ_COMPRESS_METHOD](mz_compress_method.md)| -|time_t|modified_date|Last modified unix timestamp|4.4.6, 4.5.5, 4.5.7| -|time_t|accessed_date|Last accessed unix timestamp|4.5.5, 4.5.7| -|time_t|creation_date|Creation date unix timestamp|4.5.5| -|uint32_t|crc|CRC32-B hash of uncompressed data|4.4.7| -|int64_t|compressed_size|Compressed size|4.4.8| -|int64_t|uncompressed_size|Uncompressed size|4.4.9| -|uint16_t|filename_size|Filename length|4.4.10| -|uint16_t|extrafield_size|Extrafield length|4.4.11| -|uint16_t|comment_size|Comment size|4.4.12| -|uint32_t|disk_number|Starting disk number|4.4.13| -|int64_t|disk_offset|Starting disk offset|4.4.16| -|uint16_t|internal_fa|Internal file attributes|4.4.14| -|uint16_t|external_fa|External file attributes|4.4.15| -|const char *|filename|Filename UTF-8 null-terminated string|4.4.17| -|const uint8_t *|extrafield|Extrafield buffer array|4.4.28| -|const char *|comment|Comment UTF-8 null-terminated string|4.4.18| -|uint16_t|zip64|Zip64 extension mode|[MZ_ZIP64](mz_zip64.md)| -|uint16_t|aes_version|WinZip AES version|[WinZip AES App Note](zip/winzip_aes.md)| -|uint16_t|aes_encryption_mode|WinZip AES encryption mode|[WinZip AES App Note](zip/winzip_aes.md)| - -For more information about each field please consult the referenced app note section. - -## Extended Notes - -### verison_madeby - -> The upper byte indicates the compatibility of the file attribute information... The lower byte indicates the ZIP specification version... supported by the software used to encode the file. - -The preprocessor define `MZ_VERSION_MADEBY` contains the version made by value for the current compiler runtime. To get the file attribute information use the preprocessor define `MZ_HOST_SYSTEM(version_madeby)`. - -### version_needed - -When writing zip entries, this will automatically be filled in if the value is zero. - -### flag - -|Flag|Value|Description| -|-|-|-| -| MZ_ZIP_FLAG_ENCRYPTED | 0x1 | Entry is encrypted. If using AES encryption `aes_version` needs to be set to `MZ_AES_VERSION` | -| MZ_ZIP_FLAG_LZMA_EOS_MARKER | 0x2 | Entry contains LZMA end of stream marker | -| MZ_ZIP_FLAG_DEFLATE_MAX | 0x2 | Entry compressed with deflate max algorithm | -| MZ_ZIP_FLAG_DEFLATE_NORMAL | 0 | Entry compressed with deflate normal algorithm | -| MZ_ZIP_FLAG_DEFLATE_FAST | 0x4 | Entry compressed with deflate fast algorithm | -| MZ_ZIP_FLAG_DEFLATE_SUPER_FAST | MAX + FAST | Entry compressed with deflate super fast algorithm | -| MZ_ZIP_FLAG_DATA_DESCRIPTOR | 0x08 | Entry contains data descriptor bytes at the end of the compressed content which contain the compressed and uncompressed size. Local file header contains zeros for these values. | -| MZ_ZIP_FLAG_UTF8 | 0x800 | Entry filename is UTF-8 encoded | -| MZ_ZIP_FLAG_MASK_LOCAL_INFO | 0x2000 | Local file header info is masked | - -### creation_date - -Creation date is only supported on Windows. - -### external_fa - -External file attributes. These attributes are native host system attribute values for the entry. To get the host system use `MZ_HOST_SYSTEM(version_madeby)`. It is possible to convert from one host system's attributes to another using `mz_zip_attrib_convert`. - -### aes_version - -This attribute must be set to `MZ_AES_VERSION` when AES encryption is used. - -### aes_encryption_mode - -AES encryption mode, by default 256-bit encryption is used for compression. - -|Flag|Value|Description| -|-|-|-| -| MZ_AES_ENCRYPTION_MODE_128 | 0x01 | 128-bit AES encryption | -| MZ_AES_ENCRYPTION_MODE_192 | 0x02 | 192-bit AES encryption | -| MZ_AES_ENCRYPTION_MODE_256 | 0x03 | 256-bit AES encryption | \ No newline at end of file diff --git a/minizip-ng/doc/mz_zip_rw.md b/minizip-ng/doc/mz_zip_rw.md deleted file mode 100644 index ca7d2a2..0000000 --- a/minizip-ng/doc/mz_zip_rw.md +++ /dev/null @@ -1,2076 +0,0 @@ -## MZ_ZIP_RW - -The _mz_zip_reader_ and _mz_zip_writer_ objects allows you to easily extract or create zip files. - -- [Reader Callbacks](#reader-callbacks) - - [mz_zip_reader_overwrite_cb](#mz_zip_reader_overwrite_cb) - - [mz_zip_reader_password_cb](#mz_zip_reader_password_cb) - - [mz_zip_reader_progress_cb](#mz_zip_reader_progress_cb) - - [mz_zip_reader_entry_cb](#mz_zip_reader_entry_cb) -- [Reader Open/Close](#reader-openclose) - - [mz_zip_reader_is_open](#mz_zip_reader_is_open) - - [mz_zip_reader_open](#mz_zip_reader_open) - - [mz_zip_reader_open_file](#mz_zip_reader_open_file) - - [mz_zip_reader_open_file_in_memory](#mz_zip_reader_open_file_in_memory) - - [mz_zip_reader_open_buffer](#mz_zip_reader_open_buffer) - - [mz_zip_reader_close](#mz_zip_reader_close) -- [Reader Entry Enumeration](#reader-entry-enumeration) - - [mz_zip_reader_goto_first_entry](#mz_zip_reader_goto_first_entry) - - [mz_zip_reader_goto_next_entry](#mz_zip_reader_goto_next_entry) - - [mz_zip_reader_locate_entry](#mz_zip_reader_locate_entry) -- [Reader Entry](#reader-entry) - - [mz_zip_reader_entry_open](#mz_zip_reader_entry_open) - - [mz_zip_reader_entry_close](#mz_zip_reader_entry_close) - - [mz_zip_reader_entry_read](#mz_zip_reader_entry_read) - - [mz_zip_reader_entry_has_sign](#mz_zip_reader_entry_has_sign) - - [mz_zip_reader_entry_sign_verify](#mz_zip_reader_entry_sign_verify) - - [mz_zip_reader_entry_get_hash](#mz_zip_reader_entry_get_hash) - - [mz_zip_reader_entry_get_first_hash](#mz_zip_reader_entry_get_first_hash) - - [mz_zip_reader_entry_get_info](#mz_zip_reader_entry_get_info) - - [mz_zip_reader_entry_is_dir](#mz_zip_reader_entry_is_dir) - - [mz_zip_reader_entry_save](#mz_zip_reader_entry_save) - - [mz_zip_reader_entry_save_process](#mz_zip_reader_entry_save_process) - - [mz_zip_reader_entry_save_file](#mz_zip_reader_entry_save_file) - - [mz_zip_reader_entry_save_buffer](#mz_zip_reader_entry_save_buffer) - - [mz_zip_reader_entry_save_buffer_length](#mz_zip_reader_entry_save_buffer_length) -- [Reader Bulk Extract](#reader-bulk-extract) - - [mz_zip_reader_save_all](#mz_zip_reader_save_all) -- [Reader Object](#reader-object) - - [mz_zip_reader_set_pattern](#mz_zip_reader_set_pattern) - - [mz_zip_reader_set_password](#mz_zip_reader_set_password) - - [mz_zip_reader_set_raw](#mz_zip_reader_set_raw) - - [mz_zip_reader_get_raw](#mz_zip_reader_get_raw) - - [mz_zip_reader_get_zip_cd](#mz_zip_reader_get_zip_cd) - - [mz_zip_reader_get_comment](#mz_zip_reader_get_comment) - - [mz_zip_reader_set_recover](#mz_zip_reader_set_recover) - - [mz_zip_reader_set_encoding](#mz_zip_reader_set_encoding) - - [mz_zip_reader_set_sign_required](#mz_zip_reader_set_sign_required) - - [mz_zip_reader_set_overwrite_cb](#mz_zip_reader_set_overwrite_cb) - - [mz_zip_reader_set_password_cb](#mz_zip_reader_set_password_cb) - - [mz_zip_reader_set_progress_cb](#mz_zip_reader_set_progress_cb) - - [mz_zip_reader_set_progress_interval](#mz_zip_reader_set_progress_interval) - - [mz_zip_reader_set_entry_cb](#mz_zip_reader_set_entry_cb) - - [mz_zip_reader_get_zip_handle](#mz_zip_reader_get_zip_handle) - - [mz_zip_reader_create](#mz_zip_reader_create) - - [mz_zip_reader_delete](#mz_zip_reader_delete) -- [Writer Callbacks](#writer-callbacks) - - [mz_zip_writer_overwrite_cb](#mz_zip_writer_overwrite_cb) - - [mz_zip_writer_password_cb](#mz_zip_writer_password_cb) - - [mz_zip_writer_progress_cb](#mz_zip_writer_progress_cb) - - [mz_zip_writer_entry_cb](#mz_zip_writer_entry_cb) -- [Writer Open/Close](#writer-openclose) - - [mz_zip_writer_is_open](#mz_zip_writer_is_open) - - [mz_zip_writer_open](#mz_zip_writer_open) - - [mz_zip_writer_open_file](#mz_zip_writer_open_file) - - [mz_zip_writer_open_file_in_memory](#mz_zip_writer_open_file_in_memory) - - [mz_zip_writer_close](#mz_zip_writer_close) -- [Writer Entry](#writer-entry) - - [mz_zip_writer_entry_open](#mz_zip_writer_entry_open) - - [mz_zip_writer_entry_close](#mz_zip_writer_entry_close) - - [mz_zip_writer_entry_write](#mz_zip_writer_entry_write) -- [Writer Add/Compress](#writer-addcompress) - - [mz_zip_writer_add](#mz_zip_writer_add) - - [mz_zip_writer_add_process](#mz_zip_writer_add_process) - - [mz_zip_writer_add_info](#mz_zip_writer_add_info) - - [mz_zip_writer_add_buffer](#mz_zip_writer_add_buffer) - - [mz_zip_writer_add_file](#mz_zip_writer_add_file) - - [mz_zip_writer_add_path](#mz_zip_writer_add_path) - - [mz_zip_writer_copy_from_reader](#mz_zip_writer_copy_from_reader) -- [Writer Object](#writer-object) - - [mz_zip_writer_set_password](#mz_zip_writer_set_password) - - [mz_zip_writer_set_comment](#mz_zip_writer_set_comment) - - [mz_zip_writer_set_raw](#mz_zip_writer_set_raw) - - [mz_zip_writer_get_raw](#mz_zip_writer_get_raw) - - [mz_zip_writer_set_aes](#mz_zip_writer_set_aes) - - [mz_zip_writer_set_compress_method](#mz_zip_writer_set_compress_method) - - [mz_zip_writer_set_compress_level](#mz_zip_writer_set_compress_level) - - [mz_zip_writer_set_zip_cd](#mz_zip_writer_set_zip_cd) - - [mz_zip_writer_set_certificate](#mz_zip_writer_set_certificate) - - [mz_zip_writer_set_overwrite_cb](#mz_zip_writer_set_overwrite_cb) - - [mz_zip_writer_set_password_cb](#mz_zip_writer_set_password_cb) - - [mz_zip_writer_set_progress_cb](#mz_zip_writer_set_progress_cb) - - [mz_zip_writer_set_progress_interval](#mz_zip_writer_set_progress_interval) - - [mz_zip_writer_set_entry_cb](#mz_zip_writer_set_entry_cb) - - [mz_zip_writer_get_zip_handle](#mz_zip_writer_get_zip_handle) - - [mz_zip_writer_create](#mz_zip_writer_create) - - [mz_zip_writer_delete](#mz_zip_writer_delete) - -## Reader Callbacks - -### mz_zip_reader_overwrite_cb - -Callback that called before an existing file is about to be overwritten. It can be set by calling _mz_zip_reader_set_overwrite_cb_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|userdata|Pointer that is passed to _mz_zip_reader_set_overwrite_cb_| -|mz_zip_file *|file_info|Zip entry| -|const char *|path|Target path on disk| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK to overwrite, MZ_EXIST_ERROR to skip.| - -**Example** - -See _minizip_extract_overwrite_cb_ callback in minizip.c. - -### mz_zip_reader_password_cb - -Callback that is called before a password is required to extract a password protected zip entry. It can be set by calling _mz_zip_reader_set_password_cb_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|userdata|Pointer that is passed to _mz_zip_reader_set_password_cb_| -|mz_zip_file *|file_info|Zip entry| -|char *|password|Password character array buffer| -|int32|max_password|Maximum password size| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -static int32_t example_password_cb(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password) { - strncpy(password, "my password", max_password); - return MZ_OK; -} -mz_zip_reader_set_password_cb(zip_reader, 0, example_password_cb); -``` - -### mz_zip_reader_progress_cb - -Callback that is called to report extraction progress. This can be set by calling _mz_zip_reader_set_progress_cb_. - -Progress calculation depends on whether or not raw data is being extracted. If raw data, then use `position / file_info->compressed_size` otherwise use `position / file_info->uncompressed_size`. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|userdata|Pointer that is passed to _mz_zip_reader_progress_cb_| -|mz_zip_file *|file_info|Zip entry| -|int64_t|position|File position.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** - -See _minizip_extract_progress_cb_ in minizip.c. - -### mz_zip_reader_entry_cb - -Callback that is called when a new zip entry is starting extraction. It can be set by calling _mz_zip_reader_entry_cb_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|userdata|Pointer that is passed to _mz_zip_reader_entry_cb_| -|const char *|path|Target path on disk| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** - -See _minizip_extract_entry_cb_ in minizip.c. - -## Reader Open/Close - -### mz_zip_reader_is_open - -Checks to see if the zip file is open. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if open.| - -**Example** -``` -if (mz_zip_reader_is_open(zip_reader) == MZ_OK) - printf("Zip file is open in reader\n"); -``` - -### mz_zip_reader_open - - Opens zip file from stream. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|stream|_mz_stream_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if opened.| - -**Example** -``` -void *file_stream = NULL; -const char *path = "c:\\my.zip"; - -mz_zip_reader_create(&zip_reader); -mz_stream_os_create(&file_stream); - -err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_READ); -if (err == MZ_OK) { - err = mz_zip_reader_open(zip_reader, file_stream); - if (err == MZ_OK) { - printf("Zip reader was opened %s\n", path); - mz_zip_reader_close(zip_reader); - } -} - -mz_stream_os_delete(&file_stream); -mz_zip_reader_delete(&zip_reader); -``` - -### mz_zip_reader_open_file - -Opens zip file from a file path. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|const char *|path|Path to zip file| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if opened.| - -**Example** -``` -const char *path = "c:\\my.zip"; -mz_zip_reader_create(&zip_reader); -if (mz_zip_reader_open_file(zip_reader, path) == MZ_OK) { - printf("Zip reader was opened %s\n", path); - mz_zip_reader_close(zip_reader); -} -mz_zip_reader_delete(&zip_reader); -``` - -### mz_zip_reader_open_file_in_memory - -Opens zip file from a file path into memory for faster access. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|const char *|path|Path to zip file| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if opened.| - -**Example** -``` -const char *path = "c:\\my.zip"; -mz_zip_reader_create(&zip_reader); -if (mz_zip_reader_open_file_in_memory(zip_reader, path) == MZ_OK) { - printf("Zip reader was opened in memory %s\n", path); - mz_zip_reader_close(zip_reader); -} -mz_zip_reader_delete(&zip_reader); -``` - -### mz_zip_reader_open_buffer - -Opens zip file from memory buffer. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|uint8_t *|buf|Buffer containing zip| -|int32_t|len|Length of buffer| -|int32_t|copy|Copy buffer internally if 1| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if opened.| - -**Example** -``` -uint8 *buffer = NULL; -int32 buffer_length = 0; -// TODO: Load zip file into memory buffer -mz_zip_reader_create(&zip_reader); -if (mz_zip_reader_open_buffer(zip_reader, buffer, buffer_length) == MZ_OK) { - printf("Zip reader was opened from buffer\n"); - mz_zip_reader_close(zip_reader); -} -mz_zip_reader_delete(&zip_reader); -``` - -### mz_zip_reader_close - -Closes the zip file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -if (mz_zip_reader_close(zip_reader) == MZ_OK) - printf("Zip reader closed\n"); -``` - -## Reader Entry Enumeration - -### mz_zip_reader_goto_first_entry - -Goto the first entry in the zip file. If a pattern has been specified by calling _mz_zip_reader_set_pattern_, then it goes to the first entry matching the pattern. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful, MZ_END_OF_LIST if no more entries.| - -**Example** -``` -mz_zip_file *file_info = NULL; -if ((mz_zip_reader_goto_first_entry(zip_reader) == MZ_OK) && - (mz_zip_reader_entry_get_info(zip_reader, &file_info) == MZ_OK)) { - printf("Zip first entry %s\n", file_info->filename); -} -``` - -### mz_zip_reader_goto_next_entry - -Goto the next entry in the zip file. If a pattern has been specified by calling _mz_zip_reader_set_pattern_, then it goes to the next entry matching the pattern. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful, MZ_END_OF_LIST if no more entries.| - -**Example** -``` -if (mz_zip_reader_goto_first_entry(zip_reader) == MZ_OK) { - do { - mz_zip_file *file_info = NULL; - if (mz_zip_reader_entry_get_info(zip_reader, &file_info) != MZ_OK) { - printf("Unable to get zip entry info\n"); - break; - } - printf("Zip entry %s\n", file_info->filename); - } while (mz_zip_reader_goto_next_entry(zip_reader) == MZ_OK); -} -``` - -### mz_zip_reader_locate_entry - -Locates an entry by filename. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|const char *|filename|Filename to find| -|uint8_t|ignore_case|Ignore case during search if 1.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful, MZ_END_OF_LIST if not found.| - -**Example** -``` -const char *search_filename = "test1.txt"; -if (mz_zip_reader_locate_entry(zip_reader, search_filename, 1) == MZ_OK) - printf("Found %s\n", search_filename); -else - printf("Could not find %s\n", search_filename); -``` - -## Reader Entry - -### mz_zip_reader_entry_open - -Opens an entry for reading. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -if (mz_zip_reader_goto_first_entry(zip_reader) == MZ_OK) { - if (mz_zip_reader_entry_open(zip_reader) == MZ_OK) { - char buf[120]; - int32_t bytes_read = 0; - bytes_read = mz_zip_reader_entry_read(zip_reader, buf, sizeof(buf)); - if (bytes_read > 0) { - printf("Bytes read from entry %d\n", bytes_read); - } - mz_zip_reader_entry_close(zip_reader); - } -} -``` - -### mz_zip_reader_entry_close - -Closes an entry that has been opened for reading or writing. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -if (mz_zip_reader_entry_open(zip_reader) == MZ_OK) { - if (mz_zip_reader_entry_close(zip_reader) == MZ_OK) { - printf("Entry closed successfully\n"); - } -} -``` - -### mz_zip_reader_entry_read - -Reads an entry after being opened. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|buf|Buffer to read into| -|int32_t|len|Maximum length of buffer to read into| - -**Return** -|Type|Description| -|-|-| -|int32_t|If < 0 then [MZ_ERROR](mz_error.md) code, otherwise number of bytes read. When there are no more bytes left to read then 0 is returned.| - -**Example** -``` -if (mz_zip_reader_goto_first_entry(zip_reader) == MZ_OK) { - if (mz_zip_reader_entry_open(zip_reader) == MZ_OK) { - char buf[4096]; - int32_t bytes_read = 0; - int32_t err = MZ_OK; - do { - bytes_read = mz_zip_reader_entry_read(zip_reader, buf, sizeof(buf)); - if (bytes_read < 0) { - err = bytes_read; - break; - } - printf("Bytes read from entry %d\n", bytes_read); - } while (bytes_read > 0); - mz_zip_reader_entry_close(zip_reader); - } -} -``` - -### mz_zip_reader_entry_has_sign - -Checks to see if the entry has a signature. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if has signature.| - -**Example** -``` -if (mz_zip_reader_entry_has_sign(zip_reader) == MZ_OK) - printf("Entry has signature attached\n"); -``` - -### mz_zip_reader_entry_sign_verify - -Verifies a signature stored with the entry. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if signature is valid.| - -**Example** -``` -if (mz_zip_reader_entry_has_sign(zip_reader) == MZ_OK) { - printf("Entry has signature attached\n"); - if (mz_zip_reader_entry_sign_verify(zip_reader) == MZ_OK) { - printf("Entry signature is valid\n); - } else { - printf("Entry signature is invalid\n"); - } -} -``` - -### mz_zip_reader_entry_get_hash - -Gets a hash algorithm from the entry's extra field. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|uint16_t|algorithm|[MZ_HASH](mz_hash.md) algorithm identifier| -|uint8_t *|digest|Digest buffer| -|int32_t|digest_size|Maximum digest buffer size| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if hash found.| - -**Example** -``` -if (mz_zip_reader_goto_first_entry(zip_reader) == MZ_OK) { - uint8_t sha1_digest[MZ_HASH_SHA1_SIZE]; - if (mz_zip_reader_entry_get_hash(zip_reader, MZ_HASH_SHA1, sha1_digest, sizeof(sha1_digest)) == MZ_OK) { - printf("Found sha1 digest for entry\n"); - } -} -``` - -### mz_zip_reader_entry_get_first_hash - -Gets the most secure hash algorithm from the entry's extra field. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|uint16_t *|algorithm|Pointer to store [MZ_HASH](mz_hash.md) algorithm identifier| -|uint16_t *|digest_size|Pointer to store digest size| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if hash found.| - -**Example** -``` -uint16_t algorithm = 0; -uint16_t digest_size = 0; -if (mz_zip_reader_entry_get_first_hash(zip_reader, &algorithm, &digest_size) == MZ_OK) { - printf("Found hash: algo %d size %d\n", algorithm, digest_size); -} -``` - -### mz_zip_reader_entry_get_info - -Gets the current entry file info. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|mz_zip_file **|file_info|Pointer to [mz_zip_file](mz_zip_file.md) structure| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -mz_zip_file *file_info = NULL; -if (mz_zip_reader_goto_first_entry(zip_reader) == MZ_OK) { - if (mz_zip_reader_entry_get_info(zip_reader, &file_info) == MZ_OK) { - printf("First entry: %s\n", file_info->filename); - } -} -``` - -### mz_zip_reader_entry_is_dir - -Gets the current entry is a directory. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -if (mz_zip_reader_goto_first_entry(zip_reader) == MZ_OK) { - if (mz_zip_reader_entry_is_dir(zip_reader) == MZ_OK) { - printf("Entry is a directory\n"); - } -} -``` - -### mz_zip_reader_entry_save - -Save the current entry to a steam. Each time the function needs to write to the stream it will call the _mz_stream_write_cb_ callback with the _stream_ pointer. This is a blocking call that will not return until the entire entry is written to the stream or until an error has occured. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|stream|_mz_stream_ instance| -|mz_stream_write_cb|write_cb|Stream write callback| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -void *file_stream = NULL; -const char *path = "c:\\my.zip"; -const char *entry_path = "c:\\entry.dat"; - -mz_zip_reader_create(&zip_reader); - -err = mz_zip_reader_open_file(zip_reader, path); -if (err == MZ_OK) { - printf("Zip reader was opened %s\n", path); - err = mz_zip_reader_goto_first_entry(zip_reader); - if (err == MZ_OK) { - mz_stream_os_create(&entry_stream); - err = mz_stream_os_open(entry_stream, entry_path, MZ_OPEN_MODE_WRITE); - if (err == MZ_OK) { - err = mz_zip_reader_entry_save(zip_reader, file_stream, mz_stream_os_write); - mz_stream_os_close(entry_stream); - } - mz_stream_os_delete(&entry_stream); - } - mz_zip_reader_close(zip_reader); -} - -mz_zip_reader_delete(&zip_reader); -``` - -### mz_zip_reader_entry_save_process - -Saves a portion of the current entry to a stream. Each time the function is called it will read from the zip file once and then write the output to the _mz_stream_write_cb_ callback with _stream_ pointer. This is intended to be used when writing zip file in a process loop. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|stream|_mz_stream_ instance| -|mz_stream_write_cb|write_cb|Stream write callback| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if more to process, MZ_END_OF_STREAM if no more data to process.| - -**Example** -``` -int32_t err = MZ_OK; -// TODO: Open zip reader and entry stream. -while (1) { - err = mz_zip_reader_entry_save_process(zip_reader, entry_stream, mz_stream_os_write); - if (err != MZ_OK) { - printf("There was an error writing to stream (%d)\n", err); - break; - } - if (err == MZ_END_OF_STREAM) { - printf("Finished writing to stream\n"); - break; - } -} -``` - -### mz_zip_reader_entry_save_file - -Save the current entry to a file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|const char *|path|Path to save entry on disk| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -if (mz_zip_reader_goto_first_entry(zip_reader) == MZ_OK) { - if (mz_zip_reader_entry_save_file(zip_reader, "entry1.bin") == MZ_OK) { - printf("First entry saved to disk successfully\n"); - } -} -``` - -### mz_zip_reader_entry_save_buffer - -Save the current entry to a memory buffer. To get the size required use _mz_zip_reader_entry_save_buffer_length_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|buf|Buffer to decompress to| -|int32_t|len|Maximum size of buffer| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful, or MZ_BUF_ERROR if _buf_ is too small.| - -**Example** -``` -int32_t buf_size = (int32_t)mz_zip_reader_entry_save_buffer_length(zip_reader); -char *buf = (char *)malloc(buf_size); -int32_t err = mz_zip_reader_entry_save_buffer(zip_reader, buf, buf_size); -if (err == MZ_OK) { - // TODO: Do something with buffer -} -free(buf); -``` - -### mz_zip_reader_entry_save_buffer_length - -Gets the length of the buffer required to save. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -int32_t buf_size = (int32_t)mz_zip_reader_entry_save_buffer_length(zip_reader); -char *buf = (char *)malloc(buf_size); -int32_t err = mz_zip_reader_entry_save_buffer(zip_reader, buf, buf_size); -if (err == MZ_OK) { - // TODO: Do something with buffer -} -free(buf); -``` - -## Reader Bulk Extract - -### mz_zip_reader_save_all - -Save all files into a directory. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|const char *|destination_dir|Directory to extract all files to| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *destination_dir = "c:\\temp\\"; -if (mz_zip_reader_save_all(zip_reader, destination_dir) == MZ_OK) { - printf("All files successfully saved to %s\n", destination_dir); -} -``` - -## Reader Object - -### mz_zip_reader_set_pattern - -Sets the match pattern for entries in the zip file, if null all entries are matched. This match pattern is used when calling _mz_zip_reader_goto_first_entry_ and _mz_zip_reader_goto_next_entry_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|const char *|pattern|Search pattern or NULL if not used| -|uint8_t|ignore_case|Ignore case when matching if 1| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -int32_t matches = 0; -const char *pattern = "*.txt"; -mz_zip_reader_set_pattern(zip_reader, pattern, 1); -if (mz_zip_reader_goto_first_entry(zip_reader) == MZ_OK) { - do { - matches += 1; - } while (mz_zip_reader_goto_next_entry(zip_reader) == MZ_OK); -} -printf("Found %d zip entries matching pattern %s\n", matches, pattern); -``` - -### mz_zip_reader_set_password - -Sets the password required for extracting entire zip file. If not specified, then _mz_zip_reader_password_cb_ will be called for password protected zip entries. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|const char *|password|Password to use for entire zip file| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_reader_set_password(zip_handle, "mypassword"); -``` - -### mz_zip_reader_set_raw - -Sets whether or not it should save the entry raw. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|uint8_t|raw|Save entry as raw data if 1| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_reader_set_raw(zip_reader, 1); -``` - -### mz_zip_reader_get_raw - -Gets whether or not it should save the entry raw. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|uint8_t *|raw|Pointer to store if saving as raw data| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -uint8_t raw = 0; -mz_zip_reader_get_raw(zip_reader, &raw); -printf("Entry will be saved as %s data\n", (raw) ? "raw gzip" : "decompressed"); -``` - -### mz_zip_reader_get_zip_cd - -Gets whether or not the archive has a zipped central directory. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|uint8_t *|zip_cd|Pointer to store if central directory is zipped| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -uint8_t zip_cd = 0; -mz_zip_reader_get_zip_cd(zip_reader, &zip_cd); -printf("Central directory %s zipped\n", (zip_cd) ? "is" : "is not"); -``` - -### mz_zip_reader_get_comment - -Gets the comment for the central directory. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|const char **|comment|Pointer to store global comment pointer| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -const char *global_comment = NULL; -if (mz_zip_reader_get_comment(zip_reader, &global_comment) == MZ_OK) { - printf("Zip comment: %s\n", global_comment); -} -``` - -### mz_zip_reader_set_recover - -Sets the ability to recover the central dir by reading local file headers. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|uint8_t|recover|Set to 1 if recover method is supported, 0 otherwise.| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_reader_set_recover(zip_reader, 1); -``` - -### mz_zip_reader_set_encoding - -Sets whether or not it should support a special character encoding in zip file names. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|int32_t|encoding|[MZ_ENCODING](mz_encoding.md) identifier| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_reader_set_encoding(zip_reader, MZ_ENCODING_CODEPAGE_437); -``` - -### mz_zip_reader_set_sign_required - -Sets whether or not it a signature is required. If enabled, it will prevent extraction of zip entries that do not have verified signatures. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|uint8_t|sign_required|Valid CMS signatures are required if 1| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_reader_set_sign_required(zip_reader, 1); -``` - -### mz_zip_reader_set_overwrite_cb - -Sets the callback for what to do when a file is about to be overwritten. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|userdata|User supplied data| -|mz_zip_reader_overwrite_cb|cb|_mz_zip_reader_overwrite_cb_ function pointer| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** - -See example for _mz_zip_reader_overwrite_cb_. - -### mz_zip_reader_set_password_cb - -Sets the callback for what to do when a password is required and hasn't been set. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|userdata|User supplied data| -|mz_zip_reader_password_cb|cb|_mz_zip_reader_password_cb_ function pointer| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** - -See example for _mz_zip_reader_password_cb_. - -### mz_zip_reader_set_progress_cb - -Sets the callback that gets called to update extraction progress. This callback is called on an interval specified by _mz_zip_reader_set_progress_interval_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|userdata|User supplied data| -|mz_zip_reader_progress_cb|cb|_mz_zip_reader_progress_cb_ function pointer| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** - -See example for _mz_zip_reader_progress_cb_. - -### mz_zip_reader_set_progress_interval - -Let at least milliseconds pass between calls to progress callback. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|uint32_t|milliseconds|Number of milliseconds to wait before calling _mz_zip_reader_progress_cb_ during extraction| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_reader_set_progress_interval(zip_reader, 1000); // Wait 1 sec -``` - -### mz_zip_reader_set_entry_cb - -Sets callback for when a new zip file entry is encountered during extraction. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void *|userdata|User supplied data| -|mz_zip_reader_entry_cb|cb|_mz_zip_reader_entry_cb_ function pointer| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** - -See example for _mz_zip_reader_entry_cb_. - -### mz_zip_reader_get_zip_handle - -Gets the underlying zip instance handle. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|void **|zip_handle|Pointer to store _mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -void *zip_handle = NULL; -mz_zip_reader_get_zip_handle(zip_reader, &zip_handle); -mz_zip_goto_first_entry(zip_handle); -``` - -### mz_zip_reader_create - -Creates a _mz_zip_reader_ instance and returns its pointer. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void **|handle|Pointer to store the _mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|void *|Pointer to the _mz_zip_reader_ instance| - -**Example** -``` -void *zip_reader = NULL; -mz_zip_reader_create(&zip_reader); -``` - -### mz_zip_reader_delete - -Deletes a _mz_zip_reader_ instance and resets its pointer to zero. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void **|handle|Pointer to the _mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -void *zip_reader = NULL; -mz_zip_reader_create(&zip_reader); -mz_zip_reader_delete(&zip_reader); -``` - -## Writer Callbacks - -### mz_zip_writer_overwrite_cb - -Callback that is called when it is about to overwrite an existing zip file. This callback can be set by calling _mz_zip_writer_set_overwrite_cb_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void **|handle|Pointer to the _mz_zip_writer_ instance| -|void *|userdata|User data pointer| -|const char *|path|Zip file path that will be overwritten| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if it should overwrite| - -**Example** -``` -int32_t writer_overwrite_cb(void *handle, void *userdata, const char *path) { - printf("Zip file is going to be overwritten %s\n", path); - // if not ok return MZ_INTERNAL_ERROR; - return MZ_OK; -} -mz_zip_writer_set_overwrite_cb(zip_writer, NULL, writer_overwrite_cb); -``` - -Also see _minizip_add_overwrite_cb_ for advanced example. - -### mz_zip_writer_password_cb - -Callback that is called when it needs a password. Any entries that are added with the _MZ_ZIP_FLAG_ENCRYPTED_ flag will need a password. This callback can be set by calling _mz_zip_writer_set_password_cb_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void **|handle|Pointer to the _mz_zip_writer_ instance| -|void *|userdata|User data pointer| -|mz_zip_file *|file_info|Entry that needs password when adding| -|char *|password|Password character buffer| -|int32_t|max_password|Maximum password buffer size| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -int32_t writer_password_cb(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password) { - printf("Supplying password for %s\n", file_info->filename); - strncpy(password, "mypassword", max_password - 1); - password[max_password - 1] = 0; - return MZ_OK; -} -mz_zip_writer_set_password_cb(zip_writer, NULL, writer_password_cb); -``` - -### mz_zip_writer_progress_cb - -Callback that is called during compression to report progress. It is called on an interval specified by _mz_zip_writer_set_progress_interval_. This callback can be set by calling _mz_zip_writer_set_progress_cb_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void **|handle|Pointer to the _mz_zip_writer_ instance| -|void *|userdata|User data pointer| -|mz_zip_file *|file_info|Entry that is being compressed| -|int64_t|position|File write position. To calculate progress when writing raw use `position / file_info->compressed_size`. To calculate progress when writing data to be compressed use `position / file_info->uncompressed_size`.| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** - -See example in _minizip_extract_progress_cb_. - -### mz_zip_writer_entry_cb - -Callback that is called for each entry that is compressed. This callback can be set by calling _mz_zip_writer_set_entry_cb. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void **|handle|Pointer to the _mz_zip_writer_ instance| -|void *|userdata|User data pointer| -|mz_zip_file *|file_info|Entry that is being compressed| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** - -See example in _minizip_extract_entry_cb. - -## Writer Open/Close - -### mz_zip_writer_is_open - -Checks to see if the zip file is open. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if open.| - -**Example** -``` -if (mz_zip_writer_is_open(zip_writer) == MZ_OK) - printf("Zip file is open in writer\n"); -``` - -### mz_zip_writer_open - - Opens zip file from stream. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void *|stream|_mz_stream_ instance| -|uint8_t|append|Opens in append mode if 1| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if opened.| - -**Example** -``` -void *file_stream = NULL; -const char *path = "c:\\my.zip"; - -mz_zip_writer_create(&zip_writer); -mz_stream_os_create(&file_stream); - -err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_WRITE | MZ_OPEN_MODE_CREATE); -if (err == MZ_OK) { - err = mz_zip_writer_open(zip_writer, file_stream, 0); - if (err == MZ_OK) { - printf("Zip writer was opened %s\n", path); - mz_zip_writer_close(zip_writer); - } -} - -mz_stream_os_delete(&file_stream); -mz_zip_writer_delete(&zip_writer); -``` - -### mz_zip_writer_open_file - -Opens zip file from a file path. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_reader_ instance| -|const char *|path|Path to zip file| -|int64_t|disk_size|Disk size in bytes if using disk spanning, otherwise 0| -|uint8_t|append|Opens in append mode if 1| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if opened.| - -**Example** -``` -const char *path = "c:\\my.zip"; -mz_zip_writer_create(&zip_writer); -if (mz_zip_writer_open_file(zip_writer, path, 0, 0) == MZ_OK) { - printf("Zip writer was opened %s\n", path); - mz_zip_writer_close(zip_writer); -} -mz_zip_writer_delete(&zip_writer); -``` - -### mz_zip_writer_open_file_in_memory - -Opens zip file from a file path into memory for faster access. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|const char *|path|Path to zip file| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if opened.| - -**Example** -``` -const char *path = "c:\\my.zip"; -mz_zip_writer_create(&zip_writer); -if (mz_zip_writer_open_file_in_memory(zip_writer, path) == MZ_OK) { - printf("Zip writer was opened in memory %s\n", path); - mz_zip_writer_close(zip_writer); -} -mz_zip_writer_delete(&zip_writer); -``` - -### mz_zip_writer_close - -Closes the zip file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -if (mz_zip_writer_close(zip_writer) == MZ_OK) - printf("Zip writer closed\n"); -``` - -## Writer Entry - -### mz_zip_writer_entry_open - -Opens an entry in the zip file for writing. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|mz_zip_file *|file_info|Zip entry info for entry that is being written| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -mz_zip_file file_info = { 0 }; - -file_info.filename = "newfile.txt"; -file_info.modified_date = time(NULL); -file_info.version_madeby = MZ_VERSION_MADEBY; -file_info.compression_method = MZ_COMPRESS_METHOD_STORE; -file_info.flag = MZ_ZIP_FLAG_UTF8; - -if (mz_zip_writer_entry_open(zip_writer, &file_info) == MZ_OK) { - printf("Started writing new entry %s\n", file_info.filename); -} -``` - -### mz_zip_writer_entry_close - -Closes entry in zip file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -if (mz_zip_writer_close(zip_writer) == MZ_OK) { - printf("Stopped writing new entry\n"); -} -``` - -### mz_zip_writer_entry_write - -Writes data into entry for zip. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void *|buf|Buffer of data to write| -int32_t|len|Number of bytes to write| - -**Return** -|Type|Description| -|-|-| -|int32_t|Bytes written or [MZ_ERROR](mz_error.md) code if less than 0.| - - -**Example** -``` -mz_zip_file file_info = { 0 }; - -file_info.filename = "newfile.txt"; -file_info.modified_date = time(NULL); -file_info.version_madeby = MZ_VERSION_MADEBY; -file_info.compression_method = MZ_COMPRESS_METHOD_STORE; -file_info.flag = MZ_ZIP_FLAG_UTF8; - -if (mz_zip_writer_entry_open(zip_writer, &file_info) == MZ_OK) { - printf("Started writing new entry %s\n", file_info.filename); - int32_t bytes_written = mz_zip_writer_entry_write(zip_writer, "test", 4); - if (bytes_written == 4) { - printf("Successfully wrote test\n"); - } - mz_zip_writer_entry_close(zip_writer); -} -``` - -## Writer Add/Compress - -### mz_zip_writer_add - -Writes all data to the currently open entry in the zip. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void *|stream|_mz_stream_ instance| -|mz_stream_read_cb|read_cb|Callback to read from when adding new entry| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -mz_stream_mem_create(&mem_stream); -mz_stream_mem_set_grow(mem_stream, 1); -mz_stream_mem_write(mem_stream, "test", 4); -mz_stream_mem_seek(mem_stream, 0, MZ_SEEK_SET); - -mz_zip_file file_info = { 0 }; - -file_info.filename = "newfile.txt"; -file_info.modified_date = time(NULL); -file_info.version_madeby = MZ_VERSION_MADEBY; -file_info.compression_method = MZ_COMPRESS_METHOD_STORE; -file_info.flag = MZ_ZIP_FLAG_UTF8; - -if (mz_zip_writer_entry_open(zip_writer, &file_info) == MZ_OK) { - if (mz_zip_writer_add(zip_writer, mem_stream, mz_stream_mem_read) == MZ_OK) { - printf("Added new entry from stream\n"); - } - mz_zip_writer_entry_close(zip_writer); -} - -mz_stream_mem_delete(&mem_stream); -``` - -### mz_zip_writer_add_process - -Writes a portion of data to the currently open entry in the zip. This function is intended to be used in process loops where you don't want to compress the entire file in one function. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void *|stream|_mz_stream_ instance| -|mz_stream_read_cb|read_cb|Callback to read from when adding new entry| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful or MZ_END_OF_STREAM if done.| - -**Example** - -See source code for _mz_zip_writer_add_. - -### mz_zip_writer_add_info - -Adds an entry to the zip based on the info. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void *|stream|_mz_stream_ instance| -|mz_stream_read_cb|read_cb|Callback to read from when adding new entry| -|mz_file_info *|file_info|Zip entry information for adding new entry| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -mz_stream_mem_create(&mem_stream); -mz_stream_mem_set_grow(mem_stream, 1); -mz_stream_mem_write(mem_stream, "test", 4); -mz_stream_mem_seek(mem_stream, 0, MZ_SEEK_SET); - -mz_zip_file file_info = { 0 }; - -file_info.filename = "newfile.txt"; -file_info.modified_date = time(NULL); -file_info.version_madeby = MZ_VERSION_MADEBY; -file_info.compression_method = MZ_COMPRESS_METHOD_STORE; -file_info.flag = MZ_ZIP_FLAG_UTF8; - -if (mz_zip_writer_add_info(zip_writer, mem_stream, mz_stream_mem_read, &file_info) == MZ_OK) { - printf("Added new entry from stream\n"); -} - -mz_stream_mem_delete(&mem_stream); -``` - -### mz_zip_writer_add_buffer - -Adds an entry to the zip with a memory buffer. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void *|buf|Buffer to read when compressing| -|int32_t|len|Length of buffer to read| -|mz_file_info *|file_info|Zip entry information for adding new entry| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -mz_zip_file file_info = { 0 }; - -file_info.filename = "newfile.txt"; -file_info.modified_date = time(NULL); -file_info.version_madeby = MZ_VERSION_MADEBY; -file_info.compression_method = MZ_COMPRESS_METHOD_STORE; -file_info.flag = MZ_ZIP_FLAG_UTF8; - -char *contents = "test"; - -if (mz_zip_writer_add_buffer(zip_writer, contents, strlen(contents), &file_info) == MZ_OK) { - printf("Added new entry from buffer\n"); -} -``` - -### mz_zip_writer_add_file - -Adds an entry to the zip from a file. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|const char *|path|Path to file on disk to add| -|const char *|filename_in_zip|Filename in zip to write| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -const char *path = "c:\\mydatafiles\\tx101.txt"; -const char *filename_in_zip = "101.txt; -if (mz_zip_writer_add_file(zip_writer, path, filename_in_zip) == MZ_OK) { - printf("Entry added to zip %s as %s\n", path, filename_in_zip); -} -``` - -### mz_zip_writer_add_path - -Enumerates a directory or pattern and adds entries to the zip. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|const char *|path|Path of directory to add (can include search pattern)| -|const char *|root_path|Root directory to start adding from. Entries will be named in the relative to this root path| -|uint8_t|include_path|Include the full path if 1| -|uint8_t|recursive|Process directory recursively if 1| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** -``` -if (mz_zip_writer_add_path(zip_writer, "c:\\dir1\\dir2\\", "c:\\dir1\", 0, 1) == MZ_OK) { - printf("Added entries from c:\\dir1\\dir2\\ recursively\n"); -} -``` - -### mz_zip_writer_copy_from_reader - -Adds an entry from a zip reader instance. This copies the current entry from the zip reader instance. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void *|reader|_mz_zip_reader_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful.| - -**Example** - -See source code for _minizip_erase_ where it erases a zip entry by copying all entries from the source zip file to the target zip file. - -## Writer Object - -### mz_zip_writer_set_password - -Password to use for encrypting files in the zip. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|const char *|password|Password string| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_writer_set_password(zip_writer, "myzippass"); -``` - -### mz_zip_writer_set_comment - -Comment to use for the archive. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|const char *|comment|Global zip file comment string| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_writer_set_comment(zip_writer, "This is my zip file -- hands off!"); -``` - -### mz_zip_writer_set_raw - -Sets whether or not we should write the entry raw. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|uint8_t|raw|Write data in zip in raw mode (don't compress) if 1| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_writer_set_raw(zip_writer, 1); -``` - -### mz_zip_writer_get_raw - -Gets whether or not we should write the entry raw. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|uint8_t *|raw|Pointer to store if using raw mode| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -uint8_t raw = 0; -mz_zip_writer_get_raw(zip_writer, &raw); -printf("Writing zip entries in mode: %s\n", (raw) ? "raw" : "normal"); -``` - -### mz_zip_writer_set_aes - -Use aes encryption when adding files in zip. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|uint8_t|aes|Encrypt files with AES 256-bit if 1| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_writer_set_aes(zip_writer, 1); -``` - -### mz_zip_writer_set_compress_method - -Sets the compression method when adding files in zip. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|uint16_t|compress_method|[MZ_COMPRESS_METHOD](mz_compress_method.md) compression method when adding entries| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_writer_set_compress_method(zip_writer, MZ_COMPRESS_METHOD_STORE); -``` - -### mz_zip_writer_set_compress_level - -Sets the compression level when adding files in zip. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|int16_t|compress_level|[MZ_COMPRESS_LEVEL](mz_compress_level.md) compression level when adding entries| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_writer_set_compress_level(zip_writer, MZ_COMPRESS_LEVEL_BEST); -``` - -### mz_zip_writer_set_zip_cd - -Sets whether or not the central directory should be zipped. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|uint8_t|zip_cd|Zip the central directory if 1| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_writer_set_zip_cd(zip_writer, 1); -``` - -### mz_zip_writer_set_certificate - -Sets the certificate and timestamp url to use for signing when adding files in zip. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|const char *|cert_path|Path to certificate to sign entries with| -|const char *|cert_pwd|Password for certificate to sign with| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -mz_zip_writer_set_certificate(zip_writer, "c:\\mycerts\\zip_cert.pfx", "mycertpwd"); -``` - -### mz_zip_writer_set_overwrite_cb - -Sets the callback for what to do when a zip file is about to be overwritten. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void *|userdata|User supplied data| -|mz_zip_writer_overwrite_cb|cb|_mz_zip_writer_overwrite_cb_ function pointer| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** - -See example for _mz_zip_writer_overwrite_cb_. - -### mz_zip_writer_set_password_cb - -Sets the callback for what to do when a password for an entry. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void *|userdata|User supplied data| -|mz_zip_writer_password_cb|cb|_mz_zip_writer_password_cb_ function pointer| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** - -See example for _mz_zip_writer_password_cb_. - -### mz_zip_writer_set_progress_cb - -Sets the callback that gets called to update compression progress. This callback is called on an interval specified by _mz_zip_writer_set_progress_interval_. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void *|userdata|User supplied data| -|mz_zip_writer_progress_cb|cb|_mz_zip_writer_progress_cb_ function pointer| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** - -See example for _mz_zip_writer_progress_cb_. - -### mz_zip_writer_set_progress_interval - -Let at least milliseconds pass between calls to progress callback. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|uint32_t|milliseconds|Number of milliseconds to wait before calling _mz_zip_writer_progress_cb_ during extraction| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -mz_zip_writer_set_progress_interval(zip_writer, 1000); // Wait 1 sec -``` - -### mz_zip_writer_set_entry_cb - -Sets callback for when a new zip file entry is encountered during compression. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void *|userdata|User supplied data| -|mz_zip_writer_entry_cb|cb|_mz_zip_writer_entry_cb_ function pointer| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** - -See example for _mz_zip_writer_entry_cb_. - -### mz_zip_writer_get_zip_handle - -Gets the underlying zip instance handle. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void *|handle|_mz_zip_writer_ instance| -|void **|zip_handle|Pointer to store _mz_zip_ instance| - -**Return** -|Type|Description| -|-|-| -|int32_t|[MZ_ERROR](mz_error.md) code, MZ_OK if successful| - -**Example** -``` -void *zip_handle = NULL; -mz_zip_writer_get_zip_handle(zip_writer, &zip_handle); -``` - -### mz_zip_writer_create - -Creates a _mz_zip_writer_ instance and returns its pointer. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void **|handle|Pointer to store the _mz_zip_writer_ instance| - -**Return** -|Type|Description| -|-|-| -|void *|Pointer to the _mz_zip_writer_ instance| - -**Example** -``` -void *zip_writer = NULL; -mz_zip_writer_create(&zip_writer); -``` - -### mz_zip_writer_delete - -Deletes a _mz_zip_writer_ instance and resets its pointer to zero. - -**Arguments** -|Type|Name|Description| -|-|-|-| -|void **|handle|Pointer to the _mz_zip_writer_ instance| - -**Return** -|Type|Description| -|-|-| -|void|No return| - -**Example** -``` -void *zip_writer = NULL; -mz_zip_writer_create(&zip_writer); -mz_zip_writer_delete(&zip_writer); -``` diff --git a/minizip-ng/doc/zip/appnote.iz.txt b/minizip-ng/doc/zip/appnote.iz.txt deleted file mode 100644 index 362f31f..0000000 --- a/minizip-ng/doc/zip/appnote.iz.txt +++ /dev/null @@ -1,3686 +0,0 @@ -[Info-ZIP note, 20040528: this file is based on PKWARE's appnote.txt of - 15 February 1996, taking into account PKWARE's revised appnote.txt - version 6.2.0 of 26 April 2004. It has been unofficially corrected - and extended by Info-ZIP without explicit permission by PKWARE. - Although Info-ZIP believes the information to be accurate and complete, - it is provided under a disclaimer similar to the PKWARE disclaimer below, - differing only in the substitution of "Info-ZIP" for "PKWARE". In other - words, use this information at your own risk, but we think it's correct. - - Specification info from PKWARE that was obviously wrong has been corrected - silently (e.g. missing structure fields, wrong numbers). - As of PKZIPW 2.50, two new incompatibilities have been introduced by PKWARE; - they are noted below. Note that the "NTFS tag" conflict is currently not - real; PKZIPW 2.50 actually tags NTFS files as having come from a FAT - file system, too.] - -File: APPNOTE.TXT - .ZIP File Format Specification -Version: 6.2.0 - NOTIFICATION OF CHANGE -Revised: 04/26/2004 [2004-05-28 Info-ZIP] -Copyright (c) 1989 - 2004 PKWARE Inc., All Rights Reserved. - -I. Purpose ----------- - -This specification is intended to define a cross-platform, -interoperable file format. Since its first publication -in 1989, PKWARE has remained committed to ensuring the -interoperability of the .ZIP file format through this -specification. We trust that all .ZIP compatible vendors -and application developers that have adopted this format -will share and support this commitment. - - -II. Disclaimer --------------- - -Although PKWARE will attempt to supply current and accurate -information relating to its file formats, algorithms, and the -subject programs, the possibility of error or omission can not -be eliminated. PKWARE therefore expressly disclaims any warranty -that the information contained in the associated materials relating -to the subject programs and/or the format of the files created or -accessed by the subject programs and/or the algorithms used by -the subject programs, or any other matter, is current, correct or -accurate as delivered. Any risk of damage due to any possible -inaccurate information is assumed by the user of the information. -Furthermore, the information relating to the subject programs -and/or the file formats created or accessed by the subject -programs and/or the algorithms used by the subject programs is -subject to change without notice. - -If the version of this file is marked as a NOTIFICATION OF CHANGE, -the content defines an Early Feature Specification (EFS) change -to the .ZIP file format that may be subject to modification prior -to publication of the Final Feature Specification (FFS). This -document may also contain information on Planned Feature -Specifications (PFS) defining recognized future extensions. - - -III. Change Log ---------------- - -Version Change Description Date -------- ------------------ ---------- -5.2 -Single Password Symmetric Encryption 06/02/2003 - storage - -6.1.0 -Smart Card compatibility 01/20/2004 - -Documentation on certificate storage - -6.2.0 -Introduction of Central Directory 04/26/2004 - Encryption for encrypting metadata - -Added OS/X to Version Made By values - - -IV. General Format of a .ZIP file ---------------------------------- - - Files stored in arbitrary order. Large .ZIP files can span multiple - diskette media or be split into user-defined segment sizes. [The - minimum user-defined segment size for a split .ZIP file is 64K. - (removed by PKWare 2003-06-01)] - - Overall .ZIP file format: - - [local file header 1] - [file data 1] - [data descriptor 1] - . - . - . - [local file header n] - [file data n] - [data descriptor n] - [archive decryption header] (EFS) - [archive extra data record] (EFS) - [central directory] - [zip64 end of central directory record] - [zip64 end of central directory locator] - [end of central directory record] - - - A. Local file header: - - local file header signature 4 bytes (0x04034b50) - version needed to extract 2 bytes - general purpose bit flag 2 bytes - compression method 2 bytes - last mod file time 2 bytes - last mod file date 2 bytes - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - file name length 2 bytes - extra field length 2 bytes - - file name (variable size) - extra field (variable size) - - - B. File data - - Immediately following the local header for a file - is the compressed or stored data for the file. - The series of [local file header][file data][data - descriptor] repeats for each file in the .ZIP archive. - - - C. Data descriptor: - - [Info-ZIP discrepancy: - The Info-ZIP zip program starts the data descriptor with a 4-byte - PK-style signature. Despite the specification, none of the PKWARE - programs supports the data descriptor. PKZIP 4.0 -fix function - (and PKZIPFIX 2.04) ignores the data descriptor info even when bit 3 - of the general purpose bit flag is set. - data descriptor signature 4 bytes (0x08074b50) - ] - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - - This descriptor exists only if bit 3 of the general - purpose bit flag is set (see below). It is byte aligned - and immediately follows the last byte of compressed data. - This descriptor is used only when it was not possible to - seek in the output .ZIP file, e.g., when the output .ZIP file - was standard output or a non seekable device. For Zip64 format - archives, the compressed and uncompressed sizes are 8 bytes each. - - - D. Archive decryption header: (EFS) - - The Archive Decryption Header is introduced in version 6.2 - of the ZIP format specification. This record exists in support - of the Central Directory Encryption Feature implemented as part of - the Strong Encryption Specification as described in this document. - When the Central Directory Structure is encrypted, this decryption - header will precede the encrypted data segment. The encrypted - data segment will consist of the Archive extra data record (if - present) and the encrypted Central Directory Structure data. - The format of this data record is identical to the Decryption - header record preceding compressed file data. If the central - directory structure is encrypted, the location of the start of - this data record is determined using the Start of Central Directory - field in the Zip64 End of Central Directory record. Refer to the - section on the Strong Encryption Specification for information - on the fields used in the Archive Decryption Header record. - - - E. Archive extra data record: (EFS) - - archive extra data signature 4 bytes (0x08064b50) - extra field length 4 bytes - extra field data (variable size) - - The Archive Extra Data Record is introduced in version 6.2 - of the ZIP format specification. This record exists in support - of the Central Directory Encryption Feature implemented as part of - the Strong Encryption Specification as described in this document. - When present, this record immediately precedes the central - directory data structure. The size of this data record will be - included in the Size of the Central Directory field in the - End of Central Directory record. If the central directory structure - is compressed, but not encrypted, the location of the start of - this data record is determined using the Start of Central Directory - field in the Zip64 End of Central Directory record. - - - F. Central directory structure: - - [file header 1] - . - . - . - [file header n] - [digital signature] - - File header: - - central file header signature 4 bytes (0x02014b50) - version made by 2 bytes - version needed to extract 2 bytes - general purpose bit flag 2 bytes - compression method 2 bytes - last mod file time 2 bytes - last mod file date 2 bytes - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - file name length 2 bytes - extra field length 2 bytes - file comment length 2 bytes - disk number start 2 bytes - internal file attributes 2 bytes - external file attributes 4 bytes - relative offset of local header 4 bytes - - file name (variable size) - extra field (variable size) - file comment (variable size) - - Digital signature: - - header signature 4 bytes (0x05054b50) - size of data 2 bytes - signature data (variable size) - - With the introduction of the Central Directory Encryption - feature in version 6.2 of this specification, the Central - Directory Structure may be stored both compressed and encrypted. - Although not required, it is assumed when encrypting the - Central Directory Structure, that it will be compressed - for greater storage efficiency. Information on the - Central Directory Encryption feature can be found in the section - describing the Strong Encryption Specification. The Digital - Signature record will be neither compressed nor encrypted. - - - G. Zip64 end of central directory record - - zip64 end of central dir - signature 4 bytes (0x06064b50) - size of zip64 end of central - directory record 8 bytes - version made by 2 bytes - version needed to extract 2 bytes - number of this disk 4 bytes - number of the disk with the - start of the central directory 4 bytes - total number of entries in the - central directory on this disk 8 bytes - total number of entries in the - central directory 8 bytes - size of the central directory 8 bytes - offset of start of central - directory with respect to - the starting disk number 8 bytes - zip64 extensible data sector (variable size) - - The above record structure defines Version 1 of the - Zip64 end of central directory record. Version 1 was - implemented in versions of this specification preceding - 6.2 in support of the ZIP64(tm) large file feature. The - introduction of the Central Directory Encryption feature - implemented in version 6.2 as part of the Strong Encryption - Specification defines Version 2 of this record structure. - Refer to the section describing the Strong Encryption - Specification for details on the version 2 format for - this record. - - - H. Zip64 end of central directory locator - - zip64 end of central dir locator - signature 4 bytes (0x07064b50) - number of the disk with the - start of the zip64 end of - central directory 4 bytes - relative offset of the zip64 - end of central directory record 8 bytes - total number of disks 4 bytes - - - I. End of central directory record: - - end of central dir signature 4 bytes (0x06054b50) - number of this disk 2 bytes - number of the disk with the - start of the central directory 2 bytes - total number of entries in the - central directory on this disk 2 bytes - total number of entries in - the central directory 2 bytes - size of the central directory 4 bytes - offset of start of central - directory with respect to - the starting disk number 4 bytes - .ZIP file comment length 2 bytes - .ZIP file comment (variable size) - - - J. Explanation of fields: - - version made by (2 bytes) - - [PKWARE describes "OS made by" now (since 1998) as follows: - The upper byte indicates the compatibility of the file - attribute information. If the external file attributes - are compatible with MS-DOS and can be read by PKZIP for - DOS version 2.04g then this value will be zero. If these - attributes are not compatible, then this value will - identify the host system on which the attributes are - compatible.] - The upper byte indicates the host system (OS) for the - file. Software can use this information to determine - the line record format for text files etc. The current - mappings are: - - 0 - FAT file system (DOS, OS/2, NT) + PKWARE 2.50+ VFAT, NTFS - 1 - Amiga - 2 - OpenVMS - 3 - Unix - 4 - VM/CMS - 5 - Atari ST - 6 - HPFS file system (OS/2, NT 3.x) - 7 - Macintosh - 8 - Z-System - 9 - CP/M - --------------------------------------------------------------------- - PKWARE assignment | Info-ZIP assignment - -----------------------------------|--------------------------------- - 10 - Windows NTFS | TOPS-20 - (since PKZIPW 2.50, but | (assigned Oct-1992, - not used by any PKWARE prog) | no longer used) - 11 - MVS | NTFS file system (WinNT) - | (actively used by Info-ZIP's - | Zip for NT since Sep-1993) - 12 - VSE | SMS/QDOS - --------------------------------------------------------------------- - 13 - Acorn RISC OS - 14 - VFAT file system (Win95, NT) [Info-ZIP reservation, unused] - 15 - MVS [PKWARE describes this assignment as "alternate MVS"] - 16 - BeOS (BeBox or PowerMac) - 17 - Tandem - 18 - OS/400 (IBM) | THEOS - 19 - OS/X (Darwin) - 20 thru 29 - unused - 30 - AtheOS/Syllable - 31 thru 255 - unused - - The lower byte indicates the ZIP specification version - (the version of this document) supported by the software - used to encode the file. The value/10 indicates the major - version number, and the value mod 10 is the minor version - number. - - version needed to extract (2 bytes) - - The minimum supported ZIP specification version needed to - extract the file, mapped as above. This value is based on - the specific format features a ZIP program must support to - be able to extract the file. If multiple features are - applied to a file, the minimum version should be set to the - feature having the highest value. New features or feature - changes affecting the published format specification will be - implemented using higher version numbers than the last - published value to avoid conflict. - - Current minimum feature versions are as defined below: - - 1.0 - Default value - 1.1 - File is a volume label - 2.0 - File is a folder (directory) - 2.0 - File is compressed using Deflate compression - 2.0 - File is encrypted using traditional PKWARE encryption - 2.1 - File is compressed using Deflate64(tm) - 2.5 - File is compressed using PKWARE DCL Implode - 2.7 - File is a patch data set - 4.5 - File uses ZIP64 format extensions - 4.6 - File is compressed using BZIP2 compression* - 5.0 - File is encrypted using DES - 5.0 - File is encrypted using 3DES - 5.0 - File is encrypted using original RC2 encryption - 5.0 - File is encrypted using RC4 encryption - 5.1 - File is encrypted using AES encryption - 5.1 - File is encrypted using corrected RC2 encryption** - 5.2 - File is encrypted using corrected RC2-64 encryption** - 6.1 - File is encrypted using non-OAEP key wrapping*** - 6.2 - Central directory encryption - - - * Early 7.x (pre-7.2) versions of PKZIP incorrectly set the - version needed to extract for BZIP2 compression to be 50 - when it should have been 46. - - ** Refer to the section on Strong Encryption Specification - for additional information regarding RC2 corrections. - - *** Certificate encryption using non-OAEP key wrapping is the - intended mode of operation for all versions beginning with 6.1. - Support for OAEP key wrapping should only be used for - backward compatibility when sending ZIP files to be opened by - versions of PKZIP older than 6.1 (5.0 or 6.0). - - When using ZIP64 extensions, the corresponding value in the - Zip64 end of central directory record should also be set. - This field currently supports only the value 45 to indicate - ZIP64 extensions are present. - - general purpose bit flag: (2 bytes) - - Bit 0: If set, indicates that the file is encrypted. - - (For Method 6 - Imploding) - Bit 1: If the compression method used was type 6, - Imploding, then this bit, if set, indicates - an 8K sliding dictionary was used. If clear, - then a 4K sliding dictionary was used. - Bit 2: If the compression method used was type 6, - Imploding, then this bit, if set, indicates - 3 Shannon-Fano trees were used to encode the - sliding dictionary output. If clear, then 2 - Shannon-Fano trees were used. - - (For Methods 8 and 9 - Deflating) - Bit 2 Bit 1 - 0 0 Normal (-en) compression option was used. - 0 1 Maximum (-exx/-ex) compression option was used. - 1 0 Fast (-ef) compression option was used. - 1 1 Super Fast (-es) compression option was used. - - Note: Bits 1 and 2 are undefined if the compression - method is any other. - - Bit 3: If this bit is set, the fields crc-32, compressed - size and uncompressed size are set to zero in the - local header. The correct values are put in the - data descriptor immediately following the compressed - data. (Note: PKZIP version 2.04g for DOS only - recognizes this bit for method 8 compression, newer - versions of PKZIP recognize this bit for any - compression method.) - [Info-ZIP note: This bit was introduced by PKZIP 2.04 for - DOS. In general, this feature can only be reliably used - together with compression methods that allow intrinsic - detection of the "end-of-compressed-data" condition. From - the set of compression methods described in this Zip archive - specification, only "deflate" and "bzip2" fulfill this - requirement. - Especially, the method STORED does not work! - The Info-ZIP tools recognize this bit regardless of the - compression method; but, they rely on correctly set - "compressed size" information in the central directory entry.] - - Bit 4: Reserved for use with method 8, for enhanced - deflating. - - Bit 5: If this bit is set, this indicates that the file is - compressed patched data. (Note: Requires PKZIP - version 2.70 or greater) - - Bit 6: Strong encryption. If this bit is set, you should - set the version needed to extract value to at least - 50 and you must also set bit 0. If AES encryption - is used, the version needed to extract value must - be at least 51. - - Bit 7: Currently unused. - - Bit 8: Currently unused. - - Bit 9: Currently unused. - - Bit 10: Currently unused. - - Bit 11: Currently unused. - - Bit 12: Reserved by PKWARE for enhanced compression. - - Bit 13: Used when encrypting the Central Directory to indicate - selected data values in the Local Header are masked to - hide their actual values. See the section describing - the Strong Encryption Specification for details. - - Bit 14: Reserved by PKWARE. - - Bit 15: Reserved by PKWARE. - - compression method: (2 bytes) - - (see accompanying documentation for algorithm - descriptions) - - 0 - The file is stored (no compression) - 1 - The file is Shrunk - 2 - The file is Reduced with compression factor 1 - 3 - The file is Reduced with compression factor 2 - 4 - The file is Reduced with compression factor 3 - 5 - The file is Reduced with compression factor 4 - 6 - The file is Imploded - 7 - Reserved for Tokenizing compression algorithm - 8 - The file is Deflated - 9 - Enhanced Deflating using Deflate64(tm) - 10 - PKWARE Data Compression Library Imploding - 11 - Reserved by PKWARE - 12 - File is compressed using BZIP2 algorithm - - date and time fields: (2 bytes each) - - The date and time are encoded in standard MS-DOS format. - If input came from standard input, the date and time are - those at which compression was started for this data. - If encrypting the central directory and general purpose bit - flag 13 is set indicating masking, the value stored in the - Local Header will be zero. - - CRC-32: (4 bytes) - - The CRC-32 algorithm was generously contributed by - David Schwaderer and can be found in his excellent - book "C Programmers Guide to NetBIOS" published by - Howard W. Sams & Co. Inc. The 'magic number' for - the CRC is 0xdebb20e3. The proper CRC pre and post - conditioning is used, meaning that the CRC register - is pre-conditioned with all ones (a starting value - of 0xffffffff) and the value is post-conditioned by - taking the one's complement of the CRC residual. - If bit 3 of the general purpose flag is set, this - field is set to zero in the local header and the correct - value is put in the data descriptor and in the central - directory. If encrypting the central directory and general - purpose bit flag 13 is set indicating masking, the value - stored in the Local Header will be zero. - - compressed size: (4 bytes) - uncompressed size: (4 bytes) - - The size of the file compressed and uncompressed, - respectively. If bit 3 of the general purpose bit flag - is set, these fields are set to zero in the local header - and the correct values are put in the data descriptor and - in the central directory. If an archive is in zip64 format - and the value in this field is 0xFFFFFFFF, the size will be - in the corresponding 8 byte zip64 extended information - extra field. If encrypting the central directory and general - purpose bit flag 13 is set indicating masking, the value stored - for the uncompressed size in the Local Header will be zero. - - file name length: (2 bytes) - extra field length: (2 bytes) - file comment length: (2 bytes) - - The length of the file name, extra field, and comment - fields respectively. The combined length of any - directory record and these three fields should not - generally exceed 65,535 bytes. If input came from standard - input, the file name length is set to zero. - - [Info-ZIP note: - This feature is not yet supported by any PKWARE version of ZIP - (at least not in PKZIP for DOS and PKZIP for Windows/WinNT). - The Info-ZIP programs handle standard input differently: - If input came from standard input, the filename is set to "-" - (length one).] - - - disk number start: (2 bytes) - - The number of the disk on which this file begins. If an - archive is in zip64 format and the value in this field is - 0xFFFF, the size will be in the corresponding 4 byte zip64 - extended information extra field. - - internal file attributes: (2 bytes) - - Bits 1 and 2 are reserved for use by PKWARE. - - The lowest bit of this field indicates, if set, that - the file is apparently an ASCII or text file. If not - set, that the file apparently contains binary data. - The remaining bits are unused in version 1.0. - - The 0x0002 bit of this field indicates, if set, that a - 4 byte variable record length control field precedes each - logical record indicating the length of the record. This - flag is independent of text control characters, and if used - in conjunction with text data, includes any control - characters in the total length of the record. This value is - provided for mainframe data transfer support. - - external file attributes: (4 bytes) - - The mapping of the external attributes is - host-system dependent (see 'version made by'). For - MS-DOS, the low order byte is the MS-DOS directory - attribute byte. If input came from standard input, this - field is set to zero. - - relative offset of local header: (4 bytes) - - This is the offset from the start of the first disk on - which this file appears, to where the local header should - be found. If an archive is in zip64 format and the value - in this field is 0xFFFFFFFF, the size will be in the - corresponding 8 byte zip64 extended information extra field. - - file name: (Variable) - - The name of the file, with optional relative path. - The path stored should not contain a drive or - device letter, or a leading slash. All slashes - should be forward slashes '/' as opposed to - backwards slashes '\' for compatibility with Amiga - and Unix file systems etc. If input came from standard - input, there is no file name field. If encrypting - the central directory and general purpose bit flag 13 is set - indicating masking, the file name stored in the Local Header - will not be the actual file name. A masking value consisting - of a unique hexadecimal value will be stored. This value will - be sequentially incremented for each file in the archive. See - the section on the Strong Encryption Specification for details - on retrieving the encrypted file name. - [Info-ZIP discrepancy: - If input came from standard input, the file name is set - to "-" (without the quotes). - As far as we know, the PKWARE specification for "input from - stdin" is not supported by PKZIP/PKUNZIP for DOS, OS/2, Windows - Windows NT.] - - extra field: (Variable) - - This is for expansion. If additional information - needs to be stored for special needs or for specific - platforms, it should be stored here. Earlier versions - of the software can then safely skip this file, and - find the next file or header. This field will be 0 - length in version 1.0. - - In order to allow different programs and different types - of information to be stored in the 'extra' field in .ZIP - files, the following structure should be used for all - programs storing data in this field: - - header1+data1 + header2+data2 . . . - - Each header should consist of: - - Header ID - 2 bytes - Data Size - 2 bytes - - Note: all fields stored in Intel low-byte/high-byte order. - - The Header ID field indicates the type of data that is in - the following data block. - - Header ID's of 0 thru 31 are reserved for use by PKWARE. - The remaining ID's can be used by third party vendors for - proprietary usage. - - The current Header ID mappings defined by PKWARE are: - - 0x0001 ZIP64 extended information extra field - 0x0007 AV Info - 0x0008 Reserved for future Unicode file name data (PFS) - 0x0009 OS/2 extended attributes (also Info-ZIP) - 0x000a NTFS (Win9x/WinNT FileTimes) - 0x000c OpenVMS (also Info-ZIP) - 0x000d Unix - 0x000e Reserved for file stream and fork descriptors - 0x000f Patch Descriptor - 0x0014 PKCS#7 Store for X.509 Certificates - 0x0015 X.509 Certificate ID and Signature for - individual file - 0x0016 X.509 Certificate ID for Central Directory - 0x0017 Strong Encryption Header - 0x0018 Record Management Controls - 0x0019 PKCS#7 Encryption Recipient Certificate List - 0x0065 IBM S/390 (Z390), AS/400 (I400) attributes - - uncompressed - 0x0066 Reserved for IBM S/390 (Z390), AS/400 (I400) - attributes - compressed - - The Header ID mappings defined by Info-ZIP and third parties are: - - 0x07c8 Info-ZIP Macintosh (old, J. Lee) - 0x2605 ZipIt Macintosh (first version) - 0x2705 ZipIt Macintosh v 1.3.5 and newer (w/o full filename) - 0x2805 ZipIt Macintosh 1.3.5+ - 0x334d Info-ZIP Macintosh (new, D. Haase's 'Mac3' field) - 0x4154 Tandem NSK - 0x4341 Acorn/SparkFS (David Pilling) - 0x4453 Windows NT security descriptor (binary ACL) - 0x4704 VM/CMS - 0x470f MVS - 0x4854 Theos, old inofficial port - 0x4b46 FWKCS MD5 (see below) - 0x4c41 OS/2 access control list (text ACL) - 0x4d49 Info-ZIP OpenVMS (obsolete) - 0x4d63 Macintosh SmartZIP, by Macro Bambini - 0x4f4c Xceed original location extra field - 0x5356 AOS/VS (binary ACL) - 0x5455 extended timestamp - 0x554e Xceed unicode extra field - 0x5855 Info-ZIP Unix (original; also OS/2, NT, etc.) - 0x6542 BeOS (BeBox, PowerMac, etc.) - 0x6854 Theos - 0x7441 AtheOS (AtheOS/Syllable attributes) - 0x756e ASi Unix - 0x7855 Info-ZIP Unix (new) - 0xfb4a SMS/QDOS - - Detailed descriptions of Extra Fields defined by third - party mappings will be documented as information on - these data structures is made available to PKWARE. - PKWARE does not guarantee the accuracy of any published - third party data. - - The Data Size field indicates the size of the following - data block. Programs can use this value to skip to the - next header block, passing over any data blocks that are - not of interest. - - Note: As stated above, the size of the entire .ZIP file - header, including the file name, comment, and extra - field should not exceed 64K in size. - - In case two different programs should appropriate the same - Header ID value, it is strongly recommended that each - program place a unique signature of at least two bytes in - size (and preferably 4 bytes or bigger) at the start of - each data area. Every program should verify that its - unique signature is present, in addition to the Header ID - value being correct, before assuming that it is a block of - known type. - - In the following descriptions, note that "Short" means two bytes, - "Long" means four bytes, and "Long-Long" means eight bytes, - regardless of their native sizes. Unless specifically noted, all - integer fields should be interpreted as unsigned (non-negative) - numbers. - - - -ZIP64 Extended Information Extra Field (0x0001): - =============================================== - - The following is the layout of the ZIP64 extended - information "extra" block. If one of the size or - offset fields in the Local or Central directory - record is too small to hold the required data, - a ZIP64 extended information record is created. - The order of the fields in the ZIP64 extended - information record is fixed, but the fields will - only appear if the corresponding Local or Central - directory record field is set to 0xFFFF or 0xFFFFFFFF. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (ZIP64) 0x0001 2 bytes Tag for this "extra" block type - Size 2 bytes Size of this "extra" block - Original - Size 8 bytes Original uncompressed file size - Compressed - Size 8 bytes Size of compressed data - Relative Header - Offset 8 bytes Offset of local header record - Disk Start - Number 4 bytes Number of the disk on which - this file starts - - This entry in the Local header must include BOTH original - and compressed file sizes. - - - -OS/2 Extended Attributes Extra Field (0x0009): - ============================================= - - The following is the layout of the OS/2 extended attributes "extra" - block. (Last Revision 19960922) - - Note: all fields stored in Intel low-byte/high-byte order. - - Local-header version: - - Value Size Description - ----- ---- ----------- - (OS/2) 0x0009 Short tag for this extra block type - TSize Short total data size for this block - BSize Long uncompressed EA data size - CType Short compression type - EACRC Long CRC value for uncompressed EA data - (var.) variable compressed EA data - - Central-header version: - - Value Size Description - ----- ---- ----------- - (OS/2) 0x0009 Short tag for this extra block type - TSize Short total data size for this block (4) - BSize Long size of uncompressed local EA data - - The value of CType is interpreted according to the "compression - method" section above; i.e., 0 for stored, 8 for deflated, etc. - - The OS/2 extended attribute structure (FEA2LIST) is - compressed and then stored in its entirety within this - structure. There will only ever be one "block" of data in - the variable-length field. - - - -OS/2 Access Control List Extra Field: - ==================================== - - The following is the layout of the OS/2 ACL extra block. - (Last Revision 19960922) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (ACL) 0x4c41 Short tag for this extra block type ("AL") - TSize Short total data size for this block - BSize Long uncompressed ACL data size - CType Short compression type - EACRC Long CRC value for uncompressed ACL data - (var.) variable compressed ACL data - - Central-header version: - - Value Size Description - ----- ---- ----------- - (ACL) 0x4c41 Short tag for this extra block type ("AL") - TSize Short total data size for this block (4) - BSize Long size of uncompressed local ACL data - - The value of CType is interpreted according to the "compression - method" section above; i.e., 0 for stored, 8 for deflated, etc. - - The uncompressed ACL data consist of a text header of the form - "ACL1:%hX,%hd\n", where the first field is the OS/2 ACCINFO acc_attr - member and the second is acc_count, followed by acc_count strings - of the form "%s,%hx\n", where the first field is acl_ugname (user - group name) and the second acl_access. This block type will be - extended for other operating systems as needed. - - - -Windows NT Security Descriptor Extra Field (0x4453): - =================================================== - - The following is the layout of the NT Security Descriptor (another - type of ACL) extra block. (Last Revision 19960922) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (SD) 0x4453 Short tag for this extra block type ("SD") - TSize Short total data size for this block - BSize Long uncompressed SD data size - Version Byte version of uncompressed SD data format - CType Short compression type - EACRC Long CRC value for uncompressed SD data - (var.) variable compressed SD data - - Central-header version: - - Value Size Description - ----- ---- ----------- - (SD) 0x4453 Short tag for this extra block type ("SD") - TSize Short total data size for this block (4) - BSize Long size of uncompressed local SD data - - The value of CType is interpreted according to the "compression - method" section above; i.e., 0 for stored, 8 for deflated, etc. - Version specifies how the compressed data are to be interpreted - and allows for future expansion of this extra field type. Currently - only version 0 is defined. - - For version 0, the compressed data are to be interpreted as a single - valid Windows NT SECURITY_DESCRIPTOR data structure, in self-relative - format. - - - -PKWARE Win95/WinNT Extra Field (0x000a): - ======================================= - - The following description covers PKWARE's "NTFS" attributes - "extra" block, introduced with the release of PKZIP 2.50 for - Windows. (Last Revision 20001118) - - (Note: At this time the Mtime, Atime and Ctime values may - be used on any WIN32 system.) - [Info-ZIP note: In the current implementations, this field has - a fixed total data size of 32 bytes and is only stored as local - extra field.] - - Value Size Description - ----- ---- ----------- - (NTFS) 0x000a Short Tag for this "extra" block type - TSize Short Total Data Size for this block - Reserved Long for future use - Tag1 Short NTFS attribute tag value #1 - Size1 Short Size of attribute #1, in bytes - (var.) SubSize1 Attribute #1 data - . - . - . - TagN Short NTFS attribute tag value #N - SizeN Short Size of attribute #N, in bytes - (var.) SubSizeN Attribute #N data - - For NTFS, values for Tag1 through TagN are as follows: - (currently only one set of attributes is defined for NTFS) - - Tag Size Description - ----- ---- ----------- - 0x0001 2 bytes Tag for attribute #1 - Size1 2 bytes Size of attribute #1, in bytes (24) - Mtime 8 bytes 64-bit NTFS file last modification time - Atime 8 bytes 64-bit NTFS file last access time - Ctime 8 bytes 64-bit NTFS file creation time - - The total length for this block is 28 bytes, resulting in a - fixed size value of 32 for the TSize field of the NTFS block. - - The NTFS filetimes are 64-bit unsigned integers, stored in Intel - (least significant byte first) byte order. They determine the - number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch", - which is "01-Jan-1601 00:00:00 UTC". - - - -PKWARE OpenVMS Extra Field (0x000c): - =================================== - - The following is the layout of PKWARE's OpenVMS attributes - "extra" block. (Last Revision 12/17/91) - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (VMS) 0x000c Short Tag for this "extra" block type - TSize Short Total Data Size for this block - CRC Long 32-bit CRC for remainder of the block - Tag1 Short OpenVMS attribute tag value #1 - Size1 Short Size of attribute #1, in bytes - (var.) Size1 Attribute #1 data - . - . - . - TagN Short OpenVMS attribute tage value #N - SizeN Short Size of attribute #N, in bytes - (var.) SizeN Attribute #N data - - Rules: - - 1. There will be one or more of attributes present, which - will each be preceded by the above TagX & SizeX values. - These values are identical to the ATR$C_XXXX and - ATR$S_XXXX constants which are defined in ATR.H under - OpenVMS C. Neither of these values will ever be zero. - - 2. No word alignment or padding is performed. - - 3. A well-behaved PKZIP/OpenVMS program should never produce - more than one sub-block with the same TagX value. Also, - there will never be more than one "extra" block of type - 0x000c in a particular directory record. - - - -Info-ZIP VMS Extra Field: - ======================== - - The following is the layout of Info-ZIP's VMS attributes extra - block for VAX or Alpha AXP. The local-header and central-header - versions are identical. (Last Revision 19960922) - - Value Size Description - ----- ---- ----------- - (VMS2) 0x4d49 Short tag for this extra block type ("JM") - TSize Short total data size for this block - ID Long block ID - Flags Short info bytes - BSize Short uncompressed block size - Reserved Long (reserved) - (var.) variable compressed VMS file-attributes block - - The block ID is one of the following unterminated strings: - - "VFAB" struct FAB - "VALL" struct XABALL - "VFHC" struct XABFHC - "VDAT" struct XABDAT - "VRDT" struct XABRDT - "VPRO" struct XABPRO - "VKEY" struct XABKEY - "VMSV" version (e.g., "V6.1"; truncated at hyphen) - "VNAM" reserved - - The lower three bits of Flags indicate the compression method. The - currently defined methods are: - - 0 stored (not compressed) - 1 simple "RLE" - 2 deflated - - The "RLE" method simply replaces zero-valued bytes with zero-valued - bits and non-zero-valued bytes with a "1" bit followed by the byte - value. - - The variable-length compressed data contains only the data corre- - sponding to the indicated structure or string. Typically multiple - VMS2 extra fields are present (each with a unique block type). - - - -Info-ZIP Macintosh Extra Field: - ============================== - - The following is the layout of the (old) Info-ZIP resource-fork extra - block for Macintosh. The local-header and central-header versions - are identical. (Last Revision 19960922) - - Value Size Description - ----- ---- ----------- - (Mac) 0x07c8 Short tag for this extra block type - TSize Short total data size for this block - "JLEE" beLong extra-field signature - FInfo 16 bytes Macintosh FInfo structure - CrDat beLong HParamBlockRec fileParam.ioFlCrDat - MdDat beLong HParamBlockRec fileParam.ioFlMdDat - Flags beLong info bits - DirID beLong HParamBlockRec fileParam.ioDirID - VolName 28 bytes volume name (optional) - - All fields but the first two are in native Macintosh format - (big-endian Motorola order, not little-endian Intel). The least - significant bit of Flags is 1 if the file is a data fork, 0 other- - wise. In addition, if this extra field is present, the filename - has an extra 'd' or 'r' appended to indicate data fork or resource - fork. The 28-byte VolName field may be omitted. - - - -ZipIt Macintosh Extra Field (long): - ================================== - - The following is the layout of the ZipIt extra block for Macintosh. - The local-header and central-header versions are identical. - (Last Revision 19970130) - - Value Size Description - ----- ---- ----------- - (Mac2) 0x2605 Short tag for this extra block type - TSize Short total data size for this block - "ZPIT" beLong extra-field signature - FnLen Byte length of FileName - FileName variable full Macintosh filename - FileType Byte[4] four-byte Mac file type string - Creator Byte[4] four-byte Mac creator string - - - -ZipIt Macintosh Extra Field (short, for files): - ============================================== - - The following is the layout of a shortened variant of the - ZipIt extra block for Macintosh (without "full name" entry). - This variant is used by ZipIt 1.3.5 and newer for entries of - files (not directories) that do not have a MacBinary encoded - file. The local-header and central-header versions are identical. - (Last Revision 20030602) - - Value Size Description - ----- ---- ----------- - (Mac2b) 0x2705 Short tag for this extra block type - TSize Short total data size for this block (min. 12) - "ZPIT" beLong extra-field signature - FileType Byte[4] four-byte Mac file type string - Creator Byte[4] four-byte Mac creator string - fdFlags beShort attributes from FInfo.frFlags, - may be omitted - 0x0000 beShort reserved, may be omitted - - - -ZipIt Macintosh Extra Field (short, for directories): - ==================================================== - - The following is the layout of a shortened variant of the - ZipIt extra block for Macintosh used only for directory - entries. This variant is used by ZipIt 1.3.5 and newer to - save some optional Mac-specific information about directories. - The local-header and central-header versions are identical. - - Value Size Description - ----- ---- ----------- - (Mac2c) 0x2805 Short tag for this extra block type - TSize Short total data size for this block (12) - "ZPIT" beLong extra-field signature - frFlags beShort attributes from DInfo.frFlags, may - be omitted - View beShort ZipIt view flag, may be omitted - - - The View field specifies ZipIt-internal settings as follows: - - Bits of the Flags: - bit 0 if set, the folder is shown expanded (open) - when the archive contents are viewed in ZipIt. - bits 1-15 reserved, zero; - - - -Info-ZIP Macintosh Extra Field (new): - ==================================== - - The following is the layout of the (new) Info-ZIP extra - block for Macintosh, designed by Dirk Haase. - All values are in little-endian. - (Last Revision 19981005) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (Mac3) 0x334d Short tag for this extra block type ("M3") - TSize Short total data size for this block - BSize Long uncompressed finder attribute data size - Flags Short info bits - fdType Byte[4] Type of the File (4-byte string) - fdCreator Byte[4] Creator of the File (4-byte string) - (CType) Short compression type - (CRC) Long CRC value for uncompressed MacOS data - Attribs variable finder attribute data (see below) - - - Central-header version: - - Value Size Description - ----- ---- ----------- - (Mac3) 0x334d Short tag for this extra block type ("M3") - TSize Short total data size for this block - BSize Long uncompressed finder attribute data size - Flags Short info bits - fdType Byte[4] Type of the File (4-byte string) - fdCreator Byte[4] Creator of the File (4-byte string) - - The third bit of Flags in both headers indicates whether - the LOCAL extra field is uncompressed (and therefore whether CType - and CRC are omitted): - - Bits of the Flags: - bit 0 if set, file is a data fork; otherwise unset - bit 1 if set, filename will be not changed - bit 2 if set, Attribs is uncompressed (no CType, CRC) - bit 3 if set, date and times are in 64 bit - if zero date and times are in 32 bit. - bit 4 if set, timezone offsets fields for the native - Mac times are omitted (UTC support deactivated) - bits 5-15 reserved; - - - Attributes: - - Attribs is a Mac-specific block of data in little-endian format with - the following structure (if compressed, uncompress it first): - - Value Size Description - ----- ---- ----------- - fdFlags Short Finder Flags - fdLocation.v Short Finder Icon Location - fdLocation.h Short Finder Icon Location - fdFldr Short Folder containing file - - FXInfo 16 bytes Macintosh FXInfo structure - FXInfo-Structure: - fdIconID Short - fdUnused[3] Short unused but reserved 6 bytes - fdScript Byte Script flag and number - fdXFlags Byte More flag bits - fdComment Short Comment ID - fdPutAway Long Home Dir ID - - FVersNum Byte file version number - may be not used by MacOS - ACUser Byte directory access rights - - FlCrDat ULong date and time of creation - FlMdDat ULong date and time of last modification - FlBkDat ULong date and time of last backup - These time numbers are original Mac FileTime values (local time!). - Currently, date-time width is 32-bit, but future version may - support be 64-bit times (see flags) - - CrGMTOffs Long(signed!) difference "local Creat. time - UTC" - MdGMTOffs Long(signed!) difference "local Modif. time - UTC" - BkGMTOffs Long(signed!) difference "local Backup time - UTC" - These "local time - UTC" differences (stored in seconds) may be - used to support timestamp adjustment after inter-timezone transfer. - These fields are optional; bit 4 of the flags word controls their - presence. - - Charset Short TextEncodingBase (Charset) - valid for the following two fields - - FullPath variable Path of the current file. - Zero terminated string (C-String) - Currently coded in the native Charset. - - Comment variable Finder Comment of the current file. - Zero terminated string (C-String) - Currently coded in the native Charset. - - - -SmartZIP Macintosh Extra Field: - ==================================== - - The following is the layout of the SmartZIP extra - block for Macintosh, designed by Marco Bambini. - - Local-header version: - - Value Size Description - ----- ---- ----------- - 0x4d63 Short tag for this extra block type ("cM") - TSize Short total data size for this block (64) - "dZip" beLong extra-field signature - fdType Byte[4] Type of the File (4-byte string) - fdCreator Byte[4] Creator of the File (4-byte string) - fdFlags beShort Finder Flags - fdLocation.v beShort Finder Icon Location - fdLocation.h beShort Finder Icon Location - fdFldr beShort Folder containing file - CrDat beLong HParamBlockRec fileParam.ioFlCrDat - MdDat beLong HParamBlockRec fileParam.ioFlMdDat - frScroll.v Byte vertical pos. of folder's scroll bar - fdScript Byte Script flag and number - frScroll.h Byte horizontal pos. of folder's scroll bar - fdXFlags Byte More flag bits - FileName Byte[32] full Macintosh filename (pascal string) - - All fields but the first two are in native Macintosh format - (big-endian Motorola order, not little-endian Intel). - The extra field size is fixed to 64 bytes. - The local-header and central-header versions are identical. - - - -Acorn SparkFS Extra Field: - ========================= - - The following is the layout of David Pilling's SparkFS extra block - for Acorn RISC OS. The local-header and central-header versions are - identical. (Last Revision 19960922) - - Value Size Description - ----- ---- ----------- - (Acorn) 0x4341 Short tag for this extra block type ("AC") - TSize Short total data size for this block (20) - "ARC0" Long extra-field signature - LoadAddr Long load address or file type - ExecAddr Long exec address - Attr Long file permissions - Zero Long reserved; always zero - - The following bits of Attr are associated with the given file - permissions: - - bit 0 user-writable ('W') - bit 1 user-readable ('R') - bit 2 reserved - bit 3 locked ('L') - bit 4 publicly writable ('w') - bit 5 publicly readable ('r') - bit 6 reserved - bit 7 reserved - - - -VM/CMS Extra Field: - ================== - - The following is the layout of the file-attributes extra block for - VM/CMS. The local-header and central-header versions are - identical. (Last Revision 19960922) - - Value Size Description - ----- ---- ----------- - (VM/CMS) 0x4704 Short tag for this extra block type - TSize Short total data size for this block - flData variable file attributes data - - flData is an uncompressed fldata_t struct. - - - -MVS Extra Field: - =============== - - The following is the layout of the file-attributes extra block for - MVS. The local-header and central-header versions are identical. - (Last Revision 19960922) - - Value Size Description - ----- ---- ----------- - (MVS) 0x470f Short tag for this extra block type - TSize Short total data size for this block - flData variable file attributes data - - flData is an uncompressed fldata_t struct. - - - -PKWARE Unix Extra Field (0x000d): - ================================ - - The following is the layout of PKWARE's Unix "extra" block. - It was introduced with the release of PKZIP for Unix 2.50. - Note: all fields are stored in Intel low-byte/high-byte order. - (Last Revision 19980901) - - This field has a minimum data size of 12 bytes and is only stored - as local extra field. - - Value Size Description - ----- ---- ----------- - (Unix0) 0x000d Short Tag for this "extra" block type - TSize Short Total Data Size for this block - AcTime Long time of last access (UTC/GMT) - ModTime Long time of last modification (UTC/GMT) - UID Short Unix user ID - GID Short Unix group ID - (var) variable Variable length data field - - The variable length data field will contain file type - specific data. Currently the only values allowed are - the original "linked to" file names for hard or symbolic - links, and the major and minor device node numbers for - character and block device nodes. Since device nodes - cannot be either symbolic or hard links, only one set of - variable length data is stored. Link files will have the - name of the original file stored. This name is NOT NULL - terminated. Its size can be determined by checking TSize - - 12. Device entries will have eight bytes stored as two 4 - byte entries (in little-endian format). The first entry - will be the major device number, and the second the minor - device number. - - [Info-ZIP note: The fixed part of this field has the same layout as - Info-ZIP's abandoned "Unix1 timestamps & owner ID info" extra field; - only the two tag bytes are different.] - - - -PATCH Descriptor Extra Field (0x000f): - ===================================== - - The following is the layout of the Patch Descriptor "extra" - block. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (Patch) 0x000f Short Tag for this "extra" block type - TSize Short Size of the total "extra" block - Version Short Version of the descriptor - Flags Long Actions and reactions (see below) - OldSize Long Size of the file about to be patched - OldCRC Long 32-bit CRC of the file about to be patched - NewSize Long Size of the resulting file - NewCRC Long 32-bit CRC of the resulting file - - - Actions and reactions - - Bits Description - ---- ---------------- - 0 Use for auto detection - 1 Treat as a self-patch - 2-3 RESERVED - 4-5 Action (see below) - 6-7 RESERVED - 8-9 Reaction (see below) to absent file - 10-11 Reaction (see below) to newer file - 12-13 Reaction (see below) to unknown file - 14-15 RESERVED - 16-31 RESERVED - - Actions - - Action Value - ------ ----- - none 0 - add 1 - delete 2 - patch 3 - - Reactions - - Reaction Value - -------- ----- - ask 0 - skip 1 - ignore 2 - fail 3 - - Patch support is provided by PKPatchMaker(tm) technology and is - covered under U.S. Patents and Patents Pending. - - - -PKCS#7 Store for X.509 Certificates (0x0014): - ============================================ - - This field contains information about each of the certificates - files may be signed with. When the Central Directory Encryption - feature is enabled for a ZIP file, this record will appear in - the Archive Extra Data Record, otherwise it will appear in the - first central directory record and will be ignored in any - other record. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (Store) 0x0014 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the store data - SData TSize Data about the store - - SData - Value Size Description - ----- ---- ----------- - Version 2 bytes Version number, 0x0001 for now - StoreD (variable) Actual store data - - The StoreD member is suitable for passing as the pbData - member of a CRYPT_DATA_BLOB to the CertOpenStore() function - in Microsoft's CryptoAPI. The SSize member above will be - cbData + 6, where cbData is the cbData member of the same - CRYPT_DATA_BLOB. The encoding type to pass to - CertOpenStore() should be - PKCS_7_ANS_ENCODING | X509_ASN_ENCODING. - - - -X.509 Certificate ID and Signature for individual file (0x0015): - =============================================================== - - This field contains the information about which certificate in - the PKCS#7 store was used to sign a particular file. It also - contains the signature data. This field can appear multiple - times, but can only appear once per certificate. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (CID) 0x0015 2 bytes Tag for this "extra" block type - CSize 2 bytes Size of Method - Method (variable) - - Method - Value Size Description - ----- ---- ----------- - Version 2 bytes Version number, for now 0x0001 - AlgID 2 bytes Algorithm ID used for signing - IDSize 2 bytes Size of Certificate ID data - CertID (variable) Certificate ID data - SigSize 2 bytes Size of Signature data - Sig (variable) Signature data - - CertID - Value Size Description - ----- ---- ----------- - Size1 4 bytes Size of CertID, should be (IDSize - 4) - Size1 4 bytes A bug in version one causes this value - to appear twice. - IssSize 4 bytes Issuer data size - Issuer (variable) Issuer data - SerSize 4 bytes Serial Number size - Serial (variable) Serial Number data - - The Issuer and IssSize members are suitable for creating a - CRYPT_DATA_BLOB to be the Issuer member of a CERT_INFO - struct. The Serial and SerSize members would be the - SerialNumber member of the same CERT_INFO struct. This - struct would be used to find the certificate in the store - the file was signed with. Those structures are from the MS - CryptoAPI. - - Sig and SigSize are the actual signature data and size - generated by signing the file with the MS CryptoAPI using a - hash created with the given AlgID. - - - -X.509 Certificate ID and Signature for central directory (0x0016): - ================================================================= - - This field contains the information about which certificate in - the PKCS#7 store was used to sign the central directory structure. - When the Central Directory Encryption feature is enabled for a - ZIP file, this record will appear in the Archive Extra Data Record, - otherwise it will appear in the first central directory record, - along with the store. The data structure is the - same as the CID, except that SigSize will be 0, and there - will be no Sig member. - - This field is also kept after the last central directory - record, as the signature data (ID 0x05054b50, it looks like - a central directory record of a different type). This - second copy of the data is the Signature Data member of the - record, and will have a SigSize that is non-zero, and will - have Sig data. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (CDID) 0x0016 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of data that follows - TData TSize Data - - - -Strong Encryption Header (0x0017) (EFS): - =============================== - - Value Size Description - ----- ---- ----------- - 0x0017 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of data that follows - Format 2 bytes Format definition for this record - AlgID 2 bytes Encryption algorithm identifier - Bitlen 2 bytes Bit length of encryption key - Flags 2 bytes Processing flags - CertData TSize-8 Certificate decryption extra field data - (refer to the explanation for CertData - in the section describing the - Certificate Processing Method under - the Strong Encryption Specification) - - - -Record Management Controls (0x0018): - =================================== - - Value Size Description - ----- ---- ----------- -(Rec-CTL) 0x0018 2 bytes Tag for this "extra" block type - CSize 2 bytes Size of total extra block data - Tag1 2 bytes Record control attribute 1 - Size1 2 bytes Size of attribute 1, in bytes - Data1 Size1 Attribute 1 data - . - . - . - TagN 2 bytes Record control attribute N - SizeN 2 bytes Size of attribute N, in bytes - DataN SizeN Attribute N data - - - -PKCS#7 Encryption Recipient Certificate List (0x0019): (EFS) - ===================================================== - - This field contains the information about each of the certificates - that files may be encrypted with. This field should only appear - in the archive extra data record. This field is not required and - serves only to aide archive modifications by preserving public - encryption data. Individual security requirements may dictate - that this data be omitted to deter information exposure. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (CStore) 0x0019 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the store data - TData TSize Data about the store - - TData: - - Value Size Description - ----- ---- ----------- - Version 2 bytes Format version number - must 0x0001 at this time - CStore (var) PKCS#7 data blob - - - -MVS Extra Field (PKWARE, 0x0065): - ================================ - - The following is the layout of the MVS "extra" block. - Note: Some fields are stored in Big Endian format. - All text is in EBCDIC format unless otherwise specified. - - Value Size Description - ----- ---- ----------- - (MVS) 0x0065 2 bytes Tag for this "extra" block type - TSize 2 bytes Size for the following data block - ID 4 bytes EBCDIC "Z390" 0xE9F3F9F0 or - "T4MV" for TargetFour - (var) TSize-4 Attribute data - - - -OS/400 Extra Field (0x0065): - =========================== - - The following is the layout of the OS/400 "extra" block. - Note: Some fields are stored in Big Endian format. - All text is in EBCDIC format unless otherwise specified. - - Value Size Description - ----- ---- ----------- - (OS400) 0x0065 2 bytes Tag for this "extra" block type - TSize 2 bytes Size for the following data block - ID 4 bytes EBCDIC "I400" 0xC9F4F0F0 or - "T4MV" for TargetFour - (var) TSize-4 Attribute data - - - -Extended Timestamp Extra Field: - ============================== - - The following is the layout of the extended-timestamp extra block. - (Last Revision 19970118) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (time) 0x5455 Short tag for this extra block type ("UT") - TSize Short total data size for this block - Flags Byte info bits - (ModTime) Long time of last modification (UTC/GMT) - (AcTime) Long time of last access (UTC/GMT) - (CrTime) Long time of original creation (UTC/GMT) - - Central-header version: - - Value Size Description - ----- ---- ----------- - (time) 0x5455 Short tag for this extra block type ("UT") - TSize Short total data size for this block - Flags Byte info bits (refers to local header!) - (ModTime) Long time of last modification (UTC/GMT) - - The central-header extra field contains the modification time only, - or no timestamp at all. TSize is used to flag its presence or - absence. But note: - - If "Flags" indicates that Modtime is present in the local header - field, it MUST be present in the central header field, too! - This correspondence is required because the modification time - value may be used to support trans-timezone freshening and - updating operations with zip archives. - - The time values are in standard Unix signed-long format, indicating - the number of seconds since 1 January 1970 00:00:00. The times - are relative to Coordinated Universal Time (UTC), also sometimes - referred to as Greenwich Mean Time (GMT). To convert to local time, - the software must know the local timezone offset from UTC/GMT. - - The lower three bits of Flags in both headers indicate which time- - stamps are present in the LOCAL extra field: - - bit 0 if set, modification time is present - bit 1 if set, access time is present - bit 2 if set, creation time is present - bits 3-7 reserved for additional timestamps; not set - - Those times that are present will appear in the order indicated, but - any combination of times may be omitted. (Creation time may be - present without access time, for example.) TSize should equal - (1 + 4*(number of set bits in Flags)), as the block is currently - defined. Other timestamps may be added in the future. - - - -Info-ZIP Unix Extra Field (type 1): - ================================== - - The following is the layout of the old Info-ZIP extra block for - Unix. It has been replaced by the extended-timestamp extra block - (0x5455) and the Unix type 2 extra block (0x7855). - (Last Revision 19970118) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (Unix1) 0x5855 Short tag for this extra block type ("UX") - TSize Short total data size for this block - AcTime Long time of last access (UTC/GMT) - ModTime Long time of last modification (UTC/GMT) - UID Short Unix user ID (optional) - GID Short Unix group ID (optional) - - Central-header version: - - Value Size Description - ----- ---- ----------- - (Unix1) 0x5855 Short tag for this extra block type ("UX") - TSize Short total data size for this block - AcTime Long time of last access (GMT/UTC) - ModTime Long time of last modification (GMT/UTC) - - The file access and modification times are in standard Unix signed- - long format, indicating the number of seconds since 1 January 1970 - 00:00:00. The times are relative to Coordinated Universal Time - (UTC), also sometimes referred to as Greenwich Mean Time (GMT). To - convert to local time, the software must know the local timezone - offset from UTC/GMT. The modification time may be used by non-Unix - systems to support inter-timezone freshening and updating of zip - archives. - - The local-header extra block may optionally contain UID and GID - info for the file. The local-header TSize value is the only - indication of this. Note that Unix UIDs and GIDs are usually - specific to a particular machine, and they generally require root - access to restore. - - This extra field type is obsolete, but it has been in use since - mid-1994. Therefore future archiving software should continue to - support it. Some guidelines: - - An archive member should either contain the old "Unix1" - extra field block or the new extra field types "time" and/or - "Unix2". - - If both the old "Unix1" block type and one or both of the new - block types "time" and "Unix2" are found, the "Unix1" block - should be considered invalid and ignored. - - Unarchiving software should recognize both old and new extra - field block types, but the info from new types overrides the - old "Unix1" field. - - Archiving software should recognize "Unix1" extra fields for - timestamp comparison but never create it for updated, freshened - or new archive members. When copying existing members to a new - archive, any "Unix1" extra field blocks should be converted to - the new "time" and/or "Unix2" types. - - - -Info-ZIP Unix Extra Field (type 2): - ================================== - - The following is the layout of the new Info-ZIP extra block for - Unix. (Last Revision 19960922) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (Unix2) 0x7855 Short tag for this extra block type ("Ux") - TSize Short total data size for this block (4) - UID Short Unix user ID - GID Short Unix group ID - - Central-header version: - - Value Size Description - ----- ---- ----------- - (Unix2) 0x7855 Short tag for this extra block type ("Ux") - TSize Short total data size for this block (0) - - The data size of the central-header version is zero; it is used - solely as a flag that UID/GID info is present in the local-header - extra field. If additional fields are ever added to the local - version, the central version may be extended to indicate this. - - Note that Unix UIDs and GIDs are usually specific to a particular - machine, and they generally require root access to restore. - - - -ASi Unix Extra Field: - ==================== - - The following is the layout of the ASi extra block for Unix. The - local-header and central-header versions are identical. - (Last Revision 19960916) - - Value Size Description - ----- ---- ----------- - (Unix3) 0x756e Short tag for this extra block type ("nu") - TSize Short total data size for this block - CRC Long CRC-32 of the remaining data - Mode Short file permissions - SizDev Long symlink'd size OR major/minor dev num - UID Short user ID - GID Short group ID - (var.) variable symbolic link filename - - Mode is the standard Unix st_mode field from struct stat, containing - user/group/other permissions, setuid/setgid and symlink info, etc. - - If Mode indicates that this file is a symbolic link, SizDev is the - size of the file to which the link points. Otherwise, if the file - is a device, SizDev contains the standard Unix st_rdev field from - struct stat (includes the major and minor numbers of the device). - SizDev is undefined in other cases. - - If Mode indicates that the file is a symbolic link, the final field - will be the name of the file to which the link points. The file- - name length can be inferred from TSize. - - [Note that TSize may incorrectly refer to the data size not counting - the CRC; i.e., it may be four bytes too small.] - - - -BeOS Extra Field: - ================ - - The following is the layout of the file-attributes extra block for - BeOS. (Last Revision 19970531) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (BeOS) 0x6542 Short tag for this extra block type ("Be") - TSize Short total data size for this block - BSize Long uncompressed file attribute data size - Flags Byte info bits - (CType) Short compression type - (CRC) Long CRC value for uncompressed file attribs - Attribs variable file attribute data - - Central-header version: - - Value Size Description - ----- ---- ----------- - (BeOS) 0x6542 Short tag for this extra block type ("Be") - TSize Short total data size for this block (5) - BSize Long size of uncompr. local EF block data - Flags Byte info bits - - The least significant bit of Flags in both headers indicates whether - the LOCAL extra field is uncompressed (and therefore whether CType - and CRC are omitted): - - bit 0 if set, Attribs is uncompressed (no CType, CRC) - bits 1-7 reserved; if set, assume error or unknown data - - Currently the only supported compression types are deflated (type 8) - and stored (type 0); the latter is not used by Info-ZIP's Zip but is - supported by UnZip. - - Attribs is a BeOS-specific block of data in big-endian format with - the following structure (if compressed, uncompress it first): - - Value Size Description - ----- ---- ----------- - Name variable attribute name (null-terminated string) - Type Long attribute type (32-bit unsigned integer) - Size Long Long data size for this sub-block (64 bits) - Data variable attribute data - - The attribute structure is repeated for every attribute. The Data - field may contain anything--text, flags, bitmaps, etc. - - - -AtheOS Extra Field: - ================== - - The following is the layout of the file-attributes extra block for - AtheOS. This field is a very close spin-off from the BeOS e.f. - The only differences are: - - a new extra field signature - - numeric field in the attributes data are stored in little-endian - format ("i386" was initial hardware for AtheOS) - (Last Revision 20040908) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (AtheOS) 0x7441 Short tag for this extra block type ("At") - TSize Short total data size for this block - BSize Long uncompressed file attribute data size - Flags Byte info bits - (CType) Short compression type - (CRC) Long CRC value for uncompressed file attribs - Attribs variable file attribute data - - Central-header version: - - Value Size Description - ----- ---- ----------- - (AtheOS) 0x7441 Short tag for this extra block type ("At") - TSize Short total data size for this block (5) - BSize Long size of uncompr. local EF block data - Flags Byte info bits - - The least significant bit of Flags in both headers indicates whether - the LOCAL extra field is uncompressed (and therefore whether CType - and CRC are omitted): - - bit 0 if set, Attribs is uncompressed (no CType, CRC) - bits 1-7 reserved; if set, assume error or unknown data - - Currently the only supported compression types are deflated (type 8) - and stored (type 0); the latter is not used by Info-ZIP's Zip but is - supported by UnZip. - - Attribs is a AtheOS-specific block of data in little-endian format - with the following structure (if compressed, uncompress it first): - - Value Size Description - ----- ---- ----------- - Name variable attribute name (null-terminated string) - Type Long attribute type (32-bit unsigned integer) - Size Long Long data size for this sub-block (64 bits) - Data variable attribute data - - The attribute structure is repeated for every attribute. The Data - field may contain anything--text, flags, bitmaps, etc. - - - -SMS/QDOS Extra Field: - ==================== - - The following is the layout of the file-attributes extra block for - SMS/QDOS. The local-header and central-header versions are identical. - (Last Revision 19960929) - - Value Size Description - ----- ---- ----------- - (QDOS) 0xfb4a Short tag for this extra block type - TSize Short total data size for this block - LongID Long extra-field signature - (ExtraID) Long additional signature/flag bytes - QDirect 64 bytes qdirect structure - - LongID may be "QZHD" or "QDOS". In the latter case, ExtraID will - be present. Its first three bytes are "02\0"; the last byte is - currently undefined. - - QDirect contains the file's uncompressed directory info (qdirect - struct). Its elements are in native (big-endian) format: - - d_length beLong file length - d_access byte file access type - d_type byte file type - d_datalen beLong data length - d_reserved beLong unused - d_szname beShort size of filename - d_name 36 bytes filename - d_update beLong time of last update - d_refdate beLong file version number - d_backup beLong time of last backup (archive date) - - - -AOS/VS Extra Field: - ================== - - The following is the layout of the extra block for Data General - AOS/VS. The local-header and central-header versions are identical. - (Last Revision 19961125) - - Value Size Description - ----- ---- ----------- - (AOSVS) 0x5356 Short tag for this extra block type ("VS") - TSize Short total data size for this block - "FCI\0" Long extra-field signature - Version Byte version of AOS/VS extra block (10 = 1.0) - Fstat variable fstat packet - AclBuf variable raw ACL data ($MXACL bytes) - - Fstat contains the file's uncompressed fstat packet, which is one of - the following: - - normal fstat packet (P_FSTAT struct) - DIR/CPD fstat packet (P_FSTAT_DIR struct) - unit (device) fstat packet (P_FSTAT_UNIT struct) - IPC file fstat packet (P_FSTAT_IPC struct) - - AclBuf contains the raw ACL data; its length is $MXACL. - - - -Tandem NSK Extra Field: - ====================== - - The following is the layout of the file-attributes extra block for - Tandem NSK. The local-header and central-header versions are - identical. (Last Revision 19981221) - - Value Size Description - ----- ---- ----------- - (TA) 0x4154 Short tag for this extra block type ("TA") - TSize Short total data size for this block (20) - NSKattrs 20 Bytes NSK attributes - - - -THEOS Extra Field: - ================= - - The following is the layout of the file-attributes extra block for - Theos. The local-header and central-header versions are identical. - (Last Revision 19990206) - - Value Size Description - ----- ---- ----------- - (Theos) 0x6854 Short 'Th' signature - size Short size of extra block - flags Byte reserved for future use - filesize Long file size - fileorg Byte type of file (see below) - keylen Short key length for indexed and keyed files, - data segment size for 16 bits programs - reclen Short record length for indexed,keyed and direct, - text segment size for 16 bits programs - filegrow Byte growing factor for indexed,keyed and direct - protect Byte protections (see below) - reserved Short reserved for future use - - File types - ========== - - 0x80 library (keyed access list of files) - 0x40 directory - 0x10 stream file - 0x08 direct file - 0x04 keyed file - 0x02 indexed file - 0x0e reserved - 0x01 16 bits real mode program (obsolete) - 0x21 16 bits protected mode program - 0x41 32 bits protected mode program - - Protection codes - ================ - - User protection - --------------- - 0x01 non readable - 0x02 non writable - 0x04 non executable - 0x08 non erasable - - Other protection - ---------------- - 0x10 non readable - 0x20 non writable - 0x40 non executable Theos before 4.0 - 0x40 modified Theos 4.x - 0x80 not hidden - - - -THEOS old inofficial Extra Field: - ================================ - - The following is the layout of an inoffical former version of a - Theos file-attributes extra blocks. This layout was never published - and is no longer created. However, UnZip can optionally support it - when compiling with the option flag OLD_THEOS_EXTRA defined. - Both the local-header and central-header versions are identical. - (Last Revision 19990206) - - Value Size Description - ----- ---- ----------- - (THS0) 0x4854 Short 'TH' signature - size Short size of extra block - flags Short reserved for future use - filesize Long file size - reclen Short record length for indexed,keyed and direct, - text segment size for 16 bits programs - keylen Short key length for indexed and keyed files, - data segment size for 16 bits programs - filegrow Byte growing factor for indexed,keyed and direct - reserved 3 Bytes reserved for future use - - - -FWKCS MD5 Extra Field (0x4b46): - ============================== - - The FWKCS Contents_Signature System, used in automatically - identifying files independent of filename, optionally adds - and uses an extra field to support the rapid creation of - an enhanced contents_signature. - There is no local-header version; the following applies - only to the central header. (Last Revision 19961207) - - Central-header version: - - Value Size Description - ----- ---- ----------- - (MD5) 0x4b46 Short tag for this extra block type ("FK") - TSize Short total data size for this block (19) - "MD5" 3 bytes extra-field signature - MD5hash 16 bytes 128-bit MD5 hash of uncompressed data - (low byte first) - - When FWKCS revises a .ZIP file central directory to add - this extra field for a file, it also replaces the - central directory entry for that file's uncompressed - file length with a measured value. - - FWKCS provides an option to strip this extra field, if - present, from a .ZIP file central directory. In adding - this extra field, FWKCS preserves .ZIP file Authenticity - Verification; if stripping this extra field, FWKCS - preserves all versions of AV through PKZIP version 2.04g. - - FWKCS, and FWKCS Contents_Signature System, are - trademarks of Frederick W. Kantor. - - (1) R. Rivest, RFC1321.TXT, MIT Laboratory for Computer - Science and RSA Data Security, Inc., April 1992. - ll.76-77: "The MD5 algorithm is being placed in the - public domain for review and possible adoption as a - standard." - - - file comment: (Variable) - - The comment for this file. - - number of this disk: (2 bytes) - - The number of this disk, which contains central - directory end record. If an archive is in zip64 format - and the value in this field is 0xFFFF, the size will - be in the corresponding 4 byte zip64 end of central - directory field. - - number of the disk with the start of the central directory: (2 bytes) - - The number of the disk on which the central - directory starts. If an archive is in zip64 format - and the value in this field is 0xFFFF, the size will - be in the corresponding 4 byte zip64 end of central - directory field. - - total number of entries in the central dir on this disk: (2 bytes) - - The number of central directory entries on this disk. - If an archive is in zip64 format and the value in - this field is 0xFFFF, the size will be in the - corresponding 8 byte zip64 end of central - directory field. - - total number of entries in the central dir: (2 bytes) - - The total number of files in the .ZIP file. If an - archive is in zip64 format and the value in this field - is 0xFFFF, the size will be in the corresponding 8 byte - zip64 end of central directory field. - - size of the central directory: (4 bytes) - - The size (in bytes) of the entire central directory. - If an archive is in zip64 format and the value in - this field is 0xFFFFFFFF, the size will be in the - corresponding 8 byte zip64 end of central - directory field. - - offset of start of central directory with respect to - the starting disk number: (4 bytes) - - Offset of the start of the central directory on the - disk on which the central directory starts. If an - archive is in zip64 format and the value in this - field is 0xFFFFFFFF, the size will be in the - corresponding 8 byte zip64 end of central - directory field. - - .ZIP file comment length: (2 bytes) - - The length of the comment for this .ZIP file. - - .ZIP file comment: (Variable) - - The comment for this .ZIP file. ZIP file comment data - is stored unsecured. No encryption or data authentication - is applied to this area at this time. Confidential information - should not be stored in this section. - - zip64 extensible data sector (variable size) - - (currently reserved for use by PKWARE) - - - K. General notes: - - 1) All fields unless otherwise noted are unsigned and stored - in Intel low-byte:high-byte, low-word:high-word order. - - 2) String fields are not null terminated, since the - length is given explicitly. - - 3) Local headers should not span disk boundaries. Also, even - though the central directory can span disk boundaries, no - single record in the central directory should be split - across disks. - - 4) The entries in the central directory may not necessarily - be in the same order that files appear in the .ZIP file. - - 5) Spanned/Split archives created using PKZIP for Windows - (V2.50 or greater), PKZIP Command Line (V2.50 or greater), - or PKZIP Explorer will include a special spanning - signature as the first 4 bytes of the first segment of - the archive. This signature (0x08074b50) will be - followed immediately by the local header signature for - the first file in the archive. A special spanning - marker may also appear in spanned/split archives if the - spanning or splitting process starts but only requires - one segment. In this case the 0x08074b50 signature - will be replaced with the temporary spanning marker - signature of 0x30304b50. Spanned/split archives - created with this special signature are compatible with - all versions of PKZIP from PKWARE. Split archives can - only be uncompressed by other versions of PKZIP that - know how to create a split archive. - - 6) If one of the fields in the end of central directory - record is too small to hold required data, the field - should be set to -1 (0xFFFF or 0xFFFFFFFF) and the - Zip64 format record should be created. - - 7) The end of central directory record and the - Zip64 end of central directory locator record must - reside on the same disk when splitting or spanning - an archive. - -V. UnShrinking - Method 1 -------------------------- - -Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm -with partial clearing. The initial code size is 9 bits, and -the maximum code size is 13 bits. Shrinking differs from -conventional Dynamic Ziv-Lempel-Welch implementations in several -respects: - -1) The code size is controlled by the compressor, and is not - automatically increased when codes larger than the current - code size are created (but not necessarily used). When - the decompressor encounters the code sequence 256 - (decimal) followed by 1, it should increase the code size - read from the input stream to the next bit size. No - blocking of the codes is performed, so the next code at - the increased size should be read from the input stream - immediately after where the previous code at the smaller - bit size was read. Again, the decompressor should not - increase the code size used until the sequence 256,1 is - encountered. - -2) When the table becomes full, total clearing is not - performed. Rather, when the compressor emits the code - sequence 256,2 (decimal), the decompressor should clear - all leaf nodes from the Ziv-Lempel tree, and continue to - use the current code size. The nodes that are cleared - from the Ziv-Lempel tree are then re-used, with the lowest - code value re-used first, and the highest code value - re-used last. The compressor can emit the sequence 256,2 - at any time. - - -VI. Expanding - Methods 2-5 ---------------------------- - -The Reducing algorithm is actually a combination of two -distinct algorithms. The first algorithm compresses repeated -byte sequences, and the second algorithm takes the compressed -stream from the first algorithm and applies a probabilistic -compression method. - -The probabilistic compression stores an array of 'follower -sets' S(j), for j=0 to 255, corresponding to each possible -ASCII character. Each set contains between 0 and 32 -characters, to be denoted as S(j)[0],...,S(j)[m], where m<32. -The sets are stored at the beginning of the data area for a -Reduced file, in reverse order, with S(255) first, and S(0) -last. - -The sets are encoded as { N(j), S(j)[0],...,S(j)[N(j)-1] }, -where N(j) is the size of set S(j). N(j) can be 0, in which -case the follower set for S(j) is empty. Each N(j) value is -encoded in 6 bits, followed by N(j) eight bit character values -corresponding to S(j)[0] to S(j)[N(j)-1] respectively. If -N(j) is 0, then no values for S(j) are stored, and the value -for N(j-1) immediately follows. - -Immediately after the follower sets, is the compressed data -stream. The compressed data stream can be interpreted for the -probabilistic decompression as follows: - - -let Last-Character <- 0. -loop until done - if the follower set S(Last-Character) is empty then - read 8 bits from the input stream, and copy this - value to the output stream. - otherwise if the follower set S(Last-Character) is non-empty then - read 1 bit from the input stream. - if this bit is not zero then - read 8 bits from the input stream, and copy this - value to the output stream. - otherwise if this bit is zero then - read B(N(Last-Character)) bits from the input - stream, and assign this value to I. - Copy the value of S(Last-Character)[I] to the - output stream. - - assign the last value placed on the output stream to - Last-Character. -end loop - - -B(N(j)) is defined as the minimal number of bits required to -encode the value N(j)-1. - - -The decompressed stream from above can then be expanded to -re-create the original file as follows: - - -let State <- 0. - -loop until done - read 8 bits from the input stream into C. - case State of - 0: if C is not equal to DLE (144 decimal) then - copy C to the output stream. - otherwise if C is equal to DLE then - let State <- 1. - - 1: if C is non-zero then - let V <- C. - let Len <- L(V) - let State <- F(Len). - otherwise if C is zero then - copy the value 144 (decimal) to the output stream. - let State <- 0 - - 2: let Len <- Len + C - let State <- 3. - - 3: move backwards D(V,C) bytes in the output stream - (if this position is before the start of the output - stream, then assume that all the data before the - start of the output stream is filled with zeros). - copy Len+3 bytes from this position to the output stream. - let State <- 0. - end case -end loop - - -The functions F,L, and D are dependent on the 'compression -factor', 1 through 4, and are defined as follows: - -For compression factor 1: - L(X) equals the lower 7 bits of X. - F(X) equals 2 if X equals 127 otherwise F(X) equals 3. - D(X,Y) equals the (upper 1 bit of X) * 256 + Y + 1. -For compression factor 2: - L(X) equals the lower 6 bits of X. - F(X) equals 2 if X equals 63 otherwise F(X) equals 3. - D(X,Y) equals the (upper 2 bits of X) * 256 + Y + 1. -For compression factor 3: - L(X) equals the lower 5 bits of X. - F(X) equals 2 if X equals 31 otherwise F(X) equals 3. - D(X,Y) equals the (upper 3 bits of X) * 256 + Y + 1. -For compression factor 4: - L(X) equals the lower 4 bits of X. - F(X) equals 2 if X equals 15 otherwise F(X) equals 3. - D(X,Y) equals the (upper 4 bits of X) * 256 + Y + 1. - - -VII. Imploding - Method 6 -------------------------- - -The Imploding algorithm is actually a combination of two distinct -algorithms. The first algorithm compresses repeated byte -sequences using a sliding dictionary. The second algorithm is -used to compress the encoding of the sliding dictionary output, -using multiple Shannon-Fano trees. - -The Imploding algorithm can use a 4K or 8K sliding dictionary -size. The dictionary size used can be determined by bit 1 in the -general purpose flag word; a 0 bit indicates a 4K dictionary -while a 1 bit indicates an 8K dictionary. - -The Shannon-Fano trees are stored at the start of the compressed -file. The number of trees stored is defined by bit 2 in the -general purpose flag word; a 0 bit indicates two trees stored, a -1 bit indicates three trees are stored. If 3 trees are stored, -the first Shannon-Fano tree represents the encoding of the -Literal characters, the second tree represents the encoding of -the Length information, the third represents the encoding of the -Distance information. When 2 Shannon-Fano trees are stored, the -Length tree is stored first, followed by the Distance tree. - -The Literal Shannon-Fano tree, if present is used to represent -the entire ASCII character set, and contains 256 values. This -tree is used to compress any data not compressed by the sliding -dictionary algorithm. When this tree is present, the Minimum -Match Length for the sliding dictionary is 3. If this tree is -not present, the Minimum Match Length is 2. - -The Length Shannon-Fano tree is used to compress the Length part -of the (length,distance) pairs from the sliding dictionary -output. The Length tree contains 64 values, ranging from the -Minimum Match Length, to 63 plus the Minimum Match Length. - -The Distance Shannon-Fano tree is used to compress the Distance -part of the (length,distance) pairs from the sliding dictionary -output. The Distance tree contains 64 values, ranging from 0 to -63, representing the upper 6 bits of the distance value. The -distance values themselves will be between 0 and the sliding -dictionary size, either 4K or 8K. - -The Shannon-Fano trees themselves are stored in a compressed -format. The first byte of the tree data represents the number of -bytes of data representing the (compressed) Shannon-Fano tree -minus 1. The remaining bytes represent the Shannon-Fano tree -data encoded as: - - High 4 bits: Number of values at this bit length + 1. (1 - 16) - Low 4 bits: Bit Length needed to represent value + 1. (1 - 16) - -The Shannon-Fano codes can be constructed from the bit lengths -using the following algorithm: - -1) Sort the Bit Lengths in ascending order, while retaining the - order of the original lengths stored in the file. - -2) Generate the Shannon-Fano trees: - - Code <- 0 - CodeIncrement <- 0 - LastBitLength <- 0 - i <- number of Shannon-Fano codes - 1 (either 255 or 63) - - loop while i >= 0 - Code = Code + CodeIncrement - if BitLength(i) <> LastBitLength then - LastBitLength=BitLength(i) - CodeIncrement = 1 shifted left (16 - LastBitLength) - ShannonCode(i) = Code - i <- i - 1 - end loop - - -3) Reverse the order of all the bits in the above ShannonCode() - vector, so that the most significant bit becomes the least - significant bit. For example, the value 0x1234 (hex) would - become 0x2C48 (hex). - -4) Restore the order of Shannon-Fano codes as originally stored - within the file. - -Example: - - This example will show the encoding of a Shannon-Fano tree - of size 8. Notice that the actual Shannon-Fano trees used - for Imploding are either 64 or 256 entries in size. - -Example: 0x02, 0x42, 0x01, 0x13 - - The first byte indicates 3 values in this table. Decoding the - bytes: - 0x42 = 5 codes of 3 bits long - 0x01 = 1 code of 2 bits long - 0x13 = 2 codes of 4 bits long - - This would generate the original bit length array of: - (3, 3, 3, 3, 3, 2, 4, 4) - - There are 8 codes in this table for the values 0 thru 7. Using - the algorithm to obtain the Shannon-Fano codes produces: - - Reversed Order Original -Val Sorted Constructed Code Value Restored Length ---- ------ ----------------- -------- -------- ------ -0: 2 1100000000000000 11 101 3 -1: 3 1010000000000000 101 001 3 -2: 3 1000000000000000 001 110 3 -3: 3 0110000000000000 110 010 3 -4: 3 0100000000000000 010 100 3 -5: 3 0010000000000000 100 11 2 -6: 4 0001000000000000 1000 1000 4 -7: 4 0000000000000000 0000 0000 4 - - -The values in the Val, Order Restored and Original Length columns -now represent the Shannon-Fano encoding tree that can be used for -decoding the Shannon-Fano encoded data. How to parse the -variable length Shannon-Fano values from the data stream is beyond -the scope of this document. (See the references listed at the end of -this document for more information.) However, traditional decoding -schemes used for Huffman variable length decoding, such as the -Greenlaw algorithm, can be successfully applied. - -The compressed data stream begins immediately after the -compressed Shannon-Fano data. The compressed data stream can be -interpreted as follows: - -loop until done - read 1 bit from input stream. - - if this bit is non-zero then (encoded data is literal data) - if Literal Shannon-Fano tree is present - read and decode character using Literal Shannon-Fano tree. - otherwise - read 8 bits from input stream. - copy character to the output stream. - otherwise (encoded data is sliding dictionary match) - if 8K dictionary size - read 7 bits for offset Distance (lower 7 bits of offset). - otherwise - read 6 bits for offset Distance (lower 6 bits of offset). - - using the Distance Shannon-Fano tree, read and decode the - upper 6 bits of the Distance value. - - using the Length Shannon-Fano tree, read and decode - the Length value. - - Length <- Length + Minimum Match Length - - if Length = 63 + Minimum Match Length - read 8 bits from the input stream, - add this value to Length. - - move backwards Distance+1 bytes in the output stream, and - copy Length characters from this position to the output - stream. (if this position is before the start of the output - stream, then assume that all the data before the start of - the output stream is filled with zeros). -end loop - -VIII. Tokenizing - Method 7 ---------------------------- - -This method is not used by PKZIP. - -IX. Deflating - Method 8 ------------------------- - -The Deflate algorithm is similar to the Implode algorithm using -a sliding dictionary of up to 32K with secondary compression -from Huffman/Shannon-Fano codes. - -The compressed data is stored in blocks with a header describing -the block and the Huffman codes used in the data block. The header -format is as follows: - - Bit 0: Last Block bit This bit is set to 1 if this is the last - compressed block in the data. - Bits 1-2: Block type - 00 (0) - Block is stored - All stored data is byte aligned. - Skip bits until next byte, then next word = block - length, followed by the ones compliment of the block - length word. Remaining data in block is the stored - data. - - 01 (1) - Use fixed Huffman codes for literal and distance codes. - Lit Code Bits Dist Code Bits - --------- ---- --------- ---- - 0 - 143 8 0 - 31 5 - 144 - 255 9 - 256 - 279 7 - 280 - 287 8 - - Literal codes 286-287 and distance codes 30-31 are - never used but participate in the huffman construction. - - 10 (2) - Dynamic Huffman codes. (See expanding Huffman codes) - - 11 (3) - Reserved - Flag a "Error in compressed data" if seen. - -Expanding Huffman Codes ------------------------ -If the data block is stored with dynamic Huffman codes, the Huffman -codes are sent in the following compressed format: - - 5 Bits: # of Literal codes sent - 257 (257 - 286) - All other codes are never sent. - 5 Bits: # of Dist codes - 1 (1 - 32) - 4 Bits: # of Bit Length codes - 4 (4 - 19) - -The Huffman codes are sent as bit lengths and the codes are built as -described in the implode algorithm. The bit lengths themselves are -compressed with Huffman codes. There are 19 bit length codes: - - 0 - 15: Represent bit lengths of 0 - 15 - 16: Copy the previous bit length 3 - 6 times. - The next 2 bits indicate repeat length (0 = 3, ... ,3 = 6) - Example: Codes 8, 16 (+2 bits 11), 16 (+2 bits 10) will - expand to 12 bit lengths of 8 (1 + 6 + 5) - 17: Repeat a bit length of 0 for 3 - 10 times. (3 bits of length) - 18: Repeat a bit length of 0 for 11 - 138 times (7 bits of length) - -The lengths of the bit length codes are sent packed 3 bits per value -(0 - 7) in the following order: - - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 - -The Huffman codes should be built as described in the Implode algorithm -except codes are assigned starting at the shortest bit length, i.e. the -shortest code should be all 0's rather than all 1's. Also, codes with -a bit length of zero do not participate in the tree construction. The -codes are then used to decode the bit lengths for the literal and -distance tables. - -The bit lengths for the literal tables are sent first with the number -of entries sent described by the 5 bits sent earlier. There are up -to 286 literal characters; the first 256 represent the respective 8 -bit character, code 256 represents the End-Of-Block code, the remaining -29 codes represent copy lengths of 3 thru 258. There are up to 30 -distance codes representing distances from 1 thru 32k as described -below. - - Length Codes - ------------ - Extra Extra Extra Extra - Code Bits Length Code Bits Lengths Code Bits Lengths Code Bits Length(s) - ---- ---- ------ ---- ---- ------- ---- ---- ------- ---- ---- --------- - 257 0 3 265 1 11,12 273 3 35-42 281 5 131-162 - 258 0 4 266 1 13,14 274 3 43-50 282 5 163-194 - 259 0 5 267 1 15,16 275 3 51-58 283 5 195-226 - 260 0 6 268 1 17,18 276 3 59-66 284 5 227-258 - 261 0 7 269 2 19-22 277 4 67-82 285 0 258 - 262 0 8 270 2 23-26 278 4 83-98 - 263 0 9 271 2 27-30 279 4 99-114 - 264 0 10 272 2 31-34 280 4 115-130 - - Distance Codes - -------------- - Extra Extra Extra Extra - Code Bits Dist Code Bits Dist Code Bits Distance Code Bits Distance - ---- ---- ---- ---- ---- ------ ---- ---- -------- ---- ---- -------- - 0 0 1 8 3 17-24 16 7 257-384 24 11 4097-6144 - 1 0 2 9 3 25-32 17 7 385-512 25 11 6145-8192 - 2 0 3 10 4 33-48 18 8 513-768 26 12 8193-12288 - 3 0 4 11 4 49-64 19 8 769-1024 27 12 12289-16384 - 4 1 5,6 12 5 65-96 20 9 1025-1536 28 13 16385-24576 - 5 1 7,8 13 5 97-128 21 9 1537-2048 29 13 24577-32768 - 6 2 9-12 14 6 129-192 22 10 2049-3072 - 7 2 13-16 15 6 193-256 23 10 3073-4096 - -The compressed data stream begins immediately after the -compressed header data. The compressed data stream can be -interpreted as follows: - -do - read header from input stream. - - if stored block - skip bits until byte aligned - read count and 1's compliment of count - copy count bytes data block - otherwise - loop until end of block code sent - decode literal character from input stream - if literal < 256 - copy character to the output stream - otherwise - if literal = end of block - break from loop - otherwise - decode distance from input stream - - move backwards distance bytes in the output stream, and - copy length characters from this position to the output - stream. - end loop -while not last block - -if data descriptor exists - skip bits until byte aligned - check data descriptor signature - read crc and sizes -endif - -X. Enhanced Deflating - Method 9 --------------------------------- - -The Enhanced Deflating algorithm is similar to Deflate but -uses a sliding dictionary of up to 64K. Deflate64(tm) is supported -by the Deflate extractor. - -[This description is inofficial. It has been deduced by Info-ZIP from -close inspection of PKZIP 4.x Deflate64(tm) compressed output.] - -The Deflate64 algorithm is almost identical to the normal Deflate algorithm. -Differences are: - -- The sliding window size is 64k. - -- The previously unused distance codes 30 and 31 are now used to describe - match distances from 32k-48k and 48k-64k. - Extra - Code Bits Distance - ---- ---- ----------- - .. .. ... - 29 13 24577-32768 - 30 14 32769-49152 - 31 14 49153-65536 - -- The semantics of the "maximum match length" code #258 has been changed to - allow the specification of arbitrary large match lengths (up to 64k). - Extra - Code Bits Lengths - ---- ---- ------ - ... .. ... - 284 5 227-258 - 285 16 3-65538 - -Whereas the first two modifications fit into the framework of Deflate, -this last change breaks compatibility with Deflate method 8. Thus, a -Deflate64 decompressor cannot decode normal deflated data. - -XI. BZIP2 - Method 12 ---------------------- - -BZIP2 is an open-source data compression algorithm developed by -Julian Seward. Information and source code for this algorithm -can be found on the internet. - - -XII. Traditional PKWARE Encryption ----------------------------------- - -The following information discusses the decryption steps -required to support traditional PKWARE encryption. This -form of encryption is considered weak by today's standards -and its use is recommended only for situations with -low security needs or for compatibility with older .ZIP -applications. - -XIII. Decryption ----------------- - -The encryption used in PKZIP was generously supplied by Roger -Schlafly. PKWARE is grateful to Mr. Schlafly for his expert -help and advice in the field of data encryption. - -PKZIP encrypts the compressed data stream. Encrypted files must -be decrypted before they can be extracted. - -Each encrypted file has an extra 12 bytes stored at the start of -the data area defining the encryption header for that file. The -encryption header is originally set to random values, and then -itself encrypted, using three, 32-bit keys. The key values are -initialized using the supplied encryption password. After each byte -is encrypted, the keys are then updated using pseudo-random number -generation techniques in combination with the same CRC-32 algorithm -used in PKZIP and described elsewhere in this document. - -The following is the basic steps required to decrypt a file: - -1) Initialize the three 32-bit keys with the password. -2) Read and decrypt the 12-byte encryption header, further - initializing the encryption keys. -3) Read and decrypt the compressed data stream using the - encryption keys. - - -Step 1 - Initializing the encryption keys ------------------------------------------ - -Key(0) <- 305419896 -Key(1) <- 591751049 -Key(2) <- 878082192 - -loop for i <- 0 to length(password)-1 - update_keys(password(i)) -end loop - - -Where update_keys() is defined as: - - -update_keys(char): - Key(0) <- crc32(key(0),char) - Key(1) <- Key(1) + (Key(0) & 000000ffH) - Key(1) <- Key(1) * 134775813 + 1 - Key(2) <- crc32(key(2),key(1) >> 24) -end update_keys - - -Where crc32(old_crc,char) is a routine that given a CRC value and a -character, returns an updated CRC value after applying the CRC-32 -algorithm described elsewhere in this document. - - -Step 2 - Decrypting the encryption header ------------------------------------------ - -The purpose of this step is to further initialize the encryption -keys, based on random data, to render a plaintext attack on the -data ineffective. - - -Read the 12-byte encryption header into Buffer, in locations -Buffer(0) thru Buffer(11). - -loop for i <- 0 to 11 - C <- buffer(i) ^ decrypt_byte() - update_keys(C) - buffer(i) <- C -end loop - - -Where decrypt_byte() is defined as: - - -unsigned char decrypt_byte() - local unsigned short temp - temp <- Key(2) | 2 - decrypt_byte <- (temp * (temp ^ 1)) >> 8 -end decrypt_byte - - -After the header is decrypted, the last 1 or 2 bytes in Buffer -should be the high-order word/byte of the CRC for the file being -decrypted, stored in Intel low-byte/high-byte order, or the high-order -byte of the file time if bit 3 of the general purpose bit flag is set. -Versions of PKZIP prior to 2.0 used a 2 byte CRC check; a 1 byte CRC check is -used on versions after 2.0. This can be used to test if the password -supplied is correct or not. - - -Step 3 - Decrypting the compressed data stream ----------------------------------------------- - -The compressed data stream can be decrypted as follows: - - -loop until done - read a character into C - Temp <- C ^ decrypt_byte() - update_keys(temp) - output Temp -end loop - - -XIV. Strong Encryption Specification (EFS) ------------------------------------------- - -Version 5.x of this specification introduced support for strong -encryption algorithms. These algorithms can be used with either -a password or an X.509v3 digital certificate to encrypt each file. -This format specification supports either password or certificate -based encryption to meet the security needs of today, to enable -interoperability between users within both PKI and non-PKI -environments, and to ensure interoperability between different -computing platforms that are running a ZIP program. - -Password based encryption is the most common form of encryption -people are familiar with. However, inherent weaknesses with -passwords (e.g. susceptibility to dictionary/brute force attack) -as well as password management and support issues make certificate -based encryption a more secure and scalable option. Industry -efforts and support are defining and moving towards more advanced -security solutions built around X.509v3 digital certificates and -Public Key Infrastructures(PKI) because of the greater scalability, -administrative options, and more robust security over traditional -password-based encryption. - -Most standard encryption algorithms are supported with this -specification. Reference implementations for many of these -algorithms are available from either commercial or open source -distributors. Readily available cryptographic toolkits make -implementation of the encryption features straight-forward. -This document is not intended to provide a treatise on data -encryption principles or theory. Its purpose is to document the -data structures required for implementing interoperable data -encryption within the .ZIP format. It is strongly recommended that -you have a good understanding of data encryption before reading -further. - -The algorithms introduced in Version 5.0 of this specification -include: - - RC2 40 bit, 64 bit, and 128 bit - RC4 40 bit, 64 bit, and 128 bit - DES - 3DES 112 bit and 168 bit - -Version 5.1 adds support for the following: - - AES 128 bit, 192 bit, and 256 bit - -Version 6.1 introduces encryption data changes to support -interoperability with SmartCard and USB Token certificate storage -methods which do not support the OAEP strengthening standard. - -Version 6.2 introduces support for encrypting metadata by compressing -and encrypting the central directory data structure to reduce information -leakage. Information leakage can occur in legacy ZIP applications -through exposure of information about a file even though that file is -stored encrypted. The information exposed consists of file -characteristics stored within the records and fields defined by this -specification. This includes data such as a files name, its original -size, timestamp and CRC32 value. - -Central Directory Encryption provides greater protection against -information leakage by encrypting the Central Directory structure and -by masking key values that are replicated in the unencrypted Local -Header. ZIP compatible programs that cannot interpret an encrypted -Central Directory structure cannot rely on the data in the corresponding -Local Header for decompression information. - -Extra Field records that may contain information about a file that should -not be exposed should not be stored in the Local Header and should only -be written to the Central Directory where they can be encrypted. This -design currently does not support streaming. Information in the End of -Central Directory record, the ZIP64 End of Central Directory Locator, -and the ZIP64 End of Central Directory record are not encrypted. Access -to view data on files within a ZIP file with an encrypted Central Directory -requires the appropriate password or private key for decryption prior to -viewing any files, or any information about the files, in the archive. - -Older ZIP compatible programs not familiar with the Central Directory -Encryption feature will no longer be able to recognize the Central -Directory and may assume the ZIP file is corrupt. Programs that -attempt streaming access using Local Headers will see invalid -information for each file. Central Directory Encryption need not be -used for every ZIP file. Its use is recommended for greater security. -ZIP files not using Central Directory Encryption should operate as -in the past. - -The details of the strong encryption specification for certificates -remain under development as design and testing issues are worked out -for the range of algorithms, encryption methods, certificate processing -and cross-platform support necessary to meet the advanced security needs -of .ZIP file users today and in the future. - -This feature specification is intended to support basic encryption needs -of today, such as password support. However this specification is also -designed to lay the foundation for future advanced security needs. - -Encryption provides data confidentiality and privacy. It is -recommended that you combine X.509 digital signing with encryption -to add authentication and non-repudiation. - - -Single Password Symmetric Encryption Method: -------------------------------------------- - -The Single Password Symmetric Encryption Method using strong -encryption algorithms operates similarly to the traditional -PKWARE encryption defined in this format. Additional data -structures are added to support the processing needs of the -strong algorithms. - -The Strong Encryption data structures are: - -1. General Purpose Bits - Bits 0 and 6 of the General Purpose bit -flag in both local and central header records. Both bits set -indicates strong encryption. Bit 13, when set indicates the Central -Directory is encrypted and that selected fields in the Local Header -are masked to hide their actual value. - - -2. Extra Field 0x0017 in central header only. - - Fields to consider in this record are: - - Format - the data format identifier for this record. The only - value allowed at this time is the integer value 2. - - AlgId - integer identifier of the encryption algorithm from the - following range - - 0x6601 - DES - 0x6602 - RC2 (version needed to extract < 5.2) - 0x6603 - 3DES 168 - 0x6609 - 3DES 112 - 0x660E - AES 128 - 0x660F - AES 192 - 0x6610 - AES 256 - 0x6702 - RC2 (version needed to extract >= 5.2) - 0x6801 - RC4 - 0xFFFF - Unknown algorithm - - Bitlen - Explicit bit length of key - - 40 - 56 - 64 - 112 - 128 - 168 - 192 - 256 - - Flags - Processing flags needed for decryption - - 0x0001 - Password is required to decrypt - 0x0002 - Certificates only - 0x0003 - Password or certificate required to decrypt - - Values > 0x0003 reserved for certificate processing - - -3. Decryption header record preceeding compressed file data. - - -Decryption Header: - - Value Size Description - ----- ---- ----------- - IVSize 2 bytes Size of initialization vector (IV) - IVData IVSize Initialization vector for this file - Size 4 bytes Size of remaining decryption header data - Format 2 bytes Format definition for this record - AlgID 2 bytes Encryption algorithm identifier - Bitlen 2 bytes Bit length of encryption key - Flags 2 bytes Processing flags - ErdSize 2 bytes Size of Encrypted Random Data - ErdData ErdSize Encrypted Random Data - Reserved1 4 bytes Reserved certificate processing data - Reserved2 (var) Reserved for certificate processing data - VSize 2 bytes Size of password validation data - VData VSize-4 Password validation data - VCRC32 4 bytes Standard ZIP CRC32 of password validation data - - IVData - The size of the IV should match the algorithm block size. - The IVData can be completely random data. If the size of - the randomly generated data does not match the block size - it should be complemented with zero's or truncated as - necessary. If IVSize is 0, then IV = CRC32 + Uncompressed - File Size (as a 64 bit little-endian, unsigned integer value). - - Format - the data format identifier for this record. The only - value allowed at this time is the integer value 3. - - AlgId - integer identifier of the encryption algorithm from the - following range - - 0x6601 - DES - 0x6602 - RC2 (version needed to extract < 5.2) - 0x6603 - 3DES 168 - 0x6609 - 3DES 112 - 0x660E - AES 128 - 0x660F - AES 192 - 0x6610 - AES 256 - 0x6702 - RC2 (version needed to extract >= 5.2) - 0x6801 - RC4 - 0xFFFF - Unknown algorithm - - Bitlen - Explicit bit length of key - - 40 - 56 - 64 - 112 - 128 - 168 - 192 - 256 - - Flags - Processing flags needed for decryption - - 0x0001 - Password is required to decrypt - 0x0002 - Certificates only - 0x0003 - Password or certificate required to decrypt - - Values > 0x0003 reserved for certificate processing - - ErdData - Encrypted random data is used to generate a file - session key for encrypting each file. SHA1 is - used to calculate hash data used to derive keys. - File session keys are derived from a master session - key generated from the user-supplied password. - If the Flags field in the decryption header contains - the value 0x4000, then the ErdData field must be - decrypted using 3DES. - - Reserved1 - Reserved for certificate processing, if value is - zero, then Reserved2 data is absent. See the explanation - under the Certificate Processing Method for details on - this data structure. - - Reserved2 - If present, the size of the Reserved2 data structure - is located by skipping the first 4 bytes of this field - and using the next 2 bytes as the remaining size. See - the explanation under the Certificate Processing Method - for details on this data structure. - - VSize - This size value will always include the 4 bytes of the - VCRC32 data and will be greater than 4 bytes. - - VData - Random data for password validation. This data is VSize - in length and VSize must be a multiple of the encryption - block size. VCRC32 is a checksum value of VData. - VData and VCRC32 are stored encrypted and start the - stream of encrypted data for a file. - -4. Single Password Central Directory Encryption - -Central Directory Encryption is achieved within the .ZIP format by -encrypting the Central Directory structure. This encapsulates the metadata -most often used for processing .ZIP files. Additional metadata is stored for -redundancy in the Local Header for each file. The process of concealing -metadata by encrypting the Central Directory does not protect the data within -the Local Header. To avoid information leakage from the exposed metadata -in the Local Header, the fields containing information about a file are masked. - -Local Header: - -Masking replaces the true content of the fields for a file in the Local -Header with false information. When masked, the Local Header is not -suitable for streaming access and the options for data recovery of damaged -archives is reduced. Extra Data fields that may contain confidential -data should not be stored within the Local Header. The value set into -the Version needed to extract field should be the correct value needed to -extract the file without regard to Central Directory Encryption. The fields -within the Local Header targeted for masking when the Central Directory is -encrypted are: - - Field Name Mask Value - ------------------ --------------------------- - compression method 0 - last mod file time 0 - last mod file date 0 - crc-32 0 - compressed size 0 - uncompressed size 0 - file name (variable size) Base 16 value from the - range 1 - FFFFFFFFFFFFFFFF - represented as a string whose - size will be set into the - file name length field - -The Base 16 value assigned as a masked file name is simply a sequentially -incremented value for each file starting with 1 for the first file. -Modifications to a ZIP file may cause different values to be stored for -each file. For compatibility, the file name field in the Local Header -should never be left blank. As of Version 6.2 of this specification, -the Compression Method and Compressed Size fields are not yet masked. - -Encrypting the Central Directory: - -Encryption of the Central Directory does not include encryption of the -Central Directory Signature data, the ZIP64 End of Central Directory -record, the ZIP64 End of Central Directory Locator, or the End -of Central Directory record. The ZIP file comment data is never -encrypted. - -Before encrypting the Central Directory, it may optionally be compressed. -Compression is not required, but for storage efficiency it is assumed -this structure will be compressed before encrypting. Similarly, this -specification supports compressing the Central Directory without -requiring that it also be encrypted. Early implementations of this -feature will assume the encryption method applied to files matches the -encryption applied to the Central Directory. - -Encryption of the Central Directory is done in a manner similar to -that of file encryption. The encrypted data is preceded by a -decryption header. The decryption header is known as the Archive -Decryption Header. The fields of this record are identical to -the decryption header preceding each encrypted file. The location -of the Archive Decryption Header is determined by the value in the -Start of the Central Directory field in the ZIP64 End of Central -Directory record. When the Central Directory is encrypted, the -ZIP64 End of Central Directory record will always be present. - -The layout of the ZIP64 End of Central Directory record for all -versions starting with 6.2 of this specification will follow the -Version 2 format. The Version 2 format is as follows: - -The first 48 bytes will remain identical to that of Version 1. -The record signature for both Version 1 and Version 2 will be -0x06064b50. Immediately following the 48th byte, which identifies -the end of the field known as the Offset of Start of Central -Directory With Respect to the Starting Disk Number will begin the -new fields defining Version 2 of this record. - -New fields for Version 2: - -Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - Compression Method 2 bytes Method used to compress the - Central Directory - Compressed Size 8 bytes Size of the compressed data - Original Size 8 bytes Original uncompressed size - AlgId 2 bytes Encryption algorithm ID - BitLen 2 bytes Encryption key length - Flags 2 bytes Encryption flags - HashID 2 bytes Hash algorithm identifier - Hash Length 2 bytes Length of hash data - Hash Data (variable) Hash data - -The Compression Method accepts the same range of values as the -corresponding field in the Central Header. - -The Compressed Size and Original Size values will not include the -data of the Central Directory Signature which is compressed or -encrypted. - -The AlgId, BitLen, and Flags fields accept the same range of values -the corresponding fields within the 0x0017 record. - -Hash ID identifies the algorithm used to hash the Central Directory -data. This data does not have to be hashed, in which case the -values for both the HashID and Hash Length will be 0. Possible -values for HashID are: - - Value Algorithm - ------ --------- - 0x0000 none - 0x0001 CRC32 - 0x8003 MD5 - 0x8004 SHA1 - -When the Central Directory data is signed, the same hash algorithm -used to hash the Central Directory for signing should be used. -This is recommended for processing efficiency, however, it is -permissible for any of the above algorithms to be used independent -of the signing process. - -The Hash Data will contain the hash data for the Central Directory. -The length of this data will vary depending on the algorithm used. - -The Version Needed to Extract should be set to 62. - -The value for the Total Number of Entries on the Current Disk will -be 0. These records will no longer support random access when -encrypting the Central Directory. - -When the Central Directory is compressed and/or encrypted, the -End of Central Directory record will store the value 0xFFFFFFFF -as the value for the Total Number of Entries in the Central -Directory. The value stored in the Total Number of Entries in -the Central Directory on this Disk field will be 0. The actual -values will be stored in the equivalent fields of the ZIP64 -End of Central Directory record. - -Decrypting and decompressing the Central Directory is accomplished -in the same manner as decrypting and decompressing a file. - - -5. Useful Tips - -Strong Encryption is always applied to a file after compression. The -block oriented algorithms all operate in Cypher Block Chaining (CBC) -mode. The block size used for AES encryption is 16. All other block -algorithms use a block size of 8. Two ID's are defined for RC2 to -account for a discrepancy found in the implementation of the RC2 -algorithm in the cryptographic library on Windows XP SP1 and all -earlier versions of Windows. - -A pseudo-code representation of the encryption process is as follows: - -Password = GetUserPassword() -RD = Random() -ERD = Encrypt(RD,DeriveKey(SHA1(Password))) -For Each File - IV = Random() - VData = Random() - FileSessionKey = DeriveKey(SHA1(IV + RD)) - Encrypt(VData + VCRC32 + FileData,FileSessionKey) -Done - -The function names and parameter requirements will depend on -the choice of the cryptographic toolkit selected. Almost any -toolkit supporting the reference implementations for each -algorithm can be used. The RSA BSAFE(r), OpenSSL, and Microsoft -CryptoAPI libraries are all known to work well. - - -Certificate Processing Method: ------------------------------ - -The Certificate Processing Method for ZIP file encryption remains -under development. The information provided here serves as a guide -to those interested in certificate-based data decryption. This -information may be subject to change in future versions of this -specification and is subject to change without notice. - -OAEP Processing with Certificate-based Encryption: - -Versions of PKZIP available during this development phase of the -certificate processing method may set a value of 61 into the -version needed to extract field for a file. This indicates that -non-OAEP key wrapping is used. This affects certificate encryption -only, and password encryption functions should not be affected by -this value. This means values of 61 may be found on files encrypted -with certificates only, or on files encrypted with both password -encryption and certificate encryption. Files encrypted with both -methods can safely be decrypted using the password methods documented. - -OAEP stands for Optimal Asymmetric Encryption Padding. It is a -strengthening technique used for small encoded items such as decryption -keys. This is commonly applied in cryptographic key-wrapping techniques -and is supported by PKCS #1. Versions 5.0 and 6.0 of this specification -were designed to support OAEP key-wrapping for certificate-based -decryption keys for additional security. - -Support for private keys stored on Smart Cards or Tokens introduced -a conflict with this OAEP logic. Most card and token products do -not support the additional strengthening applied to OAEP key-wrapped -data. In order to resolve this conflict, versions 6.1 and above of this -specification will no longer support OAEP when encrypting using -digital certificates. - -Certificate Processing Data Fields: - -The Certificate Processing Method of this specification defines the -following additional data fields: - - -1. Certificate Flag Values - -Additional processing flags that can be present in the Flags field of both -the 0x0017 field of the central directory Extra Field and the Decryption -header record preceding compressed file data are: - - 0x0007 - reserved for future use - 0x000F - reserved for future use - 0x0100 - Indicates non-OAEP key wrapping was used. If this - this field is set, the version needed to extract must - be at least 61. This means OAEP key wrapping is not - used when generating a Master Session Key using - ErdData. - 0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the - same algorithm used for encrypting the file contents. - 0x8000 - reserved for future use - - -2. CertData - Extra Field 0x0017 record certificate data structure - -The data structure used to store certificate data within the section -of the Extra Field defined by the CertData field of the 0x0017 -record are as shown: - - Value Size Description - ----- ---- ----------- - RCount 4 bytes Number of recipients. - HashAlg 2 bytes Hash algorithm identifier - HSize 2 bytes Hash size - SRList (var) Simple list of recipients hashed public keys - - - RCount This defines the number intended recipients whose - public keys were used for encryption. This identifies - the number of elements in the SRList. - - HashAlg This defines the hash algorithm used to calculate - the public key hash of each public key used - for encryption. This field currently supports - only the following value for SHA-1 - - 0x8004 - SHA1 - - HSize This defines the size of a hashed public key. - - SRList This is a variable length list of the hashed - public keys for each intended recipient. Each - element in this list is HSize. The total size of - SRList is determined using RCount * HSize. - - -3. Reserved1 - Certificate Decryption Header Reserved1 Data: - - Value Size Description - ----- ---- ----------- - RCount 4 bytes Number of recipients. - - RCount This defines the number intended recipients whose - public keys were used for encryption. This defines - the number of elements in the REList field defined below. - - -4. Reserved2 - Certificate Decryption Header Reserved2 Data Structures: - - - Value Size Description - ----- ---- ----------- - HashAlg 2 bytes Hash algorithm identifier - HSize 2 bytes Hash size - REList (var) List of recipient data elements - - - HashAlg This defines the hash algorithm used to calculate - the public key hash of each public key used - for encryption. This field currently supports - only the following value for SHA-1 - - 0x8004 - SHA1 - - HSize This defines the size of a hashed public key - defined in REHData. - - REList This is a variable length of list of recipient data. - Each element in this list consists of a Recipient - Element data structure as follows: - - - Recipient Element (REList) Data Structure: - - Value Size Description - ----- ---- ----------- - RESize 2 bytes Size of REHData + REKData - REHData HSize Hash of recipients public key - REKData (var) Simple key blob - - - RESize This defines the size of an individual REList - element. This value is the combined size of the - REHData field + REKData field. REHData is defined by - HSize. REKData is variable and can be calculated - for each REList element using RESize and HSize. - - REHData Hashed public key for this recipient. - - REKData Simple Key Blob. The format of this data structure - is identical to that defined in the Microsoft - CryptoAPI and generated using the CryptExportKey() - function. The version of the Simple Key Blob - supported at this time is 0x02 as defined by - Microsoft. - -5. Certificate Processing - Central Directory Encryption: - -Central Directory Encryption using Digital Certificates will -operate in a manner similar to that of Single Password Central -Directory Encryption. This record will only be present when there -is data to place into it. Currently, data is placed into this -record when digital certificates are used for either encrypting -or signing the files within a ZIP file. When only password -encryption is used with no certificate encryption or digital -signing, this record is not currently needed. When present, this -record will appear before the start of the actual Central Directory -data structure and will be located immediately after the Archive -Decryption Header if the Central Directory is encrypted. - -The Archive Extra Data record will be used to store the following -information. Additional data may be added in future versions. - -Extra Data Fields: - -0x0014 - PKCS#7 Store for X.509 Certificates -0x0016 - X.509 Certificate ID and Signature for central directory -0x0019 - PKCS#7 Encryption Recipient Certificate List - -The 0x0014 and 0x0016 Extra Data records that otherwise would be -located in the first record of the Central Directory for digital -certificate processing. When encrypting or compressing the Central -Directory, the 0x0014 and 0x0016 records must be located in the -Archive Extra Data record and they should not remain in the first -Central Directory record. The Archive Extra Data record will also -be used to store the 0x0019 data. - -When present, the size of the Archive Extra Data record will be -included in the size of the Central Directory. The data of the -Archive Extra Data record will also be compressed and encrypted -along with the Central Directory data structure. - -6. Certificate Processing Differences: - -The Certificate Processing Method of encryption differs from the -Single Password Symmetric Encryption Method as follows. Instead -of using a user-defined password to generate a master session key, -cryptographically random data is used. The key material is then -wrapped using standard key-wrapping techniques. This key material -is wrapped using the public key of each recipient that will need -to decrypt the file using their corresponding private key. - -This specification currently assumes digital certificates will follow -the X.509 V3 format for 1024 bit and higher RSA format digital -certificates. Implementation of this Certificate Processing Method -requires supporting logic for key access and management. This logic -is outside the scope of this specification. - - -License Agreement: ------------------ - -The features set forth in this Section XIV (the "Strong Encryption -Specification") are covered by a pending patent application. Portions of -this Strong Encryption technology are available for use at no charge -under the following terms and conditions. - -1. License Grant. - - a. NOTICE TO USER. PLEASE READ THIS ENTIRE SECTION XIV OF THE - APPNOTE (THE "AGREEMENT") CAREFULLY. BY USING ALL OR ANY PORTION OF THE - LICENSED TECHNOLOGY, YOU ACCEPT ALL THE TERMS AND CONDITIONS OF THIS - AGREEMENT AND YOU AGREE THAT THIS AGREEMENT IS ENFORCEABLE LIKE ANY - WRITTEN NEGOTIATED AGREEMENT SIGNED BY YOU. IF YOU DO NOT AGREE, DO NOT - USE THE LICENSED TECHNOLOGY. - - b. Definitions. - - i. "Licensed Technology" shall mean that proprietary technology now or - hereafter owned or controlled by PKWare, Inc. ("PKWARE") or any - subsidiary or affiliate that covers or is necessary to be used to give - software the ability to a) extract and decrypt data from zip files - encrypted using any methods of data encryption and key processing which - are published in this APPNOTE or any prior APPNOTE, as supplemented by - any Additional Compatibility Information; and b) encrypt file contents - as part of .ZIP file processing using only the Single Password Symmetric - Encryption Method as published in this APPNOTE or any prior APPNOTE, as - supplemented by any Additional Compatibility Information. For purposes - of this AGREEMENT, "Additional Compatibility Information" means, with - regard to any method of data encryption and key processing published in - this or any prior APPNOTE, any corrections, additions, or clarifications - to the information in such APPNOTE that are required in order to give - software the ability to successfully extract and decrypt zip files (or, - but solely in the case of the Single Password Symmetric Encryption Method, - to successfully encrypt zip files) in a manner interoperable with the - actual implementation of such method in any PKWARE product that is - documented or publicly described by PKWARE as being able to create, or - to extract and decrypt, zip files using that method. - - ii. "Licensed Products" shall mean any products you produce that - incorporate the Licensed Technology. - - c. License to Licensed Technology. - - PKWARE hereby grants to you a non-exclusive license to use the Licensed - Technology for the purpose of manufacturing, offering, selling and using - Licensed Products, which license shall extend to permit the practice of all - claims in any patent or patent application (collectively, "Patents") now or - hereafter owned or controlled by PKWARE in any jurisdiction in the world - that are infringed by implementation of the Licensed Technology. You have - the right to sublicense rights you receive under the terms of this AGREEMENT - for the purpose of allowing sublicensee to manufacture, offer, sell and use - products that incorporate all or a portion of any of your Licensed Products, - but if you do, you agree to i) impose the same restrictions on any such - sublicensee as these terms impose on you and ii) notify the sublicensee, - by means chosen by you in your unfettered discretion, including a notice on - your web site, of the terms of this AGREEMENT and make available to each - sublicensee the full text of this APPNOTE. Further, PKWARE hereby grants to - you a non-exclusive right to reproduce and distribute, in any form, copies of - this APPNOTE, without modification. Notwithstanding anything to the contrary - in this AGREEMENT, you have the right to sublicense the rights, without any of - the restrictions described above or elsewhere in this AGREEMENT, to use, offer - to sell and sell Licensed Technology as incorporated in executable object code - or byte code forms of your Licensed Products. Any sublicense to use the - Licensed Technology incorporated in a Licensed Product granted by you shall - survive the termination of this AGREEMENT for any reason. PKWARE warrants that - this license shall continue to encumber the Licensed Technology regardless of - changes in ownership of the Licensed Technology. - - d. Proprietary Notices. - - i. With respect to any Licensed Product that is distributed by you either - in source code form or in the form of an object code library of externally - callable functions that has been designed by you for incorporation into third - party products, you agree to include, in the source code, or in the case of - an object code library, in accompanying documentation, a notice using the - words "patent pending" until a patent is issued to PKWARE covering any - portion of the Licensed Technology or PKWARE provides notice, by means - chosen by PKWARE in its unfettered discretion, that it no longer has any - patent pending covering any portion of the Licensed Technology. With respect - to any Licensed Product, upon your becoming aware that at least one patent has - been granted covering the Licensed Technology, you agree to include in any - revisions made by you to the documentation (or any source code distributed - by you) the words "Pat. No.", or "Patent Number" and the patent number or - numbers of the applicable patent or patents. PKWARE shall, from time to time, - inform you of the patent number or numbers of the patents covering the - Licensed Technology, by means chosen by PKWARE in its unfettered discretion, - including a notice on its web site. It shall be a violation of the terms of - this AGREEMENT for you to sell Licensed Products without complying with the - foregoing marking provisions. - - ii. You acknowledge that the terms of this AGREEMENT do not grant you any - license or other right to use any PKWARE trademark in connection with the sale, - offering for sale, distribution and delivery of the Licensed Products, or in - connection with the advertising, promotion and offering of the Licensed Products. - You acknowledge PKWARE's ownership of the PKZIP trademark and all other marks - owned by PKWARE. - - e. Covenant of Compliance and Remedies. - - To the extent that you have elected to implement portions of the Licensed - Technology, you agree to use reasonable diligence to comply with those portions - of this Section XIV, as modified or supplemented by Additional Compatibility - Information available to you, describing the portions of the Licensed Technology - that you have elected to implement. Upon reasonable request by PKWARE, you will - provide written notice to PKWARE identifying which version of this APPNOTE you - have relied upon for your implementation of any specified Licensed Product. - - If any substantial non-compliance with the terms of this AGREEMENT is determined - to exist, you will make such changes as necessary to bring your Licensed Products - into substantial compliance with the terms of this AGREEMENT. If, within sixty - days of receipt of notice that a Licensed Product fails to comply with the terms - of this AGREEMENT, you fail to make such changes as necessary to bring your - Licensed Products into compliance with the terms of this AGREEMENT, PKWARE may - terminate your rights under this AGREEMENT. PKWARE does not waive and expressly - reserves the right to pursue any and all additional remedies that are or may - become available to PKWARE. - - f. Warranty and Indemnification Regarding Exportation. - - You realize and acknowledge that, as between yourself and PKWARE, you are fully - responsible for compliance with the import and export laws and regulations of - any country in or to which you import or export any Licensed Products, and you - agree to hold PKWARE harmless from any claim of violation of any such import - or export laws. - - g. Patent Infringement. - - You agree that you will not bring or threaten to bring any action against PKWARE - for infringement of the claims of any patent owned or controlled by you solely - as a result of PKWARE's own implementation of the Licensed Technology. As its - exclusive remedy for your breach of the foregoing agreement, PKWARE reserves - the right to suspend or terminate all rights granted under the terms of this - AGREEMENT if you bring or threaten to bring any such action against PKWARE, - effective immediately upon delivery of written notice of suspension or - termination to you. - - h. Governing Law. - - The license granted in this AGREEMENT shall be governed by and construed under - the laws of the State of Wisconsin and the United States. - - i. Revisions and Notice. - - The license granted in this APPNOTE is irrevocable, except as expressly set - forth above. You agree and understand that any changes which PKWARE determines - to make to this APPNOTE shall be posted at the same location as the current - APPNOTE or at a location which will be identified by means chosen by PKWARE, - including a notice on its web site, and shall be available for adoption by you - immediately upon such posting, or at such other time as PKWARE shall determine. - Any changes to the terms of the license published in a subsequent version of - this AGREEMENT shall be binding upon you only with respect to your products - that (i) incorporate any Licensed Technology (as defined in the subsequent - AGREEMENT) that is not otherwise included in the definition of Licensed - Technology under this AGREEMENT, or (ii) that you expressly identify are to - be licensed under the subsequent AGREEMENT, which identification shall be by - written notice with reference to the APPNOTE (version and release date or other - unique identifier) in which the subsequent AGREEMENT is published. PKWARE - agrees to identify each change to this APPNOTE by using a unique version and - release date identifier or other unique identifier. - - j. Warranty by PKWARE - - PKWare, Inc. warrants that it has the right to grant the license hereunder. - -XV. Change Process ------------------- - -In order for the .ZIP file format to remain a viable definition, this -specification should be considered as open for periodic review and -revision. Although this format was originally designed with a -certain level of extensibility, not all changes in technology -(present or future) were or will be necessarily considered in its -design. If your application requires new definitions to the -extensible sections in this format, or if you would like to -submit new data structures, please forward your request to -zipformat@pkware.com. All submissions will be reviewed by the -ZIP File Specification Committee for possible inclusion into -future versions of this specification. Periodic revisions -to this specification will be published to ensure interoperability. -We encourage comments and feedback that may help improve clarity -or content. - - -XVI. Acknowledgements ---------------------- - -In addition to the above mentioned contributors to PKZIP and PKUNZIP, -I would like to extend special thanks to Robert Mahoney for suggesting -the extension .ZIP for this software. - - -XVII. References ----------------- - - Fiala, Edward R., and Greene, Daniel H., "Data compression with - finite windows", Communications of the ACM, Volume 32, Number 4, - April 1989, pages 490-505. - - Held, Gilbert, "Data Compression, Techniques and Applications, - Hardware and Software Considerations", John Wiley & Sons, 1987. - - Huffman, D.A., "A method for the construction of minimum-redundancy - codes", Proceedings of the IRE, Volume 40, Number 9, September 1952, - pages 1098-1101. - - Nelson, Mark, "LZW Data Compression", Dr. Dobbs Journal, Volume 14, - Number 10, October 1989, pages 29-37. - - Nelson, Mark, "The Data Compression Book", M&T Books, 1991. - - Storer, James A., "Data Compression, Methods and Theory", - Computer Science Press, 1988 - - Welch, Terry, "A Technique for High-Performance Data Compression", - IEEE Computer, Volume 17, Number 6, June 1984, pages 8-19. - - Ziv, J. and Lempel, A., "A universal algorithm for sequential data - compression", Communications of the ACM, Volume 30, Number 6, - June 1987, pages 520-540. - - Ziv, J. and Lempel, A., "Compression of individual sequences via - variable-rate coding", IEEE Transactions on Information Theory, - Volume 24, Number 5, September 1978, pages 530-536. diff --git a/minizip-ng/doc/zip/appnote.txt b/minizip-ng/doc/zip/appnote.txt deleted file mode 100644 index e8e8b7c..0000000 --- a/minizip-ng/doc/zip/appnote.txt +++ /dev/null @@ -1,3497 +0,0 @@ -File: APPNOTE.TXT - .ZIP File Format Specification -Version: 6.3.4 -Status: Final - replaces version 6.3.3 -Revised: October 1, 2014 -Copyright (c) 1989 - 2014 PKWARE Inc., All Rights Reserved. - -1.0 Introduction ---------------- - -1.1 Purpose ------------ - - 1.1.1 This specification is intended to define a cross-platform, - interoperable file storage and transfer format. Since its - first publication in 1989, PKWARE, Inc. ("PKWARE") has remained - committed to ensuring the interoperability of the .ZIP file - format through periodic publication and maintenance of this - specification. We trust that all .ZIP compatible vendors and - application developers that use and benefit from this format - will share and support this commitment to interoperability. - -1.2 Scope ---------- - - 1.2.1 ZIP is one of the most widely used compressed file formats. It is - universally used to aggregate, compress, and encrypt files into a single - interoperable container. No specific use or application need is - defined by this format and no specific implementation guidance is - provided. This document provides details on the storage format for - creating ZIP files. Information is provided on the records and - fields that describe what a ZIP file is. - -1.3 Trademarks --------------- - - 1.3.1 PKWARE, PKZIP, SecureZIP, and PKSFX are registered trademarks of - PKWARE, Inc. in the United States and elsewhere. PKPatchMaker, - Deflate64, and ZIP64 are trademarks of PKWARE, Inc. Other marks - referenced within this document appear for identification - purposes only and are the property of their respective owners. - - -1.4 Permitted Use ------------------ - - 1.4.1 This document, "APPNOTE.TXT - .ZIP File Format Specification" is the - exclusive property of PKWARE. Use of the information contained in this - document is permitted solely for the purpose of creating products, - programs and processes that read and write files in the ZIP format - subject to the terms and conditions herein. - - 1.4.2 Use of the content of this document within other publications is - permitted only through reference to this document. Any reproduction - or distribution of this document in whole or in part without prior - written permission from PKWARE is strictly prohibited. - - 1.4.3 Certain technological components provided in this document are the - patented proprietary technology of PKWARE and as such require a - separate, executed license agreement from PKWARE. Applicable - components are marked with the following, or similar, statement: - 'Refer to the section in this document entitled "Incorporating - PKWARE Proprietary Technology into Your Product" for more information'. - -1.5 Contacting PKWARE ---------------------- - - 1.5.1 If you have questions on this format, its use, or licensing, or if you - wish to report defects, request changes or additions, please contact: - - PKWARE, Inc. - 201 E. Pittsburgh Avenue, Suite 400 - Milwaukee, WI 53204 - +1-414-289-9788 - +1-414-289-9789 FAX - zipformat@pkware.com - - 1.5.2 Information about this format and copies of this document are publicly - available at: - - https://www.pkware.com/appnote - -1.6 Disclaimer --------------- - - 1.6.1 Although PKWARE will attempt to supply current and accurate - information relating to its file formats, algorithms, and the - subject programs, the possibility of error or omission cannot - be eliminated. PKWARE therefore expressly disclaims any warranty - that the information contained in the associated materials relating - to the subject programs and/or the format of the files created or - accessed by the subject programs and/or the algorithms used by - the subject programs, or any other matter, is current, correct or - accurate as delivered. Any risk of damage due to any possible - inaccurate information is assumed by the user of the information. - Furthermore, the information relating to the subject programs - and/or the file formats created or accessed by the subject - programs and/or the algorithms used by the subject programs is - subject to change without notice. - -2.0 Revisions --------------- - -2.1 Document Status --------------------- - - 2.1.1 If the STATUS of this file is marked as DRAFT, the content - defines proposed revisions to this specification which may consist - of changes to the ZIP format itself, or that may consist of other - content changes to this document. Versions of this document and - the format in DRAFT form may be subject to modification prior to - publication STATUS of FINAL. DRAFT versions are published periodically - to provide notification to the ZIP community of pending changes and to - provide opportunity for review and comment. - - 2.1.2 Versions of this document having a STATUS of FINAL are - considered to be in the final form for that version of the document - and are not subject to further change until a new, higher version - numbered document is published. Newer versions of this format - specification are intended to remain interoperable with with all prior - versions whenever technically possible. - -2.2 Change Log --------------- - - Version Change Description Date - ------- ------------------ ---------- - 5.2 -Single Password Symmetric Encryption 07/16/2003 - storage - - 6.1.0 -Smartcard compatibility 01/20/2004 - -Documentation on certificate storage - - 6.2.0 -Introduction of Central Directory 04/26/2004 - Encryption for encrypting metadata - -Added OS X to Version Made By values - - 6.2.1 -Added Extra Field placeholder for 04/01/2005 - POSZIP using ID 0x4690 - - -Clarified size field on - "zip64 end of central directory record" - - 6.2.2 -Documented Final Feature Specification 01/06/2006 - for Strong Encryption - - -Clarifications and typographical - corrections - - 6.3.0 -Added tape positioning storage 09/29/2006 - parameters - - -Expanded list of supported hash algorithms - - -Expanded list of supported compression - algorithms - - -Expanded list of supported encryption - algorithms - - -Added option for Unicode filename - storage - - -Clarifications for consistent use - of Data Descriptor records - - -Added additional "Extra Field" - definitions - - 6.3.1 -Corrected standard hash values for 04/11/2007 - SHA-256/384/512 - - 6.3.2 -Added compression method 97 09/28/2007 - - -Documented InfoZIP "Extra Field" - values for UTF-8 file name and - file comment storage - - 6.3.3 -Formatting changes to support 09/01/2012 - easier referencing of this APPNOTE - from other documents and standards - - 6.3.4 -Address change 10/01/2014 - - -3.0 Notations -------------- - - 3.1 Use of the term MUST or SHALL indicates a required element. - - 3.2 MAY NOT or SHALL NOT indicates an element is prohibited from use. - - 3.3 SHOULD indicates a RECOMMENDED element. - - 3.4 SHOULD NOT indicates an element NOT RECOMMENDED for use. - - 3.5 MAY indicates an OPTIONAL element. - - -4.0 ZIP Files -------------- - -4.1 What is a ZIP file ----------------------- - - 4.1.1 ZIP files MAY be identified by the standard .ZIP file extension - although use of a file extension is not required. Use of the - extension .ZIPX is also recognized and MAY be used for ZIP files. - Other common file extensions using the ZIP format include .JAR, .WAR, - .DOCX, .XLXS, .PPTX, .ODT, .ODS, .ODP and others. Programs reading or - writing ZIP files SHOULD rely on internal record signatures described - in this document to identify files in this format. - - 4.1.2 ZIP files SHOULD contain at least one file and MAY contain - multiple files. - - 4.1.3 Data compression MAY be used to reduce the size of files - placed into a ZIP file, but is not required. This format supports the - use of multiple data compression algorithms. When compression is used, - one of the documented compression algorithms MUST be used. Implementors - are advised to experiment with their data to determine which of the - available algorithms provides the best compression for their needs. - Compression method 8 (Deflate) is the method used by default by most - ZIP compatible application programs. - - - 4.1.4 Data encryption MAY be used to protect files within a ZIP file. - Keying methods supported for encryption within this format include - passwords and public/private keys. Either MAY be used individually - or in combination. Encryption MAY be applied to individual files. - Additional security MAY be used through the encryption of ZIP file - metadata stored within the Central Directory. See the section on the - Strong Encryption Specification for information. Refer to the section - in this document entitled "Incorporating PKWARE Proprietary Technology - into Your Product" for more information. - - 4.1.5 Data integrity MUST be provided for each file using CRC32. - - 4.1.6 Additional data integrity MAY be included through the use of - digital signatures. Individual files MAY be signed with one or more - digital signatures. The Central Directory, if signed, MUST use a - single signature. - - 4.1.7 Files MAY be placed within a ZIP file uncompressed or stored. - The term "stored" as used in the context of this document means the file - is copied into the ZIP file uncompressed. - - 4.1.8 Each data file placed into a ZIP file MAY be compressed, stored, - encrypted or digitally signed independent of how other data files in the - same ZIP file are archived. - - 4.1.9 ZIP files MAY be streamed, split into segments (on fixed or on - removable media) or "self-extracting". Self-extracting ZIP - files MUST include extraction code for a target platform within - the ZIP file. - - 4.1.10 Extensibility is provided for platform or application specific - needs through extra data fields that MAY be defined for custom - purposes. Extra data definitions MUST NOT conflict with existing - documented record definitions. - - 4.1.11 Common uses for ZIP MAY also include the use of manifest files. - Manifest files store application specific information within a file stored - within the ZIP file. This manifest file SHOULD be the first file in the - ZIP file. This specification does not provide any information or guidance on - the use of manifest files within ZIP files. Refer to the application developer - for information on using manifest files and for any additional profile - information on using ZIP within an application. - - 4.1.12 ZIP files MAY be placed within other ZIP files. - -4.2 ZIP Metadata ----------------- - - 4.2.1 ZIP files are identified by metadata consisting of defined record types - containing the storage information necessary for maintaining the files - placed into a ZIP file. Each record type MUST be identified using a header - signature that identifies the record type. Signature values begin with the - two byte constant marker of 0x4b50, representing the characters "PK". - - -4.3 General Format of a .ZIP file ---------------------------------- - - 4.3.1 A ZIP file MUST contain an "end of central directory record". A ZIP - file containing only an "end of central directory record" is considered an - empty ZIP file. Files may be added or replaced within a ZIP file, or deleted. - A ZIP file MUST have only one "end of central directory record". Other - records defined in this specification MAY be used as needed to support - storage requirements for individual ZIP files. - - 4.3.2 Each file placed into a ZIP file MUST be preceeded by a "local - file header" record for that file. Each "local file header" MUST be - accompanied by a corresponding "central directory header" record within - the central directory section of the ZIP file. - - 4.3.3 Files MAY be stored in arbitrary order within a ZIP file. A ZIP - file MAY span multiple volumes or it MAY be split into user-defined - segment sizes. All values MUST be stored in little-endian byte order unless - otherwise specified in this document for a specific data element. - - 4.3.4 Compression MUST NOT be applied to a "local file header", an "encryption - header", or an "end of central directory record". Individual "central - directory records" must not be compressed, but the aggregate of all central - directory records MAY be compressed. - - 4.3.5 File data MAY be followed by a "data descriptor" for the file. Data - descriptors are used to facilitate ZIP file streaming. - - - 4.3.6 Overall .ZIP file format: - - [local file header 1] - [encryption header 1] - [file data 1] - [data descriptor 1] - . - . - . - [local file header n] - [encryption header n] - [file data n] - [data descriptor n] - [archive decryption header] - [archive extra data record] - [central directory header 1] - . - . - . - [central directory header n] - [zip64 end of central directory record] - [zip64 end of central directory locator] - [end of central directory record] - - - 4.3.7 Local file header: - - local file header signature 4 bytes (0x04034b50) - version needed to extract 2 bytes - general purpose bit flag 2 bytes - compression method 2 bytes - last mod file time 2 bytes - last mod file date 2 bytes - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - file name length 2 bytes - extra field length 2 bytes - - file name (variable size) - extra field (variable size) - - 4.3.8 File data - - Immediately following the local header for a file - SHOULD be placed the compressed or stored data for the file. - If the file is encrypted, the encryption header for the file - SHOULD be placed after the local header and before the file - data. The series of [local file header][encryption header] - [file data][data descriptor] repeats for each file in the - .ZIP archive. - - Zero-byte files, directories, and other file types that - contain no content MUST not include file data. - - 4.3.9 Data descriptor: - - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - - 4.3.9.1 This descriptor MUST exist if bit 3 of the general - purpose bit flag is set (see below). It is byte aligned - and immediately follows the last byte of compressed data. - This descriptor SHOULD be used only when it was not possible to - seek in the output .ZIP file, e.g., when the output .ZIP file - was standard output or a non-seekable device. For ZIP64(tm) format - archives, the compressed and uncompressed sizes are 8 bytes each. - - 4.3.9.2 When compressing files, compressed and uncompressed sizes - should be stored in ZIP64 format (as 8 byte values) when a - file's size exceeds 0xFFFFFFFF. However ZIP64 format may be - used regardless of the size of a file. When extracting, if - the zip64 extended information extra field is present for - the file the compressed and uncompressed sizes will be 8 - byte values. - - 4.3.9.3 Although not originally assigned a signature, the value - 0x08074b50 has commonly been adopted as a signature value - for the data descriptor record. Implementers should be - aware that ZIP files may be encountered with or without this - signature marking data descriptors and SHOULD account for - either case when reading ZIP files to ensure compatibility. - - 4.3.9.4 When writing ZIP files, implementors SHOULD include the - signature value marking the data descriptor record. When - the signature is used, the fields currently defined for - the data descriptor record will immediately follow the - signature. - - 4.3.9.5 An extensible data descriptor will be released in a - future version of this APPNOTE. This new record is intended to - resolve conflicts with the use of this record going forward, - and to provide better support for streamed file processing. - - 4.3.9.6 When the Central Directory Encryption method is used, - the data descriptor record is not required, but MAY be used. - If present, and bit 3 of the general purpose bit field is set to - indicate its presence, the values in fields of the data descriptor - record MUST be set to binary zeros. See the section on the Strong - Encryption Specification for information. Refer to the section in - this document entitled "Incorporating PKWARE Proprietary Technology - into Your Product" for more information. - - - 4.3.10 Archive decryption header: - - 4.3.10.1 The Archive Decryption Header is introduced in version 6.2 - of the ZIP format specification. This record exists in support - of the Central Directory Encryption Feature implemented as part of - the Strong Encryption Specification as described in this document. - When the Central Directory Structure is encrypted, this decryption - header MUST precede the encrypted data segment. - - 4.3.10.2 The encrypted data segment SHALL consist of the Archive - extra data record (if present) and the encrypted Central Directory - Structure data. The format of this data record is identical to the - Decryption header record preceding compressed file data. If the - central directory structure is encrypted, the location of the start of - this data record is determined using the Start of Central Directory - field in the Zip64 End of Central Directory record. See the - section on the Strong Encryption Specification for information - on the fields used in the Archive Decryption Header record. - Refer to the section in this document entitled "Incorporating - PKWARE Proprietary Technology into Your Product" for more information. - - - 4.3.11 Archive extra data record: - - archive extra data signature 4 bytes (0x08064b50) - extra field length 4 bytes - extra field data (variable size) - - 4.3.11.1 The Archive Extra Data Record is introduced in version 6.2 - of the ZIP format specification. This record MAY be used in support - of the Central Directory Encryption Feature implemented as part of - the Strong Encryption Specification as described in this document. - When present, this record MUST immediately precede the central - directory data structure. - - 4.3.11.2 The size of this data record SHALL be included in the - Size of the Central Directory field in the End of Central - Directory record. If the central directory structure is compressed, - but not encrypted, the location of the start of this data record is - determined using the Start of Central Directory field in the Zip64 - End of Central Directory record. Refer to the section in this document - entitled "Incorporating PKWARE Proprietary Technology into Your - Product" for more information. - - 4.3.12 Central directory structure: - - [central directory header 1] - . - . - . - [central directory header n] - [digital signature] - - File header: - - central file header signature 4 bytes (0x02014b50) - version made by 2 bytes - version needed to extract 2 bytes - general purpose bit flag 2 bytes - compression method 2 bytes - last mod file time 2 bytes - last mod file date 2 bytes - crc-32 4 bytes - compressed size 4 bytes - uncompressed size 4 bytes - file name length 2 bytes - extra field length 2 bytes - file comment length 2 bytes - disk number start 2 bytes - internal file attributes 2 bytes - external file attributes 4 bytes - relative offset of local header 4 bytes - - file name (variable size) - extra field (variable size) - file comment (variable size) - - 4.3.13 Digital signature: - - header signature 4 bytes (0x05054b50) - size of data 2 bytes - signature data (variable size) - - With the introduction of the Central Directory Encryption - feature in version 6.2 of this specification, the Central - Directory Structure MAY be stored both compressed and encrypted. - Although not required, it is assumed when encrypting the - Central Directory Structure, that it will be compressed - for greater storage efficiency. Information on the - Central Directory Encryption feature can be found in the section - describing the Strong Encryption Specification. The Digital - Signature record will be neither compressed nor encrypted. - - 4.3.14 Zip64 end of central directory record - - zip64 end of central dir - signature 4 bytes (0x06064b50) - size of zip64 end of central - directory record 8 bytes - version made by 2 bytes - version needed to extract 2 bytes - number of this disk 4 bytes - number of the disk with the - start of the central directory 4 bytes - total number of entries in the - central directory on this disk 8 bytes - total number of entries in the - central directory 8 bytes - size of the central directory 8 bytes - offset of start of central - directory with respect to - the starting disk number 8 bytes - zip64 extensible data sector (variable size) - - 4.3.14.1 The value stored into the "size of zip64 end of central - directory record" should be the size of the remaining - record and should not include the leading 12 bytes. - - Size = SizeOfFixedFields + SizeOfVariableData - 12. - - 4.3.14.2 The above record structure defines Version 1 of the - zip64 end of central directory record. Version 1 was - implemented in versions of this specification preceding - 6.2 in support of the ZIP64 large file feature. The - introduction of the Central Directory Encryption feature - implemented in version 6.2 as part of the Strong Encryption - Specification defines Version 2 of this record structure. - Refer to the section describing the Strong Encryption - Specification for details on the version 2 format for - this record. Refer to the section in this document entitled - "Incorporating PKWARE Proprietary Technology into Your Product" - for more information applicable to use of Version 2 of this - record. - - 4.3.14.3 Special purpose data MAY reside in the zip64 extensible - data sector field following either a V1 or V2 version of this - record. To ensure identification of this special purpose data - it must include an identifying header block consisting of the - following: - - Header ID - 2 bytes - Data Size - 4 bytes - - The Header ID field indicates the type of data that is in the - data block that follows. - - Data Size identifies the number of bytes that follow for this - data block type. - - 4.3.14.4 Multiple special purpose data blocks MAY be present. - Each MUST be preceded by a Header ID and Data Size field. Current - mappings of Header ID values supported in this field are as - defined in APPENDIX C. - - 4.3.15 Zip64 end of central directory locator - - zip64 end of central dir locator - signature 4 bytes (0x07064b50) - number of the disk with the - start of the zip64 end of - central directory 4 bytes - relative offset of the zip64 - end of central directory record 8 bytes - total number of disks 4 bytes - - 4.3.16 End of central directory record: - - end of central dir signature 4 bytes (0x06054b50) - number of this disk 2 bytes - number of the disk with the - start of the central directory 2 bytes - total number of entries in the - central directory on this disk 2 bytes - total number of entries in - the central directory 2 bytes - size of the central directory 4 bytes - offset of start of central - directory with respect to - the starting disk number 4 bytes - .ZIP file comment length 2 bytes - .ZIP file comment (variable size) - -4.4 Explanation of fields --------------------------- - - 4.4.1 General notes on fields - - 4.4.1.1 All fields unless otherwise noted are unsigned and stored - in Intel low-byte:high-byte, low-word:high-word order. - - 4.4.1.2 String fields are not null terminated, since the length - is given explicitly. - - 4.4.1.3 The entries in the central directory may not necessarily - be in the same order that files appear in the .ZIP file. - - 4.4.1.4 If one of the fields in the end of central directory - record is too small to hold required data, the field should be - set to -1 (0xFFFF or 0xFFFFFFFF) and the ZIP64 format record - should be created. - - 4.4.1.5 The end of central directory record and the Zip64 end - of central directory locator record MUST reside on the same - disk when splitting or spanning an archive. - - 4.4.2 version made by (2 bytes) - - 4.4.2.1 The upper byte indicates the compatibility of the file - attribute information. If the external file attributes - are compatible with MS-DOS and can be read by PKZIP for - DOS version 2.04g then this value will be zero. If these - attributes are not compatible, then this value will - identify the host system on which the attributes are - compatible. Software can use this information to determine - the line record format for text files etc. - - 4.4.2.2 The current mappings are: - - 0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems) - 1 - Amiga 2 - OpenVMS - 3 - UNIX 4 - VM/CMS - 5 - Atari ST 6 - OS/2 H.P.F.S. - 7 - Macintosh 8 - Z-System - 9 - CP/M 10 - Windows NTFS - 11 - MVS (OS/390 - Z/OS) 12 - VSE - 13 - Acorn Risc 14 - VFAT - 15 - alternate MVS 16 - BeOS - 17 - Tandem 18 - OS/400 - 19 - OS X (Darwin) 20 thru 255 - unused - - 4.4.2.3 The lower byte indicates the ZIP specification version - (the version of this document) supported by the software - used to encode the file. The value/10 indicates the major - version number, and the value mod 10 is the minor version - number. - - 4.4.3 version needed to extract (2 bytes) - - 4.4.3.1 The minimum supported ZIP specification version needed - to extract the file, mapped as above. This value is based on - the specific format features a ZIP program MUST support to - be able to extract the file. If multiple features are - applied to a file, the minimum version MUST be set to the - feature having the highest value. New features or feature - changes affecting the published format specification will be - implemented using higher version numbers than the last - published value to avoid conflict. - - 4.4.3.2 Current minimum feature versions are as defined below: - - 1.0 - Default value - 1.1 - File is a volume label - 2.0 - File is a folder (directory) - 2.0 - File is compressed using Deflate compression - 2.0 - File is encrypted using traditional PKWARE encryption - 2.1 - File is compressed using Deflate64(tm) - 2.5 - File is compressed using PKWARE DCL Implode - 2.7 - File is a patch data set - 4.5 - File uses ZIP64 format extensions - 4.6 - File is compressed using BZIP2 compression* - 5.0 - File is encrypted using DES - 5.0 - File is encrypted using 3DES - 5.0 - File is encrypted using original RC2 encryption - 5.0 - File is encrypted using RC4 encryption - 5.1 - File is encrypted using AES encryption - 5.1 - File is encrypted using corrected RC2 encryption** - 5.2 - File is encrypted using corrected RC2-64 encryption** - 6.1 - File is encrypted using non-OAEP key wrapping*** - 6.2 - Central directory encryption - 6.3 - File is compressed using LZMA - 6.3 - File is compressed using PPMd+ - 6.3 - File is encrypted using Blowfish - 6.3 - File is encrypted using Twofish - - 4.4.3.3 Notes on version needed to extract - - * Early 7.x (pre-7.2) versions of PKZIP incorrectly set the - version needed to extract for BZIP2 compression to be 50 - when it should have been 46. - - ** Refer to the section on Strong Encryption Specification - for additional information regarding RC2 corrections. - - *** Certificate encryption using non-OAEP key wrapping is the - intended mode of operation for all versions beginning with 6.1. - Support for OAEP key wrapping MUST only be used for - backward compatibility when sending ZIP files to be opened by - versions of PKZIP older than 6.1 (5.0 or 6.0). - - + Files compressed using PPMd MUST set the version - needed to extract field to 6.3, however, not all ZIP - programs enforce this and may be unable to decompress - data files compressed using PPMd if this value is set. - - When using ZIP64 extensions, the corresponding value in the - zip64 end of central directory record MUST also be set. - This field should be set appropriately to indicate whether - Version 1 or Version 2 format is in use. - - - 4.4.4 general purpose bit flag: (2 bytes) - - Bit 0: If set, indicates that the file is encrypted. - - (For Method 6 - Imploding) - Bit 1: If the compression method used was type 6, - Imploding, then this bit, if set, indicates - an 8K sliding dictionary was used. If clear, - then a 4K sliding dictionary was used. - - Bit 2: If the compression method used was type 6, - Imploding, then this bit, if set, indicates - 3 Shannon-Fano trees were used to encode the - sliding dictionary output. If clear, then 2 - Shannon-Fano trees were used. - - (For Methods 8 and 9 - Deflating) - Bit 2 Bit 1 - 0 0 Normal (-en) compression option was used. - 0 1 Maximum (-exx/-ex) compression option was used. - 1 0 Fast (-ef) compression option was used. - 1 1 Super Fast (-es) compression option was used. - - (For Method 14 - LZMA) - Bit 1: If the compression method used was type 14, - LZMA, then this bit, if set, indicates - an end-of-stream (EOS) marker is used to - mark the end of the compressed data stream. - If clear, then an EOS marker is not present - and the compressed data size must be known - to extract. - - Note: Bits 1 and 2 are undefined if the compression - method is any other. - - Bit 3: If this bit is set, the fields crc-32, compressed - size and uncompressed size are set to zero in the - local header. The correct values are put in the - data descriptor immediately following the compressed - data. (Note: PKZIP version 2.04g for DOS only - recognizes this bit for method 8 compression, newer - versions of PKZIP recognize this bit for any - compression method.) - - Bit 4: Reserved for use with method 8, for enhanced - deflating. - - Bit 5: If this bit is set, this indicates that the file is - compressed patched data. (Note: Requires PKZIP - version 2.70 or greater) - - Bit 6: Strong encryption. If this bit is set, you MUST - set the version needed to extract value to at least - 50 and you MUST also set bit 0. If AES encryption - is used, the version needed to extract value MUST - be at least 51. See the section describing the Strong - Encryption Specification for details. Refer to the - section in this document entitled "Incorporating PKWARE - Proprietary Technology into Your Product" for more - information. - - Bit 7: Currently unused. - - Bit 8: Currently unused. - - Bit 9: Currently unused. - - Bit 10: Currently unused. - - Bit 11: Language encoding flag (EFS). If this bit is set, - the filename and comment fields for this file - MUST be encoded using UTF-8. (see APPENDIX D) - - Bit 12: Reserved by PKWARE for enhanced compression. - - Bit 13: Set when encrypting the Central Directory to indicate - selected data values in the Local Header are masked to - hide their actual values. See the section describing - the Strong Encryption Specification for details. Refer - to the section in this document entitled "Incorporating - PKWARE Proprietary Technology into Your Product" for - more information. - - Bit 14: Reserved by PKWARE. - - Bit 15: Reserved by PKWARE. - - 4.4.5 compression method: (2 bytes) - - 0 - The file is stored (no compression) - 1 - The file is Shrunk - 2 - The file is Reduced with compression factor 1 - 3 - The file is Reduced with compression factor 2 - 4 - The file is Reduced with compression factor 3 - 5 - The file is Reduced with compression factor 4 - 6 - The file is Imploded - 7 - Reserved for Tokenizing compression algorithm - 8 - The file is Deflated - 9 - Enhanced Deflating using Deflate64(tm) - 10 - PKWARE Data Compression Library Imploding (old IBM TERSE) - 11 - Reserved by PKWARE - 12 - File is compressed using BZIP2 algorithm - 13 - Reserved by PKWARE - 14 - LZMA (EFS) - 15 - Reserved by PKWARE - 16 - Reserved by PKWARE - 17 - Reserved by PKWARE - 18 - File is compressed using IBM TERSE (new) - 19 - IBM LZ77 z Architecture (PFS) - 97 - WavPack compressed data - 98 - PPMd version I, Rev 1 - - - 4.4.6 date and time fields: (2 bytes each) - - The date and time are encoded in standard MS-DOS format. - If input came from standard input, the date and time are - those at which compression was started for this data. - If encrypting the central directory and general purpose bit - flag 13 is set indicating masking, the value stored in the - Local Header will be zero. - - 4.4.7 CRC-32: (4 bytes) - - The CRC-32 algorithm was generously contributed by - David Schwaderer and can be found in his excellent - book "C Programmers Guide to NetBIOS" published by - Howard W. Sams & Co. Inc. The 'magic number' for - the CRC is 0xdebb20e3. The proper CRC pre and post - conditioning is used, meaning that the CRC register - is pre-conditioned with all ones (a starting value - of 0xffffffff) and the value is post-conditioned by - taking the one's complement of the CRC residual. - If bit 3 of the general purpose flag is set, this - field is set to zero in the local header and the correct - value is put in the data descriptor and in the central - directory. When encrypting the central directory, if the - local header is not in ZIP64 format and general purpose - bit flag 13 is set indicating masking, the value stored - in the Local Header will be zero. - - 4.4.8 compressed size: (4 bytes) - 4.4.9 uncompressed size: (4 bytes) - - The size of the file compressed (4.4.8) and uncompressed, - (4.4.9) respectively. When a decryption header is present it - will be placed in front of the file data and the value of the - compressed file size will include the bytes of the decryption - header. If bit 3 of the general purpose bit flag is set, - these fields are set to zero in the local header and the - correct values are put in the data descriptor and - in the central directory. If an archive is in ZIP64 format - and the value in this field is 0xFFFFFFFF, the size will be - in the corresponding 8 byte ZIP64 extended information - extra field. When encrypting the central directory, if the - local header is not in ZIP64 format and general purpose bit - flag 13 is set indicating masking, the value stored for the - uncompressed size in the Local Header will be zero. - - 4.4.10 file name length: (2 bytes) - 4.4.11 extra field length: (2 bytes) - 4.4.12 file comment length: (2 bytes) - - The length of the file name, extra field, and comment - fields respectively. The combined length of any - directory record and these three fields should not - generally exceed 65,535 bytes. If input came from standard - input, the file name length is set to zero. - - - 4.4.13 disk number start: (2 bytes) - - The number of the disk on which this file begins. If an - archive is in ZIP64 format and the value in this field is - 0xFFFF, the size will be in the corresponding 4 byte zip64 - extended information extra field. - - 4.4.14 internal file attributes: (2 bytes) - - Bits 1 and 2 are reserved for use by PKWARE. - - 4.4.14.1 The lowest bit of this field indicates, if set, - that the file is apparently an ASCII or text file. If not - set, that the file apparently contains binary data. - The remaining bits are unused in version 1.0. - - 4.4.14.2 The 0x0002 bit of this field indicates, if set, that - a 4 byte variable record length control field precedes each - logical record indicating the length of the record. The - record length control field is stored in little-endian byte - order. This flag is independent of text control characters, - and if used in conjunction with text data, includes any - control characters in the total length of the record. This - value is provided for mainframe data transfer support. - - 4.4.15 external file attributes: (4 bytes) - - The mapping of the external attributes is - host-system dependent (see 'version made by'). For - MS-DOS, the low order byte is the MS-DOS directory - attribute byte. If input came from standard input, this - field is set to zero. - - 4.4.16 relative offset of local header: (4 bytes) - - This is the offset from the start of the first disk on - which this file appears, to where the local header should - be found. If an archive is in ZIP64 format and the value - in this field is 0xFFFFFFFF, the size will be in the - corresponding 8 byte zip64 extended information extra field. - - 4.4.17 file name: (Variable) - - 4.4.17.1 The name of the file, with optional relative path. - The path stored MUST not contain a drive or - device letter, or a leading slash. All slashes - MUST be forward slashes '/' as opposed to - backwards slashes '\' for compatibility with Amiga - and UNIX file systems etc. If input came from standard - input, there is no file name field. - - 4.4.17.2 If using the Central Directory Encryption Feature and - general purpose bit flag 13 is set indicating masking, the file - name stored in the Local Header will not be the actual file name. - A masking value consisting of a unique hexadecimal value will - be stored. This value will be sequentially incremented for each - file in the archive. See the section on the Strong Encryption - Specification for details on retrieving the encrypted file name. - Refer to the section in this document entitled "Incorporating PKWARE - Proprietary Technology into Your Product" for more information. - - - 4.4.18 file comment: (Variable) - - The comment for this file. - - 4.4.19 number of this disk: (2 bytes) - - The number of this disk, which contains central - directory end record. If an archive is in ZIP64 format - and the value in this field is 0xFFFF, the size will - be in the corresponding 4 byte zip64 end of central - directory field. - - - 4.4.20 number of the disk with the start of the central - directory: (2 bytes) - - The number of the disk on which the central - directory starts. If an archive is in ZIP64 format - and the value in this field is 0xFFFF, the size will - be in the corresponding 4 byte zip64 end of central - directory field. - - 4.4.21 total number of entries in the central dir on - this disk: (2 bytes) - - The number of central directory entries on this disk. - If an archive is in ZIP64 format and the value in - this field is 0xFFFF, the size will be in the - corresponding 8 byte zip64 end of central - directory field. - - 4.4.22 total number of entries in the central dir: (2 bytes) - - The total number of files in the .ZIP file. If an - archive is in ZIP64 format and the value in this field - is 0xFFFF, the size will be in the corresponding 8 byte - zip64 end of central directory field. - - 4.4.23 size of the central directory: (4 bytes) - - The size (in bytes) of the entire central directory. - If an archive is in ZIP64 format and the value in - this field is 0xFFFFFFFF, the size will be in the - corresponding 8 byte zip64 end of central - directory field. - - 4.4.24 offset of start of central directory with respect to - the starting disk number: (4 bytes) - - Offset of the start of the central directory on the - disk on which the central directory starts. If an - archive is in ZIP64 format and the value in this - field is 0xFFFFFFFF, the size will be in the - corresponding 8 byte zip64 end of central - directory field. - - 4.4.25 .ZIP file comment length: (2 bytes) - - The length of the comment for this .ZIP file. - - 4.4.26 .ZIP file comment: (Variable) - - The comment for this .ZIP file. ZIP file comment data - is stored unsecured. No encryption or data authentication - is applied to this area at this time. Confidential information - should not be stored in this section. - - 4.4.27 zip64 extensible data sector (variable size) - - (currently reserved for use by PKWARE) - - - 4.4.28 extra field: (Variable) - - This SHOULD be used for storage expansion. If additional - information needs to be stored within a ZIP file for special - application or platform needs, it SHOULD be stored here. - Programs supporting earlier versions of this specification can - then safely skip the file, and find the next file or header. - This field will be 0 length in version 1.0. - - Existing extra fields are defined in the section - Extensible data fields that follows. - -4.5 Extensible data fields --------------------------- - - 4.5.1 In order to allow different programs and different types - of information to be stored in the 'extra' field in .ZIP - files, the following structure MUST be used for all - programs storing data in this field: - - header1+data1 + header2+data2 . . . - - Each header should consist of: - - Header ID - 2 bytes - Data Size - 2 bytes - - Note: all fields stored in Intel low-byte/high-byte order. - - The Header ID field indicates the type of data that is in - the following data block. - - Header IDs of 0 thru 31 are reserved for use by PKWARE. - The remaining IDs can be used by third party vendors for - proprietary usage. - - 4.5.2 The current Header ID mappings defined by PKWARE are: - - 0x0001 Zip64 extended information extra field - 0x0007 AV Info - 0x0008 Reserved for extended language encoding data (PFS) - (see APPENDIX D) - 0x0009 OS/2 - 0x000a NTFS - 0x000c OpenVMS - 0x000d UNIX - 0x000e Reserved for file stream and fork descriptors - 0x000f Patch Descriptor - 0x0014 PKCS#7 Store for X.509 Certificates - 0x0015 X.509 Certificate ID and Signature for - individual file - 0x0016 X.509 Certificate ID for Central Directory - 0x0017 Strong Encryption Header - 0x0018 Record Management Controls - 0x0019 PKCS#7 Encryption Recipient Certificate List - 0x0065 IBM S/390 (Z390), AS/400 (I400) attributes - - uncompressed - 0x0066 Reserved for IBM S/390 (Z390), AS/400 (I400) - attributes - compressed - 0x4690 POSZIP 4690 (reserved) - - - 4.5.3 -Zip64 Extended Information Extra Field (0x0001): - - The following is the layout of the zip64 extended - information "extra" block. If one of the size or - offset fields in the Local or Central directory - record is too small to hold the required data, - a Zip64 extended information record is created. - The order of the fields in the zip64 extended - information record is fixed, but the fields MUST - only appear if the corresponding Local or Central - directory record field is set to 0xFFFF or 0xFFFFFFFF. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- -(ZIP64) 0x0001 2 bytes Tag for this "extra" block type - Size 2 bytes Size of this "extra" block - Original - Size 8 bytes Original uncompressed file size - Compressed - Size 8 bytes Size of compressed data - Relative Header - Offset 8 bytes Offset of local header record - Disk Start - Number 4 bytes Number of the disk on which - this file starts - - This entry in the Local header MUST include BOTH original - and compressed file size fields. If encrypting the - central directory and bit 13 of the general purpose bit - flag is set indicating masking, the value stored in the - Local Header for the original file size will be zero. - - - 4.5.4 -OS/2 Extra Field (0x0009): - - The following is the layout of the OS/2 attributes "extra" - block. (Last Revision 09/05/95) - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- -(OS/2) 0x0009 2 bytes Tag for this "extra" block type - TSize 2 bytes Size for the following data block - BSize 4 bytes Uncompressed Block Size - CType 2 bytes Compression type - EACRC 4 bytes CRC value for uncompress block - (var) variable Compressed block - - The OS/2 extended attribute structure (FEA2LIST) is - compressed and then stored in its entirety within this - structure. There will only ever be one "block" of data in - VarFields[]. - - 4.5.5 -NTFS Extra Field (0x000a): - - The following is the layout of the NTFS attributes - "extra" block. (Note: At this time the Mtime, Atime - and Ctime values MAY be used on any WIN32 system.) - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- -(NTFS) 0x000a 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the total "extra" block - Reserved 4 bytes Reserved for future use - Tag1 2 bytes NTFS attribute tag value #1 - Size1 2 bytes Size of attribute #1, in bytes - (var) Size1 Attribute #1 data - . - . - . - TagN 2 bytes NTFS attribute tag value #N - SizeN 2 bytes Size of attribute #N, in bytes - (var) SizeN Attribute #N data - - For NTFS, values for Tag1 through TagN are as follows: - (currently only one set of attributes is defined for NTFS) - - Tag Size Description - ----- ---- ----------- - 0x0001 2 bytes Tag for attribute #1 - Size1 2 bytes Size of attribute #1, in bytes - Mtime 8 bytes File last modification time - Atime 8 bytes File last access time - Ctime 8 bytes File creation time - - 4.5.6 -OpenVMS Extra Field (0x000c): - - The following is the layout of the OpenVMS attributes - "extra" block. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (VMS) 0x000c 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the total "extra" block - CRC 4 bytes 32-bit CRC for remainder of the block - Tag1 2 bytes OpenVMS attribute tag value #1 - Size1 2 bytes Size of attribute #1, in bytes - (var) Size1 Attribute #1 data - . - . - . - TagN 2 bytes OpenVMS attribute tag value #N - SizeN 2 bytes Size of attribute #N, in bytes - (var) SizeN Attribute #N data - - OpenVMS Extra Field Rules: - - 4.5.6.1. There will be one or more attributes present, which - will each be preceded by the above TagX & SizeX values. - These values are identical to the ATR$C_XXXX and ATR$S_XXXX - constants which are defined in ATR.H under OpenVMS C. Neither - of these values will ever be zero. - - 4.5.6.2. No word alignment or padding is performed. - - 4.5.6.3. A well-behaved PKZIP/OpenVMS program should never produce - more than one sub-block with the same TagX value. Also, there will - never be more than one "extra" block of type 0x000c in a particular - directory record. - - 4.5.7 -UNIX Extra Field (0x000d): - - The following is the layout of the UNIX "extra" block. - Note: all fields are stored in Intel low-byte/high-byte - order. - - Value Size Description - ----- ---- ----------- -(UNIX) 0x000d 2 bytes Tag for this "extra" block type - TSize 2 bytes Size for the following data block - Atime 4 bytes File last access time - Mtime 4 bytes File last modification time - Uid 2 bytes File user ID - Gid 2 bytes File group ID - (var) variable Variable length data field - - The variable length data field will contain file type - specific data. Currently the only values allowed are - the original "linked to" file names for hard or symbolic - links, and the major and minor device node numbers for - character and block device nodes. Since device nodes - cannot be either symbolic or hard links, only one set of - variable length data is stored. Link files will have the - name of the original file stored. This name is NOT NULL - terminated. Its size can be determined by checking TSize - - 12. Device entries will have eight bytes stored as two 4 - byte entries (in little endian format). The first entry - will be the major device number, and the second the minor - device number. - - 4.5.8 -PATCH Descriptor Extra Field (0x000f): - - 4.5.8.1 The following is the layout of the Patch Descriptor - "extra" block. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- -(Patch) 0x000f 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the total "extra" block - Version 2 bytes Version of the descriptor - Flags 4 bytes Actions and reactions (see below) - OldSize 4 bytes Size of the file about to be patched - OldCRC 4 bytes 32-bit CRC of the file to be patched - NewSize 4 bytes Size of the resulting file - NewCRC 4 bytes 32-bit CRC of the resulting file - - 4.5.8.2 Actions and reactions - - Bits Description - ---- ---------------- - 0 Use for auto detection - 1 Treat as a self-patch - 2-3 RESERVED - 4-5 Action (see below) - 6-7 RESERVED - 8-9 Reaction (see below) to absent file - 10-11 Reaction (see below) to newer file - 12-13 Reaction (see below) to unknown file - 14-15 RESERVED - 16-31 RESERVED - - 4.5.8.2.1 Actions - - Action Value - ------ ----- - none 0 - add 1 - delete 2 - patch 3 - - 4.5.8.2.2 Reactions - - Reaction Value - -------- ----- - ask 0 - skip 1 - ignore 2 - fail 3 - - 4.5.8.3 Patch support is provided by PKPatchMaker(tm) technology - and is covered under U.S. Patents and Patents Pending. The use or - implementation in a product of certain technological aspects set - forth in the current APPNOTE, including those with regard to - strong encryption or patching requires a license from PKWARE. - Refer to the section in this document entitled "Incorporating - PKWARE Proprietary Technology into Your Product" for more - information. - - 4.5.9 -PKCS#7 Store for X.509 Certificates (0x0014): - - This field MUST contain information about each of the certificates - files may be signed with. When the Central Directory Encryption - feature is enabled for a ZIP file, this record will appear in - the Archive Extra Data Record, otherwise it will appear in the - first central directory record and will be ignored in any - other record. - - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- -(Store) 0x0014 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the store data - TData TSize Data about the store - - - 4.5.10 -X.509 Certificate ID and Signature for individual file (0x0015): - - This field contains the information about which certificate in - the PKCS#7 store was used to sign a particular file. It also - contains the signature data. This field can appear multiple - times, but can only appear once per certificate. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- -(CID) 0x0015 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of data that follows - TData TSize Signature Data - - 4.5.11 -X.509 Certificate ID and Signature for central directory (0x0016): - - This field contains the information about which certificate in - the PKCS#7 store was used to sign the central directory structure. - When the Central Directory Encryption feature is enabled for a - ZIP file, this record will appear in the Archive Extra Data Record, - otherwise it will appear in the first central directory record. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- -(CDID) 0x0016 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of data that follows - TData TSize Data - - 4.5.12 -Strong Encryption Header (0x0017): - - Value Size Description - ----- ---- ----------- - 0x0017 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of data that follows - Format 2 bytes Format definition for this record - AlgID 2 bytes Encryption algorithm identifier - Bitlen 2 bytes Bit length of encryption key - Flags 2 bytes Processing flags - CertData TSize-8 Certificate decryption extra field data - (refer to the explanation for CertData - in the section describing the - Certificate Processing Method under - the Strong Encryption Specification) - - See the section describing the Strong Encryption Specification - for details. Refer to the section in this document entitled - "Incorporating PKWARE Proprietary Technology into Your Product" - for more information. - - 4.5.13 -Record Management Controls (0x0018): - - Value Size Description - ----- ---- ----------- -(Rec-CTL) 0x0018 2 bytes Tag for this "extra" block type - CSize 2 bytes Size of total extra block data - Tag1 2 bytes Record control attribute 1 - Size1 2 bytes Size of attribute 1, in bytes - Data1 Size1 Attribute 1 data - . - . - . - TagN 2 bytes Record control attribute N - SizeN 2 bytes Size of attribute N, in bytes - DataN SizeN Attribute N data - - - 4.5.14 -PKCS#7 Encryption Recipient Certificate List (0x0019): - - This field MAY contain information about each of the certificates - used in encryption processing and it can be used to identify who is - allowed to decrypt encrypted files. This field should only appear - in the archive extra data record. This field is not required and - serves only to aid archive modifications by preserving public - encryption key data. Individual security requirements may dictate - that this data be omitted to deter information exposure. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- -(CStore) 0x0019 2 bytes Tag for this "extra" block type - TSize 2 bytes Size of the store data - TData TSize Data about the store - - TData: - - Value Size Description - ----- ---- ----------- - Version 2 bytes Format version number - must 0x0001 at this time - CStore (var) PKCS#7 data blob - - See the section describing the Strong Encryption Specification - for details. Refer to the section in this document entitled - "Incorporating PKWARE Proprietary Technology into Your Product" - for more information. - - 4.5.15 -MVS Extra Field (0x0065): - - The following is the layout of the MVS "extra" block. - Note: Some fields are stored in Big Endian format. - All text is in EBCDIC format unless otherwise specified. - - Value Size Description - ----- ---- ----------- -(MVS) 0x0065 2 bytes Tag for this "extra" block type - TSize 2 bytes Size for the following data block - ID 4 bytes EBCDIC "Z390" 0xE9F3F9F0 or - "T4MV" for TargetFour - (var) TSize-4 Attribute data (see APPENDIX B) - - - 4.5.16 -OS/400 Extra Field (0x0065): - - The following is the layout of the OS/400 "extra" block. - Note: Some fields are stored in Big Endian format. - All text is in EBCDIC format unless otherwise specified. - - Value Size Description - ----- ---- ----------- -(OS400) 0x0065 2 bytes Tag for this "extra" block type - TSize 2 bytes Size for the following data block - ID 4 bytes EBCDIC "I400" 0xC9F4F0F0 or - "T4MV" for TargetFour - (var) TSize-4 Attribute data (see APPENDIX A) - -4.6 Third Party Mappings ------------------------- - - 4.6.1 Third party mappings commonly used are: - - 0x07c8 Macintosh - 0x2605 ZipIt Macintosh - 0x2705 ZipIt Macintosh 1.3.5+ - 0x2805 ZipIt Macintosh 1.3.5+ - 0x334d Info-ZIP Macintosh - 0x4341 Acorn/SparkFS - 0x4453 Windows NT security descriptor (binary ACL) - 0x4704 VM/CMS - 0x470f MVS - 0x4b46 FWKCS MD5 (see below) - 0x4c41 OS/2 access control list (text ACL) - 0x4d49 Info-ZIP OpenVMS - 0x4f4c Xceed original location extra field - 0x5356 AOS/VS (ACL) - 0x5455 extended timestamp - 0x554e Xceed unicode extra field - 0x5855 Info-ZIP UNIX (original, also OS/2, NT, etc) - 0x6375 Info-ZIP Unicode Comment Extra Field - 0x6542 BeOS/BeBox - 0x7075 Info-ZIP Unicode Path Extra Field - 0x756e ASi UNIX - 0x7855 Info-ZIP UNIX (new) - 0xa220 Microsoft Open Packaging Growth Hint - 0xfd4a SMS/QDOS - - Detailed descriptions of Extra Fields defined by third - party mappings will be documented as information on - these data structures is made available to PKWARE. - PKWARE does not guarantee the accuracy of any published - third party data. - - 4.6.2 Third-party Extra Fields must include a Header ID using - the format defined in the section of this document - titled Extensible Data Fields (section 4.5). - - The Data Size field indicates the size of the following - data block. Programs can use this value to skip to the - next header block, passing over any data blocks that are - not of interest. - - Note: As stated above, the size of the entire .ZIP file - header, including the file name, comment, and extra - field should not exceed 64K in size. - - 4.6.3 In case two different programs should appropriate the same - Header ID value, it is strongly recommended that each - program SHOULD place a unique signature of at least two bytes in - size (and preferably 4 bytes or bigger) at the start of - each data area. Every program SHOULD verify that its - unique signature is present, in addition to the Header ID - value being correct, before assuming that it is a block of - known type. - - Third-party Mappings: - - 4.6.4 -ZipIt Macintosh Extra Field (long) (0x2605): - - The following is the layout of the ZipIt extra block - for Macintosh. The local-header and central-header versions - are identical. This block must be present if the file is - stored MacBinary-encoded and it should not be used if the file - is not stored MacBinary-encoded. - - Value Size Description - ----- ---- ----------- - (Mac2) 0x2605 Short tag for this extra block type - TSize Short total data size for this block - "ZPIT" beLong extra-field signature - FnLen Byte length of FileName - FileName variable full Macintosh filename - FileType Byte[4] four-byte Mac file type string - Creator Byte[4] four-byte Mac creator string - - - 4.6.5 -ZipIt Macintosh Extra Field (short, for files) (0x2705): - - The following is the layout of a shortened variant of the - ZipIt extra block for Macintosh (without "full name" entry). - This variant is used by ZipIt 1.3.5 and newer for entries of - files (not directories) that do not have a MacBinary encoded - file. The local-header and central-header versions are identical. - - Value Size Description - ----- ---- ----------- - (Mac2b) 0x2705 Short tag for this extra block type - TSize Short total data size for this block (12) - "ZPIT" beLong extra-field signature - FileType Byte[4] four-byte Mac file type string - Creator Byte[4] four-byte Mac creator string - fdFlags beShort attributes from FInfo.frFlags, - may be omitted - 0x0000 beShort reserved, may be omitted - - - 4.6.6 -ZipIt Macintosh Extra Field (short, for directories) (0x2805): - - The following is the layout of a shortened variant of the - ZipIt extra block for Macintosh used only for directory - entries. This variant is used by ZipIt 1.3.5 and newer to - save some optional Mac-specific information about directories. - The local-header and central-header versions are identical. - - Value Size Description - ----- ---- ----------- - (Mac2c) 0x2805 Short tag for this extra block type - TSize Short total data size for this block (12) - "ZPIT" beLong extra-field signature - frFlags beShort attributes from DInfo.frFlags, may - be omitted - View beShort ZipIt view flag, may be omitted - - - The View field specifies ZipIt-internal settings as follows: - - Bits of the Flags: - bit 0 if set, the folder is shown expanded (open) - when the archive contents are viewed in ZipIt. - bits 1-15 reserved, zero; - - - 4.6.7 -FWKCS MD5 Extra Field (0x4b46): - - The FWKCS Contents_Signature System, used in - automatically identifying files independent of file name, - optionally adds and uses an extra field to support the - rapid creation of an enhanced contents_signature: - - Header ID = 0x4b46 - Data Size = 0x0013 - Preface = 'M','D','5' - followed by 16 bytes containing the uncompressed file's - 128_bit MD5 hash(1), low byte first. - - When FWKCS revises a .ZIP file central directory to add - this extra field for a file, it also replaces the - central directory entry for that file's uncompressed - file length with a measured value. - - FWKCS provides an option to strip this extra field, if - present, from a .ZIP file central directory. In adding - this extra field, FWKCS preserves .ZIP file Authenticity - Verification; if stripping this extra field, FWKCS - preserves all versions of AV through PKZIP version 2.04g. - - FWKCS, and FWKCS Contents_Signature System, are - trademarks of Frederick W. Kantor. - - (1) R. Rivest, RFC1321.TXT, MIT Laboratory for Computer - Science and RSA Data Security, Inc., April 1992. - ll.76-77: "The MD5 algorithm is being placed in the - public domain for review and possible adoption as a - standard." - - - 4.6.8 -Info-ZIP Unicode Comment Extra Field (0x6375): - - Stores the UTF-8 version of the file comment as stored in the - central directory header. (Last Revision 20070912) - - Value Size Description - ----- ---- ----------- - (UCom) 0x6375 Short tag for this extra block type ("uc") - TSize Short total data size for this block - Version 1 byte version of this extra field, currently 1 - ComCRC32 4 bytes Comment Field CRC32 Checksum - UnicodeCom Variable UTF-8 version of the entry comment - - Currently Version is set to the number 1. If there is a need - to change this field, the version will be incremented. Changes - may not be backward compatible so this extra field should not be - used if the version is not recognized. - - The ComCRC32 is the standard zip CRC32 checksum of the File Comment - field in the central directory header. This is used to verify that - the comment field has not changed since the Unicode Comment extra field - was created. This can happen if a utility changes the File Comment - field but does not update the UTF-8 Comment extra field. If the CRC - check fails, this Unicode Comment extra field should be ignored and - the File Comment field in the header should be used instead. - - The UnicodeCom field is the UTF-8 version of the File Comment field - in the header. As UnicodeCom is defined to be UTF-8, no UTF-8 byte - order mark (BOM) is used. The length of this field is determined by - subtracting the size of the previous fields from TSize. If both the - File Name and Comment fields are UTF-8, the new General Purpose Bit - Flag, bit 11 (Language encoding flag (EFS)), can be used to indicate - both the header File Name and Comment fields are UTF-8 and, in this - case, the Unicode Path and Unicode Comment extra fields are not - needed and should not be created. Note that, for backward - compatibility, bit 11 should only be used if the native character set - of the paths and comments being zipped up are already in UTF-8. It is - expected that the same file comment storage method, either general - purpose bit 11 or extra fields, be used in both the Local and Central - Directory Header for a file. - - - 4.6.9 -Info-ZIP Unicode Path Extra Field (0x7075): - - Stores the UTF-8 version of the file name field as stored in the - local header and central directory header. (Last Revision 20070912) - - Value Size Description - ----- ---- ----------- - (UPath) 0x7075 Short tag for this extra block type ("up") - TSize Short total data size for this block - Version 1 byte version of this extra field, currently 1 - NameCRC32 4 bytes File Name Field CRC32 Checksum - UnicodeName Variable UTF-8 version of the entry File Name - - Currently Version is set to the number 1. If there is a need - to change this field, the version will be incremented. Changes - may not be backward compatible so this extra field should not be - used if the version is not recognized. - - The NameCRC32 is the standard zip CRC32 checksum of the File Name - field in the header. This is used to verify that the header - File Name field has not changed since the Unicode Path extra field - was created. This can happen if a utility renames the File Name but - does not update the UTF-8 path extra field. If the CRC check fails, - this UTF-8 Path Extra Field should be ignored and the File Name field - in the header should be used instead. - - The UnicodeName is the UTF-8 version of the contents of the File Name - field in the header. As UnicodeName is defined to be UTF-8, no UTF-8 - byte order mark (BOM) is used. The length of this field is determined - by subtracting the size of the previous fields from TSize. If both - the File Name and Comment fields are UTF-8, the new General Purpose - Bit Flag, bit 11 (Language encoding flag (EFS)), can be used to - indicate that both the header File Name and Comment fields are UTF-8 - and, in this case, the Unicode Path and Unicode Comment extra fields - are not needed and should not be created. Note that, for backward - compatibility, bit 11 should only be used if the native character set - of the paths and comments being zipped up are already in UTF-8. It is - expected that the same file name storage method, either general - purpose bit 11 or extra fields, be used in both the Local and Central - Directory Header for a file. - - - 4.6.10 -Microsoft Open Packaging Growth Hint (0xa220): - - Value Size Description - ----- ---- ----------- - 0xa220 Short tag for this extra block type - TSize Short size of Sig + PadVal + Padding - Sig Short verification signature (A028) - PadVal Short Initial padding value - Padding variable filled with NULL characters - -4.7 Manifest Files ------------------- - - 4.7.1 Applications using ZIP files may have a need for additional - information that must be included with the files placed into - a ZIP file. Application specific information that cannot be - stored using the defined ZIP storage records SHOULD be stored - using the extensible Extra Field convention defined in this - document. However, some applications may use a manifest - file as a means for storing additional information. One - example is the META-INF/MANIFEST.MF file used in ZIP formatted - files having the .JAR extension (JAR files). - - 4.7.2 A manifest file is a file created for the application process - that requires this information. A manifest file MAY be of any - file type required by the defining application process. It is - placed within the same ZIP file as files to which this information - applies. By convention, this file is typically the first file placed - into the ZIP file and it may include a defined directory path. - - 4.7.3 Manifest files may be compressed or encrypted as needed for - application processing of the files inside the ZIP files. - - Manifest files are outside of the scope of this specification. - - -5.0 Explanation of compression methods --------------------------------------- - - -5.1 UnShrinking - Method 1 --------------------------- - - 5.1.1 Shrinking is a Dynamic Ziv-Lempel-Welch compression algorithm - with partial clearing. The initial code size is 9 bits, and the - maximum code size is 13 bits. Shrinking differs from conventional - Dynamic Ziv-Lempel-Welch implementations in several respects: - - 5.1.2 The code size is controlled by the compressor, and is - not automatically increased when codes larger than the current - code size are created (but not necessarily used). When - the decompressor encounters the code sequence 256 - (decimal) followed by 1, it should increase the code size - read from the input stream to the next bit size. No - blocking of the codes is performed, so the next code at - the increased size should be read from the input stream - immediately after where the previous code at the smaller - bit size was read. Again, the decompressor should not - increase the code size used until the sequence 256,1 is - encountered. - - 5.1.3 When the table becomes full, total clearing is not - performed. Rather, when the compressor emits the code - sequence 256,2 (decimal), the decompressor should clear - all leaf nodes from the Ziv-Lempel tree, and continue to - use the current code size. The nodes that are cleared - from the Ziv-Lempel tree are then re-used, with the lowest - code value re-used first, and the highest code value - re-used last. The compressor can emit the sequence 256,2 - at any time. - -5.2 Expanding - Methods 2-5 ---------------------------- - - 5.2.1 The Reducing algorithm is actually a combination of two - distinct algorithms. The first algorithm compresses repeated - byte sequences, and the second algorithm takes the compressed - stream from the first algorithm and applies a probabilistic - compression method. - - 5.2.2 The probabilistic compression stores an array of 'follower - sets' S(j), for j=0 to 255, corresponding to each possible - ASCII character. Each set contains between 0 and 32 - characters, to be denoted as S(j)[0],...,S(j)[m], where m<32. - The sets are stored at the beginning of the data area for a - Reduced file, in reverse order, with S(255) first, and S(0) - last. - - 5.2.3 The sets are encoded as { N(j), S(j)[0],...,S(j)[N(j)-1] }, - where N(j) is the size of set S(j). N(j) can be 0, in which - case the follower set for S(j) is empty. Each N(j) value is - encoded in 6 bits, followed by N(j) eight bit character values - corresponding to S(j)[0] to S(j)[N(j)-1] respectively. If - N(j) is 0, then no values for S(j) are stored, and the value - for N(j-1) immediately follows. - - 5.2.4 Immediately after the follower sets, is the compressed data - stream. The compressed data stream can be interpreted for the - probabilistic decompression as follows: - - let Last-Character <- 0. - loop until done - if the follower set S(Last-Character) is empty then - read 8 bits from the input stream, and copy this - value to the output stream. - otherwise if the follower set S(Last-Character) is non-empty then - read 1 bit from the input stream. - if this bit is not zero then - read 8 bits from the input stream, and copy this - value to the output stream. - otherwise if this bit is zero then - read B(N(Last-Character)) bits from the input - stream, and assign this value to I. - Copy the value of S(Last-Character)[I] to the - output stream. - - assign the last value placed on the output stream to - Last-Character. - end loop - - B(N(j)) is defined as the minimal number of bits required to - encode the value N(j)-1. - - 5.2.5 The decompressed stream from above can then be expanded to - re-create the original file as follows: - - let State <- 0. - - loop until done - read 8 bits from the input stream into C. - case State of - 0: if C is not equal to DLE (144 decimal) then - copy C to the output stream. - otherwise if C is equal to DLE then - let State <- 1. - - 1: if C is non-zero then - let V <- C. - let Len <- L(V) - let State <- F(Len). - otherwise if C is zero then - copy the value 144 (decimal) to the output stream. - let State <- 0 - - 2: let Len <- Len + C - let State <- 3. - - 3: move backwards D(V,C) bytes in the output stream - (if this position is before the start of the output - stream, then assume that all the data before the - start of the output stream is filled with zeros). - copy Len+3 bytes from this position to the output stream. - let State <- 0. - end case - end loop - - The functions F,L, and D are dependent on the 'compression - factor', 1 through 4, and are defined as follows: - - For compression factor 1: - L(X) equals the lower 7 bits of X. - F(X) equals 2 if X equals 127 otherwise F(X) equals 3. - D(X,Y) equals the (upper 1 bit of X) * 256 + Y + 1. - For compression factor 2: - L(X) equals the lower 6 bits of X. - F(X) equals 2 if X equals 63 otherwise F(X) equals 3. - D(X,Y) equals the (upper 2 bits of X) * 256 + Y + 1. - For compression factor 3: - L(X) equals the lower 5 bits of X. - F(X) equals 2 if X equals 31 otherwise F(X) equals 3. - D(X,Y) equals the (upper 3 bits of X) * 256 + Y + 1. - For compression factor 4: - L(X) equals the lower 4 bits of X. - F(X) equals 2 if X equals 15 otherwise F(X) equals 3. - D(X,Y) equals the (upper 4 bits of X) * 256 + Y + 1. - -5.3 Imploding - Method 6 ------------------------- - - 5.3.1 The Imploding algorithm is actually a combination of two - distinct algorithms. The first algorithm compresses repeated byte - sequences using a sliding dictionary. The second algorithm is - used to compress the encoding of the sliding dictionary output, - using multiple Shannon-Fano trees. - - 5.3.2 The Imploding algorithm can use a 4K or 8K sliding dictionary - size. The dictionary size used can be determined by bit 1 in the - general purpose flag word; a 0 bit indicates a 4K dictionary - while a 1 bit indicates an 8K dictionary. - - 5.3.3 The Shannon-Fano trees are stored at the start of the - compressed file. The number of trees stored is defined by bit 2 in - the general purpose flag word; a 0 bit indicates two trees stored, - a 1 bit indicates three trees are stored. If 3 trees are stored, - the first Shannon-Fano tree represents the encoding of the - Literal characters, the second tree represents the encoding of - the Length information, the third represents the encoding of the - Distance information. When 2 Shannon-Fano trees are stored, the - Length tree is stored first, followed by the Distance tree. - - 5.3.4 The Literal Shannon-Fano tree, if present is used to represent - the entire ASCII character set, and contains 256 values. This - tree is used to compress any data not compressed by the sliding - dictionary algorithm. When this tree is present, the Minimum - Match Length for the sliding dictionary is 3. If this tree is - not present, the Minimum Match Length is 2. - - 5.3.5 The Length Shannon-Fano tree is used to compress the Length - part of the (length,distance) pairs from the sliding dictionary - output. The Length tree contains 64 values, ranging from the - Minimum Match Length, to 63 plus the Minimum Match Length. - - 5.3.6 The Distance Shannon-Fano tree is used to compress the Distance - part of the (length,distance) pairs from the sliding dictionary - output. The Distance tree contains 64 values, ranging from 0 to - 63, representing the upper 6 bits of the distance value. The - distance values themselves will be between 0 and the sliding - dictionary size, either 4K or 8K. - - 5.3.7 The Shannon-Fano trees themselves are stored in a compressed - format. The first byte of the tree data represents the number of - bytes of data representing the (compressed) Shannon-Fano tree - minus 1. The remaining bytes represent the Shannon-Fano tree - data encoded as: - - High 4 bits: Number of values at this bit length + 1. (1 - 16) - Low 4 bits: Bit Length needed to represent value + 1. (1 - 16) - - 5.3.8 The Shannon-Fano codes can be constructed from the bit lengths - using the following algorithm: - - 1) Sort the Bit Lengths in ascending order, while retaining the - order of the original lengths stored in the file. - - 2) Generate the Shannon-Fano trees: - - Code <- 0 - CodeIncrement <- 0 - LastBitLength <- 0 - i <- number of Shannon-Fano codes - 1 (either 255 or 63) - - loop while i >= 0 - Code = Code + CodeIncrement - if BitLength(i) <> LastBitLength then - LastBitLength=BitLength(i) - CodeIncrement = 1 shifted left (16 - LastBitLength) - ShannonCode(i) = Code - i <- i - 1 - end loop - - 3) Reverse the order of all the bits in the above ShannonCode() - vector, so that the most significant bit becomes the least - significant bit. For example, the value 0x1234 (hex) would - become 0x2C48 (hex). - - 4) Restore the order of Shannon-Fano codes as originally stored - within the file. - - Example: - - This example will show the encoding of a Shannon-Fano tree - of size 8. Notice that the actual Shannon-Fano trees used - for Imploding are either 64 or 256 entries in size. - - Example: 0x02, 0x42, 0x01, 0x13 - - The first byte indicates 3 values in this table. Decoding the - bytes: - 0x42 = 5 codes of 3 bits long - 0x01 = 1 code of 2 bits long - 0x13 = 2 codes of 4 bits long - - This would generate the original bit length array of: - (3, 3, 3, 3, 3, 2, 4, 4) - - There are 8 codes in this table for the values 0 thru 7. Using - the algorithm to obtain the Shannon-Fano codes produces: - - Reversed Order Original - Val Sorted Constructed Code Value Restored Length - --- ------ ----------------- -------- -------- ------ - 0: 2 1100000000000000 11 101 3 - 1: 3 1010000000000000 101 001 3 - 2: 3 1000000000000000 001 110 3 - 3: 3 0110000000000000 110 010 3 - 4: 3 0100000000000000 010 100 3 - 5: 3 0010000000000000 100 11 2 - 6: 4 0001000000000000 1000 1000 4 - 7: 4 0000000000000000 0000 0000 4 - - The values in the Val, Order Restored and Original Length columns - now represent the Shannon-Fano encoding tree that can be used for - decoding the Shannon-Fano encoded data. How to parse the - variable length Shannon-Fano values from the data stream is beyond - the scope of this document. (See the references listed at the end of - this document for more information.) However, traditional decoding - schemes used for Huffman variable length decoding, such as the - Greenlaw algorithm, can be successfully applied. - - 5.3.9 The compressed data stream begins immediately after the - compressed Shannon-Fano data. The compressed data stream can be - interpreted as follows: - - loop until done - read 1 bit from input stream. - - if this bit is non-zero then (encoded data is literal data) - if Literal Shannon-Fano tree is present - read and decode character using Literal Shannon-Fano tree. - otherwise - read 8 bits from input stream. - copy character to the output stream. - otherwise (encoded data is sliding dictionary match) - if 8K dictionary size - read 7 bits for offset Distance (lower 7 bits of offset). - otherwise - read 6 bits for offset Distance (lower 6 bits of offset). - - using the Distance Shannon-Fano tree, read and decode the - upper 6 bits of the Distance value. - - using the Length Shannon-Fano tree, read and decode - the Length value. - - Length <- Length + Minimum Match Length - - if Length = 63 + Minimum Match Length - read 8 bits from the input stream, - add this value to Length. - - move backwards Distance+1 bytes in the output stream, and - copy Length characters from this position to the output - stream. (if this position is before the start of the output - stream, then assume that all the data before the start of - the output stream is filled with zeros). - end loop - -5.4 Tokenizing - Method 7 -------------------------- - - 5.4.1 This method is not used by PKZIP. - -5.5 Deflating - Method 8 ------------------------- - - 5.5.1 The Deflate algorithm is similar to the Implode algorithm using - a sliding dictionary of up to 32K with secondary compression - from Huffman/Shannon-Fano codes. - - 5.5.2 The compressed data is stored in blocks with a header describing - the block and the Huffman codes used in the data block. The header - format is as follows: - - Bit 0: Last Block bit This bit is set to 1 if this is the last - compressed block in the data. - Bits 1-2: Block type - 00 (0) - Block is stored - All stored data is byte aligned. - Skip bits until next byte, then next word = block - length, followed by the ones compliment of the block - length word. Remaining data in block is the stored - data. - - 01 (1) - Use fixed Huffman codes for literal and distance codes. - Lit Code Bits Dist Code Bits - --------- ---- --------- ---- - 0 - 143 8 0 - 31 5 - 144 - 255 9 - 256 - 279 7 - 280 - 287 8 - - Literal codes 286-287 and distance codes 30-31 are - never used but participate in the huffman construction. - - 10 (2) - Dynamic Huffman codes. (See expanding Huffman codes) - - 11 (3) - Reserved - Flag a "Error in compressed data" if seen. - - 5.5.3 Expanding Huffman Codes - - If the data block is stored with dynamic Huffman codes, the Huffman - codes are sent in the following compressed format: - - 5 Bits: # of Literal codes sent - 256 (256 - 286) - All other codes are never sent. - 5 Bits: # of Dist codes - 1 (1 - 32) - 4 Bits: # of Bit Length codes - 3 (3 - 19) - - The Huffman codes are sent as bit lengths and the codes are built as - described in the implode algorithm. The bit lengths themselves are - compressed with Huffman codes. There are 19 bit length codes: - - 0 - 15: Represent bit lengths of 0 - 15 - 16: Copy the previous bit length 3 - 6 times. - The next 2 bits indicate repeat length (0 = 3, ... ,3 = 6) - Example: Codes 8, 16 (+2 bits 11), 16 (+2 bits 10) will - expand to 12 bit lengths of 8 (1 + 6 + 5) - 17: Repeat a bit length of 0 for 3 - 10 times. (3 bits of length) - 18: Repeat a bit length of 0 for 11 - 138 times (7 bits of length) - - The lengths of the bit length codes are sent packed 3 bits per value - (0 - 7) in the following order: - - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 - - The Huffman codes should be built as described in the Implode algorithm - except codes are assigned starting at the shortest bit length, i.e. the - shortest code should be all 0's rather than all 1's. Also, codes with - a bit length of zero do not participate in the tree construction. The - codes are then used to decode the bit lengths for the literal and - distance tables. - - The bit lengths for the literal tables are sent first with the number - of entries sent described by the 5 bits sent earlier. There are up - to 286 literal characters; the first 256 represent the respective 8 - bit character, code 256 represents the End-Of-Block code, the remaining - 29 codes represent copy lengths of 3 thru 258. There are up to 30 - distance codes representing distances from 1 thru 32k as described - below. - - Length Codes - ------------ - Extra Extra Extra Extra - Code Bits Length Code Bits Lengths Code Bits Lengths Code Bits Length(s) - ---- ---- ------ ---- ---- ------- ---- ---- ------- ---- ---- --------- - 257 0 3 265 1 11,12 273 3 35-42 281 5 131-162 - 258 0 4 266 1 13,14 274 3 43-50 282 5 163-194 - 259 0 5 267 1 15,16 275 3 51-58 283 5 195-226 - 260 0 6 268 1 17,18 276 3 59-66 284 5 227-257 - 261 0 7 269 2 19-22 277 4 67-82 285 0 258 - 262 0 8 270 2 23-26 278 4 83-98 - 263 0 9 271 2 27-30 279 4 99-114 - 264 0 10 272 2 31-34 280 4 115-130 - - Distance Codes - -------------- - Extra Extra Extra Extra - Code Bits Dist Code Bits Dist Code Bits Distance Code Bits Distance - ---- ---- ---- ---- ---- ------ ---- ---- -------- ---- ---- -------- - 0 0 1 8 3 17-24 16 7 257-384 24 11 4097-6144 - 1 0 2 9 3 25-32 17 7 385-512 25 11 6145-8192 - 2 0 3 10 4 33-48 18 8 513-768 26 12 8193-12288 - 3 0 4 11 4 49-64 19 8 769-1024 27 12 12289-16384 - 4 1 5,6 12 5 65-96 20 9 1025-1536 28 13 16385-24576 - 5 1 7,8 13 5 97-128 21 9 1537-2048 29 13 24577-32768 - 6 2 9-12 14 6 129-192 22 10 2049-3072 - 7 2 13-16 15 6 193-256 23 10 3073-4096 - - 5.5.4 The compressed data stream begins immediately after the - compressed header data. The compressed data stream can be - interpreted as follows: - - do - read header from input stream. - - if stored block - skip bits until byte aligned - read count and 1's compliment of count - copy count bytes data block - otherwise - loop until end of block code sent - decode literal character from input stream - if literal < 256 - copy character to the output stream - otherwise - if literal = end of block - break from loop - otherwise - decode distance from input stream - - move backwards distance bytes in the output stream, and - copy length characters from this position to the output - stream. - end loop - while not last block - - if data descriptor exists - skip bits until byte aligned - read crc and sizes - endif - -5.6 Enhanced Deflating - Method 9 ---------------------------------- - - 5.6.1 The Enhanced Deflating algorithm is similar to Deflate but uses - a sliding dictionary of up to 64K. Deflate64(tm) is supported - by the Deflate extractor. - -5.7 BZIP2 - Method 12 ---------------------- - - 5.7.1 BZIP2 is an open-source data compression algorithm developed by - Julian Seward. Information and source code for this algorithm - can be found on the internet. - -5.8 LZMA - Method 14 ---------------------- - - 5.8.1 LZMA is a block-oriented, general purpose data compression - algorithm developed and maintained by Igor Pavlov. It is a derivative - of LZ77 that utilizes Markov chains and a range coder. Information and - source code for this algorithm can be found on the internet. Consult - with the author of this algorithm for information on terms or - restrictions on use. - - Support for LZMA within the ZIP format is defined as follows: - - 5.8.2 The Compression method field within the ZIP Local and Central - Header records will be set to the value 14 to indicate data was - compressed using LZMA. - - 5.8.3 The Version needed to extract field within the ZIP Local and - Central Header records will be set to 6.3 to indicate the minimum - ZIP format version supporting this feature. - - 5.8.4 File data compressed using the LZMA algorithm must be placed - immediately following the Local Header for the file. If a standard - ZIP encryption header is required, it will follow the Local Header - and will precede the LZMA compressed file data segment. The location - of LZMA compressed data segment within the ZIP format will be as shown: - - [local header file 1] - [encryption header file 1] - [LZMA compressed data segment for file 1] - [data descriptor 1] - [local header file 2] - - 5.8.5 The encryption header and data descriptor records may - be conditionally present. The LZMA Compressed Data Segment - will consist of an LZMA Properties Header followed by the - LZMA Compressed Data as shown: - - [LZMA properties header for file 1] - [LZMA compressed data for file 1] - - 5.8.6 The LZMA Compressed Data will be stored as provided by the - LZMA compression library. Compressed size, uncompressed size and - other file characteristics about the file being compressed must be - stored in standard ZIP storage format. - - 5.8.7 The LZMA Properties Header will store specific data required - to decompress the LZMA compressed Data. This data is set by the - LZMA compression engine using the function WriteCoderProperties() - as documented within the LZMA SDK. - - 5.8.8 Storage fields for the property information within the LZMA - Properties Header are as follows: - - LZMA Version Information 2 bytes - LZMA Properties Size 2 bytes - LZMA Properties Data variable, defined by "LZMA Properties Size" - - 5.8.8.1 LZMA Version Information - this field identifies which version - of the LZMA SDK was used to compress a file. The first byte will - store the major version number of the LZMA SDK and the second - byte will store the minor number. - - 5.8.8.2 LZMA Properties Size - this field defines the size of the - remaining property data. Typically this size should be determined by - the version of the SDK. This size field is included as a convenience - and to help avoid any ambiguity should it arise in the future due - to changes in this compression algorithm. - - 5.8.8.3 LZMA Property Data - this variable sized field records the - required values for the decompressor as defined by the LZMA SDK. - The data stored in this field should be obtained using the - WriteCoderProperties() in the version of the SDK defined by - the "LZMA Version Information" field. - - 5.8.8.4 The layout of the "LZMA Properties Data" field is a function of - the LZMA compression algorithm. It is possible that this layout may be - changed by the author over time. The data layout in version 4.3 of the - LZMA SDK defines a 5 byte array that uses 4 bytes to store the dictionary - size in little-endian order. This is preceded by a single packed byte as - the first element of the array that contains the following fields: - - PosStateBits - LiteralPosStateBits - LiteralContextBits - - Refer to the LZMA documentation for a more detailed explanation of - these fields. - - 5.8.9 Data compressed with method 14, LZMA, may include an end-of-stream - (EOS) marker ending the compressed data stream. This marker is not - required, but its use is highly recommended to facilitate processing - and implementers should include the EOS marker whenever possible. - When the EOS marker is used, general purpose bit 1 must be set. If - general purpose bit 1 is not set, the EOS marker is not present. - -5.9 WavPack - Method 97 ------------------------ - - 5.9.1 Information describing the use of compression method 97 is - provided by WinZIP International, LLC. This method relies on the - open source WavPack audio compression utility developed by David Bryant. - Information on WavPack is available at www.wavpack.com. Please consult - with the author of this algorithm for information on terms and - restrictions on use. - - 5.9.2 WavPack data for a file begins immediately after the end of the - local header data. This data is the output from WavPack compression - routines. Within the ZIP file, the use of WavPack compression is - indicated by setting the compression method field to a value of 97 - in both the local header and the central directory header. The Version - needed to extract and version made by fields use the same values as are - used for data compressed using the Deflate algorithm. - - 5.9.3 An implementation note for storing digital sample data when using - WavPack compression within ZIP files is that all of the bytes of - the sample data should be compressed. This includes any unused - bits up to the byte boundary. An example is a 2 byte sample that - uses only 12 bits for the sample data with 4 unused bits. If only - 12 bits are passed as the sample size to the WavPack routines, the 4 - unused bits will be set to 0 on extraction regardless of their original - state. To avoid this, the full 16 bits of the sample data size - should be provided. - -5.10 PPMd - Method 98 ---------------------- - - 5.10.1 PPMd is a data compression algorithm developed by Dmitry Shkarin - which includes a carryless rangecoder developed by Dmitry Subbotin. - This algorithm is based on predictive phrase matching on multiple - order contexts. Information and source code for this algorithm - can be found on the internet. Consult with the author of this - algorithm for information on terms or restrictions on use. - - 5.10.2 Support for PPMd within the ZIP format currently is provided only - for version I, revision 1 of the algorithm. Storage requirements - for using this algorithm are as follows: - - 5.10.3 Parameters needed to control the algorithm are stored in the two - bytes immediately preceding the compressed data. These bytes are - used to store the following fields: - - Model order - sets the maximum model order, default is 8, possible - values are from 2 to 16 inclusive - - Sub-allocator size - sets the size of sub-allocator in MB, default is 50, - possible values are from 1MB to 256MB inclusive - - Model restoration method - sets the method used to restart context - model at memory insufficiency, values are: - - 0 - restarts model from scratch - default - 1 - cut off model - decreases performance by as much as 2x - 2 - freeze context tree - not recommended - - 5.10.4 An example for packing these fields into the 2 byte storage field is - illustrated below. These values are stored in Intel low-byte/high-byte - order. - - wPPMd = (Model order - 1) + - ((Sub-allocator size - 1) << 4) + - (Model restoration method << 12) - - -6.0 Traditional PKWARE Encryption ----------------------------------- - - 6.0.1 The following information discusses the decryption steps - required to support traditional PKWARE encryption. This - form of encryption is considered weak by today's standards - and its use is recommended only for situations with - low security needs or for compatibility with older .ZIP - applications. - -6.1 Traditional PKWARE Decryption ---------------------------------- - - 6.1.1 PKWARE is grateful to Mr. Roger Schlafly for his expert - contribution towards the development of PKWARE's traditional - encryption. - - 6.1.2 PKZIP encrypts the compressed data stream. Encrypted files - must be decrypted before they can be extracted to their original - form. - - 6.1.3 Each encrypted file has an extra 12 bytes stored at the start - of the data area defining the encryption header for that file. The - encryption header is originally set to random values, and then - itself encrypted, using three, 32-bit keys. The key values are - initialized using the supplied encryption password. After each byte - is encrypted, the keys are then updated using pseudo-random number - generation techniques in combination with the same CRC-32 algorithm - used in PKZIP and described elsewhere in this document. - - 6.1.4 The following are the basic steps required to decrypt a file: - - 1) Initialize the three 32-bit keys with the password. - 2) Read and decrypt the 12-byte encryption header, further - initializing the encryption keys. - 3) Read and decrypt the compressed data stream using the - encryption keys. - - 6.1.5 Initializing the encryption keys - - Key(0) <- 305419896 - Key(1) <- 591751049 - Key(2) <- 878082192 - - loop for i <- 0 to length(password)-1 - update_keys(password(i)) - end loop - - Where update_keys() is defined as: - - update_keys(char): - Key(0) <- crc32(key(0),char) - Key(1) <- Key(1) + (Key(0) & 000000ffH) - Key(1) <- Key(1) * 134775813 + 1 - Key(2) <- crc32(key(2),key(1) >> 24) - end update_keys - - Where crc32(old_crc,char) is a routine that given a CRC value and a - character, returns an updated CRC value after applying the CRC-32 - algorithm described elsewhere in this document. - - 6.1.6 Decrypting the encryption header - - The purpose of this step is to further initialize the encryption - keys, based on random data, to render a plaintext attack on the - data ineffective. - - Read the 12-byte encryption header into Buffer, in locations - Buffer(0) thru Buffer(11). - - loop for i <- 0 to 11 - C <- buffer(i) ^ decrypt_byte() - update_keys(C) - buffer(i) <- C - end loop - - Where decrypt_byte() is defined as: - - unsigned char decrypt_byte() - local unsigned short temp - temp <- Key(2) | 2 - decrypt_byte <- (temp * (temp ^ 1)) >> 8 - end decrypt_byte - - After the header is decrypted, the last 1 or 2 bytes in Buffer - should be the high-order word/byte of the CRC for the file being - decrypted, stored in Intel low-byte/high-byte order. Versions of - PKZIP prior to 2.0 used a 2 byte CRC check; a 1 byte CRC check is - used on versions after 2.0. This can be used to test if the password - supplied is correct or not. - - 6.1.7 Decrypting the compressed data stream - - The compressed data stream can be decrypted as follows: - - loop until done - read a character into C - Temp <- C ^ decrypt_byte() - update_keys(temp) - output Temp - end loop - - -7.0 Strong Encryption Specification ------------------------------------ - - 7.0.1 Portions of the Strong Encryption technology defined in this - specification are covered under patents and pending patent applications. - Refer to the section in this document entitled "Incorporating - PKWARE Proprietary Technology into Your Product" for more information. - -7.1 Strong Encryption Overview ------------------------------- - - 7.1.1 Version 5.x of this specification introduced support for strong - encryption algorithms. These algorithms can be used with either - a password or an X.509v3 digital certificate to encrypt each file. - This format specification supports either password or certificate - based encryption to meet the security needs of today, to enable - interoperability between users within both PKI and non-PKI - environments, and to ensure interoperability between different - computing platforms that are running a ZIP program. - - 7.1.2 Password based encryption is the most common form of encryption - people are familiar with. However, inherent weaknesses with - passwords (e.g. susceptibility to dictionary/brute force attack) - as well as password management and support issues make certificate - based encryption a more secure and scalable option. Industry - efforts and support are defining and moving towards more advanced - security solutions built around X.509v3 digital certificates and - Public Key Infrastructures(PKI) because of the greater scalability, - administrative options, and more robust security over traditional - password based encryption. - - 7.1.3 Most standard encryption algorithms are supported with this - specification. Reference implementations for many of these - algorithms are available from either commercial or open source - distributors. Readily available cryptographic toolkits make - implementation of the encryption features straight-forward. - This document is not intended to provide a treatise on data - encryption principles or theory. Its purpose is to document the - data structures required for implementing interoperable data - encryption within the .ZIP format. It is strongly recommended that - you have a good understanding of data encryption before reading - further. - - 7.1.4 The algorithms introduced in Version 5.0 of this specification - include: - - RC2 40 bit, 64 bit, and 128 bit - RC4 40 bit, 64 bit, and 128 bit - DES - 3DES 112 bit and 168 bit - - Version 5.1 adds support for the following: - - AES 128 bit, 192 bit, and 256 bit - - - 7.1.5 Version 6.1 introduces encryption data changes to support - interoperability with Smartcard and USB Token certificate storage - methods which do not support the OAEP strengthening standard. - - 7.1.6 Version 6.2 introduces support for encrypting metadata by compressing - and encrypting the central directory data structure to reduce information - leakage. Information leakage can occur in legacy ZIP applications - through exposure of information about a file even though that file is - stored encrypted. The information exposed consists of file - characteristics stored within the records and fields defined by this - specification. This includes data such as a file's name, its original - size, timestamp and CRC32 value. - - 7.1.7 Version 6.3 introduces support for encrypting data using the Blowfish - and Twofish algorithms. These are symmetric block ciphers developed - by Bruce Schneier. Blowfish supports using a variable length key from - 32 to 448 bits. Block size is 64 bits. Implementations should use 16 - rounds and the only mode supported within ZIP files is CBC. Twofish - supports key sizes 128, 192 and 256 bits. Block size is 128 bits. - Implementations should use 16 rounds and the only mode supported within - ZIP files is CBC. Information and source code for both Blowfish and - Twofish algorithms can be found on the internet. Consult with the author - of these algorithms for information on terms or restrictions on use. - - 7.1.8 Central Directory Encryption provides greater protection against - information leakage by encrypting the Central Directory structure and - by masking key values that are replicated in the unencrypted Local - Header. ZIP compatible programs that cannot interpret an encrypted - Central Directory structure cannot rely on the data in the corresponding - Local Header for decompression information. - - 7.1.9 Extra Field records that may contain information about a file that should - not be exposed should not be stored in the Local Header and should only - be written to the Central Directory where they can be encrypted. This - design currently does not support streaming. Information in the End of - Central Directory record, the Zip64 End of Central Directory Locator, - and the Zip64 End of Central Directory records are not encrypted. Access - to view data on files within a ZIP file with an encrypted Central Directory - requires the appropriate password or private key for decryption prior to - viewing any files, or any information about the files, in the archive. - - 7.1.10 Older ZIP compatible programs not familiar with the Central Directory - Encryption feature will no longer be able to recognize the Central - Directory and may assume the ZIP file is corrupt. Programs that - attempt streaming access using Local Headers will see invalid - information for each file. Central Directory Encryption need not be - used for every ZIP file. Its use is recommended for greater security. - ZIP files not using Central Directory Encryption should operate as - in the past. - - 7.1.11 This strong encryption feature specification is intended to provide for - scalable, cross-platform encryption needs ranging from simple password - encryption to authenticated public/private key encryption. - - 7.1.12 Encryption provides data confidentiality and privacy. It is - recommended that you combine X.509 digital signing with encryption - to add authentication and non-repudiation. - - -7.2 Single Password Symmetric Encryption Method ------------------------------------------------ - - 7.2.1 The Single Password Symmetric Encryption Method using strong - encryption algorithms operates similarly to the traditional - PKWARE encryption defined in this format. Additional data - structures are added to support the processing needs of the - strong algorithms. - - The Strong Encryption data structures are: - - 7.2.2 General Purpose Bits - Bits 0 and 6 of the General Purpose bit - flag in both local and central header records. Both bits set - indicates strong encryption. Bit 13, when set indicates the Central - Directory is encrypted and that selected fields in the Local Header - are masked to hide their actual value. - - - 7.2.3 Extra Field 0x0017 in central header only. - - Fields to consider in this record are: - - 7.2.3.1 Format - the data format identifier for this record. The only - value allowed at this time is the integer value 2. - - 7.2.3.2 AlgId - integer identifier of the encryption algorithm from the - following range - - 0x6601 - DES - 0x6602 - RC2 (version needed to extract < 5.2) - 0x6603 - 3DES 168 - 0x6609 - 3DES 112 - 0x660E - AES 128 - 0x660F - AES 192 - 0x6610 - AES 256 - 0x6702 - RC2 (version needed to extract >= 5.2) - 0x6720 - Blowfish - 0x6721 - Twofish - 0x6801 - RC4 - 0xFFFF - Unknown algorithm - - 7.2.3.3 Bitlen - Explicit bit length of key - - 32 - 448 bits - - 7.2.3.4 Flags - Processing flags needed for decryption - - 0x0001 - Password is required to decrypt - 0x0002 - Certificates only - 0x0003 - Password or certificate required to decrypt - - Values > 0x0003 reserved for certificate processing - - - 7.2.4 Decryption header record preceding compressed file data. - - -Decryption Header: - - Value Size Description - ----- ---- ----------- - IVSize 2 bytes Size of initialization vector (IV) - IVData IVSize Initialization vector for this file - Size 4 bytes Size of remaining decryption header data - Format 2 bytes Format definition for this record - AlgID 2 bytes Encryption algorithm identifier - Bitlen 2 bytes Bit length of encryption key - Flags 2 bytes Processing flags - ErdSize 2 bytes Size of Encrypted Random Data - ErdData ErdSize Encrypted Random Data - Reserved1 4 bytes Reserved certificate processing data - Reserved2 (var) Reserved for certificate processing data - VSize 2 bytes Size of password validation data - VData VSize-4 Password validation data - VCRC32 4 bytes Standard ZIP CRC32 of password validation data - - 7.2.4.1 IVData - The size of the IV should match the algorithm block size. - The IVData can be completely random data. If the size of - the randomly generated data does not match the block size - it should be complemented with zero's or truncated as - necessary. If IVSize is 0,then IV = CRC32 + Uncompressed - File Size (as a 64 bit little-endian, unsigned integer value). - - 7.2.4.2 Format - the data format identifier for this record. The only - value allowed at this time is the integer value 3. - - 7.2.4.3 AlgId - integer identifier of the encryption algorithm from the - following range - - 0x6601 - DES - 0x6602 - RC2 (version needed to extract < 5.2) - 0x6603 - 3DES 168 - 0x6609 - 3DES 112 - 0x660E - AES 128 - 0x660F - AES 192 - 0x6610 - AES 256 - 0x6702 - RC2 (version needed to extract >= 5.2) - 0x6720 - Blowfish - 0x6721 - Twofish - 0x6801 - RC4 - 0xFFFF - Unknown algorithm - - 7.2.4.4 Bitlen - Explicit bit length of key - - 32 - 448 bits - - 7.2.4.5 Flags - Processing flags needed for decryption - - 0x0001 - Password is required to decrypt - 0x0002 - Certificates only - 0x0003 - Password or certificate required to decrypt - - Values > 0x0003 reserved for certificate processing - - 7.2.4.6 ErdData - Encrypted random data is used to store random data that - is used to generate a file session key for encrypting - each file. SHA1 is used to calculate hash data used to - derive keys. File session keys are derived from a master - session key generated from the user-supplied password. - If the Flags field in the decryption header contains - the value 0x4000, then the ErdData field must be - decrypted using 3DES. If the value 0x4000 is not set, - then the ErdData field must be decrypted using AlgId. - - - 7.2.4.7 Reserved1 - Reserved for certificate processing, if value is - zero, then Reserved2 data is absent. See the explanation - under the Certificate Processing Method for details on - this data structure. - - 7.2.4.8 Reserved2 - If present, the size of the Reserved2 data structure - is located by skipping the first 4 bytes of this field - and using the next 2 bytes as the remaining size. See - the explanation under the Certificate Processing Method - for details on this data structure. - - 7.2.4.9 VSize - This size value will always include the 4 bytes of the - VCRC32 data and will be greater than 4 bytes. - - 7.2.4.10 VData - Random data for password validation. This data is VSize - in length and VSize must be a multiple of the encryption - block size. VCRC32 is a checksum value of VData. - VData and VCRC32 are stored encrypted and start the - stream of encrypted data for a file. - - - 7.2.5 Useful Tips - - 7.2.5.1 Strong Encryption is always applied to a file after compression. The - block oriented algorithms all operate in Cypher Block Chaining (CBC) - mode. The block size used for AES encryption is 16. All other block - algorithms use a block size of 8. Two IDs are defined for RC2 to - account for a discrepancy found in the implementation of the RC2 - algorithm in the cryptographic library on Windows XP SP1 and all - earlier versions of Windows. It is recommended that zero length files - not be encrypted, however programs should be prepared to extract them - if they are found within a ZIP file. - - 7.2.5.2 A pseudo-code representation of the encryption process is as follows: - - Password = GetUserPassword() - MasterSessionKey = DeriveKey(SHA1(Password)) - RD = CryptographicStrengthRandomData() - For Each File - IV = CryptographicStrengthRandomData() - VData = CryptographicStrengthRandomData() - VCRC32 = CRC32(VData) - FileSessionKey = DeriveKey(SHA1(IV + RD) - ErdData = Encrypt(RD,MasterSessionKey,IV) - Encrypt(VData + VCRC32 + FileData, FileSessionKey,IV) - Done - - 7.2.5.3 The function names and parameter requirements will depend on - the choice of the cryptographic toolkit selected. Almost any - toolkit supporting the reference implementations for each - algorithm can be used. The RSA BSAFE(r), OpenSSL, and Microsoft - CryptoAPI libraries are all known to work well. - - - 7.3 Single Password - Central Directory Encryption - -------------------------------------------------- - - 7.3.1 Central Directory Encryption is achieved within the .ZIP format by - encrypting the Central Directory structure. This encapsulates the metadata - most often used for processing .ZIP files. Additional metadata is stored for - redundancy in the Local Header for each file. The process of concealing - metadata by encrypting the Central Directory does not protect the data within - the Local Header. To avoid information leakage from the exposed metadata - in the Local Header, the fields containing information about a file are masked. - - 7.3.2 Local Header - - Masking replaces the true content of the fields for a file in the Local - Header with false information. When masked, the Local Header is not - suitable for streaming access and the options for data recovery of damaged - archives is reduced. Extra Data fields that may contain confidential - data should not be stored within the Local Header. The value set into - the Version needed to extract field should be the correct value needed to - extract the file without regard to Central Directory Encryption. The fields - within the Local Header targeted for masking when the Central Directory is - encrypted are: - - Field Name Mask Value - ------------------ --------------------------- - compression method 0 - last mod file time 0 - last mod file date 0 - crc-32 0 - compressed size 0 - uncompressed size 0 - file name (variable size) Base 16 value from the - range 1 - 0xFFFFFFFFFFFFFFFF - represented as a string whose - size will be set into the - file name length field - - The Base 16 value assigned as a masked file name is simply a sequentially - incremented value for each file starting with 1 for the first file. - Modifications to a ZIP file may cause different values to be stored for - each file. For compatibility, the file name field in the Local Header - should never be left blank. As of Version 6.2 of this specification, - the Compression Method and Compressed Size fields are not yet masked. - Fields having a value of 0xFFFF or 0xFFFFFFFF for the ZIP64 format - should not be masked. - - 7.3.3 Encrypting the Central Directory - - Encryption of the Central Directory does not include encryption of the - Central Directory Signature data, the Zip64 End of Central Directory - record, the Zip64 End of Central Directory Locator, or the End - of Central Directory record. The ZIP file comment data is never - encrypted. - - Before encrypting the Central Directory, it may optionally be compressed. - Compression is not required, but for storage efficiency it is assumed - this structure will be compressed before encrypting. Similarly, this - specification supports compressing the Central Directory without - requiring that it also be encrypted. Early implementations of this - feature will assume the encryption method applied to files matches the - encryption applied to the Central Directory. - - Encryption of the Central Directory is done in a manner similar to - that of file encryption. The encrypted data is preceded by a - decryption header. The decryption header is known as the Archive - Decryption Header. The fields of this record are identical to - the decryption header preceding each encrypted file. The location - of the Archive Decryption Header is determined by the value in the - Start of the Central Directory field in the Zip64 End of Central - Directory record. When the Central Directory is encrypted, the - Zip64 End of Central Directory record will always be present. - - The layout of the Zip64 End of Central Directory record for all - versions starting with 6.2 of this specification will follow the - Version 2 format. The Version 2 format is as follows: - - The leading fixed size fields within the Version 1 format for this - record remain unchanged. The record signature for both Version 1 - and Version 2 will be 0x06064b50. Immediately following the last - byte of the field known as the Offset of Start of Central - Directory With Respect to the Starting Disk Number will begin the - new fields defining Version 2 of this record. - - 7.3.4 New fields for Version 2 - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - Compression Method 2 bytes Method used to compress the - Central Directory - Compressed Size 8 bytes Size of the compressed data - Original Size 8 bytes Original uncompressed size - AlgId 2 bytes Encryption algorithm ID - BitLen 2 bytes Encryption key length - Flags 2 bytes Encryption flags - HashID 2 bytes Hash algorithm identifier - Hash Length 2 bytes Length of hash data - Hash Data (variable) Hash data - - The Compression Method accepts the same range of values as the - corresponding field in the Central Header. - - The Compressed Size and Original Size values will not include the - data of the Central Directory Signature which is compressed or - encrypted. - - The AlgId, BitLen, and Flags fields accept the same range of values - the corresponding fields within the 0x0017 record. - - Hash ID identifies the algorithm used to hash the Central Directory - data. This data does not have to be hashed, in which case the - values for both the HashID and Hash Length will be 0. Possible - values for HashID are: - - Value Algorithm - ------ --------- - 0x0000 none - 0x0001 CRC32 - 0x8003 MD5 - 0x8004 SHA1 - 0x8007 RIPEMD160 - 0x800C SHA256 - 0x800D SHA384 - 0x800E SHA512 - - 7.3.5 When the Central Directory data is signed, the same hash algorithm - used to hash the Central Directory for signing should be used. - This is recommended for processing efficiency, however, it is - permissible for any of the above algorithms to be used independent - of the signing process. - - The Hash Data will contain the hash data for the Central Directory. - The length of this data will vary depending on the algorithm used. - - The Version Needed to Extract should be set to 62. - - The value for the Total Number of Entries on the Current Disk will - be 0. These records will no longer support random access when - encrypting the Central Directory. - - 7.3.6 When the Central Directory is compressed and/or encrypted, the - End of Central Directory record will store the value 0xFFFFFFFF - as the value for the Total Number of Entries in the Central - Directory. The value stored in the Total Number of Entries in - the Central Directory on this Disk field will be 0. The actual - values will be stored in the equivalent fields of the Zip64 - End of Central Directory record. - - 7.3.7 Decrypting and decompressing the Central Directory is accomplished - in the same manner as decrypting and decompressing a file. - - 7.4 Certificate Processing Method - --------------------------------- - - The Certificate Processing Method for ZIP file encryption - defines the following additional data fields: - - 7.4.1 Certificate Flag Values - - Additional processing flags that can be present in the Flags field of both - the 0x0017 field of the central directory Extra Field and the Decryption - header record preceding compressed file data are: - - 0x0007 - reserved for future use - 0x000F - reserved for future use - 0x0100 - Indicates non-OAEP key wrapping was used. If this - this field is set, the version needed to extract must - be at least 61. This means OAEP key wrapping is not - used when generating a Master Session Key using - ErdData. - 0x4000 - ErdData must be decrypted using 3DES-168, otherwise use the - same algorithm used for encrypting the file contents. - 0x8000 - reserved for future use - - - 7.4.2 CertData - Extra Field 0x0017 record certificate data structure - - The data structure used to store certificate data within the section - of the Extra Field defined by the CertData field of the 0x0017 - record are as shown: - - Value Size Description - ----- ---- ----------- - RCount 4 bytes Number of recipients. - HashAlg 2 bytes Hash algorithm identifier - HSize 2 bytes Hash size - SRList (var) Simple list of recipients hashed public keys - - - RCount This defines the number intended recipients whose - public keys were used for encryption. This identifies - the number of elements in the SRList. - - HashAlg This defines the hash algorithm used to calculate - the public key hash of each public key used - for encryption. This field currently supports - only the following value for SHA-1 - - 0x8004 - SHA1 - - HSize This defines the size of a hashed public key. - - SRList This is a variable length list of the hashed - public keys for each intended recipient. Each - element in this list is HSize. The total size of - SRList is determined using RCount * HSize. - - - 7.4.3 Reserved1 - Certificate Decryption Header Reserved1 Data - - Value Size Description - ----- ---- ----------- - RCount 4 bytes Number of recipients. - - RCount This defines the number intended recipients whose - public keys were used for encryption. This defines - the number of elements in the REList field defined below. - - - 7.4.4 Reserved2 - Certificate Decryption Header Reserved2 Data Structures - - - Value Size Description - ----- ---- ----------- - HashAlg 2 bytes Hash algorithm identifier - HSize 2 bytes Hash size - REList (var) List of recipient data elements - - - HashAlg This defines the hash algorithm used to calculate - the public key hash of each public key used - for encryption. This field currently supports - only the following value for SHA-1 - - 0x8004 - SHA1 - - HSize This defines the size of a hashed public key - defined in REHData. - - REList This is a variable length of list of recipient data. - Each element in this list consists of a Recipient - Element data structure as follows: - - - Recipient Element (REList) Data Structure: - - Value Size Description - ----- ---- ----------- - RESize 2 bytes Size of REHData + REKData - REHData HSize Hash of recipients public key - REKData (var) Simple key blob - - - RESize This defines the size of an individual REList - element. This value is the combined size of the - REHData field + REKData field. REHData is defined by - HSize. REKData is variable and can be calculated - for each REList element using RESize and HSize. - - REHData Hashed public key for this recipient. - - REKData Simple Key Blob. The format of this data structure - is identical to that defined in the Microsoft - CryptoAPI and generated using the CryptExportKey() - function. The version of the Simple Key Blob - supported at this time is 0x02 as defined by - Microsoft. - -7.5 Certificate Processing - Central Directory Encryption ---------------------------------------------------------- - - 7.5.1 Central Directory Encryption using Digital Certificates will - operate in a manner similar to that of Single Password Central - Directory Encryption. This record will only be present when there - is data to place into it. Currently, data is placed into this - record when digital certificates are used for either encrypting - or signing the files within a ZIP file. When only password - encryption is used with no certificate encryption or digital - signing, this record is not currently needed. When present, this - record will appear before the start of the actual Central Directory - data structure and will be located immediately after the Archive - Decryption Header if the Central Directory is encrypted. - - 7.5.2 The Archive Extra Data record will be used to store the following - information. Additional data may be added in future versions. - - Extra Data Fields: - - 0x0014 - PKCS#7 Store for X.509 Certificates - 0x0016 - X.509 Certificate ID and Signature for central directory - 0x0019 - PKCS#7 Encryption Recipient Certificate List - - The 0x0014 and 0x0016 Extra Data records that otherwise would be - located in the first record of the Central Directory for digital - certificate processing. When encrypting or compressing the Central - Directory, the 0x0014 and 0x0016 records must be located in the - Archive Extra Data record and they should not remain in the first - Central Directory record. The Archive Extra Data record will also - be used to store the 0x0019 data. - - 7.5.3 When present, the size of the Archive Extra Data record will be - included in the size of the Central Directory. The data of the - Archive Extra Data record will also be compressed and encrypted - along with the Central Directory data structure. - -7.6 Certificate Processing Differences --------------------------------------- - - 7.6.1 The Certificate Processing Method of encryption differs from the - Single Password Symmetric Encryption Method as follows. Instead - of using a user-defined password to generate a master session key, - cryptographically random data is used. The key material is then - wrapped using standard key-wrapping techniques. This key material - is wrapped using the public key of each recipient that will need - to decrypt the file using their corresponding private key. - - 7.6.2 This specification currently assumes digital certificates will follow - the X.509 V3 format for 1024 bit and higher RSA format digital - certificates. Implementation of this Certificate Processing Method - requires supporting logic for key access and management. This logic - is outside the scope of this specification. - -7.7 OAEP Processing with Certificate-based Encryption ------------------------------------------------------ - - 7.7.1 OAEP stands for Optimal Asymmetric Encryption Padding. It is a - strengthening technique used for small encoded items such as decryption - keys. This is commonly applied in cryptographic key-wrapping techniques - and is supported by PKCS #1. Versions 5.0 and 6.0 of this specification - were designed to support OAEP key-wrapping for certificate-based - decryption keys for additional security. - - 7.7.2 Support for private keys stored on Smartcards or Tokens introduced - a conflict with this OAEP logic. Most card and token products do - not support the additional strengthening applied to OAEP key-wrapped - data. In order to resolve this conflict, versions 6.1 and above of this - specification will no longer support OAEP when encrypting using - digital certificates. - - 7.7.3 Versions of PKZIP available during initial development of the - certificate processing method set a value of 61 into the - version needed to extract field for a file. This indicates that - non-OAEP key wrapping is used. This affects certificate encryption - only, and password encryption functions should not be affected by - this value. This means values of 61 may be found on files encrypted - with certificates only, or on files encrypted with both password - encryption and certificate encryption. Files encrypted with both - methods can safely be decrypted using the password methods documented. - -8.0 Splitting and Spanning ZIP files -------------------------------------- - - 8.1 Spanned ZIP files - - 8.1.1 Spanning is the process of segmenting a ZIP file across - multiple removable media. This support has typically only - been provided for DOS formatted floppy diskettes. - - 8.2 Split ZIP files - - 8.2.1 File splitting is a newer derivation of spanning. - Splitting follows the same segmentation process as - spanning, however, it does not require writing each - segment to a unique removable medium and instead supports - placing all pieces onto local or non-removable locations - such as file systems, local drives, folders, etc. - - 8.3 File Naming Differences - - 8.3.1 A key difference between spanned and split ZIP files is - that all pieces of a spanned ZIP file have the same name. - Since each piece is written to a separate volume, no name - collisions occur and each segment can reuse the original - .ZIP file name given to the archive. - - 8.3.2 Sequence ordering for DOS spanned archives uses the DOS - volume label to determine segment numbers. Volume labels - for each segment are written using the form PKBACK#xxx, - where xxx is the segment number written as a decimal - value from 001 - nnn. - - 8.3.3 Split ZIP files are typically written to the same location - and are subject to name collisions if the spanned name - format is used since each segment will reside on the same - drive. To avoid name collisions, split archives are named - as follows. - - Segment 1 = filename.z01 - Segment n-1 = filename.z(n-1) - Segment n = filename.zip - - 8.3.4 The .ZIP extension is used on the last segment to support - quickly reading the central directory. The segment number - n should be a decimal value. - - 8.4 Spanned Self-extracting ZIP Files - - 8.4.1 Spanned ZIP files may be PKSFX Self-extracting ZIP files. - PKSFX files may also be split, however, in this case - the first segment must be named filename.exe. The first - segment of a split PKSFX archive must be large enough to - include the entire executable program. - - 8.5 Capacities and Markers - - 8.5.1 Capacities for split archives are as follows: - - Maximum number of segments = 4,294,967,295 - 1 - Maximum .ZIP segment size = 4,294,967,295 bytes - Minimum segment size = 64K - Maximum PKSFX segment size = 2,147,483,647 bytes - - 8.5.2 Segment sizes may be different however by convention, all - segment sizes should be the same with the exception of the - last, which may be smaller. Local and central directory - header records must never be split across a segment boundary. - When writing a header record, if the number of bytes remaining - within a segment is less than the size of the header record, - end the current segment and write the header at the start - of the next segment. The central directory may span segment - boundaries, but no single record in the central directory - should be split across segments. - - 8.5.3 Spanned/Split archives created using PKZIP for Windows - (V2.50 or greater), PKZIP Command Line (V2.50 or greater), - or PKZIP Explorer will include a special spanning - signature as the first 4 bytes of the first segment of - the archive. This signature (0x08074b50) will be - followed immediately by the local header signature for - the first file in the archive. - - 8.5.4 A special spanning marker may also appear in spanned/split - archives if the spanning or splitting process starts but - only requires one segment. In this case the 0x08074b50 - signature will be replaced with the temporary spanning - marker signature of 0x30304b50. Split archives can - only be uncompressed by other versions of PKZIP that - know how to create a split archive. - - 8.5.5 The signature value 0x08074b50 is also used by some - ZIP implementations as a marker for the Data Descriptor - record. Conflict in this alternate assignment can be - avoided by ensuring the position of the signature - within the ZIP file to determine the use for which it - is intended. - -9.0 Change Process ------------------- - - 9.1 In order for the .ZIP file format to remain a viable technology, this - specification should be considered as open for periodic review and - revision. Although this format was originally designed with a - certain level of extensibility, not all changes in technology - (present or future) were or will be necessarily considered in its - design. - - 9.2 If your application requires new definitions to the - extensible sections in this format, or if you would like to - submit new data structures or new capabilities, please forward - your request to zipformat@pkware.com. All submissions will be - reviewed by the ZIP File Specification Committee for possible - inclusion into future versions of this specification. - - 9.3 Periodic revisions to this specification will be published as - DRAFT or as FINAL status to ensure interoperability. We encourage - comments and feedback that may help improve clarity or content. - - -10.0 Incorporating PKWARE Proprietary Technology into Your Product ------------------------------------------------------------------- - - 10.1 The Use or Implementation in a product of APPNOTE technological - components pertaining to either strong encryption or patching requires - a separate, executed license agreement from PKWARE. Please contact - PKWARE at zipformat@pkware.com or +1-414-289-9788 with regard to - acquiring such a license. - - 10.2 Additional information regarding PKWARE proprietray technology is - available at https://www.pkware.com/appnote. - -11.0 Acknowledgements ---------------------- - - In addition to the above mentioned contributors to PKZIP and PKUNZIP, - PKWARE would like to extend special thanks to Robert Mahoney for - suggesting the extension .ZIP for this software. - -12.0 References ---------------- - - Fiala, Edward R., and Greene, Daniel H., "Data compression with - finite windows", Communications of the ACM, Volume 32, Number 4, - April 1989, pages 490-505. - - Held, Gilbert, "Data Compression, Techniques and Applications, - Hardware and Software Considerations", John Wiley & Sons, 1987. - - Huffman, D.A., "A method for the construction of minimum-redundancy - codes", Proceedings of the IRE, Volume 40, Number 9, September 1952, - pages 1098-1101. - - Nelson, Mark, "LZW Data Compression", Dr. Dobbs Journal, Volume 14, - Number 10, October 1989, pages 29-37. - - Nelson, Mark, "The Data Compression Book", M&T Books, 1991. - - Storer, James A., "Data Compression, Methods and Theory", - Computer Science Press, 1988 - - Welch, Terry, "A Technique for High-Performance Data Compression", - IEEE Computer, Volume 17, Number 6, June 1984, pages 8-19. - - Ziv, J. and Lempel, A., "A universal algorithm for sequential data - compression", Communications of the ACM, Volume 30, Number 6, - June 1987, pages 520-540. - - Ziv, J. and Lempel, A., "Compression of individual sequences via - variable-rate coding", IEEE Transactions on Information Theory, - Volume 24, Number 5, September 1978, pages 530-536. - - -APPENDIX A - AS/400 Extra Field (0x0065) Attribute Definitions --------------------------------------------------------------- - -A.1 Field Definition Structure: - - a. field length including length 2 bytes - b. field code 2 bytes - c. data x bytes - -A.2 Field Code Description - - 4001 Source type i.e. CLP etc - 4002 The text description of the library - 4003 The text description of the file - 4004 The text description of the member - 4005 x'F0' or 0 is PF-DTA, x'F1' or 1 is PF_SRC - 4007 Database Type Code 1 byte - 4008 Database file and fields definition - 4009 GZIP file type 2 bytes - 400B IFS code page 2 bytes - 400C IFS Creation Time 4 bytes - 400D IFS Access Time 4 bytes - 400E IFS Modification time 4 bytes - 005C Length of the records in the file 2 bytes - 0068 GZIP two words 8 bytes - -APPENDIX B - z/OS Extra Field (0x0065) Attribute Definitions ------------------------------------------------------------- - -B.1 Field Definition Structure: - - a. field length including length 2 bytes - b. field code 2 bytes - c. data x bytes - -B.2 Field Code Description - - 0001 File Type 2 bytes - 0002 NonVSAM Record Format 1 byte - 0003 Reserved - 0004 NonVSAM Block Size 2 bytes Big Endian - 0005 Primary Space Allocation 3 bytes Big Endian - 0006 Secondary Space Allocation 3 bytes Big Endian - 0007 Space Allocation Type1 byte flag - 0008 Modification Date Retired with PKZIP 5.0 + - 0009 Expiration Date Retired with PKZIP 5.0 + - 000A PDS Directory Block Allocation 3 bytes Big Endian binary value - 000B NonVSAM Volume List variable - 000C UNIT Reference Retired with PKZIP 5.0 + - 000D DF/SMS Management Class 8 bytes EBCDIC Text Value - 000E DF/SMS Storage Class 8 bytes EBCDIC Text Value - 000F DF/SMS Data Class 8 bytes EBCDIC Text Value - 0010 PDS/PDSE Member Info. 30 bytes - 0011 VSAM sub-filetype 2 bytes - 0012 VSAM LRECL 13 bytes EBCDIC "(num_avg num_max)" - 0013 VSAM Cluster Name Retired with PKZIP 5.0 + - 0014 VSAM KSDS Key Information 13 bytes EBCDIC "(num_length num_position)" - 0015 VSAM Average LRECL 5 bytes EBCDIC num_value padded with blanks - 0016 VSAM Maximum LRECL 5 bytes EBCDIC num_value padded with blanks - 0017 VSAM KSDS Key Length 5 bytes EBCDIC num_value padded with blanks - 0018 VSAM KSDS Key Position 5 bytes EBCDIC num_value padded with blanks - 0019 VSAM Data Name 1-44 bytes EBCDIC text string - 001A VSAM KSDS Index Name 1-44 bytes EBCDIC text string - 001B VSAM Catalog Name 1-44 bytes EBCDIC text string - 001C VSAM Data Space Type 9 bytes EBCDIC text string - 001D VSAM Data Space Primary 9 bytes EBCDIC num_value left-justified - 001E VSAM Data Space Secondary 9 bytes EBCDIC num_value left-justified - 001F VSAM Data Volume List variable EBCDIC text list of 6-character Volume IDs - 0020 VSAM Data Buffer Space 8 bytes EBCDIC num_value left-justified - 0021 VSAM Data CISIZE 5 bytes EBCDIC num_value left-justified - 0022 VSAM Erase Flag 1 byte flag - 0023 VSAM Free CI % 3 bytes EBCDIC num_value left-justified - 0024 VSAM Free CA % 3 bytes EBCDIC num_value left-justified - 0025 VSAM Index Volume List variable EBCDIC text list of 6-character Volume IDs - 0026 VSAM Ordered Flag 1 byte flag - 0027 VSAM REUSE Flag 1 byte flag - 0028 VSAM SPANNED Flag 1 byte flag - 0029 VSAM Recovery Flag 1 byte flag - 002A VSAM WRITECHK Flag 1 byte flag - 002B VSAM Cluster/Data SHROPTS 3 bytes EBCDIC "n,y" - 002C VSAM Index SHROPTS 3 bytes EBCDIC "n,y" - 002D VSAM Index Space Type 9 bytes EBCDIC text string - 002E VSAM Index Space Primary 9 bytes EBCDIC num_value left-justified - 002F VSAM Index Space Secondary 9 bytes EBCDIC num_value left-justified - 0030 VSAM Index CISIZE 5 bytes EBCDIC num_value left-justified - 0031 VSAM Index IMBED 1 byte flag - 0032 VSAM Index Ordered Flag 1 byte flag - 0033 VSAM REPLICATE Flag 1 byte flag - 0034 VSAM Index REUSE Flag 1 byte flag - 0035 VSAM Index WRITECHK Flag 1 byte flag Retired with PKZIP 5.0 + - 0036 VSAM Owner 8 bytes EBCDIC text string - 0037 VSAM Index Owner 8 bytes EBCDIC text string - 0038 Reserved - 0039 Reserved - 003A Reserved - 003B Reserved - 003C Reserved - 003D Reserved - 003E Reserved - 003F Reserved - 0040 Reserved - 0041 Reserved - 0042 Reserved - 0043 Reserved - 0044 Reserved - 0045 Reserved - 0046 Reserved - 0047 Reserved - 0048 Reserved - 0049 Reserved - 004A Reserved - 004B Reserved - 004C Reserved - 004D Reserved - 004E Reserved - 004F Reserved - 0050 Reserved - 0051 Reserved - 0052 Reserved - 0053 Reserved - 0054 Reserved - 0055 Reserved - 0056 Reserved - 0057 Reserved - 0058 PDS/PDSE Member TTR Info. 6 bytes Big Endian - 0059 PDS 1st LMOD Text TTR 3 bytes Big Endian - 005A PDS LMOD EP Rec # 4 bytes Big Endian - 005B Reserved - 005C Max Length of records 2 bytes Big Endian - 005D PDSE Flag 1 byte flag - 005E Reserved - 005F Reserved - 0060 Reserved - 0061 Reserved - 0062 Reserved - 0063 Reserved - 0064 Reserved - 0065 Last Date Referenced 4 bytes Packed Hex "yyyymmdd" - 0066 Date Created 4 bytes Packed Hex "yyyymmdd" - 0068 GZIP two words 8 bytes - 0071 Extended NOTE Location 12 bytes Big Endian - 0072 Archive device UNIT 6 bytes EBCDIC - 0073 Archive 1st Volume 6 bytes EBCDIC - 0074 Archive 1st VOL File Seq# 2 bytes Binary - -APPENDIX C - Zip64 Extensible Data Sector Mappings ---------------------------------------------------- - - -Z390 Extra Field: - - The following is the general layout of the attributes for the - ZIP 64 "extra" block for extended tape operations. - - Note: some fields stored in Big Endian format. All text is - in EBCDIC format unless otherwise specified. - - Value Size Description - ----- ---- ----------- - (Z390) 0x0065 2 bytes Tag for this "extra" block type - Size 4 bytes Size for the following data block - Tag 4 bytes EBCDIC "Z390" - Length71 2 bytes Big Endian - Subcode71 2 bytes Enote type code - FMEPos 1 byte - Length72 2 bytes Big Endian - Subcode72 2 bytes Unit type code - Unit 1 byte Unit - Length73 2 bytes Big Endian - Subcode73 2 bytes Volume1 type code - FirstVol 1 byte Volume - Length74 2 bytes Big Endian - Subcode74 2 bytes FirstVol file sequence - FileSeq 2 bytes Sequence - -APPENDIX D - Language Encoding (EFS) ------------------------------------- - -D.1 The ZIP format has historically supported only the original IBM PC character -encoding set, commonly referred to as IBM Code Page 437. This limits storing -file name characters to only those within the original MS-DOS range of values -and does not properly support file names in other character encodings, or -languages. To address this limitation, this specification will support the -following change. - -D.2 If general purpose bit 11 is unset, the file name and comment should conform -to the original ZIP character encoding. If general purpose bit 11 is set, the -filename and comment must support The Unicode Standard, Version 4.1.0 or -greater using the character encoding form defined by the UTF-8 storage -specification. The Unicode Standard is published by the The Unicode -Consortium (www.unicode.org). UTF-8 encoded data stored within ZIP files -is expected to not include a byte order mark (BOM). - -D.3 Applications may choose to supplement this file name storage through the use -of the 0x0008 Extra Field. Storage for this optional field is currently -undefined, however it will be used to allow storing extended information -on source or target encoding that may further assist applications with file -name, or file content encoding tasks. Please contact PKWARE with any -requirements on how this field should be used. - -D.4 The 0x0008 Extra Field storage may be used with either setting for general -purpose bit 11. Examples of the intended usage for this field is to store -whether "modified-UTF-8" (JAVA) is used, or UTF-8-MAC. Similarly, other -commonly used character encoding (code page) designations can be indicated -through this field. Formalized values for use of the 0x0008 record remain -undefined at this time. The definition for the layout of the 0x0008 field -will be published when available. Use of the 0x0008 Extra Field provides -for storing data within a ZIP file in an encoding other than IBM Code -Page 437 or UTF-8. - -D.5 General purpose bit 11 will not imply any encoding of file content or -password. Values defining character encoding for file content or -password must be stored within the 0x0008 Extended Language Encoding -Extra Field. - -D.6 Ed Gordon of the Info-ZIP group has defined a pair of "extra field" records -that can be used to store UTF-8 file name and file comment fields. These -records can be used for cases when the general purpose bit 11 method -for storing UTF-8 data in the standard file name and comment fields is -not desirable. A common case for this alternate method is if backward -compatibility with older programs is required. - -D.7 Definitions for the record structure of these fields are included above -in the section on 3rd party mappings for "extra field" records. These -records are identified by Header ID's 0x6375 (Info-ZIP Unicode Comment -Extra Field) and 0x7075 (Info-ZIP Unicode Path Extra Field). - -D.8 The choice of which storage method to use when writing a ZIP file is left -to the implementation. Developers should expect that a ZIP file may -contain either method and should provide support for reading data in -either format. Use of general purpose bit 11 reduces storage requirements -for file name data by not requiring additional "extra field" data for -each file, but can result in older ZIP programs not being able to extract -files. Use of the 0x6375 and 0x7075 records will result in a ZIP file -that should always be readable by older ZIP programs, but requires more -storage per file to write file name and/or file comment fields. diff --git a/minizip-ng/doc/zip/extra.fld.txt b/minizip-ng/doc/zip/extra.fld.txt deleted file mode 100644 index a7578de..0000000 --- a/minizip-ng/doc/zip/extra.fld.txt +++ /dev/null @@ -1,1243 +0,0 @@ -The following are the known types of zipfile extra fields as of this -writing. Extra fields are documented in PKWARE's appnote.txt and are -intended to allow for backward- and forward-compatible extensions to -the zipfile format. Multiple extra-field types may be chained together, -provided that the total length of all extra-field data is less than 64KB. -(In fact, PKWARE requires that the total length of the entire file header, -including timestamp, file attributes, filename, comment, extra field, etc., -be no more than 64KB.) - -Each extra-field type (or subblock) must contain a four-byte header con- -sisting of a two-byte header ID and a two-byte length (little-endian) for -the remaining data in the subblock. If there are additional subblocks -within the extra field, the header for each one will appear immediately -following the data for the previous subblock (i.e., with no padding for -alignment). - -All integer fields in the descriptions below are in little-endian (Intel) -format unless otherwise specified. Note that "Short" means two bytes, -"Long" means four bytes, and "Long-Long" means eight bytes, regardless -of their native sizes. Unless specifically noted, all integer fields should -be interpreted as unsigned (non-negative) numbers. - -Christian Spieler, 20010517 - - ------------------------- - - Header ID's of 0 thru 31 are reserved for use by PKWARE. - The remaining ID's can be used by third party vendors for - proprietary usage. - - The current Header ID mappings defined by PKWARE are: - - 0x0001 ZIP64 extended information extra field - 0x0007 AV Info - 0x0009 OS/2 extended attributes (also Info-ZIP) - 0x000a NTFS (Win9x/WinNT FileTimes) - 0x000c OpenVMS (also Info-ZIP) - 0x000d Unix - 0x000f Patch Descriptor - 0x0014 PKCS#7 Store for X.509 Certificates - 0x0015 X.509 Certificate ID and Signature for - individual file - 0x0016 X.509 Certificate ID for Central Directory - - The Header ID mappings defined by Info-ZIP and third parties are: - - 0x0065 IBM S/390 attributes - uncompressed - 0x0066 IBM S/390 attributes - compressed - 0x07c8 Info-ZIP Macintosh (old, J. Lee) - 0x2605 ZipIt Macintosh (first version) - 0x2705 ZipIt Macintosh v 1.3.5 and newer (w/o full filename) - 0x334d Info-ZIP Macintosh (new, D. Haase's 'Mac3' field ) - 0x4154 Tandem NSK - 0x4341 Acorn/SparkFS (David Pilling) - 0x4453 Windows NT security descriptor (binary ACL) - 0x4704 VM/CMS - 0x470f MVS - 0x4854 Theos, old inofficial port - 0x4b46 FWKCS MD5 (see below) - 0x4c41 OS/2 access control list (text ACL) - 0x4d49 Info-ZIP OpenVMS (obsolete) - 0x4d63 Macintosh SmartZIP, by Macro Bambini - 0x4f4c Xceed original location extra field - 0x5356 AOS/VS (binary ACL) - 0x5455 extended timestamp - 0x5855 Info-ZIP Unix (original; also OS/2, NT, etc.) - 0x554e Xceed unicode extra field - 0x6542 BeOS (BeBox, PowerMac, etc.) - 0x6854 Theos - 0x756e ASi Unix - 0x7855 Info-ZIP Unix (new) - 0xfb4a SMS/QDOS - -The following are detailed descriptions of the known extra-field block types: - - -OS/2 Extended Attributes Extra Field: - ==================================== - - The following is the layout of the OS/2 extended attributes "extra" - block. (Last Revision 19960922) - - Note: all fields stored in Intel low-byte/high-byte order. - - Local-header version: - - Value Size Description - ----- ---- ----------- - (OS/2) 0x0009 Short tag for this extra block type - TSize Short total data size for this block - BSize Long uncompressed EA data size - CType Short compression type - EACRC Long CRC value for uncompressed EA data - (var.) variable compressed EA data - - Central-header version: - - Value Size Description - ----- ---- ----------- - (OS/2) 0x0009 Short tag for this extra block type - TSize Short total data size for this block (4) - BSize Long size of uncompressed local EA data - - The value of CType is interpreted according to the "compression - method" section above; i.e., 0 for stored, 8 for deflated, etc. - - The OS/2 extended attribute structure (FEA2LIST) is compressed and - then stored in its entirety within this structure. There will only - ever be one block of data in the variable-length field. - - - -OS/2 Access Control List Extra Field: - ==================================== - - The following is the layout of the OS/2 ACL extra block. - (Last Revision 19960922) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (ACL) 0x4c41 Short tag for this extra block type ("AL") - TSize Short total data size for this block - BSize Long uncompressed ACL data size - CType Short compression type - EACRC Long CRC value for uncompressed ACL data - (var.) variable compressed ACL data - - Central-header version: - - Value Size Description - ----- ---- ----------- - (ACL) 0x4c41 Short tag for this extra block type ("AL") - TSize Short total data size for this block (4) - BSize Long size of uncompressed local ACL data - - The value of CType is interpreted according to the "compression - method" section above; i.e., 0 for stored, 8 for deflated, etc. - - The uncompressed ACL data consist of a text header of the form - "ACL1:%hX,%hd\n", where the first field is the OS/2 ACCINFO acc_attr - member and the second is acc_count, followed by acc_count strings - of the form "%s,%hx\n", where the first field is acl_ugname (user - group name) and the second acl_access. This block type will be - extended for other operating systems as needed. - - - -Windows NT Security Descriptor Extra Field: - ========================================== - - The following is the layout of the NT Security Descriptor (another - type of ACL) extra block. (Last Revision 19960922) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (SD) 0x4453 Short tag for this extra block type ("SD") - TSize Short total data size for this block - BSize Long uncompressed SD data size - Version Byte version of uncompressed SD data format - CType Short compression type - EACRC Long CRC value for uncompressed SD data - (var.) variable compressed SD data - - Central-header version: - - Value Size Description - ----- ---- ----------- - (SD) 0x4453 Short tag for this extra block type ("SD") - TSize Short total data size for this block (4) - BSize Long size of uncompressed local SD data - - The value of CType is interpreted according to the "compression - method" section above; i.e., 0 for stored, 8 for deflated, etc. - Version specifies how the compressed data are to be interpreted - and allows for future expansion of this extra field type. Currently - only version 0 is defined. - - For version 0, the compressed data are to be interpreted as a single - valid Windows NT SECURITY_DESCRIPTOR data structure, in self-relative - format. - - - -PKWARE Win95/WinNT Extra Field: - ============================== - - The following description covers PKWARE's "NTFS" attributes - "extra" block, introduced with the release of PKZIP 2.50 for - Windows. (Last Revision 20001118) - - (Note: At this time the Mtime, Atime and Ctime values may - be used on any WIN32 system.) - [Info-ZIP note: In the current implementations, this field has - a fixed total data size of 32 bytes and is only stored as local - extra field.] - - Value Size Description - ----- ---- ----------- - (NTFS) 0x000a Short Tag for this "extra" block type - TSize Short Total Data Size for this block - Reserved Long for future use - Tag1 Short NTFS attribute tag value #1 - Size1 Short Size of attribute #1, in bytes - (var.) SubSize1 Attribute #1 data - . - . - . - TagN Short NTFS attribute tag value #N - SizeN Short Size of attribute #N, in bytes - (var.) SubSize1 Attribute #N data - - For NTFS, values for Tag1 through TagN are as follows: - (currently only one set of attributes is defined for NTFS) - - Tag Size Description - ----- ---- ----------- - 0x0001 2 bytes Tag for attribute #1 - Size1 2 bytes Size of attribute #1, in bytes (24) - Mtime 8 bytes 64-bit NTFS file last modification time - Atime 8 bytes 64-bit NTFS file last access time - Ctime 8 bytes 64-bit NTFS file creation time - - The total length for this block is 28 bytes, resulting in a - fixed size value of 32 for the TSize field of the NTFS block. - - The NTFS filetimes are 64-bit unsigned integers, stored in Intel - (least significant byte first) byte order. They determine the - number of 1.0E-07 seconds (1/10th microseconds!) past WinNT "epoch", - which is "01-Jan-1601 00:00:00 UTC". - - - -PKWARE OpenVMS Extra Field: - ========================== - - The following is the layout of PKWARE's OpenVMS attributes "extra" - block. (Last Revision 12/17/91) - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (VMS) 0x000c Short Tag for this "extra" block type - TSize Short Total Data Size for this block - CRC Long 32-bit CRC for remainder of the block - Tag1 Short OpenVMS attribute tag value #1 - Size1 Short Size of attribute #1, in bytes - (var.) Size1 Attribute #1 data - . - . - . - TagN Short OpenVMS attribute tage value #N - SizeN Short Size of attribute #N, in bytes - (var.) SizeN Attribute #N data - - Rules: - - 1. There will be one or more of attributes present, which - will each be preceded by the above TagX & SizeX values. - These values are identical to the ATR$C_XXXX and - ATR$S_XXXX constants which are defined in ATR.H under - OpenVMS C. Neither of these values will ever be zero. - - 2. No word alignment or padding is performed. - - 3. A well-behaved PKZIP/OpenVMS program should never produce - more than one sub-block with the same TagX value. Also, - there will never be more than one "extra" block of type - 0x000c in a particular directory record. - - - -Info-ZIP VMS Extra Field: - ======================== - - The following is the layout of Info-ZIP's VMS attributes extra - block for VAX or Alpha AXP. The local-header and central-header - versions are identical. (Last Revision 19960922) - - Value Size Description - ----- ---- ----------- - (VMS2) 0x4d49 Short tag for this extra block type ("JM") - TSize Short total data size for this block - ID Long block ID - Flags Short info bytes - BSize Short uncompressed block size - Reserved Long (reserved) - (var.) variable compressed VMS file-attributes block - - The block ID is one of the following unterminated strings: - - "VFAB" struct FAB - "VALL" struct XABALL - "VFHC" struct XABFHC - "VDAT" struct XABDAT - "VRDT" struct XABRDT - "VPRO" struct XABPRO - "VKEY" struct XABKEY - "VMSV" version (e.g., "V6.1"; truncated at hyphen) - "VNAM" reserved - - The lower three bits of Flags indicate the compression method. The - currently defined methods are: - - 0 stored (not compressed) - 1 simple "RLE" - 2 deflated - - The "RLE" method simply replaces zero-valued bytes with zero-valued - bits and non-zero-valued bytes with a "1" bit followed by the byte - value. - - The variable-length compressed data contains only the data corre- - sponding to the indicated structure or string. Typically multiple - VMS2 extra fields are present (each with a unique block type). - - - -Info-ZIP Macintosh Extra Field: - ============================== - - The following is the layout of the (old) Info-ZIP resource-fork extra - block for Macintosh. The local-header and central-header versions - are identical. (Last Revision 19960922) - - Value Size Description - ----- ---- ----------- - (Mac) 0x07c8 Short tag for this extra block type - TSize Short total data size for this block - "JLEE" beLong extra-field signature - FInfo 16 bytes Macintosh FInfo structure - CrDat beLong HParamBlockRec fileParam.ioFlCrDat - MdDat beLong HParamBlockRec fileParam.ioFlMdDat - Flags beLong info bits - DirID beLong HParamBlockRec fileParam.ioDirID - VolName 28 bytes volume name (optional) - - All fields but the first two are in native Macintosh format - (big-endian Motorola order, not little-endian Intel). The least - significant bit of Flags is 1 if the file is a data fork, 0 other- - wise. In addition, if this extra field is present, the filename - has an extra 'd' or 'r' appended to indicate data fork or resource - fork. The 28-byte VolName field may be omitted. - - - -ZipIt Macintosh Extra Field (long): - ================================== - - The following is the layout of the ZipIt extra block for Macintosh. - The local-header and central-header versions are identical. - (Last Revision 19970130) - - Value Size Description - ----- ---- ----------- - (Mac2) 0x2605 Short tag for this extra block type - TSize Short total data size for this block - "ZPIT" beLong extra-field signature - FnLen Byte length of FileName - FileName variable full Macintosh filename - FileType Byte[4] four-byte Mac file type string - Creator Byte[4] four-byte Mac creator string - - - -ZipIt Macintosh Extra Field (short): - =================================== - - The following is the layout of a shortened variant of the - ZipIt extra block for Macintosh (without "full name" entry). - This variant is used by ZipIt 1.3.5 and newer for entries that - do not need a "full Mac filename" record. - The local-header and central-header versions are identical. - (Last Revision 19980903) - - Value Size Description - ----- ---- ----------- - (Mac2b) 0x2705 Short tag for this extra block type - TSize Short total data size for this block (12) - "ZPIT" beLong extra-field signature - FileType Byte[4] four-byte Mac file type string - Creator Byte[4] four-byte Mac creator string - - - -Info-ZIP Macintosh Extra Field (new): - ==================================== - - The following is the layout of the (new) Info-ZIP extra - block for Macintosh, designed by Dirk Haase. - All values are in little-endian. - (Last Revision 19981005) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (Mac3) 0x334d Short tag for this extra block type ("M3") - TSize Short total data size for this block - BSize Long uncompressed finder attribute data size - Flags Short info bits - fdType Byte[4] Type of the File (4-byte string) - fdCreator Byte[4] Creator of the File (4-byte string) - (CType) Short compression type - (CRC) Long CRC value for uncompressed MacOS data - Attribs variable finder attribute data (see below) - - - Central-header version: - - Value Size Description - ----- ---- ----------- - (Mac3) 0x334d Short tag for this extra block type ("M3") - TSize Short total data size for this block - BSize Long uncompressed finder attribute data size - Flags Short info bits - fdType Byte[4] Type of the File (4-byte string) - fdCreator Byte[4] Creator of the File (4-byte string) - - The third bit of Flags in both headers indicates whether - the LOCAL extra field is uncompressed (and therefore whether CType - and CRC are omitted): - - Bits of the Flags: - bit 0 if set, file is a data fork; otherwise unset - bit 1 if set, filename will be not changed - bit 2 if set, Attribs is uncompressed (no CType, CRC) - bit 3 if set, date and times are in 64 bit - if zero date and times are in 32 bit. - bit 4 if set, timezone offsets fields for the native - Mac times are omitted (UTC support deactivated) - bits 5-15 reserved; - - - Attributes: - - Attribs is a Mac-specific block of data in little-endian format with - the following structure (if compressed, uncompress it first): - - Value Size Description - ----- ---- ----------- - fdFlags Short Finder Flags - fdLocation.v Short Finder Icon Location - fdLocation.h Short Finder Icon Location - fdFldr Short Folder containing file - - FXInfo 16 bytes Macintosh FXInfo structure - FXInfo-Structure: - fdIconID Short - fdUnused[3] Short unused but reserved 6 bytes - fdScript Byte Script flag and number - fdXFlags Byte More flag bits - fdComment Short Comment ID - fdPutAway Long Home Dir ID - - FVersNum Byte file version number - may be not used by MacOS - ACUser Byte directory access rights - - FlCrDat ULong date and time of creation - FlMdDat ULong date and time of last modification - FlBkDat ULong date and time of last backup - These time numbers are original Mac FileTime values (local time!). - Currently, date-time width is 32-bit, but future version may - support be 64-bit times (see flags) - - CrGMTOffs Long(signed!) difference "local Creat. time - UTC" - MdGMTOffs Long(signed!) difference "local Modif. time - UTC" - BkGMTOffs Long(signed!) difference "local Backup time - UTC" - These "local time - UTC" differences (stored in seconds) may be - used to support timestamp adjustment after inter-timezone transfer. - These fields are optional; bit 4 of the flags word controls their - presence. - - Charset Short TextEncodingBase (Charset) - valid for the following two fields - - FullPath variable Path of the current file. - Zero terminated string (C-String) - Currently coded in the native Charset. - - Comment variable Finder Comment of the current file. - Zero terminated string (C-String) - Currently coded in the native Charset. - - - -SmartZIP Macintosh Extra Field: - ==================================== - - The following is the layout of the SmartZIP extra - block for Macintosh, designed by Marco Bambini. - - Local-header version: - - Value Size Description - ----- ---- ----------- - 0x4d63 Short tag for this extra block type ("cM") - TSize Short total data size for this block (64) - "dZip" beLong extra-field signature - fdType Byte[4] Type of the File (4-byte string) - fdCreator Byte[4] Creator of the File (4-byte string) - fdFlags beShort Finder Flags - fdLocation.v beShort Finder Icon Location - fdLocation.h beShort Finder Icon Location - fdFldr beShort Folder containing file - CrDat beLong HParamBlockRec fileParam.ioFlCrDat - MdDat beLong HParamBlockRec fileParam.ioFlMdDat - frScroll.v Byte vertical pos. of folder's scroll bar - fdScript Byte Script flag and number - frScroll.h Byte horizontal pos. of folder's scroll bar - fdXFlags Byte More flag bits - FileName Byte[32] full Macintosh filename (pascal string) - - All fields but the first two are in native Macintosh format - (big-endian Motorola order, not little-endian Intel). - The extra field size is fixed to 64 bytes. - The local-header and central-header versions are identical. - - - -Acorn SparkFS Extra Field: - ========================= - - The following is the layout of David Pilling's SparkFS extra block - for Acorn RISC OS. The local-header and central-header versions are - identical. (Last Revision 19960922) - - Value Size Description - ----- ---- ----------- - (Acorn) 0x4341 Short tag for this extra block type ("AC") - TSize Short total data size for this block (20) - "ARC0" Long extra-field signature - LoadAddr Long load address or file type - ExecAddr Long exec address - Attr Long file permissions - Zero Long reserved; always zero - - The following bits of Attr are associated with the given file - permissions: - - bit 0 user-writable ('W') - bit 1 user-readable ('R') - bit 2 reserved - bit 3 locked ('L') - bit 4 publicly writable ('w') - bit 5 publicly readable ('r') - bit 6 reserved - bit 7 reserved - - - -VM/CMS Extra Field: - ================== - - The following is the layout of the file-attributes extra block for - VM/CMS. The local-header and central-header versions are - identical. (Last Revision 19960922) - - Value Size Description - ----- ---- ----------- - (VM/CMS) 0x4704 Short tag for this extra block type - TSize Short total data size for this block - flData variable file attributes data - - flData is an uncompressed fldata_t struct. - - - -MVS Extra Field: - =============== - - The following is the layout of the file-attributes extra block for - MVS. The local-header and central-header versions are identical. - (Last Revision 19960922) - - Value Size Description - ----- ---- ----------- - (MVS) 0x470f Short tag for this extra block type - TSize Short total data size for this block - flData variable file attributes data - - flData is an uncompressed fldata_t struct. - - - -PKWARE Unix Extra Field: - ======================== - - The following is the layout of PKWARE's Unix "extra" block. - It was introduced with the release of PKZIP for Unix 2.50. - Note: all fields are stored in Intel low-byte/high-byte order. - (Last Revision 19980901) - - This field has a minimum data size of 12 bytes and is only stored - as local extra field. - - Value Size Description - ----- ---- ----------- - (Unix0) 0x000d Short Tag for this "extra" block type - TSize Short Total Data Size for this block - AcTime Long time of last access (UTC/GMT) - ModTime Long time of last modification (UTC/GMT) - UID Short Unix user ID - GID Short Unix group ID - (var) variable Variable length data field - - The variable length data field will contain file type - specific data. Currently the only values allowed are - the original "linked to" file names for hard or symbolic - links, and the major and minor device node numbers for - character and block device nodes. Since device nodes - cannot be either symbolic or hard links, only one set of - variable length data is stored. Link files will have the - name of the original file stored. This name is NOT NULL - terminated. Its size can be determined by checking TSize - - 12. Device entries will have eight bytes stored as two 4 - byte entries (in little-endian format). The first entry - will be the major device number, and the second the minor - device number. - - [Info-ZIP note: The fixed part of this field has the same layout as - Info-ZIP's abandoned "Unix1 timestamps & owner ID info" extra field; - only the two tag bytes are different.] - - - -PATCH Descriptor Extra Field: - ============================ - - The following is the layout of the Patch Descriptor "extra" - block. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (Patch) 0x000f Short Tag for this "extra" block type - TSize Short Size of the total "extra" block - Version Short Version of the descriptor - Flags Long Actions and reactions (see below) - OldSize Long Size of the file about to be patched - OldCRC Long 32-bit CRC of the file about to be patched - NewSize Long Size of the resulting file - NewCRC Long 32-bit CRC of the resulting file - - - Actions and reactions - - Bits Description - ---- ---------------- - 0 Use for autodetection - 1 Treat as selfpatch - 2-3 RESERVED - 4-5 Action (see below) - 6-7 RESERVED - 8-9 Reaction (see below) to absent file - 10-11 Reaction (see below) to newer file - 12-13 Reaction (see below) to unknown file - 14-15 RESERVED - 16-31 RESERVED - - Actions - - Action Value - ------ ----- - none 0 - add 1 - delete 2 - patch 3 - - Reactions - - Reaction Value - -------- ----- - ask 0 - skip 1 - ignore 2 - fail 3 - - - -PKCS#7 Store for X.509 Certificates: - =================================== - - This field is contains the information about each - certificate a file is signed with. This field should only - appear in the first central directory record, and will be - ignored in any other record. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (Store) 0x0014 2 bytes Tag for this "extra" block type - SSize 2 bytes Size of the store data - SData (variable) Data about the store - - SData - Value Size Description - ----- ---- ----------- - Version 2 bytes Version number, 0x0001 for now - StoreD (variable) Actual store data - - The StoreD member is suitable for passing as the pbData - member of a CRYPT_DATA_BLOB to the CertOpenStore() function - in Microsoft's CryptoAPI. The SSize member above will be - cbData + 6, where cbData is the cbData member of the same - CRYPT_DATA_BLOB. The encoding type to pass to - CertOpenStore() should be - PKCS_7_ANS_ENCODING | X509_ASN_ENCODING. - - - -X.509 Certificate ID and Signature for individual file: - ====================================================== - - This field contains the information about which certificate - in the PKCS#7 Store was used to sign the particular file. - It also contains the signature data. This field can appear - multiple times, but can only appear once per certificate. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (CID) 0x0015 2 bytes Tag for this "extra" block type - CSize 2 bytes Size of Method - Method (variable) - - Method - Value Size Description - ----- ---- ----------- - Version 2 bytes Version number, for now 0x0001 - AlgID 2 bytes Algorithm ID used for signing - IDSize 2 bytes Size of Certificate ID data - CertID (variable) Certificate ID data - SigSize 2 bytes Size of Signature data - Sig (variable) Signature data - - CertID - Value Size Description - ----- ---- ----------- - Size1 4 bytes Size of CertID, should be (IDSize - 4) - Size1 4 bytes A bug in version one causes this value - to appear twice. - IssSize 4 bytes Issuer data size - Issuer (variable) Issuer data - SerSize 4 bytes Serial Number size - Serial (variable) Serial Number data - - The Issuer and IssSize members are suitable for creating a - CRYPT_DATA_BLOB to be the Issuer member of a CERT_INFO - struct. The Serial and SerSize members would be the - SerialNumber member of the same CERT_INFO struct. This - struct would be used to find the certificate in the store - the file was signed with. Those structures are from the MS - CryptoAPI. - - Sig and SigSize are the actual signature data and size - generated by signing the file with the MS CryptoAPI using a - hash created with the given AlgID. - - - -X.509 Certificate ID and Signature for central directory: - ======================================================== - - This field contains the information about which certificate - in the PKCS#7 Store was used to sign the central directory. - It should only appear with the first central directory - record, along with the store. The data structure is the - same as the CID, except that SigSize will be 0, and there - will be no Sig member. - - This field is also kept after the last central directory - record, as the signature data (ID 0x05054b50, it looks like - a central directory record of a different type). This - second copy of the data is the Signature Data member of the - record, and will have a SigSize that is non-zero, and will - have Sig data. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (CDID) 0x0016 2 bytes Tag for this "extra" block type - CSize 2 bytes Size of Method - Method (variable) - - - -ZIP64 Extended Information Extra Field: - ====================================== - - The following is the layout of the ZIP64 extended - information "extra" block. If one of the size or - offset fields in the Local or Central directory - record is too small to hold the required data, - a ZIP64 extended information record is created. - The order of the fields in the ZIP64 extended - information record is fixed, but the fields will - only appear if the corresponding Local or Central - directory record field is set to 0xFFFF or 0xFFFFFFFF. - - Note: all fields stored in Intel low-byte/high-byte order. - - Value Size Description - ----- ---- ----------- - (ZIP64) 0x0001 2 bytes Tag for this "extra" block type - Size 2 bytes Size of this "extra" block - Original - Size 8 bytes Original uncompresseed file size - Compressed - Size 8 bytes Size of compressed data - Relative Header - Offset 8 bytes Offset of local header record - Disk Start - Number 4 bytes Number of the disk on which - this file starts - - This entry in the Local header must include BOTH original - and compressed file sizes. - - - -Extended Timestamp Extra Field: - ============================== - - The following is the layout of the extended-timestamp extra block. - (Last Revision 19970118) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (time) 0x5455 Short tag for this extra block type ("UT") - TSize Short total data size for this block - Flags Byte info bits - (ModTime) Long time of last modification (UTC/GMT) - (AcTime) Long time of last access (UTC/GMT) - (CrTime) Long time of original creation (UTC/GMT) - - Central-header version: - - Value Size Description - ----- ---- ----------- - (time) 0x5455 Short tag for this extra block type ("UT") - TSize Short total data size for this block - Flags Byte info bits (refers to local header!) - (ModTime) Long time of last modification (UTC/GMT) - - The central-header extra field contains the modification time only, - or no timestamp at all. TSize is used to flag its presence or - absence. But note: - - If "Flags" indicates that Modtime is present in the local header - field, it MUST be present in the central header field, too! - This correspondence is required because the modification time - value may be used to support trans-timezone freshening and - updating operations with zip archives. - - The time values are in standard Unix signed-long format, indicating - the number of seconds since 1 January 1970 00:00:00. The times - are relative to Coordinated Universal Time (UTC), also sometimes - referred to as Greenwich Mean Time (GMT). To convert to local time, - the software must know the local timezone offset from UTC/GMT. - - The lower three bits of Flags in both headers indicate which time- - stamps are present in the LOCAL extra field: - - bit 0 if set, modification time is present - bit 1 if set, access time is present - bit 2 if set, creation time is present - bits 3-7 reserved for additional timestamps; not set - - Those times that are present will appear in the order indicated, but - any combination of times may be omitted. (Creation time may be - present without access time, for example.) TSize should equal - (1 + 4*(number of set bits in Flags)), as the block is currently - defined. Other timestamps may be added in the future. - - - -Info-ZIP Unix Extra Field (type 1): - ================================== - - The following is the layout of the old Info-ZIP extra block for - Unix. It has been replaced by the extended-timestamp extra block - (0x5455) and the Unix type 2 extra block (0x7855). - (Last Revision 19970118) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (Unix1) 0x5855 Short tag for this extra block type ("UX") - TSize Short total data size for this block - AcTime Long time of last access (UTC/GMT) - ModTime Long time of last modification (UTC/GMT) - UID Short Unix user ID (optional) - GID Short Unix group ID (optional) - - Central-header version: - - Value Size Description - ----- ---- ----------- - (Unix1) 0x5855 Short tag for this extra block type ("UX") - TSize Short total data size for this block - AcTime Long time of last access (GMT/UTC) - ModTime Long time of last modification (GMT/UTC) - - The file access and modification times are in standard Unix signed- - long format, indicating the number of seconds since 1 January 1970 - 00:00:00. The times are relative to Coordinated Universal Time - (UTC), also sometimes referred to as Greenwich Mean Time (GMT). To - convert to local time, the software must know the local timezone - offset from UTC/GMT. The modification time may be used by non-Unix - systems to support inter-timezone freshening and updating of zip - archives. - - The local-header extra block may optionally contain UID and GID - info for the file. The local-header TSize value is the only - indication of this. Note that Unix UIDs and GIDs are usually - specific to a particular machine, and they generally require root - access to restore. - - This extra field type is obsolete, but it has been in use since - mid-1994. Therefore future archiving software should continue to - support it. Some guidelines: - - An archive member should either contain the old "Unix1" - extra field block or the new extra field types "time" and/or - "Unix2". - - If both the old "Unix1" block type and one or both of the new - block types "time" and "Unix2" are found, the "Unix1" block - should be considered invalid and ignored. - - Unarchiving software should recognize both old and new extra - field block types, but the info from new types overrides the - old "Unix1" field. - - Archiving software should recognize "Unix1" extra fields for - timestamp comparison but never create it for updated, freshened - or new archive members. When copying existing members to a new - archive, any "Unix1" extra field blocks should be converted to - the new "time" and/or "Unix2" types. - - - -Info-ZIP Unix Extra Field (type 2): - ================================== - - The following is the layout of the new Info-ZIP extra block for - Unix. (Last Revision 19960922) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (Unix2) 0x7855 Short tag for this extra block type ("Ux") - TSize Short total data size for this block (4) - UID Short Unix user ID - GID Short Unix group ID - - Central-header version: - - Value Size Description - ----- ---- ----------- - (Unix2) 0x7855 Short tag for this extra block type ("Ux") - TSize Short total data size for this block (0) - - The data size of the central-header version is zero; it is used - solely as a flag that UID/GID info is present in the local-header - extra field. If additional fields are ever added to the local - version, the central version may be extended to indicate this. - - Note that Unix UIDs and GIDs are usually specific to a particular - machine, and they generally require root access to restore. - - - -ASi Unix Extra Field: - ==================== - - The following is the layout of the ASi extra block for Unix. The - local-header and central-header versions are identical. - (Last Revision 19960916) - - Value Size Description - ----- ---- ----------- - (Unix3) 0x756e Short tag for this extra block type ("nu") - TSize Short total data size for this block - CRC Long CRC-32 of the remaining data - Mode Short file permissions - SizDev Long symlink'd size OR major/minor dev num - UID Short user ID - GID Short group ID - (var.) variable symbolic link filename - - Mode is the standard Unix st_mode field from struct stat, containing - user/group/other permissions, setuid/setgid and symlink info, etc. - - If Mode indicates that this file is a symbolic link, SizDev is the - size of the file to which the link points. Otherwise, if the file - is a device, SizDev contains the standard Unix st_rdev field from - struct stat (includes the major and minor numbers of the device). - SizDev is undefined in other cases. - - If Mode indicates that the file is a symbolic link, the final field - will be the name of the file to which the link points. The file- - name length can be inferred from TSize. - - [Note that TSize may incorrectly refer to the data size not counting - the CRC; i.e., it may be four bytes too small.] - - - -BeOS Extra Field: - ================ - - The following is the layout of the file-attributes extra block for - BeOS. (Last Revision 19970531) - - Local-header version: - - Value Size Description - ----- ---- ----------- - (BeOS) 0x6542 Short tag for this extra block type ("Be") - TSize Short total data size for this block - BSize Long uncompressed file attribute data size - Flags Byte info bits - (CType) Short compression type - (CRC) Long CRC value for uncompressed file attribs - Attribs variable file attribute data - - Central-header version: - - Value Size Description - ----- ---- ----------- - (BeOS) 0x6542 Short tag for this extra block type ("Be") - TSize Short total data size for this block (5) - BSize Long size of uncompr. local EF block data - Flags Byte info bits - - The least significant bit of Flags in both headers indicates whether - the LOCAL extra field is uncompressed (and therefore whether CType - and CRC are omitted): - - bit 0 if set, Attribs is uncompressed (no CType, CRC) - bits 1-7 reserved; if set, assume error or unknown data - - Currently the only supported compression types are deflated (type 8) - and stored (type 0); the latter is not used by Info-ZIP's Zip but is - supported by UnZip. - - Attribs is a BeOS-specific block of data in big-endian format with - the following structure (if compressed, uncompress it first): - - Value Size Description - ----- ---- ----------- - Name variable attribute name (null-terminated string) - Type Long attribute type (32-bit unsigned integer) - Size Long Long data size for this sub-block (64 bits) - Data variable attribute data - - The attribute structure is repeated for every attribute. The Data - field may contain anything--text, flags, bitmaps, etc. - - - -SMS/QDOS Extra Field: - ==================== - - The following is the layout of the file-attributes extra block for - SMS/QDOS. The local-header and central-header versions are identical. - (Last Revision 19960929) - - Value Size Description - ----- ---- ----------- - (QDOS) 0xfb4a Short tag for this extra block type - TSize Short total data size for this block - LongID Long extra-field signature - (ExtraID) Long additional signature/flag bytes - QDirect 64 bytes qdirect structure - - LongID may be "QZHD" or "QDOS". In the latter case, ExtraID will - be present. Its first three bytes are "02\0"; the last byte is - currently undefined. - - QDirect contains the file's uncompressed directory info (qdirect - struct). Its elements are in native (big-endian) format: - - d_length beLong file length - d_access byte file access type - d_type byte file type - d_datalen beLong data length - d_reserved beLong unused - d_szname beShort size of filename - d_name 36 bytes filename - d_update beLong time of last update - d_refdate beLong file version number - d_backup beLong time of last backup (archive date) - - - -AOS/VS Extra Field: - ================== - - The following is the layout of the extra block for Data General - AOS/VS. The local-header and central-header versions are identical. - (Last Revision 19961125) - - Value Size Description - ----- ---- ----------- - (AOSVS) 0x5356 Short tag for this extra block type ("VS") - TSize Short total data size for this block - "FCI\0" Long extra-field signature - Version Byte version of AOS/VS extra block (10 = 1.0) - Fstat variable fstat packet - AclBuf variable raw ACL data ($MXACL bytes) - - Fstat contains the file's uncompressed fstat packet, which is one of - the following: - - normal fstat packet (P_FSTAT struct) - DIR/CPD fstat packet (P_FSTAT_DIR struct) - unit (device) fstat packet (P_FSTAT_UNIT struct) - IPC file fstat packet (P_FSTAT_IPC struct) - - AclBuf contains the raw ACL data; its length is $MXACL. - - - -Tandem NSK Extra Field: - ====================== - - The following is the layout of the file-attributes extra block for - Tandem NSK. The local-header and central-header versions are - identical. (Last Revision 19981221) - - Value Size Description - ----- ---- ----------- - (TA) 0x4154 Short tag for this extra block type ("TA") - TSize Short total data size for this block (20) - NSKattrs 20 Bytes NSK attributes - - - -THEOS Extra Field: - ================= - - The following is the layout of the file-attributes extra block for - Theos. The local-header and central-header versions are identical. - (Last Revision 19990206) - - Value Size Description - ----- ---- ----------- - (Theos) 0x6854 Short 'Th' signature - size Short size of extra block - flags Byte reserved for future use - filesize Long file size - fileorg Byte type of file (see below) - keylen Short key length for indexed and keyed files, - data segment size for 16 bits programs - reclen Short record length for indexed,keyed and direct, - text segment size for 16 bits programs - filegrow Byte growing factor for indexed,keyed and direct - protect Byte protections (see below) - reserved Short reserved for future use - - File types - ========== - - 0x80 library (keyed access list of files) - 0x40 directory - 0x10 stream file - 0x08 direct file - 0x04 keyed file - 0x02 indexed file - 0x0e reserved - 0x01 16 bits real mode program (obsolete) - 0x21 16 bits protected mode program - 0x41 32 bits protected mode program - - Protection codes - ================ - - User protection - --------------- - 0x01 non readable - 0x02 non writable - 0x04 non executable - 0x08 non erasable - - Other protection - ---------------- - 0x10 non readable - 0x20 non writable - 0x40 non executable Theos before 4.0 - 0x40 modified Theos 4.x - 0x80 not hidden - - - -THEOS old inofficial Extra Field: - ================================ - - The following is the layout of an inoffical former version of a - Theos file-attributes extra blocks. This layout was never published - and is no longer created. However, UnZip can optionally support it - when compiling with the option flag OLD_THEOS_EXTRA defined. - Both the local-header and central-header versions are identical. - (Last Revision 19990206) - - Value Size Description - ----- ---- ----------- - (THS0) 0x4854 Short 'TH' signature - size Short size of extra block - flags Short reserved for future use - filesize Long file size - reclen Short record length for indexed,keyed and direct, - text segment size for 16 bits programs - keylen Short key length for indexed and keyed files, - data segment size for 16 bits programs - filegrow Byte growing factor for indexed,keyed and direct - reserved 3 Bytes reserved for future use - - - -FWKCS MD5 Extra Field: - ===================== - - The FWKCS Contents_Signature System, used in automatically - identifying files independent of filename, optionally adds - and uses an extra field to support the rapid creation of - an enhanced contents_signature. - There is no local-header version; the following applies - only to the central header. (Last Revision 19961207) - - Central-header version: - - Value Size Description - ----- ---- ----------- - (MD5) 0x4b46 Short tag for this extra block type ("FK") - TSize Short total data size for this block (19) - "MD5" 3 bytes extra-field signature - MD5hash 16 bytes 128-bit MD5 hash of uncompressed data - (low byte first) - - When FWKCS revises a .ZIP file central directory to add - this extra field for a file, it also replaces the - central directory entry for that file's uncompressed - file length with a measured value. - - FWKCS provides an option to strip this extra field, if - present, from a .ZIP file central directory. In adding - this extra field, FWKCS preserves .ZIP file Authenticity - Verification; if stripping this extra field, FWKCS - preserves all versions of AV through PKZIP version 2.04g. - - FWKCS, and FWKCS Contents_Signature System, are - trademarks of Frederick W. Kantor. - - (1) R. Rivest, RFC1321.TXT, MIT Laboratory for Computer - Science and RSA Data Security, Inc., April 1992. - ll.76-77: "The MD5 algorithm is being placed in the - public domain for review and possible adoption as a - standard." diff --git a/minizip-ng/doc/zip/winzip_aes.md b/minizip-ng/doc/zip/winzip_aes.md deleted file mode 100644 index e9afdb3..0000000 --- a/minizip-ng/doc/zip/winzip_aes.md +++ /dev/null @@ -1,261 +0,0 @@ - -# AES Encryption Information: -Encryption Specification AE-1 and AE-2 - -**Document version: 1.04 -Last modified: January 30, 2009** - -**NOTE: WinZipŽ users do not need to read or understand the information contained on this page. It is intended for developers of Zip file utilities.** - -Changes since the original version of this document are summarized in the [Change History](https://www.winzip.com/aes_info.htm#changes) section below. - -This document describes the file format that WinZip uses to create [AES-encrypted Zip files](https://www.winzip.com/learn/aes-encryption.html). The AE-1 encryption specification was introduced in WinZip 9.0 Beta 1, released in May 2003. The AE-2 encryption specification, a minor variant of the original AE-1 specification differing only in how the CRC is handled, was introduced in WinZip 9.0 Beta 3, released in January, 2004. Note that as of WinZip 11, WinZip itself encrypts most files using the AE-1 format and encrypts others using the AE-2 format. - -From time to time we may update the information provided here, for example to document any changes to the file formats, or to add additional notes or implementation tips. If you would like to receive e-mail announcements of any substantive changes we make to this document, you can [sign up below](https://www.winzip.com/aes_info.htm#mailing-list)for our Developer Information mailing list. - -Without compromising the basic Zip file format, WinZip Computing has extended the format specification to support AES encryption, and this document fully describes the format extension. Additionally, we are providing information about a no-cost third-party source for the actual AES encryption code--the same code that is used by WinZip. We believe that use of the free encryption code and of this specification will make it easy for all developers to add compatible advanced encryption to their Zip file utilities. - -This document is not a tutorial on encryption or Zip file structure. While we have attempted to provide the necessary details of the current WinZip AES encryption format, developers and other interested third parties will need to have or obtain an understanding of basic encryption concepts, Zip file format, etc. - -Developers should also review [AES Coding Tips](https://www.winzip.com/aes_tips.html) page. - -WinZip Computing makes no warranties regarding the information provided in this document. In particular, WinZip Computing does not represent or warrant that the information provided here is free from errors or is suitable for any particular use, or that the file formats described here will be supported in future versions of WinZip. You should test and validate all code and techniques in accordance with good programming practice. - ----------- - -**I. Encryption services** - -To perform AES encryption and decryption, WinZip uses AES functions written by Dr. Brian Gladman. The source code for these functions is available in C/C++ and Pentium family assembler for anyone to use under an open source BSD or GPL license from [the AES project page](https://www.winzip.com/gladman.cgi) on Dr. Gladman's web site. The [AES Coding Tips](https://www.winzip.com/aes_tips.html) page also has some information on the use of these functions. WinZip Computing thanks Dr. Gladman for making his AES functions available to anyone under liberal license terms. - -Dr. Gladman's encryption functions are portable to a number of operating systems and can be static linked into your applications, so there are no operating system version or library dependencies. In particular, the functions do not require Microsoft's Cryptography API. - -General information on the AES standard and the encryption algorithm (also known as _Rijndael_) is readily available on the Internet. A good place to start is [https://web.archive.org/web/20100407101917/www.nist.gov/public_affairs/releases/g00-176.htm](https://web.archive.org/web/20100407101917/www.nist.gov/public_affairs/releases/g00-176.htm). - -**II. Zip file format** - -1. Base format reference - - AES-encrypted files are stored within the guidelines of the standard Zip file format using only a new "extra data" field, a new compression method code, and a value in the CRC field dependant on the encryption version, AE-1 or AE-2. The basic Zip file format is otherwise unchanged. - - WinZip sets the version needed to extract and version made by fields in the local and central headers to the same values it would use if the file were not encrypted. - - The basic Zip file format specification used by WinZip is available via FTP from the Info-ZIP group at [https://infozip.sourceforge.io/doc/appnote-iz-latest.zip](https://infozip.sourceforge.io/doc/appnote-iz-latest.zip). - -2. Compression method and encryption flag - - As for any encrypted file, bit 0 of the "general purpose bit flags" field must be set to 1 in each AES-encrypted file's local header and central directory entry. - - Additionally, the presence of an AES-encrypted file in a Zip file is indicated by a new compression method code (decimal 99) in the file's local header and central directory entry, used along with the AES extra data field described below. There is no change in either the _version made by_ or _version needed to extract_ codes. - - The code for the actual compression method is stored in the AES extra data field (see below). - -3. CRC value - - For files encrypted using the AE-2 method, the standard Zip CRC value is _not_ used, and a 0 must be stored in this field. Corruption of encrypted data within a Zip file is instead detected via the [authentication code](https://www.winzip.com/aes_info.htm#authentication-code) field. - - Files encrypted using the AE-1 method _do_ include the standard Zip CRC value. This, along with the fact that the vendor version stored in the AES extra data field is 0x0001 for AE-1 and 0x0002 for AE-2, is the only difference between the AE-1 and AE-2 formats. - - **NOTE:** Zip utilities that support the AE-2 format are required to be able to read files that were created in the AE-1 format, and during decryption/extraction of files in AE-1 format should verify that the file's CRC matches the value stored in the CRC field. - -4. AES extra data field - 1. A file encrypted with AES encryption will have a special "extra data" field associated with it. This extra data field is stored in both the local header and central directory entry for the file. - - Note: see the Zip file format document referenced above for general information on the format and use of extra data fields. - - 2. The extra data header ID for AES encryption is 0x9901. The fields are all stored in Intel low-byte/high-byte order. The extra data field currently has a length of 11: seven data bytes plus two bytes for the header ID and two bytes for the data size. Therefore, the extra data overhead for each file in the archive is 22 bytes (11 bytes in the central header plus 11 bytes in the local header). - 3. The format of the data in the AES extra data field is as follows. See the notes below for additional information. - - |**Offset**|**Size(bytes)**|**Content**| - |:-|:-|:-| - |0|2|Extra field header ID (0x9901)| - |2|2|Data size (currently 7, but subject to possible increase in the future)| - |4|2|Integer version number specific to the zip vendor| - |6|2|2-character vendor ID| - |8|1|Integer mode value indicating AES encryption strength| - |9|2|The actual compression method used to compress the file| - - 4. Notes - - **Data size**: this value is currently 7, but because it is possible that this specification will be modified in the future to store additional data in this extra field, vendors should not assume that it will always remain 7. - - **Vendor ID**: the vendor ID field should always be set to the two ASCII characters "AE". - - **Vendor version**: the vendor version for AE-1 is 0x0001. The vendor version for AE-2 is 0x0002. - - Zip utilities that support AE-2 must also be able to process files that are encrypted in AE-1 format. The handling of the [CRC value](https://www.winzip.com/aes_info.htm#CRC) is the only difference between the AE-1 and AE-2 formats. - - - **Encryption strength**: the mode values (encryption strength) for AE-1 and AE-2 are: - - |**Value**|**Strength**| - |-|-| - |0x01|128-bit encryption key| - |0x02|192-bit encryption key| - |0x03|256-bit encryption key| - - The encryption specification supports _only_ 128-, 192-, and 256-bit encryption keys. No other key lengths are permitted. - - (Note: the current version of WinZip does not support encrypting files using 192-bit keys. This specification, however, does provide for the use of 192-bit keys, and WinZip is able to decrypt such files.) - - - **Compression method**: the compression method is the one that would otherwise have been stored in the local and central headers for the file. For example, if the file is imploded, this field will contain the compression code 6. This is needed because a compression method of 99 is used to indicate the presence of an AES-encrypted file (see [above](https://www.winzip.com/aes_info.htm#comp-method)). - -**III. Encrypted file storage format** - -1. File format - - Additional overhead data required for decryption is stored with the encrypted file itself (i.e., not in the headers). The actual format of the stored file is as follows; additional information about these fields is below. All fields are byte-aligned. - - |**Size (bytes)**|**Content**| - |:-|:-| - |Variable|Salt value| - |2|Password verification value| - |Variable|Encrypted file data| - |10|Authentication code| - - Note that the value in the "compressed size" fields of the local file header and the central directory entry is the total size of all the items listed above. In other words, it is the total size of the salt value, password verification value, encrypted data, and authentication code. - -2. Salt value - - The "salt" or "salt value" is a random or pseudo-random sequence of bytes that is combined with the encryption password to create encryption and authentication keys. The salt is generated by the encrypting application and is stored unencrypted with the file data. The addition of salt values to passwords provides a number of security benefits and makes dictionary attacks based on precomputed keys much more difficult. - - Good cryptographic practice requires that a different salt value be used for each of multiple files encrypted with the same password. If two files are encrypted with the same password and salt, they can leak information about each other. For example, it is possible to determine whether two files encrypted with the same password and salt are identical, and an attacker who somehow already knows the contents of one of two files encrypted with the same password and salt can determine some or all of the contents of the other file. Therefore, you should make every effort to use a unique salt value for each file. - - The size of the salt value depends on the length of the encryption key, as follows: - - |**Key size**|**Salt size**| - |:-|:-| - |128 bits|8 bytes| - |192 bits|12 bytes| - |256 bits|16 bytes| - -3. Password verification value - - This two-byte value is produced as part of the process that derives the encryption and decryption keys from the password. When encrypting, a verification value is derived from the encryption password and stored with the encrypted file. Before decrypting, a verification value can be derived from the decryption password and compared to the value stored with the file, serving as a quick check that will detect _most_, but not all, incorrect passwords. There is a 1 in 65,536 chance that an incorrect password will yield a matching verification value; therefore, a matching verification value cannot be absolutely relied on to indicate a correct password. - - Information on how to obtain the password verification value from Dr. Gladman's encryption library can be found on the [coding tips](https://www.winzip.com/aes_tips.html) page. - - This value is stored unencrypted. - -4. Encrypted file data - - Encryption is applied only to the content of files. It is performed after compression, and not to any other associated data. The file data is encrypted byte-for-byte using the AES encryption algorithm operating in "CTR" mode, which means that the lengths of the compressed data and the compressed, encrypted data are the same. - - It is important for implementors to note that, although the data is encrypted byte-for-byte, it is presented to the encryption and decryption functions in blocks. The block size used for encryption and decryption must be the same. To be compatible with the encryption specification, this block size must be 16 bytes (although the last block may be smaller). - -5. Authentication code - - Authentication provides a high quality check that the contents of an encrypted file have not been inadvertently changed or deliberately tampered with since they were first encrypted. In effect, this is a super-CRC check on the data in the file _after_ compression and encryption. (Additionally, authentication is essential when using CTR mode encryption because this mode is vulnerable to several trivial attacks in its absence.) - - The authentication code is derived from the output of the encryption process. [Dr. Gladman's AES code](https://www.winzip.com/aes_info.htm#encryption) provides this service, and information about how to obtain it is in the [coding tips](https://www.winzip.com/aes_tips.html). - - The authentication code is stored unencrypted. It is byte-aligned and immediately follows the last byte of encrypted data. - - For more discussion about authentication, see the [authentication code FAQ](https://www.winzip.com/aes_info.htm#auth-faq) below. - - -**IV. Changes in WinZip 11** - -Beginning with WinZip 11, WinZip makes a change in its use of the AE-1 and AE-2 file formats. The file formats themselves have not changed, and AES-encrypted files created by WinZip 11 are completely compatible with version 1.02 the WinZip AES encryption specification, which was published in January 2004. - -[WinZip 9.0](https://www.winzip.com/win/en/winzip-9.html) and [WinZip 10.0](https://www.winzip.com/win/en/winzip-10.html) stored all AES-encrypted files using the AE-2 file format, which does not store the encrypted file's CRC. WinZip 11 instead uses the AE-1 file format, which does store the CRC, for most files. This provides an extra integrity check against the possibility of hardware or software errors that occur during the actual process of [file compression/encryption](https://www.winzip.com/win/en/features/data-protection.html) or decryption/decompression. For more information on this point, see the discussion of the [CRC](https://www.winzip.com/aes_info.htm#crc-faq) below. - -Because for some very small files the CRC can be used to determine the exact contents of a file, regardless of the encryption method used, WinZip 11 continues to use the AE-2 file format, with no CRC stored, for files with an uncompressed size of less than 20 bytes. WinZip 11 also uses the AE-2 file format for files compressed in BZIP2 format, because the BZIP2 format contains its own integrity checks equivalent to those provided by the Zip format's CRC. - -Other vendors who support WinZip's AES encryption specification may want to consider making a similar change to their own implementations of the specification, to get the benefit of the extra integrity check that it provides. - -Note that the January 2004 version of the WinZip AE-2 specification, version 1.0.2, already required that all utilities that implemented the AE-2 format also be able to process files in AE-1 format, and should check on decryption/extraction of those files that the CRC was correct. - -**V. Notes** - -1. Non-files and zero-length files - - To reduce Zip file size, it is recommended that non-file entries such as folder/directory entries not be encrypted. This, however, is only a recommendation; it is permissible to encrypt or not encrypt these entries, as you prefer. - - On the other hand, it is recommended that you _do_ encrypt zero-length files. The presence of both encrypted and unencrypted files in a Zip file may trigger user warnings in some Zip file utilities, so the user experience may be improved if all files (including zero-length files) are encrypted. - - If zero-length files are encrypted, the encrypted data portion of the file storage (see [above](https://www.winzip.com/aes_info.htm#encrypted-data)) will be empty, but the remainder of the encryption overhead data must be present, both in the file storage area and in the local and central headers. - -2. "Mixed" Zip files - - There is no requirement that all files in a Zip file be encrypted or that all files that _are_ encrypted use the same encryption method or the same password. - - A Zip file can contain any combination of unencrypted files and files encrypted with any of the four currently defined encryption methods (Zip 2.0, AES-128, AES-192, AES-256). Encrypted files may use the same password or different passwords. - -3. Key Generation - - Key derivation, as used by AE-1 and AE-2 and as implemented in Dr. Gladman's library, is done according to the PBKDF2 algorithm, which is described in the [RFC2898](https://www.ietf.org/rfc/rfc2898.txt) guidelines. An iteration count of 1000 is used. An appropriate number of bits from the resulting hash value are used to compose three output values: an encryption key, an authentication key, and a password verification value. The first _n_ bits become the encryption key, the next _m_ bits become the authentication key, and the last 16 bits (two bytes) become the password verification value. - - As part of the process outlined in RFC 2898 a pseudo-random function must be called; AE-2 uses the HMAC-SHA1 function, since it is a well-respected algorithm that has been in wide use for this purpose for several years. - - Note that, when used in connection with 192- or 256-bit AES encryption, the fact that HMAC-SHA1 produces a 160-bit result means that, regardless of the password that you specify, the search space for the encryption key is unlikely to reach the theoretical 192- or 256-bit maximum, and cannot be guaranteed to exceed 160 bits. This is discussed in section B.1.1 of the [RFC2898 specification](https://www.ietf.org/rfc/rfc2898.txt). - - -**VI. FAQs** - -- **Why is the compression method field used to indicate AES encryption?** - - As opposed to using new _version made by_ and _version needed to extract_ values to signal AES encryption for a file, the new compression method is more likely to be handled gracefully by older versions of existing Zip file utilities. Zip file utilities typically do not attempt to extract files compressed with unknown methods, presumably notifying the user with an appropriate message. - -- **How can I guarantee that the salt value is unique?** - - In principle, the value of the salt should be different whenever the same password is used more than once, for the reasons described [above](https://www.winzip.com/aes_info.htm#salt), but this is difficult to guarantee. - - In practice, the number of bytes in the salt (as specified by AE-1 and AE-2) is such that using a pseudo-random value will ensure that the probability of duplicated salt values is very low and can be safely ignored. - - There is one exception to this: With the 8-byte salt values used with WinZip's 128-bit encryption it is likely that, if approximately 4 billion files are encrypted with the same password, two of the files will have the same salt, so it is advisable to stay well below this limit. Because of this, when using the same password to encrypt very large numbers of files in WinZip's AES encryption format (that is, files totalling in the millions, for example 2000 Zip files, each containing 1000 encrypted files), we recommend the use of 192-bit or 256-bit AES keys, with their 12- and 16-byte salt values, rather than 128-bit AES keys, with their 8-byte salt values. - - Although salt values do not need to be truly random, it is important that they be generated in a way that the probability of duplicated salt values is not significantly higher than that which would be expected if truly random values were being used. - - One technique for generating salt values is presented in the [coding tips](https://www.winzip.com/aes_tips.html#prng) page. - -- **Why is there an authentication code?** - - The purpose of the authentication code is to insure that, once a file's data has been compressed and encrypted, any accidental corruption of the encrypted data, and any deliberate attempts to modify the encrypted data by an attacker who does not know the password, can be detected. - - The current consensus in the cryptographic community is that associating a message authentication code (or MAC) with encrypted data has strong security value because it makes a number of attacks more difficult to engineer. For AES CTR mode encryption in particular, a MAC is especially important because a number of trivial attacks are possible in its absence. The MAC used with WinZip's AES encryption is based on[HMAC-SHA1-80](https://www.ietf.org/rfc/rfc2104.txt), a mature and widely respected authentication algorithm. - - The MAC is calculated after the file data has been compressed and encrypted. This order of calculation is referred to as Encrypt-then-MAC, and is preferred by many cryptographers to the alternative order of MAC-then-Encrypt because Encrypt-then-MAC is immune to some known attacks on MAC-then-Encrypt. - -- **What is the role of the CRC in WinZip 11?** - - Within the Zip format, the primary use of the CRC value is to detect accidental corruption of data that has been stored in the Zip file. With files encrypted according to the Zip 2.0 encryption specification, it also functions to some extent as a method of detecting deliberate attempts to modify the encrypted data, but not one that can be considered cryptographically strong. The CRC is not needed for these purposes with the WinZip AES encryption specification, where the HMAC-SHA1-based authentication code instead serves these roles. - - The CRC has a drawback in that for very small files, such as files with four or fewer bytes, the CRC can be used, independent of the encryption algorithm, to determine the unencrypted contents of the file. And, in general, it is preferable to store as little information as possible about the encrypted file in the unencrypted Zip headers. - - The CRC does serve one purpose that the authentication code does not. The CRC is computed based on the original uncompressed, unencrypted contents of the file, and it is checked after the file has been decrypted and decompressed. In contrast, the authentication code used with WinZip AES encryption is computed after compression/encryption and it is checked before decryption/decompression. In the very rare event of a hardware or software error that corrupts data during compression and encryption, or during decryption and decompression, the CRC will catch the error, but the authentication code will not. - - WinZip 9.0 and WinZip 10.0 used AE-2 for all files that they created, and did not store the CRC. As of WinZip 11, WinZip instead uses AE-1 for most files, storing the CRC as an additional integrity check against hardware or software errors occurring during the actual compression/encryption or decryption/decompression processes. WinZip 11 will continue to use AE-2, with no CRC, for very small files of less than 20 bytes. It will also use AE-2 for files compressed in BZIP2 format, because this format has internal integrity checks equivalent to a CRC check built in. - - Note that the AES-encrypted files created by WinZip 11 are fully compatible with January 2004's version 1.0.2 of the WinZip AES encryption specification, in which both the AE-1 and AE-2 variants of the file format were already defined. - - -**VII. Change history** - -**Changes made in document version 1.04, January, 2009:** Minor clarification regarding the algorithm used to generate the authentication code. - -**Changes made in document version 1.03, November, 2006:** Minor editorial and clarifying changes have been made throughout the document. The following substantive technical changes have been made: - -1. WinZip 11 Usage of AE-1 and AE-2 - - WinZip's AES encryption specification defines two formats, known as AE-1 and AE-2, which differ in whether the CRC of the encrypted file is stored in the Zip headers. While the file formats themselves remain unchanged, WinZip's usage of them is changing. Beginning with [WinZip 11](https://www.winzip.com/aes_info.htm#winzip11), WinZip uses the AE-1 format, which includes the CRC of the encrypted file, for many encrypted files, in order to provide an additional integrity check against hardware or software errors occurring during the compression/encryption or decryption/decompression processes. Note that AES-encrypted files created by WinZip 11 are completely compatible with the previous version of the WinZip encryption specification, January 2004's version 1.0.2. - -2. The discussion of [salt values](https://www.winzip.com/aes_info.htm#salt) mentions a limitation that applies to the uniqueness of salt values when very large numbers of files are encrypted with 128-bit encryption. -3. Older versions of this specification suggested that other vendors might want to use their own vendor IDs to create their own unique encryption formats. We no longer suggest that vendor-specific alternative encryption methods be created in this way. - -**Changes made in document version 1.02, January, 2004:** The introductory text at the start of the document has been rewritten, and minor editorial and clarifying changes have been made throughout the document. Two substantive technical changes have been made: - -1. AE-2 Specification - - Standard Zip files store the CRC of each file's unencrypted data. This value is used to help detect damage or other alterations to Zip files. However, storing the CRC value has a drawback in that, for a very small file, such as a file of four or fewer bytes, the CRC value can be used, independent of the encryption algorithm, to help determine the unencrypted contents of the file. - - Because of this, files encrypted with the new AE-2 method store a 0 in the CRC field of the Zip header, and use the [authentication code](https://www.winzip.com/aes_info.htm#authentication-code) instead of the CRC value to verify that encrypted data within the Zip file has not been corrupted. - - The only differences between the AE-1 and AE-2 methods are the storage in AE-2 of 0 instead of the CRC in the Zip file header,and the use in the AES extra data field of 0x0002 for AE-2 instead of 0x0001 for AE-1 as the vendor version. - - Zip utilities that support the AE-2 format are required to be able to read files that were created in the AE-1 format, and during decryption/extraction of files in AE-1 format should verify that the file's CRC matches the value stored in the CRC field. - -2. Key Generation and HMAC-SHA1 - - The description of the [key generation](https://www.winzip.com/aes_info.htm#key-generation) mechanism has been updated to point out a limitation arising from its use of HMAC-SHA1 as the pseudo-random function: When used in connection with 192- or 256-bit AES encryption, the fact that HMAC-SHA1 produces a 160-bit result means that, regardless of the password that you specify, the search space for the encryption key is unlikely to reach the theoretical 192- or 256-bit maximum, and cannot be guaranteed to exceed 160 bits. This is discussed in section B.1.1 of the [RFC2898 specification](https://www.ietf.org/rfc/rfc2898.txt). - -Document version: 1.04 -Last modified: January 30, 2009 - -CopyrightŠ 2003-2018 Corel Corporation. -All Rights Reserved diff --git a/minizip-ng/minigzip.c b/minizip-ng/minigzip.c deleted file mode 100644 index 0bd8c79..0000000 --- a/minizip-ng/minigzip.c +++ /dev/null @@ -1,182 +0,0 @@ -/* 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 /* 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/minizip-ng/minizip.c b/minizip-ng/minizip.c deleted file mode 100644 index 01bb559..0000000 --- a/minizip-ng/minizip.c +++ /dev/null @@ -1,671 +0,0 @@ -/* 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 /* 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/minizip-ng/minizip.pc.cmakein b/minizip-ng/minizip.pc.cmakein deleted file mode 100644 index 3e7c3f1..0000000 --- a/minizip-ng/minizip.pc.cmakein +++ /dev/null @@ -1,14 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=@CMAKE_INSTALL_PREFIX@ -libdir=@INSTALL_LIB_DIR@ -sharedlibdir=@INSTALL_LIB_DIR@ -includedir=@INSTALL_INC_DIR@ - -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/minizip-ng/mz.h b/minizip-ng/mz.h deleted file mode 100644 index 88ca47d..0000000 --- a/minizip-ng/mz.h +++ /dev/null @@ -1,274 +0,0 @@ -/* 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.2") -#define MZ_VERSION_BUILD (030002) - -/* 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 /* size_t, NULL, malloc */ -#include /* time_t, time() */ -#include /* memset, strncpy, strlen */ -#include - -#if defined(HAVE_STDINT_H) -# include -#elif defined(__has_include) -# if __has_include() -# include -# endif -#endif - -#ifndef __INT8_TYPE__ -typedef signed char int8_t; -#endif -#ifndef __INT16_TYPE__ -typedef short int16_t; -#endif -#ifndef __INT32_TYPE__ -typedef int int32_t; -#endif -#ifndef __INT64_TYPE__ -typedef long long int64_t; -#endif -#ifndef __UINT8_TYPE__ -typedef unsigned char uint8_t; -#endif -#ifndef __UINT16_TYPE__ -typedef unsigned short uint16_t; -#endif -#ifndef __UINT32_TYPE__ -typedef unsigned int uint32_t; -#endif -#ifndef __UINT64_TYPE__ -typedef unsigned long long uint64_t; -#endif - -#if defined(HAVE_INTTYPES_H) -# include -#elif defined(__has_include) -# if __has_include() -# include -# 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/minizip-ng/mz_compat.c b/minizip-ng/mz_compat.c deleted file mode 100644 index 5a08046..0000000 --- a/minizip-ng/mz_compat.c +++ /dev/null @@ -1,1303 +0,0 @@ -/* 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 /* 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/minizip-ng/mz_compat.h b/minizip-ng/mz_compat.h deleted file mode 100644 index 808cc74..0000000 --- a/minizip-ng/mz_compat.h +++ /dev/null @@ -1,396 +0,0 @@ -/* 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/minizip-ng/mz_crypt.c b/minizip-ng/mz_crypt.c deleted file mode 100644 index dd2cd42..0000000 --- a/minizip-ng/mz_crypt.c +++ /dev/null @@ -1,196 +0,0 @@ -/* 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/minizip-ng/mz_crypt.h b/minizip-ng/mz_crypt.h deleted file mode 100644 index 59a193c..0000000 --- a/minizip-ng/mz_crypt.h +++ /dev/null @@ -1,65 +0,0 @@ -/* 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/minizip-ng/mz_crypt_apple.c b/minizip-ng/mz_crypt_apple.c deleted file mode 100644 index 4519753..0000000 --- a/minizip-ng/mz_crypt_apple.c +++ /dev/null @@ -1,487 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include - -/***************************************************************************/ - -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/minizip-ng/mz_crypt_openssl.c b/minizip-ng/mz_crypt_openssl.c deleted file mode 100644 index e0db8d7..0000000 --- a/minizip-ng/mz_crypt_openssl.c +++ /dev/null @@ -1,629 +0,0 @@ -/* 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 -#include -#include -#include -#include -#include -#include -#include -#include - -/***************************************************************************/ - -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/minizip-ng/mz_crypt_win32.c b/minizip-ng/mz_crypt_win32.c deleted file mode 100644 index 6ec6a84..0000000 --- a/minizip-ng/mz_crypt_win32.c +++ /dev/null @@ -1,739 +0,0 @@ -/* 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 -#include - -/***************************************************************************/ - -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(×tamp_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/minizip-ng/mz_os.c b/minizip-ng/mz_os.c deleted file mode 100644 index f96befe..0000000 --- a/minizip-ng/mz_os.c +++ /dev/null @@ -1,354 +0,0 @@ -/* 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 /* 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/minizip-ng/mz_os.h b/minizip-ng/mz_os.h deleted file mode 100644 index b3e2a58..0000000 --- a/minizip-ng/mz_os.h +++ /dev/null @@ -1,175 +0,0 @@ -/* 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 -#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/minizip-ng/mz_os_posix.c b/minizip-ng/mz_os_posix.c deleted file mode 100644 index 576943d..0000000 --- a/minizip-ng/mz_os_posix.c +++ /dev/null @@ -1,367 +0,0 @@ -/* 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 /* rename */ -#include -#if defined(HAVE_ICONV) -#include -#endif - -#include -#include - -#ifndef _WIN32 -# include -# include -#endif -#if defined(__APPLE__) -# include -# include -#endif - -#if defined(HAVE_GETRANDOM) -# include -#endif -#if defined(HAVE_LIBBSD) -# include -# ifndef __u_char_defined - typedef unsigned char u_char; -# endif -# include /* 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/minizip-ng/mz_os_win32.c b/minizip-ng/mz_os_win32.c deleted file mode 100644 index 7effef7..0000000 --- a/minizip-ng/mz_os_win32.c +++ /dev/null @@ -1,658 +0,0 @@ -/* 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 - -/***************************************************************************/ - -#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/minizip-ng/mz_strm.c b/minizip-ng/mz_strm.c deleted file mode 100644 index da7d587..0000000 --- a/minizip-ng/mz_strm.c +++ /dev/null @@ -1,560 +0,0 @@ -/* 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/minizip-ng/mz_strm.h b/minizip-ng/mz_strm.h deleted file mode 100644 index 8b0027c..0000000 --- a/minizip-ng/mz_strm.h +++ /dev/null @@ -1,132 +0,0 @@ -/* 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/minizip-ng/mz_strm_buf.c b/minizip-ng/mz_strm_buf.c deleted file mode 100644 index 1dfdfdf..0000000 --- a/minizip-ng/mz_strm_buf.c +++ /dev/null @@ -1,385 +0,0 @@ -/* 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/minizip-ng/mz_strm_buf.h b/minizip-ng/mz_strm_buf.h deleted file mode 100644 index b71e6e4..0000000 --- a/minizip-ng/mz_strm_buf.h +++ /dev/null @@ -1,42 +0,0 @@ -/* 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/minizip-ng/mz_strm_bzip.c b/minizip-ng/mz_strm_bzip.c deleted file mode 100644 index 31d8bf9..0000000 --- a/minizip-ng/mz_strm_bzip.c +++ /dev/null @@ -1,374 +0,0 @@ -/* 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/minizip-ng/mz_strm_bzip.h b/minizip-ng/mz_strm_bzip.h deleted file mode 100644 index 71b2b38..0000000 --- a/minizip-ng/mz_strm_bzip.h +++ /dev/null @@ -1,45 +0,0 @@ -/* 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/minizip-ng/mz_strm_libcomp.c b/minizip-ng/mz_strm_libcomp.c deleted file mode 100644 index 27eb933..0000000 --- a/minizip-ng/mz_strm_libcomp.c +++ /dev/null @@ -1,356 +0,0 @@ -/* 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 - -/***************************************************************************/ - -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/minizip-ng/mz_strm_libcomp.h b/minizip-ng/mz_strm_libcomp.h deleted file mode 100644 index 5c3fee8..0000000 --- a/minizip-ng/mz_strm_libcomp.h +++ /dev/null @@ -1,45 +0,0 @@ -/* 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 - -#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/minizip-ng/mz_strm_lzma.c b/minizip-ng/mz_strm_lzma.c deleted file mode 100644 index 22fb972..0000000 --- a/minizip-ng/mz_strm_lzma.c +++ /dev/null @@ -1,470 +0,0 @@ -/* 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/minizip-ng/mz_strm_lzma.h b/minizip-ng/mz_strm_lzma.h deleted file mode 100644 index f447baa..0000000 --- a/minizip-ng/mz_strm_lzma.h +++ /dev/null @@ -1,43 +0,0 @@ -/* 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/minizip-ng/mz_strm_mem.c b/minizip-ng/mz_strm_mem.c deleted file mode 100644 index f4a882d..0000000 --- a/minizip-ng/mz_strm_mem.c +++ /dev/null @@ -1,272 +0,0 @@ -/* 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/minizip-ng/mz_strm_mem.h b/minizip-ng/mz_strm_mem.h deleted file mode 100644 index 5bfa13d..0000000 --- a/minizip-ng/mz_strm_mem.h +++ /dev/null @@ -1,48 +0,0 @@ -/* 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/minizip-ng/mz_strm_os.h b/minizip-ng/mz_strm_os.h deleted file mode 100644 index 614e255..0000000 --- a/minizip-ng/mz_strm_os.h +++ /dev/null @@ -1,40 +0,0 @@ -/* 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/minizip-ng/mz_strm_os_posix.c b/minizip-ng/mz_strm_os_posix.c deleted file mode 100644 index f0b5bd3..0000000 --- a/minizip-ng/mz_strm_os_posix.c +++ /dev/null @@ -1,206 +0,0 @@ -/* 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 /* fopen, fread.. */ -#include - -/***************************************************************************/ - -#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/minizip-ng/mz_strm_os_win32.c b/minizip-ng/mz_strm_os_win32.c deleted file mode 100644 index 893df54..0000000 --- a/minizip-ng/mz_strm_os_win32.c +++ /dev/null @@ -1,296 +0,0 @@ -/* 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 - -/***************************************************************************/ - -#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/minizip-ng/mz_strm_pkcrypt.c b/minizip-ng/mz_strm_pkcrypt.c deleted file mode 100644 index 41c762f..0000000 --- a/minizip-ng/mz_strm_pkcrypt.c +++ /dev/null @@ -1,338 +0,0 @@ -/* 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/minizip-ng/mz_strm_pkcrypt.h b/minizip-ng/mz_strm_pkcrypt.h deleted file mode 100644 index 453f1f9..0000000 --- a/minizip-ng/mz_strm_pkcrypt.h +++ /dev/null @@ -1,46 +0,0 @@ -/* 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/minizip-ng/mz_strm_split.c b/minizip-ng/mz_strm_split.c deleted file mode 100644 index 12c8bda..0000000 --- a/minizip-ng/mz_strm_split.c +++ /dev/null @@ -1,438 +0,0 @@ -/* 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 /* 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/minizip-ng/mz_strm_split.h b/minizip-ng/mz_strm_split.h deleted file mode 100644 index da404da..0000000 --- a/minizip-ng/mz_strm_split.h +++ /dev/null @@ -1,43 +0,0 @@ -/* 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/minizip-ng/mz_strm_wzaes.c b/minizip-ng/mz_strm_wzaes.c deleted file mode 100644 index fd01199..0000000 --- a/minizip-ng/mz_strm_wzaes.c +++ /dev/null @@ -1,362 +0,0 @@ -/* 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/minizip-ng/mz_strm_wzaes.h b/minizip-ng/mz_strm_wzaes.h deleted file mode 100644 index e27f112..0000000 --- a/minizip-ng/mz_strm_wzaes.h +++ /dev/null @@ -1,46 +0,0 @@ -/* 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/minizip-ng/mz_strm_zlib.c b/minizip-ng/mz_strm_zlib.c deleted file mode 100644 index e83bbac..0000000 --- a/minizip-ng/mz_strm_zlib.c +++ /dev/null @@ -1,393 +0,0 @@ -/* 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/minizip-ng/mz_strm_zlib.h b/minizip-ng/mz_strm_zlib.h deleted file mode 100644 index 47f7480..0000000 --- a/minizip-ng/mz_strm_zlib.h +++ /dev/null @@ -1,43 +0,0 @@ -/* 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/minizip-ng/mz_strm_zstd.c b/minizip-ng/mz_strm_zstd.c deleted file mode 100644 index 4c9c335..0000000 --- a/minizip-ng/mz_strm_zstd.c +++ /dev/null @@ -1,351 +0,0 @@ -/* 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 - -/***************************************************************************/ - -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/minizip-ng/mz_strm_zstd.h b/minizip-ng/mz_strm_zstd.h deleted file mode 100644 index 3587083..0000000 --- a/minizip-ng/mz_strm_zstd.h +++ /dev/null @@ -1,44 +0,0 @@ -/* 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/minizip-ng/mz_zip.c b/minizip-ng/mz_zip.c deleted file mode 100644 index d359336..0000000 --- a/minizip-ng/mz_zip.c +++ /dev/null @@ -1,2771 +0,0 @@ -/* 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 /* tolower */ -#include /* 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, <m) == 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, <m, 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/minizip-ng/mz_zip.h b/minizip-ng/mz_zip.h deleted file mode 100644 index e3d1fbd..0000000 --- a/minizip-ng/mz_zip.h +++ /dev/null @@ -1,259 +0,0 @@ -/* 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/minizip-ng/mz_zip_rw.c b/minizip-ng/mz_zip_rw.c deleted file mode 100644 index 5dde882..0000000 --- a/minizip-ng/mz_zip_rw.c +++ /dev/null @@ -1,1943 +0,0 @@ -/* 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) - return err; - } - - mz_os_close_dir(dir); - return MZ_OK; -} - -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/minizip-ng/mz_zip_rw.h b/minizip-ng/mz_zip_rw.h deleted file mode 100644 index 0957d0e..0000000 --- a/minizip-ng/mz_zip_rw.h +++ /dev/null @@ -1,285 +0,0 @@ -/* 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 steam */ - -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/minizip-ng/test/empty.txt b/minizip-ng/test/empty.txt deleted file mode 100644 index e69de29..0000000 diff --git a/minizip-ng/test/fuzz/standalone.c b/minizip-ng/test/fuzz/standalone.c deleted file mode 100644 index 95c0c54..0000000 --- a/minizip-ng/test/fuzz/standalone.c +++ /dev/null @@ -1,100 +0,0 @@ -/* standalone.c - Standalone fuzzer tester - part of the minizip-ng project - - Copyright (C) 2018 sebpop - https://github.com/sebpop - Copyright (C) 2018-2020 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_os.h" - -#include /* printf */ - -#ifdef __cplusplus -extern "C" { -#endif - -/***************************************************************************/ - -extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size); - -/***************************************************************************/ - -int main(int argc, char **argv) -{ - void *stream = NULL; - int64_t file_size = 0; - uint8_t *buf = NULL; - int32_t buf_length = 0; - int32_t err = MZ_OK; - int32_t read = 0; - int32_t i = 0; - - - if (argc < 1) - { - printf("Must specify an input file\n"); - return 1; - } - - printf("Running %"PRId32" inputs\n", argc - 1); - - for (i = 1; (i < argc) && (err == MZ_OK); i++) - { - read = 0; - - mz_stream_os_create(&stream); - err = mz_stream_os_open(stream, argv[i], MZ_OPEN_MODE_READ); - - if (err != MZ_OK) - { - printf("Skipping %s (%"PRId32")\n", argv[i], err); - } - else - { - mz_stream_os_seek(stream, 0, MZ_SEEK_END); - file_size = mz_stream_os_tell(stream); - if (file_size > INT32_MAX) - printf("File size is too large (%"PRId64")\n", file_size); - else - buf_length = (int32_t)file_size; - mz_stream_os_seek(stream, 0, MZ_SEEK_SET); - - buf = NULL; - if (buf_length > 0) - buf = MZ_ALLOC(buf_length); - - if (buf != NULL) - { - printf("Running %s %"PRId32"\n", argv[i], buf_length); - read = mz_stream_os_read(stream, buf, buf_length); - if (read == buf_length) - LLVMFuzzerTestOneInput(buf, buf_length); - else - err = MZ_BUF_ERROR; - - MZ_FREE(buf); - } - - mz_stream_os_close(stream); - } - - mz_stream_os_delete(&stream); - printf("Done %s (%"PRId32")\n", argv[i], err); - } - - return 0; -} - -/***************************************************************************/ - -#ifdef __cplusplus -} -#endif diff --git a/minizip-ng/test/fuzz/unzip_fuzzer.c b/minizip-ng/test/fuzz/unzip_fuzzer.c deleted file mode 100644 index 355a84b..0000000 --- a/minizip-ng/test/fuzz/unzip_fuzzer.c +++ /dev/null @@ -1,119 +0,0 @@ -/* unzip_fuzzer.c - Unzip fuzzer for libFuzzer - part of the minizip-ng project - - Copyright (C) 2018 The Chromium Authors - Copyright (C) 2018 Anand K. Mistry - Copyright (C) 2018-2020 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_mem.h" -#include "mz_zip.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/***************************************************************************/ - -#define MZ_FUZZ_TEST_PWD "test123" -#define MZ_FUZZ_TEST_FILENAME "foo" -#define MZ_FUZZ_TEST_FILENAMEUC "FOO" - -/***************************************************************************/ - -int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) -{ - mz_zip_file* file_info = NULL; - void *stream = NULL; - void *handle = NULL; - const char* archive_comment = NULL; - char buffer[1024]; - uint16_t version_madeby = 0; - uint64_t num_entries = 0; - int64_t entry_pos = 0; - int32_t err = MZ_OK; - uint8_t encrypted = 0; - - - mz_stream_mem_create(&stream); - mz_stream_mem_set_buffer(stream, (void *)data, (int32_t)size); - - mz_zip_create(&handle); - - err = mz_zip_open(handle, stream, MZ_OPEN_MODE_READ); - - if (err == MZ_OK) - { - /* Some archive properties that are non-fatal for reading the archive. */ - mz_zip_get_comment(handle, &archive_comment); - mz_zip_get_version_madeby(handle, &version_madeby); - mz_zip_get_number_entry(handle, &num_entries); - - err = mz_zip_goto_first_entry(handle); - while (err == MZ_OK) - { - err = mz_zip_entry_get_info(handle, &file_info); - if (err != MZ_OK) - break; - - encrypted = (file_info->flag & MZ_ZIP_FLAG_ENCRYPTED); - - err = mz_zip_entry_read_open(handle, 0, - encrypted ? MZ_FUZZ_TEST_PWD : NULL); - if (err != MZ_OK) - break; - - err = mz_zip_entry_is_open(handle); - if (err != MZ_OK) - break; - - /* Return value isn't checked here because we can't predict - what the value will be. */ - - mz_zip_entry_is_dir(handle); - entry_pos = mz_zip_get_entry(handle); - if (entry_pos < 0) - break; - - err = mz_zip_entry_read(handle, buffer, sizeof(buffer)); - if (err < 0) - break; - - err = mz_zip_entry_close(handle); - if (err != MZ_OK) - break; - - err = mz_zip_goto_next_entry(handle); - } - - mz_zip_entry_close(handle); - - /* Return value isn't checked here because we can't predict what the value - will be. */ - - mz_zip_locate_entry(handle, MZ_FUZZ_TEST_FILENAME, 0); - mz_zip_locate_entry(handle, MZ_FUZZ_TEST_FILENAMEUC, 0); - mz_zip_locate_entry(handle, MZ_FUZZ_TEST_FILENAME, 1); - mz_zip_locate_entry(handle, MZ_FUZZ_TEST_FILENAMEUC, 1); - - mz_zip_close(handle); - } - - mz_zip_delete(&handle); - mz_stream_mem_delete(&stream); - - return 0; -} - -/***************************************************************************/ - -#ifdef __cplusplus -} -#endif diff --git a/minizip-ng/test/fuzz/unzip_fuzzer.dict b/minizip-ng/test/fuzz/unzip_fuzzer.dict deleted file mode 100644 index e3a923c..0000000 --- a/minizip-ng/test/fuzz/unzip_fuzzer.dict +++ /dev/null @@ -1,9 +0,0 @@ -# A dictionary for more efficient fuzzing of DoStuff(). -# If the inputs contain multi-byte tokens, list them here. -# See https://llvm.org/docs/LibFuzzer.html#dictionaries -"\x50\x4b\x03\x04" -"\x50\x4b\x01\x02" -"\x50\x4b\x05\x06" -"\x50\x4b\x06\x06" -"\x50\x4b\x06\x07" -"\x50\x4b\x07\x08" diff --git a/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/as.zip b/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/as.zip deleted file mode 100644 index 2ef2ada59fe1b559307db83ed343b456c89b8367..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 233 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%0DmTZ_4_A}>dlQgutp~JYHx02G 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�XPpH7p)Hl!xE=?4 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 diff --git a/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/encrypted_pkcrypt.zip b/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/encrypted_pkcrypt.zip deleted file mode 100644 index 924f933e93432adf03e9395de50cea0c2ace84ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 198 zcmWIWW@h1H;ACK6Skj#4+cNLP7AYW`4~Ur=WEj%&^Fu>88JHKVJ&Xq7(h6<{Mi!RO z3=Ay6@r(@eyKRha3ORk>^l(eq`Xln^-ZWK~8@XPtPqz;6X6HaQEWn$QNsbwpMG`>k j7#J9Vcu6CO1-6zIVlA4L0p6@^ASH}I=n16LK^z7EQC2P0 diff --git a/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/encrypted_wzaes.zip b/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/encrypted_wzaes.zip deleted file mode 100644 index 9adf52bd7d02981c4bf2404d8df98677d0081a9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 204 zcmWIWW@a&FU}Q*USh70RmjMX0fS3=6nHjhl((>~eXRg@&*~oQY;CvT2wOgO~;~=j}p2APILS&@e1c U4De=U11V+#!r4H2I*7vn0CeC%rvLx| diff --git a/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/large_cd_comment.zip b/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/large_cd_comment.zip deleted file mode 100644 index 6dcb818acd7fbb4131a9fafddd53634e4eedf327..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65785 zcmeIuy-EW?5CGu0#Ggy*fT9*D0@^6Pft>9{NCXSZfR>_2ifHR2h+wp}7EA3d?DY+_ zv$a!*mk>p*e1LD3WmsmIS-w_Yo>-1FO{0C>*@z!eiKW=xJLn#*bbH;TC{&|9Dkm`; zvHkkEdia$5&E;t2)9J9SH0q7wos`z9wO=c~YL#e?yXxcoy|6vkh?!#H^UeMG`Nu-- z;{ENRzkkD|RXZ`u!=Iz#hKGn)6r-t*B;+zz@Q{2HI69fnlAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 U2oNAZfB*pk1PBlyKp@LL0XHZ-rT_o{ diff --git a/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/license_zstd.zip b/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/license_zstd.zip deleted file mode 100644 index c7a6009d310fd001635bf44c7cbde5eddf1ed650..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 734 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 T000310RUS7002*L00000Y-O}f diff --git a/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/permissions.zip b/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/permissions.zip deleted file mode 100644 index 87f777aeb71690beab7bb6c8c369cf5e043f9483..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 634 zcmWIWW@h1H0D{)g9&<56 k31RO4#uupO!ov(`E-1_}%w=T*`H&e1Ie;FH0ePAM0CE1ADF6Tf diff --git a/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/signed.zip b/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/signed.zip deleted file mode 100644 index d9ba8cbbbaf7530fc510125279aa22aac96ffecc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36122 zcmeI*RZwM1x*%ZO-QBftcXxMpcPq4TcXut^t#EgDhr-?6p@3rQ^qq6Nrq4`t%m-v@gJ>TJ4**c200006007`*;^;(c zbdF=?xXOCd<^w9r=0KTkDK$SQYLeYV-4j<|~MJ zZ2YUadzP_#7|0oRTLdUtYZgu74$1n%^y3i_Zw}%^9JY}wFyS5EkOV@|@WzFmEA|ol zk3chGoP5zLrM;90c}2G7C;Q@9)bkaI+(Z_2(jWS@whaE~fm?ys1jz=m`Xb)Kx~V z!CU$GBo;W4Xq4ie5MHq{!|^+A$q+qAuE8_RSN5s;dt^u6Sdop8m5z~=zNdg~E!Z2N z+bo>i-|_LX;b+)W4Vj}cI<5^lLGzjvHDql)jI7LzcC!VJWYBp<8+EF)cX8Cu z9#)k74LPuMUuF%%CT<(dF#Gx(=N0n>rLpsx%UPWhm1g#tsH48EBZlsn0>OM0&TRzt z2O`Td#vAlm`qsQ51nk}Vn=5Q0$Rj(}ZH;@DK)_^~I2y9>7N!CP6SVa4#6f%jE%Oh= z{_U+>i~<}j7DhjI?9g{~$R9s9_v}tZ&hO5;?N%FpsHj^Jkok$igR}x#>W#u!#2FY+ z)}>i(z^kblpPX1?r&8!yX;1FE0le@_k9>wrj9leJ;tgC_Sio{avGu@2K=#I*e~{#- zni-w9Shguk;JRs?TUFL$6wQ?!55(tlgljxg@d!uJP0!jo|D*PLy(I8 zp49{9zmCGS0inSDQ-`FuC4(e8|NGL-tT{ucr>ni^%n65>$NR`W8UJJ58Hp(0kU;tl zeMSzDtpMlt=kD?AwmuREP&tDc@OB0yF>k>ltpvr1`_?k72tF)@cnVJMR+w31Jj8X2>yK%X#(r2--k*y~Bu z2ceGez3gRWLxv`2Mox1bS=T&dkU25mT4cj&8pwT~PAn5gQYA6h^8Fa!w_GT~d83f5 zOZ|~!>A*<6xCg$FO3}nU3pY?QHiONkXfh4)e&00={W&e>!@<>zk*p;VMPkKtSuRMc z1NyxyD-IfMBw+4***9G&;z(H-^?FrZz*`6WhCE^=5)qRLQbH}O*}rz9HQ2fbb`c>* zPuc}BqAMM>P%jNo!~w_|LeH_})I>n=6mcEB8MMIB6g6c;09unrp+fb^%(?|M9DhY|BP-r`;LitmT9FCB(7_|BXLRzKr}&Ex`!1PGNcB~mU)PE%mbDr7d#Sl{yiY!?=X}8^CR!91F(qU zicf5rK@G3O(xg>ZIGkJ52c1$)ichor$>>26pLER2t2o~smF2P1r>g^}yU-cuvC)%J z4M_~ac8Y=qloDecT0@0o0Q_ie+xg|@+r4IR)@GfHE!Ai}7)F˚-e9tYSK5oAH<12VNvlTTO|kIl9VYi-1htHf(={A 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 diff --git a/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/storeonly.zip b/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/storeonly.zip deleted file mode 100644 index 249a01638d90bf89c797067b7b09262e250e86a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68373 zcmeI!e`r-@9LMqJ+#l{b?FUWG)VUidO4u@4TVZ8aTBuiSj@|H5Fw@;_*S6i8_YUTe zbhvUdS!$wx*fhn2h=dRdf>mk?V3rx0%ta;Z`<%18bI!fHI{o{7#LX}`U;gkcC|;tySsXhj*cp&n@7!4p;V-1s`B2taXqSAYuhws_-YUM zm9MKvsSpPO2q1s}0tg_000IagfB*srAb|hEkClzw+v#Weuw;?4P1fHsouS z{Os0$m=|h8J=j0+(=7Q^x2bZWvF2oYo6Aaj`<31KWXIE1XI(!qUOzJ(9$8V_<%Bw2!f_FL-S*aO`eT*M zt!^_!E#6X}kcInXYFl$tyyY$TDxPp=GKRnOE?W6~%j$kTEZqW*Gx^b1g5L zeYHwAYi_T2mGbEkrQU2#HpPPa)Ixhkf0wjBz3T=8W|C3`k~TIbGps^_bju3M6tq^f z#hyDbdqtl#S9GSAxvnP|qBAXbU{;!pQ(Zg0PG68kXNFBMMCYs=k<${Z<%H}KO z?H;9cdq}Q48Qa<%Po?6CmV20x%^j=P3>^D(?_!D9?GaZ{ZTZrrrRlb`sk!I94>xp6 zvowcgEtrp{D!Xj3KCv~JZj7gbdOm}x#@0krU2sz@C^3#{+bA`Q`#xWpw`SRR%}%NJ z?!DDav}S6SIchdY%@;2xF660MQBg5obHCI(cz-n|Mr!Kkq_wJYb?sHP(_B^dq}kT; z+|<_D&W_w%K|8mzBQ5jj${q8RT+*~C)ceLY*J9penai{%Yz z*-LoA`;Qit$mhDvm6g}pl4?yR6I;`6ParKdbelCrStXmo|1r&UOt2V*j4H{lZrxk-gu)HnXzp%PrqsZeF|a znRCkz4gcCb_r&7A4xSnqDp>N)Mc;FMM>>nEull$Acjow+$KoUNdxpO0Tef6h{}VgP z>Z%jlwi|jql*nUKKkRacw?IDEN6`F!r@)j=@RG9%wt3E ztxb~HYo+9cJAwpGiSNf&%E5o>X>j#aA&!9d}mgj zVL12y$;G+%d1u_$5|`QaCzs{k{hV1hJw~3raB|7+C%7|tkI!)2!eckU>eUbOD0*~v((0dGl{}<_9V!e~l5_+KHIY;X6Wq)mVeGlz95hm)|u|4bf!(1O# z(}UL2zCP)eUZnA9%CghX*>&o!u~;6S-69+GnlPfONN2)Pt$LG` zp!~`j#sF_dCV2*2&Qk$85Cjy!BtFM-LDeuaNHCbKE427A;S%GoY3t;X=>Tt5HjqJ# MK$ruh=YmZI0Q3G~<^TWy diff --git a/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/xz.zip b/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/xz.zip deleted file mode 100644 index 9beb69eecd5351e90c01133149c834eb1eb8c177..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48740 zcmV(Pimu`A%;rF4|g|ih%zHZsOH`Y_&Ku57If!)$B(PA;t9OXXa_V}ROj$HfkuUe?y zJnrh>3KiP5gccHl^mOJ;GU(qIal})904iTJ$~z}Au4P2vN_1{00R48U2gkV6qUf0M zZQ_=fXn-lu;C^&j6Y`1Uj)iEKDPa$2(`end)81a{$x0Ih1W5}Kctdqs3#}3=F>2ew z?SV5|Yz~o*$cAyQ#ok=YgOmvxQ#MIGr%6Q`59wLKXqm(AO%D1OoF`9DB{j;LQDmnD z-V0)DiL7p3sentaPF|y?2ty`(-V&j~G~VAcVIFur(`Sbb&@Ct;1BaQfs=)0|Eu@?M z8z9r4y37rD5JiC1qTKpF*9Pq@;A*|eT)QPogl*sv%KBj*u4LkXA$?go*Ketsq5v}26DC$CaV`NFN3 z;7|j_j3KbJPUqw7qAh}a2P{5(@|^txr{i=$FUcEn7`H}96C2*%Cineil=%Cz+_Tyt z|4c-WFk0NO-YQ9#+IYoE;h3}vTZRHobwpuU!>);EMBi|xi9oxK{O+;S6{itNoc;xa zjH7BWcB^X5VS*~VCZKqT25XaCk?b7b3aIs%r^SRSlTOhvR?j=J&l%iC1EzwM&HEX# zxAZLpPG~I_!}!PKHcCcozE$WJJ0neXfU?J?drH$Dr%$c$l;A%9q%8xQFLgfz+vu&2 zBV=72#mn8(`0SG4qHHa`gx2g3Lj??4!D6)#Nz~Dv#ajLqHSrNw5xj{Vh#V70nhKP+ zocTc2M&s2 zoW;JUHnwB2u5ZIph*`zF5v>mkHKAjuOZyXGK{Nn|l+z1h#<;*ZV z-1?9b5Zg-kw?+z~f^u_70O{8h7(1!196)NL1}L-;vVx26@j7d$VR|fZCCnwK+QV_Y zU$rj5e-Bk-#o2`L%Igf7v?hUpiCEUlOR;u}9Zr!u6(-nNNK3aNUDS_8Mw z`C*IaSBj&u2=is7=cyBKujP%h6YZvy#^r|;K}RMk!XNU_)ptdzSfp&0wY29mLr7fd z8b*lhU5Rk_814=(Xw zoe)A2I>zXAiomq@66)k0U*YQjK?C@iw8@;Kk1)+kXA!-n z^-;)HMvs(8lLf4`)f3m*(0at#Z`}&)IJk$`(!UzQTjD85AAJ@ihrm+9?n2cc3-TL) zVJk8DG+RF$QmyPmQW%@I{$2dD?d`lIZBtSf5ld`7DB`zZATDpfUh;i~zkY)NKeb(B zL}U7}W+K`B;UfX@^0@oxYcMt_K3cbBE+u2MKq`hY2kP|;7{j8%LjUzA(VlN(G0ktJ zvUrNpKil=_6F+iM~*>&F;^b*n2mlH&__sR2c!+eSr&M{A7opg!iO z`zv6wtvX1W#ey7QGlIf$5}s8%(*C2?TWy6~9q(_iIpo)rEWek2Hj}Jv z!Xa+QnzqERW>D1X?nc*KPc&(Kc$p z{2HZry2#lNFF+;V!_@_;cV*BB_4^9bhu7uAE&%%vrmj)Zjp~}4PccB;*dK0y1`%=t zvo7uYnbdaTzvlXa$`i-2`z1yA<$R41+AHqR(Uo`3!dU9%bZDQVkdK58kBy4=E#&2E z5+VYV;$z0gGeY!51rL4FAB~XL|9`h_y^CiD4h9!Bh*rf@eXd*n=#~QXLJ87~r7i}H zJOp6|k-U`u%MGm1d;j8jevLp*+hl<_O&gkoj>H=oX)zWJn)~MGa8IP&*-l+qMGQ)$ zewd3yS*g2Yvoj(r)=Z2u&yaGs7N9Hk4_)K=Kg&TvAq+Du9-%6*bSXV^<(DN^UbiRG z&e2RH?7#Oqs+Y>U*O$ZKFD*Od!bh2z*c4czD3^f>uZNmaBGj$c7po&4_SPDnrtY&Q z^d2diuJb^kDU>D+X4m-&Opn=5CeWX$s@MyCy#lrs?!a!5`zJ=!QfLXorNj;dlHZqc z#|oozpEkjtsMzAo6y!&Yz)uq~sDd9@P2>uWk z+VXsVyMb6=mB~Uk;#O^irq9c*HLiuGFMw9qZNI$G?;cbNGdPqMYeoyTan%bZaw_

!F5JU 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 diff --git a/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/zip64.zip b/minizip-ng/test/fuzz/unzip_fuzzer_seed_corpus/zip64.zip deleted file mode 100644 index 2ebcfeeda38c4342d73de665e2ba4736c4a6c53c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 215 zcmWIWW@gc4;Nak3m{XeJ%K!zuK$@9BgCQ+HpApF9Vo(4}FfvFmFr>_zTUdUD5uN_* zarWfN>wz5S^-p;QvM>aAvvXWH?Dd8ps1amZfHxzPJu|{4WI2#csDK1}1H4(;K$;nW LFcL^-fK37b8qzF5 diff --git a/minizip-ng/test/fuzz/zip_fuzzer.c b/minizip-ng/test/fuzz/zip_fuzzer.c deleted file mode 100644 index bf4582c..0000000 --- a/minizip-ng/test/fuzz/zip_fuzzer.c +++ /dev/null @@ -1,114 +0,0 @@ -/* zip_fuzzer.c - Zip fuzzer for libFuzzer - part of the minizip-ng project - - Copyright (C) 2018 The Chromium Authors - Copyright (C) 2018 Anand K. Mistry - Copyright (C) 2018-2020 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_mem.h" -#include "mz_zip.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/***************************************************************************/ - -#define MZ_FUZZ_TEST_FILENAME "foo" - -/***************************************************************************/ - -int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) -{ - mz_zip_file file_info; - void *fuzz_stream = NULL; - void *stream = NULL; - void *handle = NULL; - int32_t err = MZ_OK; - uint16_t value16 = 0; - uint8_t value8 = 0; - int16_t compress_level = 0; - int64_t fuzz_pos = 0; - int32_t fuzz_length = 0; - uint8_t *fuzz_buf = NULL; - - mz_stream_mem_create(&fuzz_stream); - mz_stream_mem_set_buffer(fuzz_stream, (void *)data, (int32_t)size); - - memset(&file_info, 0, sizeof(file_info)); - - file_info.flag = MZ_ZIP_FLAG_UTF8; - if ((mz_stream_read_uint8(fuzz_stream, &value8) == MZ_OK) && (value8 < 0x08)) - { - if (mz_stream_read_uint16(fuzz_stream, &value16) == MZ_OK) - file_info.flag = value16; - } - file_info.compression_method = MZ_COMPRESS_METHOD_DEFLATE; - if ((mz_stream_read_uint8(fuzz_stream, &value8) == MZ_OK) && (value8 < 0x08)) - { - file_info.compression_method = MZ_COMPRESS_METHOD_STORE; - } - else if ((mz_stream_read_uint8(fuzz_stream, &value8) == MZ_OK) && (value8 < 0x08)) - { - if (mz_stream_read_uint16(fuzz_stream, &value16) == MZ_OK) - file_info.compression_method = value16; - } - - if ((mz_stream_read_uint8(fuzz_stream, &value8) == MZ_OK) && (value8 < 0x08)) - { - if (mz_stream_read_uint16(fuzz_stream, &value16) == MZ_OK) - file_info.zip64 = value16; - } - - file_info.filename = MZ_FUZZ_TEST_FILENAME; - file_info.filename_size = (uint16_t)strlen(MZ_FUZZ_TEST_FILENAME); - - compress_level = MZ_COMPRESS_LEVEL_DEFAULT; - if ((mz_stream_read_uint8(fuzz_stream, &value8) == MZ_OK) && (value8 < 0x08)) - { - if (mz_stream_read_uint16(fuzz_stream, &value16) == MZ_OK) - compress_level = value16; - } - - mz_stream_mem_create(&stream); - mz_zip_create(&handle); - - err = mz_zip_open(handle, stream, MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_WRITE); - if (err == MZ_OK) - { - err = mz_zip_entry_write_open(handle, &file_info, compress_level, 0, NULL); - if (err == MZ_OK) - { - mz_stream_mem_get_buffer_at_current(fuzz_stream, (const void **)&fuzz_buf); - fuzz_pos = mz_stream_tell(fuzz_stream); - mz_stream_mem_get_buffer_length(fuzz_stream, &fuzz_length); - - err = mz_zip_entry_write(handle, fuzz_buf, (fuzz_length - (int32_t)fuzz_pos)); - - mz_zip_entry_close(handle); - } - - mz_zip_close(handle); - } - - mz_zip_delete(&handle); - mz_stream_mem_delete(&stream); - - mz_stream_mem_delete(&fuzz_stream); - - return 0; -} - -/***************************************************************************/ - -#ifdef __cplusplus -} -#endif diff --git a/minizip-ng/test/random.bin b/minizip-ng/test/random.bin deleted file mode 100644 index d6bb1efabbeb7934e96f8cbe4c03c2229241d012..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131072 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 Z(Wjy8P>3iak7xUsq7;3%nRC*iV9>wN?Wq6& diff --git a/minizip-ng/test/single.txt b/minizip-ng/test/single.txt deleted file mode 100644 index 56a6051..0000000 --- a/minizip-ng/test/single.txt +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/minizip-ng/test/test.c b/minizip-ng/test/test.c deleted file mode 100644 index 050cd64..0000000 --- a/minizip-ng/test/test.c +++ /dev/null @@ -1,1248 +0,0 @@ -/* test.c - Test bed area - part of the minizip-ng project - - Copyright (C) 2018-2020 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" -#ifdef HAVE_COMPAT -#include "mz_compat.h" -#endif -#include "mz_crypt.h" -#include "mz_os.h" -#include "mz_strm.h" -#ifdef HAVE_BZIP2 -#include "mz_strm_bzip.h" -#endif -#ifdef HAVE_PKCRYPT -#include "mz_strm_pkcrypt.h" -#endif -#include "mz_strm_mem.h" -#include "mz_strm_os.h" -#ifdef HAVE_WZAES -#include "mz_strm_wzaes.h" -#endif -#ifdef HAVE_ZLIB -#include "mz_strm_zlib.h" -#endif -#include "mz_zip.h" - -#include /* printf, snprintf */ - -#if defined(_MSC_VER) && (_MSC_VER < 1900) -# define snprintf _snprintf -#endif - -/***************************************************************************/ - -int32_t test_path_resolve_int(char *path, char *expected_path) -{ - char output[256]; - int32_t ok = 0; - - memset(output, 'z', sizeof(output)); - mz_path_resolve(path, output, sizeof(output)); - ok = (strcmp(output, expected_path) == 0); - printf("path resolve - %s -> %s = %s (%" PRId32 ")\n", path, expected_path, output, ok); - return !ok; -} - -int32_t test_path_resolve(void) -{ - int32_t err = MZ_OK; - - err |= test_path_resolve_int("c:\\test\\.", "c:\\test\\"); - err |= test_path_resolve_int("c:\\test\\.\\", "c:\\test\\"); - err |= test_path_resolve_int("c:\\test\\.\\.", "c:\\test\\"); - err |= test_path_resolve_int("c:\\test\\..", "c:\\"); - err |= test_path_resolve_int("c:\\test\\..\\", "c:\\"); - err |= test_path_resolve_int("c:\\test\\.\\..", "c:\\"); - err |= test_path_resolve_int("c:\\test\\.\\\\..", "c:\\"); - err |= test_path_resolve_int(".", "."); - err |= test_path_resolve_int(".\\", ""); - err |= test_path_resolve_int("..", ""); - err |= test_path_resolve_int("..\\", ""); - err |= test_path_resolve_int(".\\test\\123", "test\\123"); - err |= test_path_resolve_int(".\\..\\test\\123", "test\\123"); - err |= test_path_resolve_int("..\\..\\test\\123", "test\\123"); - err |= test_path_resolve_int("test\\.abc.txt", "test\\.abc.txt"); - err |= test_path_resolve_int("c:\\test\\123\\.\\abc.txt", "c:\\test\\123\\abc.txt"); - err |= test_path_resolve_int("c:\\test\\123\\..\\abc.txt", "c:\\test\\abc.txt"); - err |= test_path_resolve_int("c:\\test\\123\\..\\..\\abc.txt", "c:\\abc.txt"); - err |= test_path_resolve_int("c:\\test\\123\\..\\..\\..\\abc.txt", "abc.txt"); - err |= test_path_resolve_int("c:\\test\\123\\..\\.\\..\\abc.txt", "c:\\abc.txt"); - - return err; -} - -int32_t test_utf8(void) -{ - const char *test_string = "HeizīŋŊlrīŋŊckstoīŋŊabdīŋŊmpfung"; - uint8_t *utf8_string = mz_os_utf8_string_create(test_string, MZ_ENCODING_CODEPAGE_950); - if (utf8_string == NULL) - return MZ_BUF_ERROR; -#if defined(_WIN32) - wchar_t *unicode_string = mz_os_unicode_string_create((const char *)utf8_string, MZ_ENCODING_UTF8); - if (unicode_string == NULL) - return MZ_BUF_ERROR; - mz_os_unicode_string_delete(&unicode_string); -#endif - mz_os_utf8_string_delete(&utf8_string); - return MZ_OK; -} - -int32_t test_encrypt(char *method, mz_stream_create_cb crypt_create, char *password) -{ - char buf[UINT16_MAX]; - int32_t read = 0; - int32_t written = 0; - int64_t total_written = 0; - void *out_stream = NULL; - void *in_stream = NULL; - void *crypt_out_stream = NULL; - char encrypt_path[120]; - char decrypt_path[120]; - - snprintf(encrypt_path, sizeof(encrypt_path), "LICENSE.encrypt.%s", method); - snprintf(decrypt_path, sizeof(decrypt_path), "LICENSE.decrypt.%s", method); - - mz_stream_os_create(&in_stream); - - if (mz_stream_os_open(in_stream, "LICENSE", MZ_OPEN_MODE_READ) == MZ_OK) - { - read = mz_stream_os_read(in_stream, buf, UINT16_MAX); - mz_stream_os_close(in_stream); - } - - mz_stream_os_delete(&in_stream); - mz_stream_os_create(&out_stream); - - if (mz_stream_os_open(out_stream, encrypt_path, MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_WRITE) == MZ_OK) - { - crypt_create(&crypt_out_stream); - - mz_stream_set_base(crypt_out_stream, out_stream); - - if (mz_stream_open(crypt_out_stream, password, MZ_OPEN_MODE_WRITE) == MZ_OK) - { - written = mz_stream_write(crypt_out_stream, buf, read); - mz_stream_close(crypt_out_stream); - mz_stream_get_prop_int64(crypt_out_stream, MZ_STREAM_PROP_TOTAL_OUT, &total_written); - } - - mz_stream_delete(&crypt_out_stream); - - mz_stream_os_close(out_stream); - - printf("%s encrypted %" PRId32 "\n", encrypt_path, written); - } - - mz_stream_os_delete(&out_stream); - mz_stream_os_create(&in_stream); - - if (mz_stream_os_open(in_stream, encrypt_path, MZ_OPEN_MODE_READ) == MZ_OK) - { - crypt_create(&crypt_out_stream); - - mz_stream_set_base(crypt_out_stream, in_stream); - mz_stream_set_prop_int64(crypt_out_stream, MZ_STREAM_PROP_TOTAL_IN_MAX, total_written); - - if (mz_stream_open(crypt_out_stream, password, MZ_OPEN_MODE_READ) == MZ_OK) - { - read = mz_stream_read(crypt_out_stream, buf, read); - mz_stream_close(crypt_out_stream); - } - - mz_stream_delete(&crypt_out_stream); - - mz_stream_os_close(in_stream); - - printf("%s decrypted %" PRId32 "\n", decrypt_path, read); - } - - mz_stream_os_delete(&in_stream); - mz_stream_os_create(&out_stream); - - if (mz_stream_os_open(out_stream, decrypt_path, MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_WRITE) == MZ_OK) - { - mz_stream_os_write(out_stream, buf, read); - mz_stream_os_close(out_stream); - } - - mz_stream_os_delete(&out_stream); - return 0; -} - -int32_t test_compress(char *method, mz_stream_create_cb create_compress) -{ - uint8_t buf[UINT16_MAX]; - int32_t read = 0; - int64_t total_in = 0; - int64_t total_out = 0; - void *in_stream = NULL; - void *out_stream = NULL; - void *deflate_stream = NULL; - void *inflate_stream = NULL; - uint32_t crc32 = 0; - char filename[120]; - - printf("Testing compress %s\n", method); - - mz_stream_os_create(&in_stream); - - if (mz_stream_os_open(in_stream, "LICENSE", MZ_OPEN_MODE_READ) == MZ_OK) - { - read = mz_stream_os_read(in_stream, buf, UINT16_MAX); - if (read > 0) - crc32 = mz_crypt_crc32_update(crc32, (const uint8_t *)buf, read); - - mz_stream_os_close(in_stream); - } - - mz_stream_os_delete(&in_stream); - - if (read < 0) - { - printf("Failed to read LICENSE\n"); - return MZ_OPEN_ERROR; - } - - printf("LICENSE crc 0x%08x\n", crc32); - - mz_stream_os_create(&out_stream); - - snprintf(filename, sizeof(filename), "LICENSE.deflate.%s", method); - if (mz_stream_os_open(out_stream, filename, MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_WRITE) == MZ_OK) - { - create_compress(&deflate_stream); - mz_stream_set_base(deflate_stream, out_stream); - - mz_stream_open(deflate_stream, NULL, MZ_OPEN_MODE_WRITE); - mz_stream_write(deflate_stream, buf, read); - mz_stream_close(deflate_stream); - - mz_stream_get_prop_int64(deflate_stream, MZ_STREAM_PROP_TOTAL_IN, &total_in); - mz_stream_get_prop_int64(deflate_stream, MZ_STREAM_PROP_TOTAL_OUT, &total_out); - - mz_stream_delete(&deflate_stream); - - printf("%s compressed from %u to %u\n", filename, (uint32_t)total_in, (uint32_t)total_out); - - mz_stream_os_close(out_stream); - } - - mz_stream_os_delete(&out_stream); - mz_stream_os_create(&in_stream); - - if (mz_stream_os_open(in_stream, filename, MZ_OPEN_MODE_READ) == MZ_OK) - { - create_compress(&inflate_stream); - mz_stream_set_base(inflate_stream, in_stream); - - mz_stream_open(inflate_stream, NULL, MZ_OPEN_MODE_READ); - read = mz_stream_read(inflate_stream, buf, UINT16_MAX); - mz_stream_close(inflate_stream); - - mz_stream_get_prop_int64(inflate_stream, MZ_STREAM_PROP_TOTAL_IN, &total_in); - mz_stream_get_prop_int64(inflate_stream, MZ_STREAM_PROP_TOTAL_OUT, &total_out); - - mz_stream_delete(&inflate_stream); - - mz_stream_os_close(in_stream); - - printf("%s uncompressed from %u to %u\n", filename, (uint32_t)total_in, (uint32_t)total_out); - } - - mz_stream_os_delete(&in_stream); - mz_stream_os_create(&out_stream); - - crc32 = 0; - - snprintf(filename, sizeof(filename), "LICENSE.inflate.%s", method); - if (mz_stream_os_open(out_stream, filename, MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_WRITE) == MZ_OK) - { - crc32 = mz_crypt_crc32_update(crc32, (const uint8_t *)buf, read); - - mz_stream_os_close(out_stream); - - printf("%s crc 0x%08x\n", filename, crc32); - } - - mz_stream_os_delete(&out_stream); - - return MZ_OK; -} - -/***************************************************************************/ - -#ifdef HAVE_BZIP2 -int test_stream_bzip(void) -{ - return test_compress("bzip", mz_stream_bzip_create); -} -#endif -#ifdef HAVE_PKCRYPT -int test_stream_pkcrypt(void) -{ - return test_encrypt("pkcrypt", mz_stream_pkcrypt_create, "hello"); -} -#endif -#ifdef HAVE_WZAES -int test_stream_wzaes(void) -{ - int32_t iteration_count = 1000; - int32_t err = MZ_OK; - int32_t i = 0; - uint8_t key[MZ_HASH_SHA1_SIZE]; - const char *password = "passwordpasswordpasswordpassword"; - const char *salt = "8F3472E4EA57F56E36F30246DC22C173"; - - - printf("Pbkdf2 password - %s\n", password); - printf("Pbkdf2 salt - %s\n", salt); - - err = mz_crypt_pbkdf2((uint8_t *)password, (int32_t)strlen(password), - (uint8_t *)salt, (int32_t)strlen(salt), iteration_count, key, sizeof(key)); - - if (err == MZ_OK) - { - printf("Pbkdf2 key hex\n"); - for (i = 0; i < (int32_t)sizeof(key); i += 1) - printf("%02x", key[i]); - printf("\n"); - } - else - { - printf("Pbkdf2 failed - %" PRId32 "", err); - return MZ_CRYPT_ERROR; - } - - return test_encrypt("aes", mz_stream_wzaes_create, "hello"); -} -#endif -#ifdef HAVE_ZLIB -int32_t test_stream_zlib(void) -{ - return test_compress("zlib", mz_stream_zlib_create); -} - -int32_t test_stream_zlib_mem(void) -{ - mz_zip_file file_info; - void *read_mem_stream = NULL; - void *write_mem_stream = NULL; - void *os_stream = NULL; - void *zip_handle = NULL; - int32_t written = 0; - int32_t read = 0; - int32_t text_size = 0; - int32_t buffer_size = 0; - int32_t err = MZ_OK; - const uint8_t *buffer_ptr = NULL; - char *password = NULL; - char *text_name = "test"; - char *text_ptr = "test string"; - char temp[120]; - - - memset(&file_info, 0, sizeof(file_info)); - - text_size = (int32_t)strlen(text_ptr); - - /* Write zip to memory stream */ - mz_stream_mem_create(&write_mem_stream); - mz_stream_mem_set_grow_size(write_mem_stream, 128 * 1024); - mz_stream_open(write_mem_stream, NULL, MZ_OPEN_MODE_CREATE); - - mz_zip_create(&zip_handle); - err = mz_zip_open(zip_handle, write_mem_stream, MZ_OPEN_MODE_WRITE); - - if (err == MZ_OK) - { - file_info.version_madeby = MZ_VERSION_MADEBY; - file_info.compression_method = MZ_COMPRESS_METHOD_DEFLATE; - file_info.filename = text_name; - file_info.uncompressed_size = text_size; -#ifdef HAVE_WZAES - file_info.aes_version = MZ_AES_VERSION; - password = "1234"; -#endif - - err = mz_zip_entry_write_open(zip_handle, &file_info, MZ_COMPRESS_LEVEL_DEFAULT, 0, password); - if (err == MZ_OK) - { - written = mz_zip_entry_write(zip_handle, text_ptr, text_size); - if (written < MZ_OK) - err = written; - mz_zip_entry_close(zip_handle); - } - - mz_zip_close(zip_handle); - } - else - { - err = MZ_INTERNAL_ERROR; - } - - mz_zip_delete(&zip_handle); - - mz_stream_mem_get_buffer(write_mem_stream, (const void **)&buffer_ptr); - mz_stream_mem_seek(write_mem_stream, 0, MZ_SEEK_END); - buffer_size = (int32_t)mz_stream_mem_tell(write_mem_stream); - - if (err == MZ_OK) - { - /* Create a zip file on disk for inspection */ - mz_stream_os_create(&os_stream); - mz_stream_os_open(os_stream, "mytest.zip", MZ_OPEN_MODE_WRITE | MZ_OPEN_MODE_CREATE); - mz_stream_os_write(os_stream, buffer_ptr, buffer_size); - mz_stream_os_close(os_stream); - mz_stream_os_delete(&os_stream); - } - - if (err == MZ_OK) - { - /* Read from a memory stream */ - mz_stream_mem_create(&read_mem_stream); - mz_stream_mem_set_buffer(read_mem_stream, (void *)buffer_ptr, buffer_size); - mz_stream_open(read_mem_stream, NULL, MZ_OPEN_MODE_READ); - - mz_zip_create(&zip_handle); - err = mz_zip_open(zip_handle, read_mem_stream, MZ_OPEN_MODE_READ); - - if (err == MZ_OK) - { - err = mz_zip_goto_first_entry(zip_handle); - if (err == MZ_OK) - err = mz_zip_entry_read_open(zip_handle, 0, password); - if (err == MZ_OK) - read = mz_zip_entry_read(zip_handle, temp, sizeof(temp)); - - MZ_UNUSED(read); - - mz_zip_entry_close(zip_handle); - mz_zip_close(zip_handle); - } - - mz_zip_delete(&zip_handle); - - mz_stream_mem_close(&read_mem_stream); - mz_stream_mem_delete(&read_mem_stream); - read_mem_stream = NULL; - } - - mz_stream_mem_close(write_mem_stream); - mz_stream_mem_delete(&write_mem_stream); - write_mem_stream = NULL; - - return err; -} -#endif - -/***************************************************************************/ - -int32_t test_stream_find_run(char *name, int32_t count, const uint8_t *find, int32_t find_size, mz_stream_find_cb find_cb) -{ - void *mem_stream = NULL; - int32_t i = 0; - int32_t x = 0; - int32_t err = MZ_OK; - int64_t last_pos = 0; - int64_t position = 0; - - MZ_UNUSED(name); - - if (find == NULL || find_size == 0 || find_cb == NULL) - return MZ_PARAM_ERROR; - - for (i = 0; i < count; i += 1) - { -#if 1 - mz_stream_mem_create(&mem_stream); - mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_CREATE); - - for (x = 0; x < find_size; x += 1) - mz_stream_write_uint8(mem_stream, find[x]); - for (x = 0; x < i; x += 1) - mz_stream_write_uint8(mem_stream, 0); - - if (find_cb == mz_stream_find) - mz_stream_seek(mem_stream, 0, MZ_SEEK_SET); - - err = find_cb(mem_stream, (const void *)find, find_size, (int64_t)i + find_size, &position); - last_pos = mz_stream_tell(mem_stream); - mz_stream_mem_delete(&mem_stream); - -#ifdef TEST_VERBOSE - printf("Find postzero - %s (len %" PRId32 " pos %" PRId64 " ok %" PRId32 ")\n", - name, find_size, position, (position == 0)); -#endif - - if (position != 0 || last_pos != position) - break; -#endif - mz_stream_mem_create(&mem_stream); - mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_CREATE); - - for (x = 0; x < i; x += 1) - mz_stream_write_uint8(mem_stream, 0); - for (x = 0; x < find_size; x += 1) - mz_stream_write_uint8(mem_stream, find[x]); - - if (find_cb == mz_stream_find) - mz_stream_seek(mem_stream, 0, MZ_SEEK_SET); - - err = find_cb(mem_stream, (const void *)find, find_size, (int64_t)i + find_size, &position); - last_pos = mz_stream_tell(mem_stream); - mz_stream_mem_delete(&mem_stream); - -#ifdef TEST_VERBOSE - printf("Find prezero - %s (len %" PRId32 " pos %" PRId64 " ok %" PRId32 ")\n", - name, find_size, position, (position == i)); -#endif - - if (position != i || last_pos != position) - break; - - mz_stream_mem_create(&mem_stream); - mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_CREATE); - - for (x = 0; x < i; x += 1) - mz_stream_write_uint8(mem_stream, 0); - for (x = 0; x < find_size; x += 1) - mz_stream_write_uint8(mem_stream, find[x]); - for (x = 0; x < i; x += 1) - mz_stream_write_uint8(mem_stream, 0); - - if (find_cb == mz_stream_find) - mz_stream_seek(mem_stream, 0, MZ_SEEK_SET); - - err = find_cb(mem_stream, (const void *)find, find_size, (int64_t)i + find_size + i, &position); - last_pos = mz_stream_tell(mem_stream); - mz_stream_mem_delete(&mem_stream); - -#ifdef TEST_VERBOSE - printf("Find equalzero - %s (len %" PRId32 " pos %" PRId64 " ok %" PRId32 ")\n", - name, find_size, position, (position == i)); -#endif - - if (position != i || last_pos != position) - break; - - mz_stream_mem_create(&mem_stream); - mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_CREATE); - - for (x = 0; x < i; x += 1) - mz_stream_write_uint8(mem_stream, 0); - for (x = 0; x < find_size; x += 1) - mz_stream_write_uint8(mem_stream, find[x]); - for (x = 0; x < i; x += 1) - mz_stream_write_uint8(mem_stream, 0); - mz_stream_write_uint8(mem_stream, 0); - - if (find_cb == mz_stream_find) - mz_stream_seek(mem_stream, 0, MZ_SEEK_SET); - - err = find_cb(mem_stream, (const void *)find, find_size, (int64_t)i + find_size + i + 1, &position); - last_pos = mz_stream_tell(mem_stream); - mz_stream_mem_delete(&mem_stream); - -#ifdef TEST_VERBOSE - printf("Find unequalzero - %s (len %" PRId32 " pos %" PRId64 " ok %" PRId32 ")\n", - name, find_size, position, (position == i)); -#endif - - if (position != i || last_pos != position) - break; - } - - return err; -} - -int32_t test_stream_find(void) -{ - int32_t c = 1; - int32_t err = MZ_OK; - char *find = "0123456789"; - - printf("Find stream.. "); - for (c = 1; c < (int32_t)strlen(find); c += 1) - { - err = test_stream_find_run("forward", 2096, (uint8_t *)find, c, mz_stream_find); - if (err != MZ_OK) - return err; - } - - printf("OK\n"); - return MZ_OK; -} - -int32_t test_stream_find_reverse(void) -{ - int32_t c = 1; - int32_t err = MZ_OK; - char *find = "0123456789"; - - printf("Find reverse stream.. "); - for (c = 1; c < (int32_t)strlen(find); c += 1) - { - err = test_stream_find_run("backward", 2096, (uint8_t *)find, c, mz_stream_find_reverse); - if (err != MZ_OK) - return err; - } - - printf("OK\n"); - return MZ_OK; -} - -/***************************************************************************/ - -int32_t convert_buffer_to_hex_string(uint8_t *buf, int32_t buf_size, char *hex_string, int32_t max_hex_string) -{ - int32_t p = 0; - int32_t i = 0; - - if (max_hex_string > 0) - hex_string[0] = 0; - for (i = 0, p = 0; i < (int32_t)buf_size && p < max_hex_string; i += 1, p += 2) - snprintf(hex_string + p, max_hex_string - p, "%02x", buf[i]); - if (p < max_hex_string) - hex_string[p] = 0; - return MZ_OK; -} - -#ifndef MZ_ZIP_NO_CRYPTO -int32_t test_crypt_sha(void) -{ - void *sha1 = NULL; - void *sha256 = NULL; - char *test = "the quick and lazy fox did his thang"; - char computed_hash[320]; - uint8_t hash[MZ_HASH_SHA1_SIZE]; - uint8_t hash256[MZ_HASH_SHA256_SIZE]; - - printf("Sha hash input - %s\n", test); - - memset(hash, 0, sizeof(hash)); - - mz_crypt_sha_create(&sha1); - mz_crypt_sha_set_algorithm(sha1, MZ_HASH_SHA1); - mz_crypt_sha_begin(sha1); - mz_crypt_sha_update(sha1, test, (int32_t)strlen(test)); - mz_crypt_sha_end(sha1, hash, sizeof(hash)); - mz_crypt_sha_delete(&sha1); - - convert_buffer_to_hex_string(hash, sizeof(hash), computed_hash, sizeof(computed_hash)); - - printf("Sha1 hash computed - %s\n", computed_hash); - printf("Sha1 hash expected - 3efb8392b6cd8e14bd76bd08081521dc73df418c\n"); - - if (strcmp(computed_hash, "3efb8392b6cd8e14bd76bd08081521dc73df418c") != 0) - return MZ_HASH_ERROR; - - memset(hash256, 0, sizeof(hash256)); - - mz_crypt_sha_create(&sha256); - mz_crypt_sha_set_algorithm(sha256, MZ_HASH_SHA256); - mz_crypt_sha_begin(sha256); - mz_crypt_sha_update(sha256, test, (int32_t)strlen(test)); - mz_crypt_sha_end(sha256, hash256, sizeof(hash256)); - mz_crypt_sha_delete(&sha256); - - convert_buffer_to_hex_string(hash256, sizeof(hash256), computed_hash, sizeof(computed_hash)); - - printf("Sha256 hash computed - %s\n", computed_hash); - printf("Sha256 hash expected - 7a31ea0848525f7ebfeec9ee532bcc5d6d26772427e097b86cf440a56546541c\n"); - - if (strcmp(computed_hash, "7a31ea0848525f7ebfeec9ee532bcc5d6d26772427e097b86cf440a56546541c") != 0) - return MZ_HASH_ERROR; - - printf("Sha.. OK\n"); - return MZ_OK; -} - -int test_crypt_aes(void) -{ - void *aes = NULL; - char *key = "awesomekeythisis"; - char *test = "youknowitsogrowi"; - char computed_hash[320]; - int32_t key_length = 0; - int32_t test_length = 0; - uint8_t buf[120]; - uint8_t hash[MZ_HASH_SHA256_SIZE]; - - printf("Aes key - %s\n", key); - printf("Aes input - %s\n", test); - - memset(hash, 0, sizeof(hash)); - - key_length = (int32_t)strlen(key); - test_length = (int32_t)strlen(test); - - strncpy((char *)buf, test, sizeof(buf)); - - printf("Aes input hex\n"); - convert_buffer_to_hex_string(buf, test_length, computed_hash, sizeof(computed_hash)); - printf("%s\n", computed_hash); - - mz_crypt_aes_create(&aes); - mz_crypt_aes_set_mode(aes, MZ_AES_ENCRYPTION_MODE_256); - mz_crypt_aes_set_encrypt_key(aes, key, key_length); - mz_crypt_aes_encrypt(aes, buf, test_length); - mz_crypt_aes_delete(&aes); - - printf("Aes encrypted\n"); - convert_buffer_to_hex_string(buf, test_length, computed_hash, sizeof(computed_hash)); - printf("%s\n", computed_hash); - - mz_crypt_aes_create(&aes); - mz_crypt_aes_set_mode(aes, MZ_AES_ENCRYPTION_MODE_256); - mz_crypt_aes_set_decrypt_key(aes, key, key_length); - mz_crypt_aes_decrypt(aes, buf, test_length); - mz_crypt_aes_delete(&aes); - - printf("Aes decrypted\n"); - convert_buffer_to_hex_string(buf, test_length, computed_hash, sizeof(computed_hash)); - printf("%s\n", computed_hash); - - if (strcmp((char *)buf, test) != 0) - return MZ_CRYPT_ERROR; - - printf("Aes.. OK\n"); - return MZ_OK; -} - -int32_t test_crypt_hmac(void) -{ - void *hmac; - char *key = "hm123"; - char *test = "12345678"; - char computed_hash[320]; - int32_t key_length = 0; - int32_t test_length = 0; - uint8_t hash[MZ_HASH_SHA1_SIZE]; - uint8_t hash256[MZ_HASH_SHA256_SIZE]; - - key_length = (int32_t)strlen(key); - test_length = (int32_t)strlen(test); - - printf("Hmac sha1 key - %s\n", key); - printf("Hmac sha1 input - %s\n", test); - - mz_crypt_hmac_create(&hmac); - mz_crypt_hmac_set_algorithm(hmac, MZ_HASH_SHA1); - mz_crypt_hmac_init(hmac, key, key_length); - mz_crypt_hmac_update(hmac, test, test_length); - mz_crypt_hmac_end(hmac, hash, sizeof(hash)); - mz_crypt_hmac_delete(&hmac); - - printf("Hmac sha1 output hash hex\n"); - convert_buffer_to_hex_string(hash, sizeof(hash), computed_hash, sizeof(computed_hash)); - printf("%s\n", computed_hash); - - printf("Hmac sha1 expected\n"); - printf("c785a02ff303c886c304d9a4c06073dfe4c24aa9\n"); - - if (strcmp(computed_hash, "c785a02ff303c886c304d9a4c06073dfe4c24aa9") != 0) - return MZ_CRYPT_ERROR; - - printf("Hmac sha256 key - %s\n", key); - printf("Hmac sha256 input - %s\n", test); - - mz_crypt_hmac_create(&hmac); - mz_crypt_hmac_set_algorithm(hmac, MZ_HASH_SHA256); - mz_crypt_hmac_init(hmac, key, key_length); - mz_crypt_hmac_update(hmac, test, test_length); - mz_crypt_hmac_end(hmac, hash256, sizeof(hash256)); - mz_crypt_hmac_delete(&hmac); - - printf("Hmac sha256 output hash hex\n"); - convert_buffer_to_hex_string(hash256, sizeof(hash256), computed_hash, sizeof(computed_hash)); - printf("%s\n", computed_hash); - - printf("Hmac sha256 expected\n"); - printf("fb22a9c715a47a06bad4f6cee9badc31c921562f5d6b24adf2be009f73181f7a\n"); - - if (strcmp(computed_hash, "fb22a9c715a47a06bad4f6cee9badc31c921562f5d6b24adf2be009f73181f7a") != 0) - return MZ_CRYPT_ERROR; - - printf("Hmac.. OK\n"); - return MZ_OK; -} -#endif - -#if defined(HAVE_COMPAT) && defined(HAVE_ZLIB) -int32_t test_zip_compat_int(zipFile zip, char *filename) -{ - int32_t err = ZIP_OK; - zip_fileinfo file_info; - char *buffer = "test data"; - - memset(&file_info, 0, sizeof(file_info)); - file_info.dosDate = mz_zip_time_t_to_dos_date(1588561637); - - err = zipOpenNewFileInZip(zip, filename, &file_info, NULL, 0, NULL, 0, "test local comment", - Z_DEFLATED, 1); - if (err != ZIP_OK) - { - printf("Failed to create new file in zip (%" PRId32 ")\n", err); - return err; - } - err = zipWriteInFileInZip(zip, buffer, (uint32_t)strlen(buffer)); - if (err != ZIP_OK) - { - printf("Failed to write file in zip (%" PRId32 ")\n", err); - return err; - } - err = zipCloseFileInZip(zip); - if (err != ZIP_OK) - { - printf("Failed to close file in zip (%" PRId32 ")\n", err); - return err; - } - - return ZIP_OK; -} - -int32_t test_zip_compat(void) -{ - int32_t err = ZIP_OK; - zipFile zip; - - - zip = zipOpen64("compat.zip", APPEND_STATUS_CREATE); - - if (zip == NULL) - { - printf("Failed to create test zip file\n"); - return ZIP_PARAMERROR; - } - err = test_zip_compat_int(zip, "test.txt"); - if (err != ZIP_OK) - return err; - err = test_zip_compat_int(zip, "test2.txt"); - if (err != ZIP_OK) - return err; - - zipClose(zip, "test global comment"); - - if (err != ZIP_OK) - return err; - - printf("Compat zip.. OK\n"); - - return ZIP_OK; -} - -static int32_t test_unzip_compat_int(unzFile unzip) -{ - unz_global_info64 global_info64; - unz_global_info global_info; - unz_file_info64 file_info64; - unz_file_info file_info; - unz_file_pos file_pos; - int32_t err = UNZ_OK; - int32_t bytes_read = 0; - char comment[120]; - char filename[120]; - char buffer[120]; - char *test_data = "test data"; - - memset(&file_info, 0, sizeof(file_info)); - memset(&file_info64, 0, sizeof(file_info64)); - memset(&global_info, 0, sizeof(global_info)); - memset(&global_info64, 0, sizeof(global_info64)); - - comment[0] = 0; - err = unzGetGlobalComment(unzip, comment, sizeof(comment)); - if (err != UNZ_OK) - { - printf("Failed to get global comment (%" PRId32 ")\n", err); - return err; - } - if (strcmp(comment, "test global comment") != 0) - { - printf("Unexpected global comment value (%s)\n", comment); - return err; - } - err = unzGetGlobalInfo(unzip, &global_info); - if (err != UNZ_OK) - { - printf("Failed to get global info (%" PRId32 ")\n", err); - return err; - } - err = unzGetGlobalInfo64(unzip, &global_info64); - if (err != UNZ_OK) - { - printf("Failed to get global info 64-bit (%" PRId32 ")\n", err); - return err; - } - if (global_info.number_entry != 2 || global_info64.number_entry != 2) - { - printf("Invalid number of entries in zip (%" PRId32 ")\n", global_info.number_entry); - return err; - } - if (global_info.number_disk_with_CD != 0 || global_info64.number_disk_with_CD != 0) - { - printf("Invalid disk with cd (%" PRIu32 ")\n", global_info.number_disk_with_CD); - return err; - } - - err = unzLocateFile(unzip, "test.txt", (void *)1); - if (err != UNZ_OK) - { - printf("Failed to locate test file (%" PRId32 ")\n", err); - return err; - } - - err = unzGoToFirstFile(unzip); - if (err == UNZ_OK) - { - filename[0] = 0; - err = unzGetCurrentFileInfo64(unzip, &file_info64, filename, sizeof(filename), NULL, 0, NULL, 0); - if (err != UNZ_OK) - { - printf("Failed to get current file info 64-bit (%" PRId32 ")\n", err); - return err; - } - - err = unzOpenCurrentFile(unzip); - if (err != UNZ_OK) - { - printf("Failed to open current file (%" PRId32 ")\n", err); - return err; - } - bytes_read = unzReadCurrentFile(unzip, buffer, sizeof(buffer)); - if (bytes_read != (int32_t)strlen(test_data)) - { - printf("Failed to read zip entry data (%" PRId32 ")\n", err); - unzCloseCurrentFile(unzip); - return err; - } - if (unzEndOfFile(unzip) != 1) - { - printf("End of unzip not reported correctly\n"); - return UNZ_INTERNALERROR; - } - err = unzCloseCurrentFile(unzip); - if (err != UNZ_OK) - { - printf("Failed to close current file (%" PRId32 ")\n", err); - return err; - } - - if (unztell(unzip) != bytes_read) - { - printf("Unzip position not reported correctly\n"); - return UNZ_INTERNALERROR; - } - - err = unzGoToNextFile(unzip); - if (err != UNZ_OK) - { - printf("Failed to get next file info (%" PRId32 ")\n", err); - return err; - } - - comment[0] = 0; - err = unzGetCurrentFileInfo(unzip, &file_info, filename, sizeof(filename), NULL, 0, comment, sizeof(comment)); - if (err != UNZ_OK) - { - printf("Failed to get current file info (%" PRId32 ")\n", err); - return err; - } - if (strcmp(comment, "test local comment") != 0) - { - printf("Unexpected local comment value (%s)\n", comment); - return err; - } - - err = unzGetFilePos(unzip, &file_pos); - if (err != UNZ_OK) - { - printf("Failed to get file position (%" PRId32 ")\n", err); - return err; - } - if (file_pos.num_of_file != 1) - { - printf("Unzip file position not reported correctly\n"); - return UNZ_INTERNALERROR; - } - - err = unzGetOffset(unzip); - if (err <= 0) - { - printf("Unzip invalid offset reported\n"); - return UNZ_INTERNALERROR; - } - - err = unzGoToNextFile(unzip); - - if (err != UNZ_END_OF_LIST_OF_FILE) - { - printf("Failed to reach end of zip entries (%" PRId32 ")\n", err); - unzCloseCurrentFile(unzip); - return err; - } - err = unzSeek64(unzip, 0, SEEK_SET); - } - - return UNZ_OK; -} - -#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 void *ZCALLBACK fopen_file_func(void *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; -} - -static unsigned long ZCALLBACK fread_file_func(void *opaque, void *stream, void *buf, unsigned long size) -{ - return (unsigned long)fread(buf, 1, (size_t)size, (FILE *)stream); -} - -static unsigned long ZCALLBACK fwrite_file_func(void *opaque, void *stream, const void *buf, unsigned long size) -{ - return (unsigned long)fwrite(buf, 1, (size_t)size, (FILE *)stream); -} - -static long ZCALLBACK ftell_file_func(void *opaque, void *stream) -{ - return ftell((FILE *)stream); -} - -static ZPOS64_T ZCALLBACK ftell64_file_func(void *opaque, void *stream) -{ - return ftello64((FILE *)stream); -} - -static long ZCALLBACK fseek_file_func(void *opaque, void *stream, unsigned long offset, int origin) -{ - int fseek_origin = 0; - long ret = 0; - 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((FILE *)stream, offset, fseek_origin) != 0) - ret = -1; - return ret; -} - -static long ZCALLBACK fseek64_file_func(void *opaque, void *stream, ZPOS64_T offset, int origin) -{ - int fseek_origin = 0; - long ret = 0; - 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((FILE *)stream, offset, fseek_origin) != 0) - ret = -1; - return ret; -} - -static int ZCALLBACK fclose_file_func(void *opaque, void *stream) -{ - return fclose((FILE *)stream); -} - -static int ZCALLBACK ferror_file_func(void *opaque, void *stream) -{ - return ferror((FILE *)stream); -} - -void fill_ioapi32_filefunc(zlib_filefunc_def *pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen_file = fopen_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_ioapi64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def) -{ - pzlib_filefunc_def->zopen64_file = (open64_file_func)fopen_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; -} - -int32_t test_unzip_compat(void) -{ - unzFile unzip; - int32_t err = UNZ_OK; - - unzip = unzOpen("compat.zip"); - if (unzip == NULL) - { - printf("Failed to open test zip file\n"); - return UNZ_PARAMERROR; - } - err = test_unzip_compat_int(unzip); - unzClose(unzip); - - if (err != UNZ_OK) - return err; - - printf("Compat unzip.. OK\n"); - - return UNZ_OK; -} - -int32_t test_unzip_compat32(void) -{ - unzFile unzip; - int32_t err = UNZ_OK; - zlib_filefunc_def zlib_filefunc_def; - - fill_ioapi32_filefunc(&zlib_filefunc_def); - unzip = unzOpen2("compat.zip", &zlib_filefunc_def); - if (unzip == NULL) - { - printf("Failed to open test zip file\n"); - return UNZ_PARAMERROR; - } - err = test_unzip_compat_int(unzip); - unzClose(unzip); - - if (err != UNZ_OK) - return err; - - printf("Compat unzip with 32-bit ioapi.. OK\n"); - - return UNZ_OK; -} - -int32_t test_unzip_compat64(void) -{ - unzFile unzip; - int32_t err = UNZ_OK; - zlib_filefunc64_def zlib_filefunc_def; - - fill_ioapi64_filefunc(&zlib_filefunc_def); - unzip = unzOpen2_64("compat.zip", &zlib_filefunc_def); - if (unzip == NULL) - { - printf("Failed to open test zip file\n"); - return UNZ_PARAMERROR; - } - err = test_unzip_compat_int(unzip); - unzClose(unzip); - - if (err != UNZ_OK) - return err; - - printf("Compat unzip with 64-bit ioapi.. OK\n"); - - return UNZ_OK; -} -#endif - -/***************************************************************************/ - -int main(int argc, const char *argv[]) -{ - int32_t err = MZ_OK; - - MZ_UNUSED(argc); - MZ_UNUSED(argv); - - err |= test_path_resolve(); - err |= test_utf8(); - err |= test_stream_find(); - err |= test_stream_find_reverse(); - -#if !defined(MZ_ZIP_NO_COMPRESSION) && !defined(MZ_ZIP_NO_DECOMPRESSION) -#ifdef HAVE_BZIP2 - err |= test_stream_bzip(); -#endif -#ifdef HAVE_ZLIB - err |= test_stream_zlib(); - err |= test_stream_zlib_mem(); -#ifdef HAVE_COMPAT - err |= test_zip_compat(); - err |= test_unzip_compat(); - err |= test_unzip_compat32(); - err |= test_unzip_compat64(); -#endif -#endif -#endif - -#ifdef HAVE_PKCRYPT - err |= test_stream_pkcrypt(); -#endif -#if !defined(MZ_ZIP_NO_CRYPTO) -#ifdef HAVE_WZAES - err |= test_stream_wzaes(); -#endif - err |= test_crypt_sha(); - err |= test_crypt_aes(); - err |= test_crypt_hmac(); -#endif - - return err; -} - -/***************************************************************************/ diff --git a/minizip-ng/test/test.h b/minizip-ng/test/test.h deleted file mode 100644 index dfa6fb7..0000000 --- a/minizip-ng/test/test.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _MZ_TEST_H -#define _MZ_TEST_H - -#ifdef __cplusplus -extern "C" { -#endif - -/***************************************************************************/ - -int32_t test_stream_bzip(void); -int32_t test_stream_pkcrypt(void); -int32_t test_stream_wzaes(void); -int32_t test_stream_zlib(void); -int32_t test_stream_zlib_mem(void); -int32_t test_stream_find(void); -int32_t test_stream_find_reverse(void); - -int32_t test_crypt_sha(void); -int32_t test_crypt_aes(void); -int32_t test_crypt_hmac(void); - -/***************************************************************************/ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/minizip-ng/test/test.p12 b/minizip-ng/test/test.p12 deleted file mode 100644 index 764c01fa6bf6111d7a99e297be473a1b2f483602..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2603 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 ArvLx| diff --git a/minizip-ng/test/test.pem b/minizip-ng/test/test.pem deleted file mode 100644 index bd3a994..0000000 --- a/minizip-ng/test/test.pem +++ /dev/null @@ -1,61 +0,0 @@ -Bag Attributes - friendlyName: Minizip - localKeyID: 58 47 0B C9 69 23 3A 00 CD 7E 00 94 80 25 34 19 43 A8 C9 6C -subject=/CN=Minizip/O=Minizip/OU=MZ/ST=AZ/C=US/L=Phoenix/emailAddress=nathan@nathanm.com -issuer=/CN=Minizip/O=Minizip/OU=MZ/ST=AZ/C=US/L=Phoenix/emailAddress=nathan@nathanm.com ------BEGIN CERTIFICATE----- -MIIDpzCCAo+gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgDEQMA4GA1UEAwwHTWlu -aXppcDEQMA4GA1UECgwHTWluaXppcDELMAkGA1UECwwCTVoxCzAJBgNVBAgMAkFa -MQswCQYDVQQGEwJVUzEQMA4GA1UEBwwHUGhvZW5peDEhMB8GCSqGSIb3DQEJARYS -bmF0aGFuQG5hdGhhbm0uY29tMB4XDTE5MTExMTAyMjYwMVoXDTM4MDIxMDAyMjYw -MVowgYAxEDAOBgNVBAMMB01pbml6aXAxEDAOBgNVBAoMB01pbml6aXAxCzAJBgNV -BAsMAk1aMQswCQYDVQQIDAJBWjELMAkGA1UEBhMCVVMxEDAOBgNVBAcMB1Bob2Vu -aXgxITAfBgkqhkiG9w0BCQEWEm5hdGhhbkBuYXRoYW5tLmNvbTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAORnHpfjKNyRKiVoziTDXQAr5Bbaju33vhW6 -RVK1mBbDWmDQUgRa/iHlpJMxeHOmAZOezeu+h9VWJ9Co1zMO7aoJfbvHk7iYTFBY -7lFpXi5xdMvSngmNq2+DGnAylwuPjmwFmbFftML/Fk/u5P/0KB4lxLY0n5pUppO6 -sU4J6S1NjlNc19zW1fy2BXMibTxEFz9SMWCpKPy22JbBhzIWhzfQQlVHsQmx8yaR -LMLYGNurjZ8gJcObMQo7atN6IJb7rUSgTt2xLceL+aFGjb8dNap2fb/KsWNUR+OM -s8GVEjHoOrgu5xqGN2GVAeoccPyDySVk0B0nqJ1byDBoHli+fwMCAwEAAaMqMCgw -DgYDVR0PAQH/BAQDAgKEMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3 -DQEBCwUAA4IBAQBWcLT4hkSE1csTj2IhRvRoKX5eOz4g/GL4BbMsBmIYdTNcAT/M -NF5gIgeZRHJUiaaprTAawG6Kmbf9cUUSz04bWMitErJmYAPC9PmZhN501YzIsr8c -hks5+MCE0Z0P6STgor3hxGZ5RSuh6vCzKjgIONMXOevuBPCItJZmKIrOowHH/VvT -YUVcn3ZqBRPVOHeFuBugRyw8/RqpU/SpPb1Pupo9M7KVVNztpXMzfVV2tw2yNQiZ -7GSXKF65ukDfQ8t7+4cWbINmKpkDyA5Bg5lcQT3DpjKmiUTYGtqKU13m/OgbES9g -yampfcsNiorTiKw6JnSuwjv6VAZC+FZlz03b ------END CERTIFICATE----- -Bag Attributes - friendlyName: Minizip - localKeyID: 58 47 0B C9 69 23 3A 00 CD 7E 00 94 80 25 34 19 43 A8 C9 6C -Key Attributes: ------BEGIN ENCRYPTED PRIVATE KEY----- -MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIingOHkhKlgECAggA -MBQGCCqGSIb3DQMHBAh61f17heSelQSCBMimyG3FA8h7rYN9jhVWXSmzt8ep9SbB -Q0b7fBL5liTiT5kxpWYbALaKOZ9kwKha2ceeYx7J54n1O+ZguYIVqhprfpl3NpSG -RizuChi30/GRyqejhqdVmZfnGFqyxI9KQce0KXtVq/LPbhNP/YAsSgnt20n+lJ+Z -1rvSFJRsK90bN1Iawl+iqLA9iT//6xf/4BoKFJrnWUUwmqh9Vuak0a1mgalLrx9y -lvakOsKoVgylSKkAzCHZyo5riU5a2ORz7I2gQKYjxcs1hSywhHXsNdDJe3p/j4QC -7kL+20EqwfOUWMBSdPKm25H1Pkent+Zv9O9CzzTKWT/6XVYYCvdRCXy0pOcDcfkL -l2FU8Hi2x7CZ1Q2+36pVo2s/LK/J61vvSvdxDk3Q6Qp6KhwDIPc6knpcgjx6EKnB -5Dn9Jc12KXvkNdc0e6lx1KFX0p1RUYwLGPloywBgAghWsmNOOk6NT5r2fRD2YgUd -4MM823pcnGrK8l+diWO3JqR0P7ElKnxf7C3y8Ql+FNwaht8B7tyNUqgQpCdtmapi -9KOpFQ1iDY52nrwzJTp8muN9S5OPWwIs62kNkd9LpvKAHuWcBm8JR3xB9EmbLNI+ -9gQ1OzNpk7rC8vYwr98fdQ2ERdO3p0kgsgjoUZlCoTx176bmZNPffdJlW9VyUNUp -Cv/763miAHDzeLmb/In6YQHLHBAgFr2A1rAcInQeud8Dh0mDnj01JTjvcn9hM+D7 -mTMqme7OjScEf0t5JvipulMXyPuGmzJtVICiW6GXUBMGswI9oGomZyJYVtY32R8s -c3jsQRxrg8JXKL4vpgkZJ5OBBoNKkr/JOO5ebprzUr5AKSt/1PicD8AZ1g1aS3Jb -0u8gev8APVXiSzMs1WKBZvhsnh1xqsa2WhdBLvw8vuXDz7qgfbVgtSPzVudvPEHU -IC9kN2Qsuxz8B/7r7ZDMNRL0HoSxoG75umWmo7DqtTiojYrzpWvuzGqZERsAx1Ws -BZLP0eIo2u4ZGdJWYSxN0ZQtR/AiEgyE/l78Mbrea84l/4W54Se298Vflz4PANUe -wPRRcOwp99emome098jne15ZRwKKuvAMSKhukTtnrLXipR23TxfvsRBzw9IQ0Yl5 -LhLKWGCacpZSJiWg8ZQ6F3x6Ey19nJKp06vkhP4cdMVHICEkd4sON7s7wdr5BSZ8 -ZUA5pm+9s8AemEYt+V+Njx10lkUNDxVYlJB7ccL2q9jh3BDIUgNUxHEpCKk4Eala -T+qGIuu95fInd/Q0jldXSKwGdIEjejdDzN9+kj5mQwOHix7u/H8EfZTQv0vd41XW -RSpHy2MH6uOSd/LW/+yRtmjfAmiT/0IqLMia6BSqafZWvCZhPtQLSOBam7iCbQ+J -jqEqdqcwFmdLW1wQkmt1uqTTZyOZ9GyLfEqN9eTV2CD09t6fTj4jBB1Wdm+VPxdP -Pde+1jj83sCeMKg3ZHkvufOAkXbBJzH4ocz0S61V3j5AkX0g74EFeWL36F7foRmk -XkDyWJXjnkgTEtl7qC13HN2ueyS3lk8Z7frT2YRz+H8akYyCsr9S5VnnD9U42+52 -s6NzGaIfTSESjprq7E7rrHASSIbvfWV7MIddh40qWRq16YP/rgUTTyesI8QD4kkQ -kYU= ------END ENCRYPTED PRIVATE KEY----- diff --git a/minizip-ng/test/uniform.bin b/minizip-ng/test/uniform.bin deleted file mode 100644 index eb4b8f0..0000000 --- a/minizip-ng/test/uniform.bin +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file