pax_global_header 0000666 0000000 0000000 00000000064 14126475503 0014521 g ustar 00root root 0000000 0000000 52 comment=7a1ea574f9503fb40738dad63605d4bf643f3378
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/ 0000775 0000000 0000000 00000000000 14126475503 0020774 5 ustar 00root root 0000000 0000000 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/.gitignore 0000664 0000000 0000000 00000000301 14126475503 0022756 0 ustar 00root root 0000000 0000000 stage/
autobuild-parabuild-bootstrap/
zlib/*.lo
zlib/*.o
zlib/*.so*
zlib/*.a
zlib/*.pc
zlib/example*
zlib/minigzip*
zlib/*.dylib
zlib/ztest*.dSYM/
zlib/configure.log
zlib/Makefile
zlib/zconf.h
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/.gitlab-ci.yml 0000664 0000000 0000000 00000000305 14126475503 0023426 0 ustar 00root root 0000000 0000000 include:
- project: 'alchemy/infrastructure/gitlab-ci-config'
file: '3p-library.yml'
variables:
BUILD_COMMON: 0
BUILD_WINDOWS: 1
BUILD_WINDOWS64: 1
BUILD_LINUX64: 1
BUILD_MACOS: 1
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/README.md 0000664 0000000 0000000 00000000016 14126475503 0022250 0 ustar 00root root 0000000 0000000 # 3p-minizip
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/autobuild.xml 0000664 0000000 0000000 00000015217 14126475503 0023514 0 ustar 00root root 0000000 0000000
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/build-cmd.sh 0000775 0000000 0000000 00000036210 14126475503 0023175 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
cd "$(dirname "$0")"
# turn on verbose debugging output for logs.
exec 4>&1; export BASH_XTRACEFD=4; set -x
# make errors fatal
set -e
# bleat on references to undefined shell variables
set -u
MZ_SOURCE_DIR="minizip"
top="$(pwd)"
stage="$top"/stage
# load autobuild provided shell functions and variables
case "$AUTOBUILD_PLATFORM" in
windows*)
autobuild="$(cygpath -u "$AUTOBUILD")"
;;
*)
autobuild="$AUTOBUILD"
;;
esac
source_environment_tempfile="$stage/source_environment.sh"
"$autobuild" source_environment > "$source_environment_tempfile"
. "$source_environment_tempfile"
VERSION_HEADER_FILE="$MZ_SOURCE_DIR/mz.h"
version=$(sed -n -E 's/#define MZ_VERSION [(]"([0-9.]+)"[)]/\1/p' "${VERSION_HEADER_FILE}")
echo "${version}" > "${stage}/VERSION.txt"
pushd "$MZ_SOURCE_DIR"
case "$AUTOBUILD_PLATFORM" in
# ------------------------ windows, windows64 ------------------------
windows*)
load_vsvars
if [ "$AUTOBUILD_ADDRSIZE" = 32 ]
then
archflags="/arch:SSE2"
else
archflags=""
fi
mkdir -p "$stage/include/minizip"
mkdir -p "$stage/lib/debug"
mkdir -p "$stage/lib/release"
mkdir -p "build_debug"
pushd "build_debug"
# Invoke cmake and use as official build
cmake -G "$AUTOBUILD_WIN_CMAKE_GEN" -A "$AUTOBUILD_WIN_VSPLATFORM" -T host="$AUTOBUILD_WIN_VSHOST" .. -DBUILD_SHARED_LIBS:BOOL=OFF \
-DMZ_BUILD_TESTS=ON -DMZ_BUILD_UNIT_TESTS=ON -DMZ_SIGNING=OFF -DMZ_LIBCOMP=OFF -DMZ_ZIB_OVERRIDE=ON -DZLIB_COMPAT=ON -DMZ_FETCH_LIBS=OFF \
-DZLIB_INCLUDE_DIRS="$(cygpath -m $stage)/packages/include/zlib/" -DZLIB_LIBRARIES="$(cygpath -m $stage)/packages/lib/debug/zlibd.lib" -DZLIB_LIBRARY_DIRS="$(cygpath -m $stage)/packages/lib"
cmake --build . --config Debug --clean-first
# conditionally run unit tests
if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
ctest -C Debug
fi
cp -a "Debug/libminizip.lib" "$stage/lib/debug/"
popd
mkdir -p "build_release"
pushd "build_release"
# Invoke cmake and use as official build
cmake -G "$AUTOBUILD_WIN_CMAKE_GEN" -A "$AUTOBUILD_WIN_VSPLATFORM" -T host="$AUTOBUILD_WIN_VSHOST" .. -DBUILD_SHARED_LIBS:BOOL=OFF \
-DMZ_BUILD_TESTS=ON -DMZ_BUILD_UNIT_TESTS=ON -DMZ_SIGNING=OFF -DMZ_LIBCOMP=OFF -DMZ_ZIB_OVERRIDE=ON -DZLIB_COMPAT=ON -DMZ_FETCH_LIBS=OFF \
-DZLIB_INCLUDE_DIRS="$(cygpath -m $stage)/packages/include/zlib/" -DZLIB_LIBRARIES="$(cygpath -m $stage)/packages/lib/release/zlib.lib" -DZLIB_LIBRARY_DIRS="$(cygpath -m $stage)/packages/lib"
cmake --build . --config Release --clean-first
# conditionally run unit tests
if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
ctest -C Release
fi
cp -a "Release/libminizip.lib" "$stage/lib/release/"
popd
cp -a mz.h "$stage/include/minizip"
cp -a mz_os.h "$stage/include/minizip"
cp -a mz_crypt.h "$stage/include/minizip"
cp -a mz_strm.h "$stage/include/minizip"
cp -a mz_strm_buf.h "$stage/include/minizip"
cp -a mz_strm_mem.h "$stage/include/minizip"
cp -a mz_strm_split.h "$stage/include/minizip"
cp -a mz_strm_os.h "$stage/include/minizip"
cp -a mz_zip.h "$stage/include/minizip"
cp -a mz_zip_rw.h "$stage/include/minizip"
cp -a mz_strm_zlib.h "$stage/include/minizip"
cp -a mz_strm_pkcrypt.h "$stage/include/minizip"
cp -a mz_strm_wzaes.h "$stage/include/minizip"
cp -a mz_compat.h "$stage/include/minizip"
cp -a zip.h "$stage/include/minizip"
cp -a unzip.h "$stage/include/minizip"
;;
# ------------------------- darwin, darwin64 -------------------------
darwin*)
# Setup osx sdk platform
SDKNAME="macosx"
export SDKROOT=$(xcodebuild -version -sdk ${SDKNAME} Path)
export MACOSX_DEPLOYMENT_TARGET=10.13
# Setup build flags
ARCH_FLAGS="-arch x86_64"
SDK_FLAGS="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET} -isysroot ${SDKROOT}"
DEBUG_COMMON_FLAGS="$ARCH_FLAGS $SDK_FLAGS -Og -g -msse4.2 -fPIC -DPIC"
RELEASE_COMMON_FLAGS="$ARCH_FLAGS $SDK_FLAGS -O3 -g -msse4.2 -fPIC -DPIC -fstack-protector-strong"
DEBUG_CFLAGS="$DEBUG_COMMON_FLAGS"
RELEASE_CFLAGS="$RELEASE_COMMON_FLAGS"
DEBUG_CXXFLAGS="$DEBUG_COMMON_FLAGS -std=c++17"
RELEASE_CXXFLAGS="$RELEASE_COMMON_FLAGS -std=c++17"
DEBUG_CPPFLAGS="-DPIC"
RELEASE_CPPFLAGS="-DPIC"
DEBUG_LDFLAGS="$ARCH_FLAGS $SDK_FLAGS -Wl,-headerpad_max_install_names -Wl,-macos_version_min,$MACOSX_DEPLOYMENT_TARGET"
RELEASE_LDFLAGS="$ARCH_FLAGS $SDK_FLAGS -Wl,-headerpad_max_install_names -Wl,-macos_version_min,$MACOSX_DEPLOYMENT_TARGET"
mkdir -p "$stage/include/minizip"
mkdir -p "$stage/lib/debug"
mkdir -p "$stage/lib/release"
mkdir -p "build_debug"
pushd "build_debug"
CFLAGS="$DEBUG_CFLAGS" \
CXXFLAGS="$DEBUG_CXXFLAGS" \
CPPFLAGS="$DEBUG_CPPFLAGS" \
LDFLAGS="$DEBUG_LDFLAGS" \
cmake .. -GXcode -DBUILD_SHARED_LIBS:BOOL=OFF \
-DCMAKE_C_FLAGS="$DEBUG_CFLAGS" \
-DCMAKE_CXX_FLAGS="$DEBUG_CXXFLAGS" \
-DCMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL="0" \
-DCMAKE_XCODE_ATTRIBUTE_GCC_FAST_MATH=NO \
-DCMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS=YES \
-DCMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT=dwarf \
-DCMAKE_XCODE_ATTRIBUTE_LLVM_LTO=NO \
-DCMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS=sse4.2 \
-DCMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD="c++17" \
-DCMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY="libc++" \
-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY="" \
-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64 \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} \
-DCMAKE_OSX_SYSROOT=${SDKROOT} \
-DCMAKE_MACOSX_RPATH=YES -DCMAKE_INSTALL_PREFIX=$stage \
-DMZ_BUILD_TESTS=ON -DMZ_BUILD_UNIT_TESTS=ON -DMZ_SIGNING=OFF -DMZ_LIBCOMP=OFF -DMZ_ZIB_OVERRIDE=ON -DZLIB_COMPAT=ON -DMZ_FETCH_LIBS=OFF \
-DZLIB_INCLUDE_DIRS="${stage}/packages/include/zlib/" -DZLIB_LIBRARIES="${stage}/packages/lib/debug/libz.a" -DZLIB_LIBRARY_DIRS="${stage}/packages/lib"
cmake --build . --config Debug
# conditionally run unit tests
if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
ctest -C Debug
fi
cp -a Debug/libminizip*.a* "${stage}/lib/debug/"
popd
mkdir -p "build_release"
pushd "build_release"
CFLAGS="$RELEASE_CFLAGS" \
CXXFLAGS="$RELEASE_CXXFLAGS" \
CPPFLAGS="$RELEASE_CPPFLAGS" \
LDFLAGS="$RELEASE_LDFLAGS" \
cmake .. -GXcode -DBUILD_SHARED_LIBS:BOOL=OFF \
-DCMAKE_C_FLAGS="$RELEASE_CFLAGS" \
-DCMAKE_CXX_FLAGS="$RELEASE_CXXFLAGS" \
-DCMAKE_XCODE_ATTRIBUTE_GCC_OPTIMIZATION_LEVEL="3" \
-DCMAKE_XCODE_ATTRIBUTE_GCC_FAST_MATH=NO \
-DCMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS=YES \
-DCMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT=dwarf \
-DCMAKE_XCODE_ATTRIBUTE_LLVM_LTO=NO \
-DCMAKE_XCODE_ATTRIBUTE_CLANG_X86_VECTOR_INSTRUCTIONS=sse4.2 \
-DCMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD="c++17" \
-DCMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY="libc++" \
-DCMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY="" \
-DCMAKE_OSX_ARCHITECTURES:STRING=x86_64 \
-DCMAKE_OSX_DEPLOYMENT_TARGET=${MACOSX_DEPLOYMENT_TARGET} \
-DCMAKE_OSX_SYSROOT=${SDKROOT} \
-DCMAKE_MACOSX_RPATH=YES -DCMAKE_INSTALL_PREFIX=$stage \
-DMZ_BUILD_TESTS=ON -DMZ_BUILD_UNIT_TESTS=ON -DMZ_SIGNING=OFF -DMZ_LIBCOMP=OFF -DMZ_ZIB_OVERRIDE=ON -DZLIB_COMPAT=ON -DMZ_FETCH_LIBS=OFF \
-DZLIB_INCLUDE_DIRS="${stage}/packages/include/zlib/" -DZLIB_LIBRARIES="${stage}/packages/lib/release/libz.a" -DZLIB_LIBRARY_DIRS="${stage}/packages/lib"
cmake --build . --config Release
# conditionally run unit tests
if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
ctest -C Release
fi
cp -a Release/libminizip*.a* "${stage}/lib/release/"
popd
cp -a mz.h "$stage/include/minizip"
cp -a mz_os.h "$stage/include/minizip"
cp -a mz_crypt.h "$stage/include/minizip"
cp -a mz_strm.h "$stage/include/minizip"
cp -a mz_strm_buf.h "$stage/include/minizip"
cp -a mz_strm_mem.h "$stage/include/minizip"
cp -a mz_strm_split.h "$stage/include/minizip"
cp -a mz_strm_os.h "$stage/include/minizip"
cp -a mz_zip.h "$stage/include/minizip"
cp -a mz_zip_rw.h "$stage/include/minizip"
cp -a mz_strm_zlib.h "$stage/include/minizip"
cp -a mz_strm_pkcrypt.h "$stage/include/minizip"
cp -a mz_strm_wzaes.h "$stage/include/minizip"
cp -a mz_compat.h "$stage/include/minizip"
cp -a zip.h "$stage/include/minizip"
cp -a unzip.h "$stage/include/minizip"
;;
# -------------------------- linux, linux64 --------------------------
linux*)
unset DISTCC_HOSTS CC CXX CFLAGS CPPFLAGS CXXFLAGS
# Default target per autobuild build --address-size
opts="${TARGET_OPTS:--m$AUTOBUILD_ADDRSIZE}"
DEBUG_COMMON_FLAGS="$opts -Og -g -fPIC -DPIC"
RELEASE_COMMON_FLAGS="$opts -O3 -g -fPIC -DPIC -fstack-protector-strong -D_FORTIFY_SOURCE=2"
DEBUG_CFLAGS="$DEBUG_COMMON_FLAGS"
RELEASE_CFLAGS="$RELEASE_COMMON_FLAGS"
DEBUG_CXXFLAGS="$DEBUG_COMMON_FLAGS -std=c++17"
RELEASE_CXXFLAGS="$RELEASE_COMMON_FLAGS -std=c++17"
DEBUG_CPPFLAGS="-DPIC"
RELEASE_CPPFLAGS="-DPIC"
# Handle any deliberate platform targeting
if [ -z "${TARGET_CPPFLAGS:-}" ]; then
# Remove sysroot contamination from build environment
unset CPPFLAGS
else
# Incorporate special pre-processing flags
export CPPFLAGS="$TARGET_CPPFLAGS"
fi
# Fix up path for pkgconfig
if [ -d "$stage/packages/lib/release/pkgconfig" ]; then
fix_pkgconfig_prefix "$stage/packages"
fi
OLD_PKG_CONFIG_PATH="${PKG_CONFIG_PATH:-}"
mkdir -p "$stage/include/minizip"
mkdir -p "$stage/lib/debug"
mkdir -p "$stage/lib/release"
mkdir -p "build_debug"
pushd "build_debug"
# Debug first
export PKG_CONFIG_PATH="$stage/packages/lib/debug/pkgconfig:${OLD_PKG_CONFIG_PATH}"
CFLAGS="$DEBUG_CFLAGS" \
CXXFLAGS="$DEBUG_CXXFLAGS" \
CPPFLAGS="$DEBUG_CPPFLAGS" \
cmake .. -G"Unix Makefiles" -DBUILD_SHARED_LIBS:BOOL=OFF \
-DCMAKE_C_FLAGS="$DEBUG_CFLAGS" \
-DCMAKE_CXX_FLAGS="$DEBUG_CXXFLAGS" \
-DCMAKE_INSTALL_PREFIX=$stage \
-DMZ_BUILD_TESTS=ON -DMZ_BUILD_UNIT_TESTS=ON -DMZ_SIGNING=OFF -DMZ_LIBCOMP=OFF -DMZ_ZIB_OVERRIDE=ON -DZLIB_COMPAT=ON -DMZ_FETCH_LIBS=OFF \
-DZLIB_INCLUDE_DIRS="${stage}/packages/include/zlib/" -DZLIB_LIBRARIES="${stage}/packages/lib/debug/libz.a" -DZLIB_LIBRARY_DIRS="${stage}/packages/lib"
cmake --build . --config Debug
# conditionally run unit tests
if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
ctest -C Debug
fi
cp -a libminizip*.a* "${stage}/lib/debug/"
popd
mkdir -p "build_release"
pushd "build_release"
# Release last
export PKG_CONFIG_PATH="$stage/packages/lib/release/pkgconfig:${OLD_PKG_CONFIG_PATH}"
CFLAGS="$RELEASE_CFLAGS" \
CXXFLAGS="$RELEASE_CXXFLAGS" \
CPPFLAGS="$RELEASE_CPPFLAGS" \
cmake .. -G"Unix Makefiles" -DBUILD_SHARED_LIBS:BOOL=OFF \
-DCMAKE_C_FLAGS="$RELEASE_CFLAGS" \
-DCMAKE_CXX_FLAGS="$RELEASE_CXXFLAGS" \
-DCMAKE_INSTALL_PREFIX=$stage \
-DMZ_BUILD_TESTS=ON -DMZ_BUILD_UNIT_TESTS=ON -DMZ_SIGNING=OFF -DMZ_LIBCOMP=OFF -DMZ_ZIB_OVERRIDE=ON -DZLIB_COMPAT=ON -DMZ_FETCH_LIBS=OFF \
-DZLIB_INCLUDE_DIRS="${stage}/packages/include/zlib/" -DZLIB_LIBRARIES="${stage}/packages/lib/release/libz.a" -DZLIB_LIBRARY_DIRS="${stage}/packages/lib"
cmake --build . --config Release
# conditionally run unit tests
if [ "${DISABLE_UNIT_TESTS:-0}" = "0" ]; then
ctest -C Release
fi
cp -a libminizip*.a* "${stage}/lib/release/"
popd
cp -a mz.h "$stage/include/minizip"
cp -a mz_os.h "$stage/include/minizip"
cp -a mz_crypt.h "$stage/include/minizip"
cp -a mz_strm.h "$stage/include/minizip"
cp -a mz_strm_buf.h "$stage/include/minizip"
cp -a mz_strm_mem.h "$stage/include/minizip"
cp -a mz_strm_split.h "$stage/include/minizip"
cp -a mz_strm_os.h "$stage/include/minizip"
cp -a mz_zip.h "$stage/include/minizip"
cp -a mz_zip_rw.h "$stage/include/minizip"
cp -a mz_strm_zlib.h "$stage/include/minizip"
cp -a mz_strm_pkcrypt.h "$stage/include/minizip"
cp -a mz_strm_wzaes.h "$stage/include/minizip"
cp -a mz_compat.h "$stage/include/minizip"
cp -a zip.h "$stage/include/minizip"
cp -a unzip.h "$stage/include/minizip"
;;
esac
mkdir -p "$stage/LICENSES"
cp LICENSE "$stage/LICENSES/minizip-ng.txt"
# In case the section header changes, ensure that minizip-ng.txt is non-empty.
# (With -e in effect, a raw test command has the force of an assert.)
# Exiting here means we failed to match the copyright section header.
# Check the README and adjust the awk regexp accordingly.
[ -s "$stage/LICENSES/minizip-ng.txt" ]
popd
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/ 0000775 0000000 0000000 00000000000 14126475503 0022453 5 ustar 00root root 0000000 0000000 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/.github/ 0000775 0000000 0000000 00000000000 14126475503 0024013 5 ustar 00root root 0000000 0000000 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/.github/FUNDING.yml 0000664 0000000 0000000 00000000021 14126475503 0025621 0 ustar 00root root 0000000 0000000 github: nmoinvaz
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/.github/workflows/ 0000775 0000000 0000000 00000000000 14126475503 0026050 5 ustar 00root root 0000000 0000000 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/.github/workflows/codeql-analysis.yml0000664 0000000 0000000 00000003027 14126475503 0031665 0 ustar 00root root 0000000 0000000 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/.github/workflows/fuzz.yml 0000664 0000000 0000000 00000001133 14126475503 0027567 0 ustar 00root root 0000000 0000000 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/.github/workflows/main.yml 0000664 0000000 0000000 00000023176 14126475503 0027530 0 ustar 00root root 0000000 0000000 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 }}"
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/CMakeLists.txt 0000664 0000000 0000000 00000110643 14126475503 0025220 0 ustar 00root root 0000000 0000000 #***************************************************************************
# 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" OFF)
option(MZ_LZMA "Enables LZMA & XZ compression" OFF)
option(MZ_ZSTD "Enables ZSTD compression" OFF)
option(MZ_LIBCOMP "Enables Apple compression" OFF)
option(MZ_FETCH_LIBS "Enables fetching third-party libraries if not found" OFF)
option(MZ_FORCE_FETCH_LIBS "Enables fetching third-party libraries always" OFF)
# Encryption support options
option(MZ_PKCRYPT "Enables PKWARE traditional encryption" OFF)
option(MZ_WZAES "Enables WinZIP AES encryption" OFF)
option(MZ_OPENSSL "Enables OpenSSL for encryption" OFF)
option(MZ_LIBBSD "Enable libbsd crypto random" OFF)
option(MZ_SIGNING "Enables zip signing support" OFF)
# 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.3")
# API version
set(SOVERSION "3")
include(CheckLibraryExists)
include(CheckSymbolExists)
include(CheckFunctionExists)
include(CheckIncludeFile)
include(CheckTypeSize)
include(GNUInstallDirs)
include(FeatureSummary)
set(INSTALL_BIN_DIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Installation directory for executables")
set(INSTALL_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Installation directory for libraries")
set(INSTALL_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Installation directory for headers")
set(INSTALL_MAN_DIR ${CMAKE_INSTALL_MANDIR} CACHE PATH "Installation directory for manual pages")
set(STDLIB_DEF)
set(MINIZIP_DEF)
set(MINIZIP_INC)
set(MINIZIP_LIB)
set(MINIZIP_LBD)
set(MINIZIP_DEP)
set(MINIZIP_DEP_PKG)
set(MINIZIP_LFG)
# Initial source files
set(MINIZIP_SRC
mz_crypt.c
mz_os.c
mz_strm.c
mz_strm_buf.c
mz_strm_mem.c
mz_strm_split.c
mz_zip.c
mz_zip_rw.c)
# Initial header files
set(MINIZIP_HDR
mz.h
mz_os.h
mz_crypt.h
mz_strm.h
mz_strm_buf.h
mz_strm_mem.h
mz_strm_split.h
mz_strm_os.h
mz_zip.h
mz_zip_rw.h)
set(PC_PRIVATE_LIBS)
# Check for system includes
check_include_file(stdint.h HAVE_STDINT_H)
check_include_file(inttypes.h HAVE_INTTYPES_H)
if(HAVE_STDINT_H)
list(APPEND STDLIB_DEF -DHAVE_STDINT_H)
endif()
if(HAVE_INTTYPES_H)
list(APPEND STDLIB_DEF -DHAVE_INTTYPES_H)
endif()
# Check for large file support
check_type_size(off64_t OFF64_T)
if(HAVE_OFF64_T)
list(APPEND STDLIB_DEF -D__USE_LARGEFILE64)
list(APPEND STDLIB_DEF -D_LARGEFILE64_SOURCE)
endif()
# Check for fseeko support
check_function_exists(fseeko HAVE_FSEEKO)
if(NOT HAVE_FSEEKO)
list(APPEND STDLIB_DEF -DNO_FSEEKO)
endif()
# Checkout remote repository
macro(clone_repo name url)
if(NOT ${name}_REPOSITORY)
set(${name}_REPOSITORY ${url})
endif()
if(NOT ${name}_TAG)
set(${name}_TAG master)
endif()
message(STATUS "Fetching ${name} ${${name}_REPOSITORY} ${${name}_TAG}")
# Check for FetchContent cmake support
if(${CMAKE_VERSION} VERSION_LESS "3.11")
message(FATAL_ERROR "CMake 3.11 required to fetch ${name}")
else()
include(FetchContent)
string(TOLOWER ${name} name_lower)
string(TOUPPER ${name} name_upper)
FetchContent_Declare(${name}
GIT_REPOSITORY ${${name}_REPOSITORY}
GIT_TAG ${${name}_TAG}
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/${name_lower})
FetchContent_GetProperties(${name} POPULATED ${name_lower}_POPULATED)
if(NOT ${name_lower}_POPULATED)
FetchContent_Populate(${name})
endif()
set(${name_upper}_SOURCE_DIR ${${name_lower}_SOURCE_DIR})
set(${name_upper}_BINARY_DIR ${${name_lower}_BINARY_DIR})
endif()
endmacro()
if(MZ_LIBCOMP)
if(APPLE)
# Use Apple libcompression
list(APPEND MINIZIP_DEF -DHAVE_LIBCOMP)
list(APPEND MINIZIP_SRC mz_strm_libcomp.c)
list(APPEND MINIZIP_HDR mz_strm_libcomp.h)
list(APPEND MINIZIP_LIB compression)
# Disable zlib as libcompression is preferred
set(MZ_ZLIB OFF)
else()
message(STATUS "LibCompression not supported on the current platform")
set(MZ_LIBCOMP OFF)
endif()
endif()
if(MZ_ZLIB)
# Check if zlib is present
if(NOT MZ_ZIB_OVERRIDE AND NOT MZ_FORCE_FETCH_LIBS)
find_package(ZLIB QUIET)
set(ZLIB_VERSION ${ZLIB_VERSION_STRING})
endif()
if(MZ_ZIB_OVERRIDE AND NOT MZ_FORCE_FETCH_LIBS)
set(ZLIB_FOUND ON)
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(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
$
$)
#
if("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
target_compile_options(${PROJECT_NAME} PRIVATE /std:c++17 /permissive- /Z7 $<$:/Ob3> $<$:/Gy> $<$:/arch:SSE2>)
target_link_options(${PROJECT_NAME} PRIVATE /DEBUG:FULL $<$:/OPT:REF> $<$:/OPT:ICF>)
endif()
#
# Create minizip alias
add_library(MINIZIP::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
# Install files
if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL)
install(TARGETS ${PROJECT_NAME} ${MINIZIP_DEP}
EXPORT ${PROJECT_NAME}
INCLUDES DESTINATION "${INSTALL_INC_DIR}"
RUNTIME DESTINATION "${INSTALL_BIN_DIR}"
ARCHIVE DESTINATION "${INSTALL_LIB_DIR}"
LIBRARY DESTINATION "${INSTALL_LIB_DIR}")
install(EXPORT ${PROJECT_NAME}
DESTINATION "${INSTALL_CMAKE_DIR}"
NAMESPACE "MINIZIP::")
# Create and install CMake package config version file to allow find_package()
include(CMakePackageConfigHelpers)
write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
COMPATIBILITY SameMajorVersion)
set(MINIZIP_CONFIG_CONTENT "@PACKAGE_INIT@\n")
if(MINIZIP_DEP_PKG)
string(APPEND MINIZIP_CONFIG_CONTENT "include(CMakeFindDependencyMacro)\n")
foreach(PKG_NAME ${MINIZIP_DEP_PKG})
string(APPEND MINIZIP_CONFIG_CONTENT "find_dependency(${PKG_NAME} REQUIRED)\n")
endforeach()
endif()
string(APPEND MINIZIP_CONFIG_CONTENT "include(\"\${CMAKE_CURRENT_LIST_DIR}/${PROJECT_NAME}.cmake\")")
file(WRITE minizip-config.cmake.in ${MINIZIP_CONFIG_CONTENT})
# Create config for find_package()
configure_package_config_file(minizip-config.cmake.in ${PROJECT_NAME}-config.cmake
INSTALL_DESTINATION "${INSTALL_CMAKE_DIR}")
file(REMOVE minizip-config.cmake.in)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
DESTINATION "${INSTALL_CMAKE_DIR}")
endif()
if(NOT SKIP_INSTALL_HDR AND NOT SKIP_INSTALL_ALL)
install(FILES ${MINIZIP_HDR} DESTINATION "${INSTALL_INC_DIR}")
endif()
if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL)
install(FILES ${MINIZIP_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}")
endif()
# Build test executables
if(MZ_BUILD_TESTS)
if(MZ_ZLIB AND NOT MZ_LIBCOMP)
add_executable(minigzip_cmd minigzip.c)
set_target_properties(minigzip_cmd PROPERTIES OUTPUT_NAME minigzip)
target_compile_definitions(minigzip_cmd PRIVATE ${STDLIB_DEF} ${MINIZIP_DEF})
target_include_directories(minigzip_cmd PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(minigzip_cmd ${PROJECT_NAME})
if(NOT SKIP_INSTALL_BINARIES AND NOT SKIP_INSTALL_ALL)
install(TARGETS minigzip_cmd RUNTIME DESTINATION "bin")
endif()
endif()
add_executable(minizip_cmd minizip.c)
set_target_properties(minizip_cmd PROPERTIES OUTPUT_NAME ${PROJECT_NAME})
target_compile_definitions(minizip_cmd PRIVATE ${STDLIB_DEF} ${MINIZIP_DEF})
target_include_directories(minizip_cmd PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(minizip_cmd ${PROJECT_NAME})
if(NOT SKIP_INSTALL_BINARIES AND NOT SKIP_INSTALL_ALL)
install(TARGETS minizip_cmd RUNTIME DESTINATION "bin")
endif()
add_executable(test_cmd test/test.c test/test.h)
target_compile_definitions(test_cmd PRIVATE ${STDLIB_DEF} ${MINIZIP_DEF})
if(MZ_COMPAT)
target_compile_definitions(test_cmd PRIVATE -DHAVE_COMPAT)
endif()
target_include_directories(test_cmd PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(test_cmd ${PROJECT_NAME})
endif()
if(MZ_BUILD_TESTS AND MZ_BUILD_UNIT_TESTS)
enable_testing()
# Can't disable zlib testing so ctest tries to run zlib example app
if(MZ_ZLIB AND NOT MZ_LIBCOMP AND NOT ZLIB_FOUND)
add_dependencies(${PROJECT_NAME} example)
if(HAVE_OFF64_T)
add_dependencies(${PROJECT_NAME} example64)
endif()
endif()
add_test(NAME test_cmd COMMAND test_cmd WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
function(create_compress_tests EXTRA_NAME EXTRA_ARGS)
if(MZ_DECOMPRESS_ONLY)
return()
endif()
list(FIND EXTRA_ARGS "-z" ZIPCD_IDX)
if(${ZIPCD_IDX} EQUAL -1)
set(COMPRESS_METHOD_NAMES "raw")
set(COMPRESS_METHOD_ARGS "-0")
endif()
if(MZ_ZLIB OR MZ_LIBCOMP)
list(APPEND COMPRESS_METHOD_NAMES "deflate")
list(APPEND COMPRESS_METHOD_ARGS "-9")
endif()
if(MZ_BZIP2)
list(APPEND COMPRESS_METHOD_NAMES "bzip2")
list(APPEND COMPRESS_METHOD_ARGS "-b")
endif()
if(MZ_LZMA)
list(APPEND COMPRESS_METHOD_NAMES "lzma")
list(APPEND COMPRESS_METHOD_ARGS "-m")
endif()
if(MZ_LZMA OR MZ_LIBCOMP)
list(APPEND COMPRESS_METHOD_NAMES "xz")
list(APPEND COMPRESS_METHOD_ARGS "-n")
endif()
if(MZ_ZSTD)
list(APPEND COMPRESS_METHOD_NAMES "zstd")
list(APPEND COMPRESS_METHOD_ARGS "-t")
endif()
list(LENGTH COMPRESS_METHOD_NAMES COMPRESS_METHOD_COUNT)
math(EXPR COMPRESS_METHOD_COUNT "${COMPRESS_METHOD_COUNT}-1")
foreach(INDEX RANGE ${COMPRESS_METHOD_COUNT})
list(GET COMPRESS_METHOD_NAMES ${INDEX} COMPRESS_METHOD_NAME)
list(GET COMPRESS_METHOD_ARGS ${INDEX} COMPRESS_METHOD_ARG)
add_test(NAME ${COMPRESS_METHOD_NAME}-zip-${EXTRA_NAME}
COMMAND minizip_cmd ${COMPRESS_METHOD_ARG} -o ${EXTRA_ARGS}
result.zip test.c test.h empty.txt random.bin uniform.bin fuzz
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
add_test(NAME ${COMPRESS_METHOD_NAME}-list-${EXTRA_NAME}
COMMAND minizip_cmd -l ${EXTRA_ARGS} result.zip
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
if(NOT MZ_COMPRESS_ONLY)
add_test(NAME ${COMPRESS_METHOD_NAME}-unzip-${EXTRA_NAME}
COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out result.zip
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
endif()
add_test(NAME ${COMPRESS_METHOD_NAME}-append-${EXTRA_NAME}
COMMAND minizip_cmd ${COMPRESS_METHOD_ARG} -a ${EXTRA_ARGS}
result.zip single.txt
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
if(NOT MZ_COMPRESS_ONLY)
add_test(NAME ${COMPRESS_METHOD_NAME}-append-unzip-${EXTRA_NAME}
COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out result.zip
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
endif()
add_test(NAME ${COMPRESS_METHOD_NAME}-erase-${EXTRA_NAME}
COMMAND minizip_cmd -o -e result.zip test.c test.h
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
if(NOT MZ_COMPRESS_ONLY)
add_test(NAME ${COMPRESS_METHOD_NAME}-erase-unzip-${EXTRA_NAME}
COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out result.zip
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
endif()
endforeach()
endfunction()
# Perform tests against ourself
create_compress_tests("generic" "")
create_compress_tests("span" "-k;1024")
create_compress_tests("zipcd" "-z")
if(MZ_PKCRYPT)
create_compress_tests("pkcrypt" "-p;test123")
endif()
if(MZ_WZAES)
create_compress_tests("wzaes" "-s;-p;test123")
endif()
if(MZ_SIGNING)
create_compress_tests("signed" "-h;test.p12;-w;test")
create_compress_tests("secure" "-z;-h;test.p12;-w;test")
endif()
# Perform tests on others
if(NOT MZ_COMPRESS_ONLY)
if(MZ_ZLIB OR MZ_LIBCOMP)
add_test(NAME unzip-tiny
COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out
fuzz/unzip_fuzzer_seed_corpus/tiny.zip
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
endif()
if(MZ_BZIP2)
add_test(NAME unzip-bzip2
COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out
fuzz/unzip_fuzzer_seed_corpus/bzip2.zip
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
endif()
if(MZ_LZMA)
add_test(NAME unzip-lzma
COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out
fuzz/unzip_fuzzer_seed_corpus/lzma.zip
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
endif()
if(MZ_PKCRYPT)
add_test(NAME unzip-pkcrypt
COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out -p test123
fuzz/unzip_fuzzer_seed_corpus/encrypted_pkcrypt.zip
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
endif()
if(MZ_WZAES)
add_test(NAME unzip-wzaes
COMMAND minizip_cmd -x -o ${EXTRA_ARGS} -d out -p test123
fuzz/unzip_fuzzer_seed_corpus/encrypted_wzaes.zip
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
endif()
endif()
if(NOT MZ_COMPRESS_ONLY AND NOT MZ_DECOMPRESS_ONLY)
if(MZ_ZLIB AND NOT MZ_LIBCOMP)
add_test(NAME gz
COMMAND minigzip_cmd random.bin
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
add_test(NAME ungz
COMMAND minigzip_cmd -x -d out random.bin.gz
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/test)
endif()
endif()
endif()
#Build fuzzer executables
if(MZ_BUILD_FUZZ_TESTS)
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
enable_language(CXX)
if(DEFINED ENV{LIB_FUZZING_ENGINE})
set(FUZZING_ENGINE $ENV{LIB_FUZZING_ENGINE})
set(FUZZING_ENGINE_FOUND TRUE)
else()
find_library(FUZZING_ENGINE "FuzzingEngine")
endif()
endif()
if(NOT FUZZING_ENGINE_FOUND)
set(FUZZER_SRC "test/fuzz/standalone.c")
else()
set(FUZZER_SRC)
endif()
macro(configure_fuzz_test target)
add_executable(${target} "test/fuzz/${target}.c" ${FUZZER_SRC})
set_target_properties(${target} PROPERTIES LINKER_LANGUAGE CXX)
target_compile_definitions(${target} PRIVATE ${STDLIB_DEF})
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(${target} ${PROJECT_NAME})
add_dependencies(${target} ${PROJECT_NAME})
if(FUZZING_ENGINE_FOUND)
target_link_libraries(${target} ${FUZZING_ENGINE})
endif()
endmacro()
configure_fuzz_test(zip_fuzzer)
configure_fuzz_test(unzip_fuzzer)
if(NOT SKIP_INSTALL_BINARIES AND NOT SKIP_INSTALL_ALL)
install(TARGETS zip_fuzzer RUNTIME DESTINATION "bin")
install(TARGETS unzip_fuzzer RUNTIME DESTINATION "bin")
endif()
endif()
# Compatibility options
add_feature_info(MZ_COMPAT MZ_COMPAT "Enables compatibility layer")
# Compression library options
add_feature_info(MZ_ZLIB MZ_ZLIB "Enables ZLIB compression")
add_feature_info(MZ_BZIP2 MZ_BZIP2 "Enables BZIP2 compression")
add_feature_info(MZ_LZMA MZ_LZMA "Enables LZMA & XZ compression")
add_feature_info(MZ_ZSTD MZ_ZSTD "Enables ZSTD compression")
add_feature_info(MZ_LIBCOMP MZ_LIBCOMP "Enables Apple compression")
add_feature_info(MZ_FETCH_LIBS MZ_FETCH_LIBS "Enables fetching third-party libraries if not found")
add_feature_info(MZ_FORCE_FETCH_LIBS MZ_FORCE_FETCH_LIBS "Enables fetching third-party libraries always")
# Encryption support options
add_feature_info(MZ_PKCRYPT MZ_PKCRYPT "Enables PKWARE traditional encryption")
add_feature_info(MZ_WZAES MZ_WZAES "Enables WinZIP AES encryption")
add_feature_info(MZ_OPENSSL MZ_OPENSSL "Enables OpenSSL for encryption")
add_feature_info(MZ_LIBBSD MZ_LIBBSD "Build with libbsd for crypto random")
add_feature_info(MZ_SIGNING MZ_SIGNING "Enables zip signing support")
# Character conversion options
add_feature_info(MZ_ICONV MZ_ICONV "Enables iconv string encoding conversion library")
# Code generation options
add_feature_info(MZ_COMPRESS_ONLY MZ_COMPRESS_ONLY "Only support compression")
add_feature_info(MZ_DECOMPRESS_ONLY MZ_DECOMPRESS_ONLY "Only support decompression")
add_feature_info(MZ_FILE32_API MZ_FILE32_API "Builds using posix 32-bit file api")
# Build and continuous integration options
add_feature_info(MZ_BUILD_TESTS MZ_BUILD_TESTS "Builds minizip test executable")
add_feature_info(MZ_BUILD_UNIT_TESTS MZ_BUILD_UNIT_TESTS "Builds minizip unit test project")
add_feature_info(MZ_BUILD_FUZZ_TESTS MZ_BUILD_FUZZ_TESTS "Builds minizip fuzzer executables")
add_feature_info(MZ_CODE_COVERAGE MZ_CODE_COVERAGE "Builds with code coverage flags")
feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES INCLUDE_QUIET_PACKAGES)
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/INDEX.md 0000664 0000000 0000000 00000003013 14126475503 0023641 0 ustar 00root root 0000000 0000000
## 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 |
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/LICENSE 0000664 0000000 0000000 00000001555 14126475503 0023466 0 ustar 00root root 0000000 0000000 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.
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/README.md 0000664 0000000 0000000 00000016651 14126475503 0023743 0 ustar 00root root 0000000 0000000 # minizip-ng 3.0.3
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_TESTS=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.
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/ 0000775 0000000 0000000 00000000000 14126475503 0023220 5 ustar 00root root 0000000 0000000 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/README.md 0000664 0000000 0000000 00000014217 14126475503 0024504 0 ustar 00root root 0000000 0000000 # 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.
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_compress_level.md 0000664 0000000 0000000 00000000450 14126475503 0027271 0 ustar 00root root 0000000 0000000 # 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| 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_compress_method.md 0000664 0000000 0000000 00000000641 14126475503 0027444 0 ustar 00root root 0000000 0000000 # 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.
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_encoding.md 0000664 0000000 0000000 00000001131 14126475503 0026032 0 ustar 00root root 0000000 0000000 # 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)|
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_error.md 0000664 0000000 0000000 00000002173 14126475503 0025404 0 ustar 00root root 0000000 0000000 # 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|
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_extrafield.md 0000664 0000000 0000000 00000002406 14126475503 0026401 0 ustar 00root root 0000000 0000000 # 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.
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_hash.md 0000664 0000000 0000000 00000000671 14126475503 0025177 0 ustar 00root root 0000000 0000000 # 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|
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_host_system.md 0000664 0000000 0000000 00000001361 14126475503 0026632 0 ustar 00root root 0000000 0000000 # 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");
}
``` 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_open_mode.md 0000664 0000000 0000000 00000000537 14126475503 0026222 0 ustar 00root root 0000000 0000000 # 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| 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_os.md 0000664 0000000 0000000 00000047210 14126475503 0024675 0 ustar 00root root 0000000 0000000 # 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);
```
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_seek.md 0000664 0000000 0000000 00000000270 14126475503 0025176 0 ustar 00root root 0000000 0000000 # 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| 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_zip.md 0000664 0000000 0000000 00000125772 14126475503 0025070 0 ustar 00root root 0000000 0000000 # 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);
```
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_zip64.md 0000664 0000000 0000000 00000001176 14126475503 0025231 0 ustar 00root root 0000000 0000000 # 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.|
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_zip_file.md 0000664 0000000 0000000 00000007711 14126475503 0026057 0 ustar 00root root 0000000 0000000 # 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 | 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/mz_zip_rw.md 0000664 0000000 0000000 00000146171 14126475503 0025574 0 ustar 00root root 0000000 0000000 ## 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);
```
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/zip/ 0000775 0000000 0000000 00000000000 14126475503 0024022 5 ustar 00root root 0000000 0000000 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/zip/appnote.iz.txt 0000664 0000000 0000000 00000475463 14126475503 0026675 0 ustar 00root root 0000000 0000000 [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.
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/zip/appnote.txt 0000664 0000000 0000000 00000461777 14126475503 0026257 0 ustar 00root root 0000000 0000000 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.
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/zip/extra.fld.txt 0000664 0000000 0000000 00000155771 14126475503 0026472 0 ustar 00root root 0000000 0000000 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."
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/doc/zip/winzip_aes.md 0000664 0000000 0000000 00000066746 14126475503 0026537 0 ustar 00root root 0000000 0000000
# 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/minigzip.c 0000664 0000000 0000000 00000013110 14126475503 0024441 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/minizip.c 0000664 0000000 0000000 00000054572 14126475503 0024313 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/minizip.pc.cmakein 0000664 0000000 0000000 00000000620 14126475503 0026062 0 ustar 00root root 0000000 0000000 prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
sharedlibdir=@CMAKE_INSTALL_FULL_LIBDIR@
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
Name: @PROJECT_NAME@
Description: Minizip zip file manipulation library
Version: @VERSION@
Requires: zlib
Libs: -L${libdir} -L${sharedlibdir} -l@PROJECT_NAME@
Libs.private:@PC_PRIVATE_LIBS@
Cflags: -I${includedir}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz.h 0000664 0000000 0000000 00000017262 14126475503 0023262 0 ustar 00root root 0000000 0000000 /* 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.3")
#define MZ_VERSION_BUILD (030003)
/* 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_MAX
typedef signed char int8_t;
#endif
#ifndef INT16_MAX
typedef short int16_t;
#endif
#ifndef INT32_MAX
typedef int int32_t;
#endif
#ifndef INT64_MAX
typedef long long int64_t;
#endif
#ifndef UINT8_MAX
typedef unsigned char uint8_t;
#endif
#ifndef UINT16_MAX
typedef unsigned short uint16_t;
#endif
#ifndef UINT32_MAX
typedef unsigned int uint32_t;
#endif
#ifndef UINT64_MAX
typedef unsigned long long uint64_t;
#endif
#if defined(HAVE_INTTYPES_H)
# include
#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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_compat.c 0000664 0000000 0000000 00000124364 14126475503 0024622 0 ustar 00root root 0000000 0000000 /* 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;
}
/***************************************************************************/
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_compat.h 0000664 0000000 0000000 00000043767 14126475503 0024636 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_crypt.c 0000664 0000000 0000000 00000016717 14126475503 0024502 0 ustar 00root root 0000000 0000000 /* 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
/***************************************************************************/
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_crypt.h 0000664 0000000 0000000 00000005237 14126475503 0024502 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_crypt_apple.c 0000664 0000000 0000000 00000032636 14126475503 0025661 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_crypt_openssl.c 0000664 0000000 0000000 00000040503 14126475503 0026233 0 ustar 00root root 0000000 0000000 /* 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
#if defined(MZ_ZIP_SIGNING)
/* Note: https://www.imperialviolet.org/2015/10/17/boringssl.html says that
BoringSSL does not support CMS. "#include " will fail. See
https://bugs.chromium.org/p/boringssl/issues/detail?id=421
*/
#include
#include
#include
#endif
/***************************************************************************/
static void mz_crypt_init(void) {
static int32_t openssl_initialized = 0;
if (openssl_initialized == 0) {
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
ENGINE_load_builtin_engines();
ENGINE_register_all_complete();
openssl_initialized = 1;
}
}
int32_t mz_crypt_rand(uint8_t *buf, int32_t size) {
int32_t result = 0;
result = RAND_bytes(buf, size);
if (!result)
return MZ_CRYPT_ERROR;
return size;
}
/***************************************************************************/
typedef struct mz_crypt_sha_s {
SHA256_CTX ctx256;
SHA_CTX ctx1;
int32_t initialized;
int32_t error;
uint16_t algorithm;
} mz_crypt_sha;
/***************************************************************************/
void mz_crypt_sha_reset(void *handle) {
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
sha->error = 0;
sha->initialized = 0;
mz_crypt_init();
}
int32_t mz_crypt_sha_begin(void *handle) {
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
int32_t result = 0;
if (sha == NULL)
return MZ_PARAM_ERROR;
mz_crypt_sha_reset(handle);
if (sha->algorithm == MZ_HASH_SHA1)
result = SHA1_Init(&sha->ctx1);
else
result = SHA256_Init(&sha->ctx256);
if (!result) {
sha->error = ERR_get_error();
return MZ_HASH_ERROR;
}
sha->initialized = 1;
return MZ_OK;
}
int32_t mz_crypt_sha_update(void *handle, const void *buf, int32_t size) {
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
int32_t result = 0;
if (sha == NULL || buf == NULL || !sha->initialized)
return MZ_PARAM_ERROR;
if (sha->algorithm == MZ_HASH_SHA1)
result = SHA1_Update(&sha->ctx1, buf, size);
else
result = SHA256_Update(&sha->ctx256, buf, size);
if (!result) {
sha->error = ERR_get_error();
return MZ_HASH_ERROR;
}
return size;
}
int32_t mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size) {
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
int32_t result = 0;
if (sha == NULL || digest == NULL || !sha->initialized)
return MZ_PARAM_ERROR;
if (sha->algorithm == MZ_HASH_SHA1) {
if (digest_size < MZ_HASH_SHA1_SIZE)
return MZ_BUF_ERROR;
result = SHA1_Final(digest, &sha->ctx1);
} else {
if (digest_size < MZ_HASH_SHA256_SIZE)
return MZ_BUF_ERROR;
result = SHA256_Final(digest, &sha->ctx256);
}
if (!result) {
sha->error = ERR_get_error();
return MZ_HASH_ERROR;
}
return MZ_OK;
}
void mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm) {
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
sha->algorithm = algorithm;
}
void *mz_crypt_sha_create(void **handle) {
mz_crypt_sha *sha = NULL;
sha = (mz_crypt_sha *)MZ_ALLOC(sizeof(mz_crypt_sha));
if (sha != NULL) {
memset(sha, 0, sizeof(mz_crypt_sha));
sha->algorithm = MZ_HASH_SHA256;
}
if (handle != NULL)
*handle = sha;
return sha;
}
void mz_crypt_sha_delete(void **handle) {
mz_crypt_sha *sha = NULL;
if (handle == NULL)
return;
sha = (mz_crypt_sha *)*handle;
if (sha != NULL) {
mz_crypt_sha_reset(*handle);
MZ_FREE(sha);
}
*handle = NULL;
}
/***************************************************************************/
typedef struct mz_crypt_aes_s {
AES_KEY key;
int32_t mode;
int32_t error;
uint8_t *key_copy;
int32_t key_length;
} mz_crypt_aes;
/***************************************************************************/
void mz_crypt_aes_reset(void *handle) {
MZ_UNUSED(handle);
mz_crypt_init();
}
int32_t mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size) {
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
if (aes == NULL || buf == NULL)
return MZ_PARAM_ERROR;
if (size != MZ_AES_BLOCK_SIZE)
return MZ_PARAM_ERROR;
AES_encrypt(buf, buf, &aes->key);
/* Equivalent to AES_ecb_encrypt with AES_ENCRYPT */
return size;
}
int32_t mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size) {
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
if (aes == NULL || buf == NULL)
return MZ_PARAM_ERROR;
if (size != MZ_AES_BLOCK_SIZE)
return MZ_PARAM_ERROR;
AES_decrypt(buf, buf, &aes->key);
/* Equivalent to AES_ecb_encrypt with AES_DECRYPT */
return size;
}
int32_t mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length) {
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
int32_t result = 0;
int32_t key_bits = 0;
if (aes == NULL || key == NULL)
return MZ_PARAM_ERROR;
mz_crypt_aes_reset(handle);
key_bits = key_length * 8;
result = AES_set_encrypt_key(key, key_bits, &aes->key);
if (result) {
aes->error = ERR_get_error();
return MZ_HASH_ERROR;
}
return MZ_OK;
}
int32_t mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length) {
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
int32_t result = 0;
int32_t key_bits = 0;
if (aes == NULL || key == NULL)
return MZ_PARAM_ERROR;
mz_crypt_aes_reset(handle);
key_bits = key_length * 8;
result = AES_set_decrypt_key(key, key_bits, &aes->key);
if (result) {
aes->error = ERR_get_error();
return MZ_HASH_ERROR;
}
return MZ_OK;
}
void mz_crypt_aes_set_mode(void *handle, int32_t mode) {
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
aes->mode = mode;
}
void *mz_crypt_aes_create(void **handle) {
mz_crypt_aes *aes = NULL;
aes = (mz_crypt_aes *)MZ_ALLOC(sizeof(mz_crypt_aes));
if (aes != NULL)
memset(aes, 0, sizeof(mz_crypt_aes));
if (handle != NULL)
*handle = aes;
return aes;
}
void mz_crypt_aes_delete(void **handle) {
mz_crypt_aes *aes = NULL;
if (handle == NULL)
return;
aes = (mz_crypt_aes *)*handle;
if (aes != NULL)
MZ_FREE(aes);
*handle = NULL;
}
/***************************************************************************/
typedef struct mz_crypt_hmac_s {
HMAC_CTX *ctx;
int32_t initialized;
int32_t error;
uint16_t algorithm;
} mz_crypt_hmac;
/***************************************************************************/
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER < 0x2070000fL))
static HMAC_CTX *HMAC_CTX_new(void) {
HMAC_CTX *ctx = OPENSSL_malloc(sizeof(HMAC_CTX));
if (ctx != NULL)
HMAC_CTX_init(ctx);
return ctx;
}
static void HMAC_CTX_free(HMAC_CTX *ctx) {
if (ctx != NULL) {
HMAC_CTX_cleanup(ctx);
OPENSSL_free(ctx);
}
}
#endif
/***************************************************************************/
void mz_crypt_hmac_reset(void *handle) {
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
HMAC_CTX_free(hmac->ctx);
hmac->ctx = NULL;
hmac->error = 0;
mz_crypt_init();
}
int32_t mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length) {
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
int32_t result = 0;
const EVP_MD *evp_md = NULL;
if (hmac == NULL || key == NULL)
return MZ_PARAM_ERROR;
mz_crypt_hmac_reset(handle);
hmac->ctx = HMAC_CTX_new();
if (hmac->algorithm == MZ_HASH_SHA1)
evp_md = EVP_sha1();
else
evp_md = EVP_sha256();
result = HMAC_Init_ex(hmac->ctx, key, key_length, evp_md, NULL);
if (!result) {
hmac->error = ERR_get_error();
return MZ_HASH_ERROR;
}
return MZ_OK;
}
int32_t mz_crypt_hmac_update(void *handle, const void *buf, int32_t size) {
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
int32_t result = 0;
if (hmac == NULL || buf == NULL)
return MZ_PARAM_ERROR;
result = HMAC_Update(hmac->ctx, buf, size);
if (!result) {
hmac->error = ERR_get_error();
return MZ_HASH_ERROR;
}
return MZ_OK;
}
int32_t mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size) {
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
int32_t result = 0;
if (hmac == NULL || digest == NULL)
return MZ_PARAM_ERROR;
if (hmac->algorithm == MZ_HASH_SHA1) {
if (digest_size < MZ_HASH_SHA1_SIZE)
return MZ_BUF_ERROR;
result = HMAC_Final(hmac->ctx, digest, (uint32_t *)&digest_size);
} else {
if (digest_size < MZ_HASH_SHA256_SIZE)
return MZ_BUF_ERROR;
result = HMAC_Final(hmac->ctx, digest, (uint32_t *)&digest_size);
}
if (!result) {
hmac->error = ERR_get_error();
return MZ_HASH_ERROR;
}
return MZ_OK;
}
void mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm) {
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
hmac->algorithm = algorithm;
}
int32_t mz_crypt_hmac_copy(void *src_handle, void *target_handle) {
mz_crypt_hmac *source = (mz_crypt_hmac *)src_handle;
mz_crypt_hmac *target = (mz_crypt_hmac *)target_handle;
int32_t result = 0;
if (source == NULL || target == NULL)
return MZ_PARAM_ERROR;
mz_crypt_hmac_reset(target_handle);
if (target->ctx == NULL)
target->ctx = HMAC_CTX_new();
result = HMAC_CTX_copy(target->ctx, source->ctx);
if (!result) {
target->error = ERR_get_error();
return MZ_HASH_ERROR;
}
return MZ_OK;
}
void *mz_crypt_hmac_create(void **handle) {
mz_crypt_hmac *hmac = NULL;
hmac = (mz_crypt_hmac *)MZ_ALLOC(sizeof(mz_crypt_hmac));
if (hmac != NULL) {
memset(hmac, 0, sizeof(mz_crypt_hmac));
hmac->algorithm = MZ_HASH_SHA256;
}
if (handle != NULL)
*handle = hmac;
return hmac;
}
void mz_crypt_hmac_delete(void **handle) {
mz_crypt_hmac *hmac = NULL;
if (handle == NULL)
return;
hmac = (mz_crypt_hmac *)*handle;
if (hmac != NULL) {
mz_crypt_hmac_reset(*handle);
MZ_FREE(hmac);
}
*handle = NULL;
}
/***************************************************************************/
#if defined(MZ_ZIP_SIGNING)
int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size,
const char *cert_pwd, uint8_t **signature, int32_t *signature_size) {
PKCS12 *p12 = NULL;
EVP_PKEY *evp_pkey = NULL;
BUF_MEM *buf_mem = NULL;
BIO *cert_bio = NULL;
BIO *message_bio = NULL;
BIO *signature_bio = NULL;
CMS_ContentInfo *cms = NULL;
CMS_SignerInfo *signer_info = NULL;
STACK_OF(X509) *ca_stack = NULL;
X509 *cert = NULL;
int32_t result = 0;
int32_t err = MZ_OK;
if (message == NULL || cert_data == NULL || signature == NULL || signature_size == NULL)
return MZ_PARAM_ERROR;
mz_crypt_init();
*signature = NULL;
*signature_size = 0;
cert_bio = BIO_new_mem_buf(cert_data, cert_data_size);
if (d2i_PKCS12_bio(cert_bio, &p12) == NULL)
err = MZ_SIGN_ERROR;
if (err == MZ_OK)
result = PKCS12_parse(p12, cert_pwd, &evp_pkey, &cert, &ca_stack);
if (result) {
cms = CMS_sign(NULL, NULL, ca_stack, NULL, CMS_BINARY | CMS_PARTIAL);
if (cms)
signer_info = CMS_add1_signer(cms, cert, evp_pkey, EVP_sha256(), 0);
if (signer_info == NULL) {
err = MZ_SIGN_ERROR;
} else {
message_bio = BIO_new_mem_buf(message, message_size);
signature_bio = BIO_new(BIO_s_mem());
result = CMS_final(cms, message_bio, NULL, CMS_BINARY);
if (result)
result = i2d_CMS_bio(signature_bio, cms);
if (result) {
BIO_flush(signature_bio);
BIO_get_mem_ptr(signature_bio, &buf_mem);
*signature_size = buf_mem->length;
*signature = MZ_ALLOC(buf_mem->length);
memcpy(*signature, buf_mem->data, buf_mem->length);
}
#if 0
BIO *yy = BIO_new_file("xyz", "wb");
BIO_write(yy, *signature, *signature_size);
BIO_flush(yy);
BIO_free(yy);
#endif
}
}
if (!result)
err = MZ_SIGN_ERROR;
if (cms)
CMS_ContentInfo_free(cms);
if (signature_bio)
BIO_free(signature_bio);
if (cert_bio)
BIO_free(cert_bio);
if (message_bio)
BIO_free(message_bio);
if (p12)
PKCS12_free(p12);
if (err != MZ_OK && *signature != NULL) {
MZ_FREE(*signature);
*signature = NULL;
*signature_size = 0;
}
return err;
}
int32_t mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size) {
CMS_ContentInfo *cms = NULL;
STACK_OF(X509) *signers = NULL;
STACK_OF(X509) *intercerts = NULL;
X509_STORE *cert_store = NULL;
X509_LOOKUP *lookup = NULL;
X509_STORE_CTX *store_ctx = NULL;
BIO *message_bio = NULL;
BIO *signature_bio = NULL;
BUF_MEM *buf_mem = NULL;
int32_t signer_count = 0;
int32_t result = 0;
int32_t i = 0;
int32_t err = MZ_SIGN_ERROR;
if (message == NULL || message_size == 0 || signature == NULL || signature_size == 0)
return MZ_PARAM_ERROR;
mz_crypt_init();
cert_store = X509_STORE_new();
X509_STORE_load_locations(cert_store, "cacert.pem", NULL);
X509_STORE_set_default_paths(cert_store);
#if 0
BIO *yy = BIO_new_file("xyz", "wb");
BIO_write(yy, signature, signature_size);
BIO_flush(yy);
BIO_free(yy);
#endif
lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_file());
if (lookup != NULL)
X509_LOOKUP_load_file(lookup, "cacert.pem", X509_FILETYPE_PEM);
lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_hash_dir());
if (lookup != NULL)
X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
signature_bio = BIO_new_mem_buf(signature, signature_size);
message_bio = BIO_new(BIO_s_mem());
cms = d2i_CMS_bio(signature_bio, NULL);
if (cms) {
result = CMS_verify(cms, NULL, cert_store, NULL, message_bio, CMS_NO_SIGNER_CERT_VERIFY | CMS_BINARY);
if (result)
signers = CMS_get0_signers(cms);
if (signers)
intercerts = CMS_get1_certs(cms);
if (intercerts) {
/* Verify signer certificates */
signer_count = sk_X509_num(signers);
if (signer_count > 0)
err = MZ_OK;
for (i = 0; i < signer_count; i++) {
store_ctx = X509_STORE_CTX_new();
X509_STORE_CTX_init(store_ctx, cert_store, sk_X509_value(signers, i), intercerts);
result = X509_verify_cert(store_ctx);
if (store_ctx)
X509_STORE_CTX_free(store_ctx);
if (!result) {
err = MZ_SIGN_ERROR;
break;
}
}
}
BIO_get_mem_ptr(message_bio, &buf_mem);
if (err == MZ_OK) {
/* Verify the message */
if (((int32_t)buf_mem->length != message_size) ||
(memcmp(buf_mem->data, message, message_size) != 0))
err = MZ_SIGN_ERROR;
}
}
#if 0
if (!result)
printf(ERR_error_string(ERR_get_error(), NULL));
#endif
if (cms)
CMS_ContentInfo_free(cms);
if (message_bio)
BIO_free(message_bio);
if (signature_bio)
BIO_free(signature_bio);
if (cert_store)
X509_STORE_free(cert_store);
return err;
}
#endif
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_crypt_win32.c 0000664 0000000 0000000 00000053670 14126475503 0025523 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_os.c 0000664 0000000 0000000 00000021542 14126475503 0023752 0 ustar 00root root 0000000 0000000 /* 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;
}
/***************************************************************************/
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_os.h 0000664 0000000 0000000 00000012573 14126475503 0023763 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_os_posix.c 0000664 0000000 0000000 00000021322 14126475503 0025170 0 ustar 00root root 0000000 0000000 /* 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);
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_os_win32.c 0000664 0000000 0000000 00000047271 14126475503 0025003 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm.c 0000664 0000000 0000000 00000040000 14126475503 0024304 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm.h 0000664 0000000 0000000 00000013476 14126475503 0024332 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_buf.c 0000664 0000000 0000000 00000032017 14126475503 0025151 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_buf.h 0000664 0000000 0000000 00000002460 14126475503 0025155 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_bzip.c 0000664 0000000 0000000 00000023413 14126475503 0025341 0 ustar 00root root 0000000 0000000 /* 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);
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_bzip.h 0000664 0000000 0000000 00000002632 14126475503 0025346 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_libcomp.c 0000664 0000000 0000000 00000023270 14126475503 0026023 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_libcomp.h 0000664 0000000 0000000 00000002663 14126475503 0026033 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_lzma.c 0000664 0000000 0000000 00000032216 14126475503 0025341 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_lzma.h 0000664 0000000 0000000 00000002561 14126475503 0025346 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_mem.c 0000664 0000000 0000000 00000016072 14126475503 0025156 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_mem.h 0000664 0000000 0000000 00000003271 14126475503 0025160 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_os.h 0000664 0000000 0000000 00000002250 14126475503 0025017 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_os_posix.c 0000664 0000000 0000000 00000012335 14126475503 0026241 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_os_win32.c 0000664 0000000 0000000 00000017636 14126475503 0026052 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_pkcrypt.c 0000664 0000000 0000000 00000025311 14126475503 0026070 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_pkcrypt.h 0000664 0000000 0000000 00000003241 14126475503 0026073 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_split.c 0000664 0000000 0000000 00000031653 14126475503 0025535 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_split.h 0000664 0000000 0000000 00000002570 14126475503 0025536 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_wzaes.c 0000664 0000000 0000000 00000026522 14126475503 0025532 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_wzaes.h 0000664 0000000 0000000 00000003053 14126475503 0025531 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_zlib.c 0000664 0000000 0000000 00000024230 14126475503 0025333 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_zlib.h 0000664 0000000 0000000 00000002561 14126475503 0025343 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_zstd.c 0000664 0000000 0000000 00000022453 14126475503 0025364 0 ustar 00root root 0000000 0000000 /* 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;
}
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_strm_zstd.h 0000664 0000000 0000000 00000002625 14126475503 0025370 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_zip.c 0000664 0000000 0000000 00000311414 14126475503 0024133 0 ustar 00root root 0000000 0000000 /* 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;
}
/***************************************************************************/
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_zip.h 0000664 0000000 0000000 00000025114 14126475503 0024137 0 ustar 00root root 0000000 0000000 /* 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 */
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_zip_rw.c 0000664 0000000 0000000 00000172511 14126475503 0024646 0 ustar 00root root 0000000 0000000 /* mz_zip_rw.c -- Zip reader/writer
part of the minizip-ng project
Copyright (C) 2010-2021 Nathan Moinvaziri
https://github.com/zlib-ng/minizip-ng
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_crypt.h"
#include "mz_os.h"
#include "mz_strm.h"
#include "mz_strm_buf.h"
#include "mz_strm_mem.h"
#include "mz_strm_os.h"
#include "mz_strm_split.h"
#include "mz_strm_wzaes.h"
#include "mz_zip.h"
#include "mz_zip_rw.h"
/***************************************************************************/
#define MZ_DEFAULT_PROGRESS_INTERVAL (1000u)
#define MZ_ZIP_CD_FILENAME ("__cdcd__")
/***************************************************************************/
typedef struct mz_zip_reader_s {
void *zip_handle;
void *file_stream;
void *buffered_stream;
void *split_stream;
void *mem_stream;
void *hash;
uint16_t hash_algorithm;
uint16_t hash_digest_size;
mz_zip_file *file_info;
const char *pattern;
uint8_t pattern_ignore_case;
const char *password;
void *overwrite_userdata;
mz_zip_reader_overwrite_cb
overwrite_cb;
void *password_userdata;
mz_zip_reader_password_cb
password_cb;
void *progress_userdata;
mz_zip_reader_progress_cb
progress_cb;
uint32_t progress_cb_interval_ms;
void *entry_userdata;
mz_zip_reader_entry_cb
entry_cb;
uint8_t raw;
uint8_t buffer[UINT16_MAX];
int32_t encoding;
uint8_t sign_required;
uint8_t cd_verified;
uint8_t cd_zipped;
uint8_t entry_verified;
uint8_t recover;
} mz_zip_reader;
/***************************************************************************/
int32_t mz_zip_reader_is_open(void *handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
if (reader == NULL)
return MZ_PARAM_ERROR;
if (reader->zip_handle == NULL)
return MZ_PARAM_ERROR;
return MZ_OK;
}
int32_t mz_zip_reader_open(void *handle, void *stream) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
reader->cd_verified = 0;
reader->cd_zipped = 0;
mz_zip_create(&reader->zip_handle);
mz_zip_set_recover(reader->zip_handle, reader->recover);
err = mz_zip_open(reader->zip_handle, stream, MZ_OPEN_MODE_READ);
if (err != MZ_OK) {
mz_zip_reader_close(handle);
return err;
}
mz_zip_reader_unzip_cd(reader);
return MZ_OK;
}
int32_t mz_zip_reader_open_file(void *handle, const char *path) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
mz_zip_reader_close(handle);
mz_stream_os_create(&reader->file_stream);
mz_stream_buffered_create(&reader->buffered_stream);
mz_stream_split_create(&reader->split_stream);
mz_stream_set_base(reader->buffered_stream, reader->file_stream);
mz_stream_set_base(reader->split_stream, reader->buffered_stream);
err = mz_stream_open(reader->split_stream, path, MZ_OPEN_MODE_READ);
if (err == MZ_OK)
err = mz_zip_reader_open(handle, reader->split_stream);
return err;
}
int32_t mz_zip_reader_open_file_in_memory(void *handle, const char *path) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
void *file_stream = NULL;
int64_t file_size = 0;
int32_t err = 0;
mz_zip_reader_close(handle);
mz_stream_os_create(&file_stream);
err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_READ);
if (err != MZ_OK) {
mz_stream_os_delete(&file_stream);
mz_zip_reader_close(handle);
return err;
}
mz_stream_os_seek(file_stream, 0, MZ_SEEK_END);
file_size = mz_stream_os_tell(file_stream);
mz_stream_os_seek(file_stream, 0, MZ_SEEK_SET);
if ((file_size <= 0) || (file_size > UINT32_MAX)) {
/* Memory size is too large or too small */
mz_stream_os_close(file_stream);
mz_stream_os_delete(&file_stream);
mz_zip_reader_close(handle);
return MZ_MEM_ERROR;
}
mz_stream_mem_create(&reader->mem_stream);
mz_stream_mem_set_grow_size(reader->mem_stream, (int32_t)file_size);
mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_CREATE);
err = mz_stream_copy(reader->mem_stream, file_stream, (int32_t)file_size);
mz_stream_os_close(file_stream);
mz_stream_os_delete(&file_stream);
if (err == MZ_OK)
err = mz_zip_reader_open(handle, reader->mem_stream);
if (err != MZ_OK)
mz_zip_reader_close(handle);
return err;
}
int32_t mz_zip_reader_open_buffer(void *handle, uint8_t *buf, int32_t len, uint8_t copy) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
mz_zip_reader_close(handle);
mz_stream_mem_create(&reader->mem_stream);
if (copy) {
mz_stream_mem_set_grow_size(reader->mem_stream, len);
mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_CREATE);
mz_stream_mem_write(reader->mem_stream, buf, len);
mz_stream_mem_seek(reader->mem_stream, 0, MZ_SEEK_SET);
} else {
mz_stream_mem_open(reader->mem_stream, NULL, MZ_OPEN_MODE_READ);
mz_stream_mem_set_buffer(reader->mem_stream, buf, len);
}
if (err == MZ_OK)
err = mz_zip_reader_open(handle, reader->mem_stream);
return err;
}
int32_t mz_zip_reader_close(void *handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
if (reader->zip_handle != NULL) {
err = mz_zip_close(reader->zip_handle);
mz_zip_delete(&reader->zip_handle);
}
if (reader->split_stream != NULL) {
mz_stream_split_close(reader->split_stream);
mz_stream_split_delete(&reader->split_stream);
}
if (reader->buffered_stream != NULL)
mz_stream_buffered_delete(&reader->buffered_stream);
if (reader->file_stream != NULL)
mz_stream_os_delete(&reader->file_stream);
if (reader->mem_stream != NULL) {
mz_stream_mem_close(reader->mem_stream);
mz_stream_mem_delete(&reader->mem_stream);
}
return err;
}
/***************************************************************************/
int32_t mz_zip_reader_unzip_cd(void *handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
mz_zip_file *cd_info = NULL;
void *cd_mem_stream = NULL;
void *new_cd_stream = NULL;
void *file_extra_stream = NULL;
uint64_t number_entry = 0;
int32_t err = MZ_OK;
err = mz_zip_reader_goto_first_entry(handle);
if (err != MZ_OK)
return err;
err = mz_zip_reader_entry_get_info(handle, &cd_info);
if (err != MZ_OK)
return err;
if (strcmp(cd_info->filename, MZ_ZIP_CD_FILENAME) != 0)
return mz_zip_reader_goto_first_entry(handle);
err = mz_zip_reader_entry_open(handle);
if (err != MZ_OK)
return err;
mz_stream_mem_create(&file_extra_stream);
mz_stream_mem_set_buffer(file_extra_stream, (void *)cd_info->extrafield, cd_info->extrafield_size);
err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_CDCD, INT32_MAX, NULL);
if (err == MZ_OK)
err = mz_stream_read_uint64(file_extra_stream, &number_entry);
mz_stream_mem_delete(&file_extra_stream);
if (err != MZ_OK)
return err;
mz_zip_get_cd_mem_stream(reader->zip_handle, &cd_mem_stream);
if (mz_stream_mem_is_open(cd_mem_stream) != MZ_OK)
mz_stream_mem_open(cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE);
err = mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);
if (err == MZ_OK)
err = mz_stream_copy_stream(cd_mem_stream, NULL, handle, mz_zip_reader_entry_read,
(int32_t)cd_info->uncompressed_size);
if (err == MZ_OK) {
reader->cd_zipped = 1;
mz_zip_set_cd_stream(reader->zip_handle, 0, cd_mem_stream);
mz_zip_set_number_entry(reader->zip_handle, number_entry);
err = mz_zip_reader_goto_first_entry(handle);
}
reader->cd_verified = reader->entry_verified;
mz_stream_mem_delete(&new_cd_stream);
return err;
}
/***************************************************************************/
static int32_t mz_zip_reader_locate_entry_cb(void *handle, void *userdata, mz_zip_file *file_info) {
mz_zip_reader *reader = (mz_zip_reader *)userdata;
int32_t result = 0;
MZ_UNUSED(handle);
result = mz_path_compare_wc(file_info->filename, reader->pattern, reader->pattern_ignore_case);
return result;
}
int32_t mz_zip_reader_goto_first_entry(void *handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
if (mz_zip_reader_is_open(handle) != MZ_OK)
return MZ_PARAM_ERROR;
if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
mz_zip_reader_entry_close(handle);
if (reader->pattern == NULL)
err = mz_zip_goto_first_entry(reader->zip_handle);
else
err = mz_zip_locate_first_entry(reader->zip_handle, reader, mz_zip_reader_locate_entry_cb);
reader->file_info = NULL;
if (err == MZ_OK)
err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);
return err;
}
int32_t mz_zip_reader_goto_next_entry(void *handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
if (mz_zip_reader_is_open(handle) != MZ_OK)
return MZ_PARAM_ERROR;
if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
mz_zip_reader_entry_close(handle);
if (reader->pattern == NULL)
err = mz_zip_goto_next_entry(reader->zip_handle);
else
err = mz_zip_locate_next_entry(reader->zip_handle, reader, mz_zip_reader_locate_entry_cb);
reader->file_info = NULL;
if (err == MZ_OK)
err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);
return err;
}
int32_t mz_zip_reader_locate_entry(void *handle, const char *filename, uint8_t ignore_case) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
mz_zip_reader_entry_close(handle);
err = mz_zip_locate_entry(reader->zip_handle, filename, ignore_case);
reader->file_info = NULL;
if (err == MZ_OK)
err = mz_zip_entry_get_info(reader->zip_handle, &reader->file_info);
return err;
}
/***************************************************************************/
int32_t mz_zip_reader_entry_open(void *handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
const char *password = NULL;
char password_buf[120];
reader->entry_verified = 0;
if (mz_zip_reader_is_open(reader) != MZ_OK)
return MZ_PARAM_ERROR;
if (reader->file_info == NULL)
return MZ_PARAM_ERROR;
/* If the entry isn't open for reading, open it */
if (mz_zip_entry_is_open(reader->zip_handle) == MZ_OK)
return MZ_OK;
password = reader->password;
/* Check if we need a password and ask for it if we need to */
if ((reader->file_info->flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL) &&
(reader->password_cb != NULL)) {
reader->password_cb(handle, reader->password_userdata, reader->file_info,
password_buf, sizeof(password_buf));
password = password_buf;
}
err = mz_zip_entry_read_open(reader->zip_handle, reader->raw, password);
#ifndef MZ_ZIP_NO_CRYPTO
if (err != MZ_OK)
return err;
if (mz_zip_reader_entry_get_first_hash(handle, &reader->hash_algorithm, &reader->hash_digest_size) == MZ_OK) {
mz_crypt_sha_create(&reader->hash);
if (reader->hash_algorithm == MZ_HASH_SHA1)
mz_crypt_sha_set_algorithm(reader->hash, MZ_HASH_SHA1);
else if (reader->hash_algorithm == MZ_HASH_SHA256)
mz_crypt_sha_set_algorithm(reader->hash, MZ_HASH_SHA256);
else
err = MZ_SUPPORT_ERROR;
if (err == MZ_OK)
mz_crypt_sha_begin(reader->hash);
#ifdef MZ_ZIP_SIGNING
if (err == MZ_OK) {
if (mz_zip_reader_entry_has_sign(handle) == MZ_OK) {
err = mz_zip_reader_entry_sign_verify(handle);
if (err == MZ_OK)
reader->entry_verified = 1;
} else if (reader->sign_required && !reader->cd_verified)
err = MZ_SIGN_ERROR;
}
#endif
} else if (reader->sign_required && !reader->cd_verified)
err = MZ_SIGN_ERROR;
#endif
return err;
}
int32_t mz_zip_reader_entry_close(void *handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
int32_t err_close = MZ_OK;
#ifndef MZ_ZIP_NO_CRYPTO
int32_t err_hash = MZ_OK;
uint8_t computed_hash[MZ_HASH_MAX_SIZE];
uint8_t expected_hash[MZ_HASH_MAX_SIZE];
if (reader->hash != NULL) {
mz_crypt_sha_end(reader->hash, computed_hash, sizeof(computed_hash));
mz_crypt_sha_delete(&reader->hash);
err_hash = mz_zip_reader_entry_get_hash(handle, reader->hash_algorithm, expected_hash,
reader->hash_digest_size);
if (err_hash == MZ_OK) {
/* Verify expected hash against computed hash */
if (memcmp(computed_hash, expected_hash, reader->hash_digest_size) != 0)
err = MZ_CRC_ERROR;
}
}
#endif
err_close = mz_zip_entry_close(reader->zip_handle);
if (err == MZ_OK)
err = err_close;
return err;
}
int32_t mz_zip_reader_entry_read(void *handle, void *buf, int32_t len) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t read = 0;
read = mz_zip_entry_read(reader->zip_handle, buf, len);
#ifndef MZ_ZIP_NO_CRYPTO
if ((read > 0) && (reader->hash != NULL))
mz_crypt_sha_update(reader->hash, buf, read);
#endif
return read;
}
int32_t mz_zip_reader_entry_has_sign(void *handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
if (reader == NULL || mz_zip_entry_is_open(reader->zip_handle) != MZ_OK)
return MZ_PARAM_ERROR;
return mz_zip_extrafield_contains(reader->file_info->extrafield,
reader->file_info->extrafield_size, MZ_ZIP_EXTENSION_SIGN, NULL);
}
#if !defined(MZ_ZIP_NO_CRYPTO) && defined(MZ_ZIP_SIGNING)
int32_t mz_zip_reader_entry_sign_verify(void *handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
void *file_extra_stream = NULL;
int32_t err = MZ_OK;
uint8_t *signature = NULL;
uint16_t signature_size = 0;
uint8_t hash[MZ_HASH_MAX_SIZE];
if (reader == NULL || mz_zip_entry_is_open(reader->zip_handle) != MZ_OK)
return MZ_PARAM_ERROR;
mz_stream_mem_create(&file_extra_stream);
mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,
reader->file_info->extrafield_size);
err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_SIGN, INT32_MAX, &signature_size);
if ((err == MZ_OK) && (signature_size > 0)) {
signature = (uint8_t *)MZ_ALLOC(signature_size);
if (mz_stream_read(file_extra_stream, signature, signature_size) != signature_size)
err = MZ_READ_ERROR;
}
mz_stream_mem_delete(&file_extra_stream);
if (err == MZ_OK) {
/* Get most secure hash to verify signature against */
err = mz_zip_reader_entry_get_hash(handle, reader->hash_algorithm, hash, reader->hash_digest_size);
}
if (err == MZ_OK) {
/* Verify the pkcs signature */
err = mz_crypt_sign_verify(hash, reader->hash_digest_size, signature, signature_size);
}
if (signature != NULL)
MZ_FREE(signature);
return err;
}
#endif
int32_t mz_zip_reader_entry_get_hash(void *handle, uint16_t algorithm, uint8_t *digest, int32_t digest_size) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
void *file_extra_stream = NULL;
int32_t err = MZ_OK;
int32_t return_err = MZ_EXIST_ERROR;
uint16_t cur_algorithm = 0;
uint16_t cur_digest_size = 0;
mz_stream_mem_create(&file_extra_stream);
mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,
reader->file_info->extrafield_size);
do {
err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_HASH, INT32_MAX, NULL);
if (err != MZ_OK)
break;
err = mz_stream_read_uint16(file_extra_stream, &cur_algorithm);
if (err == MZ_OK)
err = mz_stream_read_uint16(file_extra_stream, &cur_digest_size);
if ((err == MZ_OK) && (cur_algorithm == algorithm) && (cur_digest_size <= digest_size) &&
(cur_digest_size <= MZ_HASH_MAX_SIZE)) {
/* Read hash digest */
if (mz_stream_read(file_extra_stream, digest, digest_size) == cur_digest_size)
return_err = MZ_OK;
break;
} else {
err = mz_stream_seek(file_extra_stream, cur_digest_size, MZ_SEEK_CUR);
}
} while (err == MZ_OK);
mz_stream_mem_delete(&file_extra_stream);
return return_err;
}
int32_t mz_zip_reader_entry_get_first_hash(void *handle, uint16_t *algorithm, uint16_t *digest_size) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
void *file_extra_stream = NULL;
int32_t err = MZ_OK;
uint16_t cur_algorithm = 0;
uint16_t cur_digest_size = 0;
if (reader == NULL || algorithm == NULL)
return MZ_PARAM_ERROR;
mz_stream_mem_create(&file_extra_stream);
mz_stream_mem_set_buffer(file_extra_stream, (void *)reader->file_info->extrafield,
reader->file_info->extrafield_size);
err = mz_zip_extrafield_find(file_extra_stream, MZ_ZIP_EXTENSION_HASH, INT32_MAX, NULL);
if (err == MZ_OK)
err = mz_stream_read_uint16(file_extra_stream, &cur_algorithm);
if (err == MZ_OK)
err = mz_stream_read_uint16(file_extra_stream, &cur_digest_size);
if (algorithm != NULL)
*algorithm = cur_algorithm;
if (digest_size != NULL)
*digest_size = cur_digest_size;
mz_stream_mem_delete(&file_extra_stream);
return err;
}
int32_t mz_zip_reader_entry_get_info(void *handle, mz_zip_file **file_info) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
if (file_info == NULL || mz_zip_reader_is_open(handle) != MZ_OK)
return MZ_PARAM_ERROR;
*file_info = reader->file_info;
if (*file_info == NULL)
return MZ_EXIST_ERROR;
return err;
}
int32_t mz_zip_reader_entry_is_dir(void *handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
if (mz_zip_reader_is_open(handle) != MZ_OK)
return MZ_PARAM_ERROR;
return mz_zip_entry_is_dir(reader->zip_handle);
}
int32_t mz_zip_reader_entry_save_process(void *handle, void *stream, mz_stream_write_cb write_cb) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
int32_t read = 0;
int32_t written = 0;
if (mz_zip_reader_is_open(reader) != MZ_OK)
return MZ_PARAM_ERROR;
if (reader->file_info == NULL)
return MZ_PARAM_ERROR;
if (write_cb == NULL)
return MZ_PARAM_ERROR;
/* If the entry isn't open for reading, open it */
if (mz_zip_entry_is_open(reader->zip_handle) != MZ_OK)
err = mz_zip_reader_entry_open(handle);
if (err != MZ_OK)
return err;
/* Unzip entry in zip file */
read = mz_zip_reader_entry_read(handle, reader->buffer, sizeof(reader->buffer));
if (read == 0) {
/* If we are done close the entry */
err = mz_zip_reader_entry_close(handle);
if (err != MZ_OK)
return err;
return MZ_END_OF_STREAM;
}
if (read > 0) {
/* Write the data to the specified stream */
written = write_cb(stream, reader->buffer, read);
if (written != read)
return MZ_WRITE_ERROR;
}
return read;
}
int32_t mz_zip_reader_entry_save(void *handle, void *stream, mz_stream_write_cb write_cb) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
uint64_t current_time = 0;
uint64_t update_time = 0;
int64_t current_pos = 0;
int64_t update_pos = 0;
int32_t err = MZ_OK;
int32_t written = 0;
if (mz_zip_reader_is_open(reader) != MZ_OK)
return MZ_PARAM_ERROR;
if (reader->file_info == NULL)
return MZ_PARAM_ERROR;
/* Update the progress at the beginning */
if (reader->progress_cb != NULL)
reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);
/* Write data to stream until done */
while (err == MZ_OK) {
written = mz_zip_reader_entry_save_process(handle, stream, write_cb);
if (written == MZ_END_OF_STREAM)
break;
if (written > 0)
current_pos += written;
if (written < 0)
err = written;
/* Update progress if enough time have passed */
current_time = mz_os_ms_time();
if ((current_time - update_time) > reader->progress_cb_interval_ms) {
if (reader->progress_cb != NULL)
reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);
update_pos = current_pos;
update_time = current_time;
}
}
/* Update the progress at the end */
if (reader->progress_cb != NULL && update_pos != current_pos)
reader->progress_cb(handle, reader->progress_userdata, reader->file_info, current_pos);
return err;
}
int32_t mz_zip_reader_entry_save_file(void *handle, const char *path) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
void *stream = NULL;
uint32_t target_attrib = 0;
int32_t err_attrib = 0;
int32_t err = MZ_OK;
int32_t err_cb = MZ_OK;
char pathwfs[512];
char directory[512];
if (mz_zip_reader_is_open(reader) != MZ_OK)
return MZ_PARAM_ERROR;
if (reader->file_info == NULL || path == NULL)
return MZ_PARAM_ERROR;
/* Convert to forward slashes for unix which doesn't like backslashes */
strncpy(pathwfs, path, sizeof(pathwfs) - 1);
pathwfs[sizeof(pathwfs) - 1] = 0;
mz_path_convert_slashes(pathwfs, MZ_PATH_SLASH_UNIX);
if (reader->entry_cb != NULL)
reader->entry_cb(handle, reader->entry_userdata, reader->file_info, pathwfs);
strncpy(directory, pathwfs, sizeof(directory) - 1);
directory[sizeof(directory) - 1] = 0;
mz_path_remove_filename(directory);
/* If it is a directory entry then create a directory instead of writing file */
if ((mz_zip_entry_is_dir(reader->zip_handle) == MZ_OK) &&
(mz_zip_entry_is_symlink(reader->zip_handle) != MZ_OK)) {
err = mz_dir_make(directory);
return err;
}
/* Check if file exists and ask if we want to overwrite */
if ((mz_os_file_exists(pathwfs) == MZ_OK) && (reader->overwrite_cb != NULL)) {
err_cb = reader->overwrite_cb(handle, reader->overwrite_userdata, reader->file_info, pathwfs);
if (err_cb != MZ_OK)
return err;
/* We want to overwrite the file so we delete the existing one */
mz_os_unlink(pathwfs);
}
/* If symbolic link then properly construct destination path and link path */
if (mz_zip_entry_is_symlink(reader->zip_handle) == MZ_OK) {
mz_path_remove_slash(pathwfs);
mz_path_remove_filename(directory);
}
/* Create the output directory if it doesn't already exist */
if (mz_os_is_dir(directory) != MZ_OK) {
err = mz_dir_make(directory);
if (err != MZ_OK)
return err;
}
/* If it is a symbolic link then create symbolic link instead of writing file */
if (mz_zip_entry_is_symlink(reader->zip_handle) == MZ_OK) {
mz_os_make_symlink(pathwfs, reader->file_info->linkname);
/* Don't check return value because we aren't validating symbolic link target */
return err;
}
/* Create the file on disk so we can save to it */
mz_stream_os_create(&stream);
err = mz_stream_os_open(stream, pathwfs, MZ_OPEN_MODE_CREATE);
if (err == MZ_OK)
err = mz_zip_reader_entry_save(handle, stream, mz_stream_write);
mz_stream_close(stream);
mz_stream_delete(&stream);
if (err == MZ_OK) {
/* Set the time of the file that has been created */
mz_os_set_file_date(pathwfs, reader->file_info->modified_date,
reader->file_info->accessed_date, reader->file_info->creation_date);
}
if (err == MZ_OK) {
/* Set file attributes for the correct system */
err_attrib = mz_zip_attrib_convert(MZ_HOST_SYSTEM(reader->file_info->version_madeby),
reader->file_info->external_fa, MZ_VERSION_MADEBY_HOST_SYSTEM, &target_attrib);
if (err_attrib == MZ_OK)
mz_os_set_file_attribs(pathwfs, target_attrib);
}
return err;
}
int32_t mz_zip_reader_entry_save_buffer(void *handle, void *buf, int32_t len) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
void *mem_stream = NULL;
int32_t err = MZ_OK;
if (mz_zip_reader_is_open(reader) != MZ_OK)
return MZ_PARAM_ERROR;
if (reader->file_info == NULL)
return MZ_PARAM_ERROR;
if (reader->file_info->uncompressed_size > INT32_MAX)
return MZ_PARAM_ERROR;
if (len != (int32_t)reader->file_info->uncompressed_size)
return MZ_BUF_ERROR;
/* Create a memory stream backed by our buffer and save to it */
mz_stream_mem_create(&mem_stream);
mz_stream_mem_set_buffer(mem_stream, buf, len);
err = mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_READ);
if (err == MZ_OK)
err = mz_zip_reader_entry_save(handle, mem_stream, mz_stream_mem_write);
mz_stream_mem_delete(&mem_stream);
return err;
}
int32_t mz_zip_reader_entry_save_buffer_length(void *handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
if (mz_zip_reader_is_open(reader) != MZ_OK)
return MZ_PARAM_ERROR;
if (reader->file_info == NULL)
return MZ_PARAM_ERROR;
if (reader->file_info->uncompressed_size > INT32_MAX)
return MZ_PARAM_ERROR;
/* Get the maximum size required for the save buffer */
return (int32_t)reader->file_info->uncompressed_size;
}
/***************************************************************************/
int32_t mz_zip_reader_save_all(void *handle, const char *destination_dir) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
int32_t err = MZ_OK;
uint8_t *utf8_string = NULL;
char path[512];
char utf8_name[256];
char resolved_name[256];
err = mz_zip_reader_goto_first_entry(handle);
if (err == MZ_END_OF_LIST)
return err;
while (err == MZ_OK) {
/* Construct output path */
path[0] = 0;
strncpy(utf8_name, reader->file_info->filename, sizeof(utf8_name) - 1);
utf8_name[sizeof(utf8_name) - 1] = 0;
if ((reader->encoding > 0) && (reader->file_info->flag & MZ_ZIP_FLAG_UTF8) == 0) {
utf8_string = mz_os_utf8_string_create(reader->file_info->filename, reader->encoding);
if (utf8_string) {
strncpy(utf8_name, (char *)utf8_string, sizeof(utf8_name) - 1);
utf8_name[sizeof(utf8_name) - 1] = 0;
mz_os_utf8_string_delete(&utf8_string);
}
}
err = mz_path_resolve(utf8_name, resolved_name, sizeof(resolved_name));
if (err != MZ_OK)
break;
if (destination_dir != NULL)
mz_path_combine(path, destination_dir, sizeof(path));
mz_path_combine(path, resolved_name, sizeof(path));
/* Save file to disk */
err = mz_zip_reader_entry_save_file(handle, path);
if (err == MZ_OK)
err = mz_zip_reader_goto_next_entry(handle);
}
if (err == MZ_END_OF_LIST)
return MZ_OK;
return err;
}
/***************************************************************************/
void mz_zip_reader_set_pattern(void *handle, const char *pattern, uint8_t ignore_case) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
reader->pattern = pattern;
reader->pattern_ignore_case = ignore_case;
}
void mz_zip_reader_set_password(void *handle, const char *password) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
reader->password = password;
}
void mz_zip_reader_set_raw(void *handle, uint8_t raw) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
reader->raw = raw;
}
int32_t mz_zip_reader_get_raw(void *handle, uint8_t *raw) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
if (raw == NULL)
return MZ_PARAM_ERROR;
*raw = reader->raw;
return MZ_OK;
}
int32_t mz_zip_reader_get_zip_cd(void *handle, uint8_t *zip_cd) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
if (zip_cd == NULL)
return MZ_PARAM_ERROR;
*zip_cd = reader->cd_zipped;
return MZ_OK;
}
int32_t mz_zip_reader_get_comment(void *handle, const char **comment) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
if (mz_zip_reader_is_open(reader) != MZ_OK)
return MZ_PARAM_ERROR;
if (comment == NULL)
return MZ_PARAM_ERROR;
return mz_zip_get_comment(reader->zip_handle, comment);
}
int32_t mz_zip_reader_set_recover(void *handle, uint8_t recover) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
if (reader == NULL)
return MZ_PARAM_ERROR;
reader->recover = recover;
return MZ_OK;
}
void mz_zip_reader_set_encoding(void *handle, int32_t encoding) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
reader->encoding = encoding;
}
void mz_zip_reader_set_sign_required(void *handle, uint8_t sign_required) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
reader->sign_required = sign_required;
}
void mz_zip_reader_set_overwrite_cb(void *handle, void *userdata, mz_zip_reader_overwrite_cb cb) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
reader->overwrite_cb = cb;
reader->overwrite_userdata = userdata;
}
void mz_zip_reader_set_password_cb(void *handle, void *userdata, mz_zip_reader_password_cb cb) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
reader->password_cb = cb;
reader->password_userdata = userdata;
}
void mz_zip_reader_set_progress_cb(void *handle, void *userdata, mz_zip_reader_progress_cb cb) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
reader->progress_cb = cb;
reader->progress_userdata = userdata;
}
void mz_zip_reader_set_progress_interval(void *handle, uint32_t milliseconds) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
reader->progress_cb_interval_ms = milliseconds;
}
void mz_zip_reader_set_entry_cb(void *handle, void *userdata, mz_zip_reader_entry_cb cb) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
reader->entry_cb = cb;
reader->entry_userdata = userdata;
}
int32_t mz_zip_reader_get_zip_handle(void *handle, void **zip_handle) {
mz_zip_reader *reader = (mz_zip_reader *)handle;
if (zip_handle == NULL)
return MZ_PARAM_ERROR;
*zip_handle = reader->zip_handle;
if (*zip_handle == NULL)
return MZ_EXIST_ERROR;
return MZ_OK;
}
/***************************************************************************/
void *mz_zip_reader_create(void **handle) {
mz_zip_reader *reader = NULL;
reader = (mz_zip_reader *)MZ_ALLOC(sizeof(mz_zip_reader));
if (reader != NULL) {
memset(reader, 0, sizeof(mz_zip_reader));
reader->recover = 1;
reader->progress_cb_interval_ms = MZ_DEFAULT_PROGRESS_INTERVAL;
}
if (handle != NULL)
*handle = reader;
return reader;
}
void mz_zip_reader_delete(void **handle) {
mz_zip_reader *reader = NULL;
if (handle == NULL)
return;
reader = (mz_zip_reader *)*handle;
if (reader != NULL) {
mz_zip_reader_close(reader);
MZ_FREE(reader);
}
*handle = NULL;
}
/***************************************************************************/
typedef struct mz_zip_writer_s {
void *zip_handle;
void *file_stream;
void *buffered_stream;
void *split_stream;
void *sha256;
void *mem_stream;
void *file_extra_stream;
mz_zip_file file_info;
void *overwrite_userdata;
mz_zip_writer_overwrite_cb
overwrite_cb;
void *password_userdata;
mz_zip_writer_password_cb
password_cb;
void *progress_userdata;
mz_zip_writer_progress_cb
progress_cb;
uint32_t progress_cb_interval_ms;
void *entry_userdata;
mz_zip_writer_entry_cb
entry_cb;
const char *password;
const char *comment;
uint8_t *cert_data;
int32_t cert_data_size;
const char *cert_pwd;
uint16_t compress_method;
int16_t compress_level;
uint8_t follow_links;
uint8_t store_links;
uint8_t zip_cd;
uint8_t aes;
uint8_t raw;
uint8_t buffer[UINT16_MAX];
} mz_zip_writer;
/***************************************************************************/
int32_t mz_zip_writer_zip_cd(void *handle) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
mz_zip_file cd_file;
uint64_t number_entry = 0;
int64_t cd_mem_length = 0;
int32_t err = MZ_OK;
int32_t extrafield_size = 0;
void *file_extra_stream = NULL;
void *cd_mem_stream = NULL;
memset(&cd_file, 0, sizeof(cd_file));
mz_zip_get_number_entry(writer->zip_handle, &number_entry);
mz_zip_get_cd_mem_stream(writer->zip_handle, &cd_mem_stream);
mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_END);
cd_mem_length = (uint32_t)mz_stream_tell(cd_mem_stream);
mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);
cd_file.filename = MZ_ZIP_CD_FILENAME;
cd_file.modified_date = time(NULL);
cd_file.version_madeby = MZ_VERSION_MADEBY;
cd_file.compression_method = writer->compress_method;
cd_file.uncompressed_size = (int32_t)cd_mem_length;
cd_file.flag = MZ_ZIP_FLAG_UTF8;
if (writer->password != NULL)
cd_file.flag |= MZ_ZIP_FLAG_ENCRYPTED;
mz_stream_mem_create(&file_extra_stream);
mz_stream_mem_open(file_extra_stream, NULL, MZ_OPEN_MODE_CREATE);
mz_zip_extrafield_write(file_extra_stream, MZ_ZIP_EXTENSION_CDCD, 8);
mz_stream_write_uint64(file_extra_stream, number_entry);
mz_stream_mem_get_buffer(file_extra_stream, (const void **)&cd_file.extrafield);
mz_stream_mem_get_buffer_length(file_extra_stream, &extrafield_size);
cd_file.extrafield_size = (uint16_t)extrafield_size;
err = mz_zip_writer_entry_open(handle, &cd_file);
if (err == MZ_OK) {
mz_stream_copy_stream(handle, mz_zip_writer_entry_write, cd_mem_stream,
NULL, (int32_t)cd_mem_length);
mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);
mz_stream_mem_set_buffer_limit(cd_mem_stream, 0);
err = mz_zip_writer_entry_close(writer);
}
mz_stream_mem_delete(&file_extra_stream);
return err;
}
/***************************************************************************/
int32_t mz_zip_writer_is_open(void *handle) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
if (writer == NULL)
return MZ_PARAM_ERROR;
if (writer->zip_handle == NULL)
return MZ_PARAM_ERROR;
return MZ_OK;
}
static int32_t mz_zip_writer_open_int(void *handle, void *stream, int32_t mode) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
int32_t err = MZ_OK;
mz_zip_create(&writer->zip_handle);
err = mz_zip_open(writer->zip_handle, stream, mode);
if (err != MZ_OK) {
mz_zip_writer_close(handle);
return err;
}
return MZ_OK;
}
int32_t mz_zip_writer_open(void *handle, void *stream, uint8_t append) {
int32_t mode = MZ_OPEN_MODE_WRITE;
if (append) {
mode |= MZ_OPEN_MODE_APPEND;
} else {
mode |= MZ_OPEN_MODE_CREATE;
}
return mz_zip_writer_open_int(handle, stream, mode);
}
int32_t mz_zip_writer_open_file(void *handle, const char *path, int64_t disk_size, uint8_t append) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
int32_t mode = MZ_OPEN_MODE_READWRITE;
int32_t err = MZ_OK;
int32_t err_cb = 0;
char directory[320];
mz_zip_writer_close(handle);
if (mz_os_file_exists(path) != MZ_OK) {
/* If the file doesn't exist, we don't append file */
mode |= MZ_OPEN_MODE_CREATE;
/* Create destination directory if it doesn't already exist */
if (strchr(path, '/') != NULL || strrchr(path, '\\') != NULL) {
strncpy(directory, path, sizeof(directory));
mz_path_remove_filename(directory);
if (mz_os_file_exists(directory) != MZ_OK)
mz_dir_make(directory);
}
} else if (append) {
mode |= MZ_OPEN_MODE_APPEND;
} else {
if (writer->overwrite_cb != NULL)
err_cb = writer->overwrite_cb(handle, writer->overwrite_userdata, path);
if (err_cb == MZ_INTERNAL_ERROR)
return err;
if (err_cb == MZ_OK)
mode |= MZ_OPEN_MODE_CREATE;
else
mode |= MZ_OPEN_MODE_APPEND;
}
mz_stream_os_create(&writer->file_stream);
mz_stream_buffered_create(&writer->buffered_stream);
mz_stream_split_create(&writer->split_stream);
mz_stream_set_base(writer->buffered_stream, writer->file_stream);
mz_stream_set_base(writer->split_stream, writer->buffered_stream);
mz_stream_split_set_prop_int64(writer->split_stream, MZ_STREAM_PROP_DISK_SIZE, disk_size);
err = mz_stream_open(writer->split_stream, path, mode);
if (err == MZ_OK)
err = mz_zip_writer_open_int(handle, writer->split_stream, mode);
return err;
}
int32_t mz_zip_writer_open_file_in_memory(void *handle, const char *path) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
void *file_stream = NULL;
int64_t file_size = 0;
int32_t err = 0;
mz_zip_writer_close(handle);
mz_stream_os_create(&file_stream);
err = mz_stream_os_open(file_stream, path, MZ_OPEN_MODE_READ);
if (err != MZ_OK) {
mz_stream_os_delete(&file_stream);
mz_zip_writer_close(handle);
return err;
}
mz_stream_os_seek(file_stream, 0, MZ_SEEK_END);
file_size = mz_stream_os_tell(file_stream);
mz_stream_os_seek(file_stream, 0, MZ_SEEK_SET);
if ((file_size <= 0) || (file_size > UINT32_MAX)) {
/* Memory size is too large or too small */
mz_stream_os_close(file_stream);
mz_stream_os_delete(&file_stream);
mz_zip_writer_close(handle);
return MZ_MEM_ERROR;
}
mz_stream_mem_create(&writer->mem_stream);
mz_stream_mem_set_grow_size(writer->mem_stream, (int32_t)file_size);
mz_stream_mem_open(writer->mem_stream, NULL, MZ_OPEN_MODE_CREATE);
err = mz_stream_copy(writer->mem_stream, file_stream, (int32_t)file_size);
mz_stream_os_close(file_stream);
mz_stream_os_delete(&file_stream);
if (err == MZ_OK)
err = mz_zip_writer_open(handle, writer->mem_stream, 1);
if (err != MZ_OK)
mz_zip_writer_close(handle);
return err;
}
int32_t mz_zip_writer_close(void *handle) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
int32_t err = MZ_OK;
if (writer->zip_handle != NULL) {
mz_zip_set_version_madeby(writer->zip_handle, MZ_VERSION_MADEBY);
if (writer->comment)
mz_zip_set_comment(writer->zip_handle, writer->comment);
if (writer->zip_cd)
mz_zip_writer_zip_cd(writer);
err = mz_zip_close(writer->zip_handle);
mz_zip_delete(&writer->zip_handle);
}
if (writer->split_stream != NULL) {
mz_stream_split_close(writer->split_stream);
mz_stream_split_delete(&writer->split_stream);
}
if (writer->buffered_stream != NULL)
mz_stream_buffered_delete(&writer->buffered_stream);
if (writer->file_stream != NULL)
mz_stream_os_delete(&writer->file_stream);
if (writer->mem_stream != NULL) {
mz_stream_mem_close(writer->mem_stream);
mz_stream_mem_delete(&writer->mem_stream);
}
return err;
}
/***************************************************************************/
int32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
int32_t err = MZ_OK;
const char *password = NULL;
char password_buf[120];
/* Copy file info to access data upon close */
memcpy(&writer->file_info, file_info, sizeof(mz_zip_file));
if (writer->entry_cb != NULL)
writer->entry_cb(handle, writer->entry_userdata, &writer->file_info);
password = writer->password;
/* Check if we need a password and ask for it if we need to */
if ((writer->file_info.flag & MZ_ZIP_FLAG_ENCRYPTED) && (password == NULL) &&
(writer->password_cb != NULL)) {
writer->password_cb(handle, writer->password_userdata, &writer->file_info,
password_buf, sizeof(password_buf));
password = password_buf;
}
#ifndef MZ_ZIP_NO_CRYPTO
if (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK) {
/* Start calculating sha256 */
mz_crypt_sha_create(&writer->sha256);
mz_crypt_sha_set_algorithm(writer->sha256, MZ_HASH_SHA256);
mz_crypt_sha_begin(writer->sha256);
}
#endif
/* Open entry in zip */
err = mz_zip_entry_write_open(writer->zip_handle, &writer->file_info, writer->compress_level,
writer->raw, password);
return err;
}
#if !defined(MZ_ZIP_NO_CRYPTO) && defined(MZ_ZIP_SIGNING)
int32_t mz_zip_writer_entry_sign(void *handle, uint8_t *message, int32_t message_size,
uint8_t *cert_data, int32_t cert_data_size, const char *cert_pwd) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
int32_t err = MZ_OK;
int32_t signature_size = 0;
uint8_t *signature = NULL;
if (writer == NULL || cert_data == NULL || cert_data_size <= 0)
return MZ_PARAM_ERROR;
if (mz_zip_entry_is_open(writer->zip_handle) != MZ_OK)
return MZ_PARAM_ERROR;
/* Sign message with certificate */
err = mz_crypt_sign(message, message_size, cert_data, cert_data_size, cert_pwd,
&signature, &signature_size);
if ((err == MZ_OK) && (signature != NULL)) {
/* Write signature zip extra field */
err = mz_zip_extrafield_write(writer->file_extra_stream, MZ_ZIP_EXTENSION_SIGN,
(uint16_t)signature_size);
if (err == MZ_OK) {
if (mz_stream_write(writer->file_extra_stream, signature, signature_size) != signature_size)
err = MZ_WRITE_ERROR;
}
MZ_FREE(signature);
}
return err;
}
#endif
int32_t mz_zip_writer_entry_close(void *handle) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
int32_t err = MZ_OK;
#ifndef MZ_ZIP_NO_CRYPTO
const uint8_t *extrafield = NULL;
int32_t extrafield_size = 0;
int16_t field_length_hash = 0;
uint8_t sha256[MZ_HASH_SHA256_SIZE];
if (writer->sha256 != NULL) {
mz_crypt_sha_end(writer->sha256, sha256, sizeof(sha256));
mz_crypt_sha_delete(&writer->sha256);
/* Copy extrafield so we can append our own fields before close */
mz_stream_mem_create(&writer->file_extra_stream);
mz_stream_mem_open(writer->file_extra_stream, NULL, MZ_OPEN_MODE_CREATE);
/* Write sha256 hash to extrafield */
field_length_hash = 4 + MZ_HASH_SHA256_SIZE;
err = mz_zip_extrafield_write(writer->file_extra_stream, MZ_ZIP_EXTENSION_HASH, field_length_hash);
if (err == MZ_OK)
err = mz_stream_write_uint16(writer->file_extra_stream, MZ_HASH_SHA256);
if (err == MZ_OK)
err = mz_stream_write_uint16(writer->file_extra_stream, MZ_HASH_SHA256_SIZE);
if (err == MZ_OK) {
if (mz_stream_write(writer->file_extra_stream, sha256, sizeof(sha256)) != MZ_HASH_SHA256_SIZE)
err = MZ_WRITE_ERROR;
}
#ifdef MZ_ZIP_SIGNING
if ((err == MZ_OK) && (writer->cert_data != NULL) && (writer->cert_data_size > 0)) {
/* Sign entry if not zipping cd or if it is cd being zipped */
if (!writer->zip_cd || strcmp(writer->file_info.filename, MZ_ZIP_CD_FILENAME) == 0) {
err = mz_zip_writer_entry_sign(handle, sha256, sizeof(sha256),
writer->cert_data, writer->cert_data_size, writer->cert_pwd);
}
}
#endif
if ((writer->file_info.extrafield != NULL) && (writer->file_info.extrafield_size > 0))
mz_stream_mem_write(writer->file_extra_stream, writer->file_info.extrafield,
writer->file_info.extrafield_size);
/* Update extra field for central directory after adding extra fields */
mz_stream_mem_get_buffer(writer->file_extra_stream, (const void **)&extrafield);
mz_stream_mem_get_buffer_length(writer->file_extra_stream, &extrafield_size);
mz_zip_entry_set_extrafield(writer->zip_handle, extrafield, (uint16_t)extrafield_size);
}
#endif
if (err == MZ_OK) {
if (writer->raw)
err = mz_zip_entry_close_raw(writer->zip_handle, writer->file_info.uncompressed_size,
writer->file_info.crc);
else
err = mz_zip_entry_close(writer->zip_handle);
}
if (writer->file_extra_stream != NULL)
mz_stream_mem_delete(&writer->file_extra_stream);
return err;
}
int32_t mz_zip_writer_entry_write(void *handle, const void *buf, int32_t len) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
int32_t written = 0;
written = mz_zip_entry_write(writer->zip_handle, buf, len);
#ifndef MZ_ZIP_NO_CRYPTO
if ((written > 0) && (writer->sha256 != NULL))
mz_crypt_sha_update(writer->sha256, buf, written);
#endif
return written;
}
/***************************************************************************/
int32_t mz_zip_writer_add_process(void *handle, void *stream, mz_stream_read_cb read_cb) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
int32_t read = 0;
int32_t written = 0;
int32_t err = MZ_OK;
if (mz_zip_writer_is_open(writer) != MZ_OK)
return MZ_PARAM_ERROR;
/* If the entry isn't open for writing, open it */
if (mz_zip_entry_is_open(writer->zip_handle) != MZ_OK)
return MZ_PARAM_ERROR;
if (read_cb == NULL)
return MZ_PARAM_ERROR;
read = read_cb(stream, writer->buffer, sizeof(writer->buffer));
if (read == 0)
return MZ_END_OF_STREAM;
if (read < 0) {
err = read;
return err;
}
written = mz_zip_writer_entry_write(handle, writer->buffer, read);
if (written != read)
return MZ_WRITE_ERROR;
return written;
}
int32_t mz_zip_writer_add(void *handle, void *stream, mz_stream_read_cb read_cb) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
uint64_t current_time = 0;
uint64_t update_time = 0;
int64_t current_pos = 0;
int64_t update_pos = 0;
int32_t err = MZ_OK;
int32_t written = 0;
/* Update the progress at the beginning */
if (writer->progress_cb != NULL)
writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);
/* Write data to stream until done */
while (err == MZ_OK) {
written = mz_zip_writer_add_process(handle, stream, read_cb);
if (written == MZ_END_OF_STREAM)
break;
if (written > 0)
current_pos += written;
if (written < 0)
err = written;
/* Update progress if enough time have passed */
current_time = mz_os_ms_time();
if ((current_time - update_time) > writer->progress_cb_interval_ms) {
if (writer->progress_cb != NULL)
writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);
update_pos = current_pos;
update_time = current_time;
}
}
/* Update the progress at the end */
if (writer->progress_cb != NULL && update_pos != current_pos)
writer->progress_cb(handle, writer->progress_userdata, &writer->file_info, current_pos);
return err;
}
int32_t mz_zip_writer_add_info(void *handle, void *stream, mz_stream_read_cb read_cb, mz_zip_file *file_info) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
int32_t err = MZ_OK;
if (mz_zip_writer_is_open(handle) != MZ_OK)
return MZ_PARAM_ERROR;
if (file_info == NULL)
return MZ_PARAM_ERROR;
/* Add to zip */
err = mz_zip_writer_entry_open(handle, file_info);
if (err != MZ_OK)
return err;
if (stream != NULL) {
if (mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK) {
err = mz_zip_writer_add(handle, stream, read_cb);
if (err != MZ_OK)
return err;
}
}
err = mz_zip_writer_entry_close(handle);
return err;
}
int32_t mz_zip_writer_add_buffer(void *handle, void *buf, int32_t len, mz_zip_file *file_info) {
void *mem_stream = NULL;
int32_t err = MZ_OK;
if (mz_zip_writer_is_open(handle) != MZ_OK)
return MZ_PARAM_ERROR;
if (buf == NULL)
return MZ_PARAM_ERROR;
/* Create a memory stream backed by our buffer and add from it */
mz_stream_mem_create(&mem_stream);
mz_stream_mem_set_buffer(mem_stream, buf, len);
err = mz_stream_mem_open(mem_stream, NULL, MZ_OPEN_MODE_READ);
if (err == MZ_OK)
err = mz_zip_writer_add_info(handle, mem_stream, mz_stream_mem_read, file_info);
mz_stream_mem_delete(&mem_stream);
return err;
}
int32_t mz_zip_writer_add_file(void *handle, const char *path, const char *filename_in_zip) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
mz_zip_file file_info;
uint32_t target_attrib = 0;
uint32_t src_attrib = 0;
int32_t err = MZ_OK;
uint8_t src_sys = 0;
void *stream = NULL;
char link_path[1024];
const char *filename = filename_in_zip;
if (mz_zip_writer_is_open(handle) != MZ_OK)
return MZ_PARAM_ERROR;
if (path == NULL)
return MZ_PARAM_ERROR;
if (filename == NULL) {
err = mz_path_get_filename(path, &filename);
if (err != MZ_OK)
return err;
}
memset(&file_info, 0, sizeof(file_info));
/* The path name saved, should not include a leading slash. */
/* If it did, windows/xp and dynazip couldn't read the zip file. */
while (filename[0] == '\\' || filename[0] == '/')
filename += 1;
/* Get information about the file on disk so we can store it in zip */
file_info.version_madeby = MZ_VERSION_MADEBY;
file_info.compression_method = writer->compress_method;
file_info.filename = filename;
file_info.uncompressed_size = mz_os_get_file_size(path);
file_info.flag = MZ_ZIP_FLAG_UTF8;
if (writer->zip_cd)
file_info.flag |= MZ_ZIP_FLAG_MASK_LOCAL_INFO;
if (writer->aes)
file_info.aes_version = MZ_AES_VERSION;
mz_os_get_file_date(path, &file_info.modified_date, &file_info.accessed_date,
&file_info.creation_date);
mz_os_get_file_attribs(path, &src_attrib);
src_sys = MZ_HOST_SYSTEM(file_info.version_madeby);
if ((src_sys != MZ_HOST_SYSTEM_MSDOS) && (src_sys != MZ_HOST_SYSTEM_WINDOWS_NTFS)) {
/* High bytes are OS specific attributes, low byte is always DOS attributes */
if (mz_zip_attrib_convert(src_sys, src_attrib, MZ_HOST_SYSTEM_MSDOS, &target_attrib) == MZ_OK)
file_info.external_fa = target_attrib;
file_info.external_fa |= (src_attrib << 16);
} else {
file_info.external_fa = src_attrib;
}
if (writer->store_links && mz_os_is_symlink(path) == MZ_OK) {
err = mz_os_read_symlink(path, link_path, sizeof(link_path));
if (err == MZ_OK)
file_info.linkname = link_path;
} else if (mz_os_is_dir(path) != MZ_OK) {
mz_stream_os_create(&stream);
err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ);
}
if (err == MZ_OK)
err = mz_zip_writer_add_info(handle, stream, mz_stream_read, &file_info);
if (stream != NULL) {
mz_stream_close(stream);
mz_stream_delete(&stream);
}
return err;
}
int32_t mz_zip_writer_add_path(void *handle, const char *path, const char *root_path,
uint8_t include_path, uint8_t recursive) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
DIR *dir = NULL;
struct dirent *entry = NULL;
int32_t err = MZ_OK;
int16_t is_dir = 0;
const char *filename = NULL;
const char *filenameinzip = path;
char *wildcard_ptr = NULL;
char full_path[1024];
char path_dir[1024];
if (strrchr(path, '*') != NULL) {
strncpy(path_dir, path, sizeof(path_dir) - 1);
path_dir[sizeof(path_dir) - 1] = 0;
mz_path_remove_filename(path_dir);
wildcard_ptr = path_dir + strlen(path_dir) + 1;
root_path = path = path_dir;
} else {
if (mz_os_is_dir(path) == MZ_OK)
is_dir = 1;
/* Construct the filename that our file will be stored in the zip as */
if (root_path == NULL)
root_path = path;
/* Should the file be stored with any path info at all? */
if (!include_path) {
if (!is_dir && root_path == path) {
if (mz_path_get_filename(filenameinzip, &filename) == MZ_OK)
filenameinzip = filename;
} else {
filenameinzip += strlen(root_path);
}
}
if (!writer->store_links && !writer->follow_links) {
if (mz_os_is_symlink(path) == MZ_OK)
return err;
}
if (*filenameinzip != 0)
err = mz_zip_writer_add_file(handle, path, filenameinzip);
if (!is_dir)
return err;
if (writer->store_links) {
if (mz_os_is_symlink(path) == MZ_OK)
return err;
}
}
dir = mz_os_open_dir(path);
if (dir == NULL)
return MZ_EXIST_ERROR;
while ((entry = mz_os_read_dir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
full_path[0] = 0;
mz_path_combine(full_path, path, sizeof(full_path));
mz_path_combine(full_path, entry->d_name, sizeof(full_path));
if (!recursive && mz_os_is_dir(full_path) == MZ_OK)
continue;
if ((wildcard_ptr != NULL) && (mz_path_compare_wc(entry->d_name, wildcard_ptr, 1) != MZ_OK))
continue;
err = mz_zip_writer_add_path(handle, full_path, root_path, include_path, recursive);
if (err != MZ_OK)
break;
}
mz_os_close_dir(dir);
return err;
}
int32_t mz_zip_writer_copy_from_reader(void *handle, void *reader) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
mz_zip_file *file_info = NULL;
int64_t compressed_size = 0;
int64_t uncompressed_size = 0;
uint32_t crc32 = 0;
int32_t err = MZ_OK;
uint8_t original_raw = 0;
void *reader_zip_handle = NULL;
void *writer_zip_handle = NULL;
if (mz_zip_reader_is_open(reader) != MZ_OK)
return MZ_PARAM_ERROR;
if (mz_zip_writer_is_open(writer) != MZ_OK)
return MZ_PARAM_ERROR;
err = mz_zip_reader_entry_get_info(reader, &file_info);
if (err != MZ_OK)
return err;
mz_zip_reader_get_zip_handle(reader, &reader_zip_handle);
mz_zip_writer_get_zip_handle(writer, &writer_zip_handle);
/* Open entry for raw reading */
err = mz_zip_entry_read_open(reader_zip_handle, 1, NULL);
if (err == MZ_OK) {
/* Write entry raw, save original raw value */
original_raw = writer->raw;
writer->raw = 1;
err = mz_zip_writer_entry_open(writer, file_info);
if ((err == MZ_OK) &&
(mz_zip_attrib_is_dir(writer->file_info.external_fa, writer->file_info.version_madeby) != MZ_OK)) {
err = mz_zip_writer_add(writer, reader_zip_handle, mz_zip_entry_read);
}
if (err == MZ_OK) {
err = mz_zip_entry_read_close(reader_zip_handle, &crc32, &compressed_size, &uncompressed_size);
if (err == MZ_OK)
err = mz_zip_entry_write_close(writer_zip_handle, crc32, compressed_size, uncompressed_size);
}
if (mz_zip_entry_is_open(reader_zip_handle) == MZ_OK)
mz_zip_entry_close(reader_zip_handle);
if (mz_zip_entry_is_open(writer_zip_handle) == MZ_OK)
mz_zip_entry_close(writer_zip_handle);
writer->raw = original_raw;
}
return err;
}
/***************************************************************************/
void mz_zip_writer_set_password(void *handle, const char *password) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->password = password;
}
void mz_zip_writer_set_comment(void *handle, const char *comment) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->comment = comment;
}
void mz_zip_writer_set_raw(void *handle, uint8_t raw) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->raw = raw;
}
int32_t mz_zip_writer_get_raw(void *handle, uint8_t *raw) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
if (raw == NULL)
return MZ_PARAM_ERROR;
*raw = writer->raw;
return MZ_OK;
}
void mz_zip_writer_set_aes(void *handle, uint8_t aes) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->aes = aes;
}
void mz_zip_writer_set_compress_method(void *handle, uint16_t compress_method) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->compress_method = compress_method;
}
void mz_zip_writer_set_compress_level(void *handle, int16_t compress_level) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->compress_level = compress_level;
}
void mz_zip_writer_set_follow_links(void *handle, uint8_t follow_links) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->follow_links = follow_links;
}
void mz_zip_writer_set_store_links(void *handle, uint8_t store_links) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->store_links = store_links;
}
void mz_zip_writer_set_zip_cd(void *handle, uint8_t zip_cd) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->zip_cd = zip_cd;
}
int32_t mz_zip_writer_set_certificate(void *handle, const char *cert_path, const char *cert_pwd) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
void *cert_stream = NULL;
uint8_t *cert_data = NULL;
int32_t cert_data_size = 0;
int32_t err = MZ_OK;
if (cert_path == NULL)
return MZ_PARAM_ERROR;
cert_data_size = (int32_t)mz_os_get_file_size(cert_path);
if (cert_data_size == 0)
return MZ_PARAM_ERROR;
if (writer->cert_data != NULL) {
MZ_FREE(writer->cert_data);
writer->cert_data = NULL;
}
cert_data = (uint8_t *)MZ_ALLOC(cert_data_size);
/* Read pkcs12 certificate from disk */
mz_stream_os_create(&cert_stream);
err = mz_stream_os_open(cert_stream, cert_path, MZ_OPEN_MODE_READ);
if (err == MZ_OK) {
if (mz_stream_os_read(cert_stream, cert_data, cert_data_size) != cert_data_size)
err = MZ_READ_ERROR;
mz_stream_os_close(cert_stream);
}
mz_stream_os_delete(&cert_stream);
if (err == MZ_OK) {
writer->cert_data = cert_data;
writer->cert_data_size = cert_data_size;
writer->cert_pwd = cert_pwd;
} else {
MZ_FREE(cert_data);
}
return err;
}
void mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->overwrite_cb = cb;
writer->overwrite_userdata = userdata;
}
void mz_zip_writer_set_password_cb(void *handle, void *userdata, mz_zip_writer_password_cb cb) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->password_cb = cb;
writer->password_userdata = userdata;
}
void mz_zip_writer_set_progress_cb(void *handle, void *userdata, mz_zip_writer_progress_cb cb) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->progress_cb = cb;
writer->progress_userdata = userdata;
}
void mz_zip_writer_set_progress_interval(void *handle, uint32_t milliseconds) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->progress_cb_interval_ms = milliseconds;
}
void mz_zip_writer_set_entry_cb(void *handle, void *userdata, mz_zip_writer_entry_cb cb) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->entry_cb = cb;
writer->entry_userdata = userdata;
}
int32_t mz_zip_writer_get_zip_handle(void *handle, void **zip_handle) {
mz_zip_writer *writer = (mz_zip_writer *)handle;
if (zip_handle == NULL)
return MZ_PARAM_ERROR;
*zip_handle = writer->zip_handle;
if (*zip_handle == NULL)
return MZ_EXIST_ERROR;
return MZ_OK;
}
/***************************************************************************/
void *mz_zip_writer_create(void **handle) {
mz_zip_writer *writer = NULL;
writer = (mz_zip_writer *)MZ_ALLOC(sizeof(mz_zip_writer));
if (writer != NULL) {
memset(writer, 0, sizeof(mz_zip_writer));
#if defined(HAVE_WZAES)
writer->aes = 1;
#endif
#if defined(HAVE_ZLIB) || defined(HAVE_LIBCOMP)
writer->compress_method = MZ_COMPRESS_METHOD_DEFLATE;
#elif defined(HAVE_BZIP2)
writer->compress_method = MZ_COMPRESS_METHOD_BZIP2;
#elif defined(HAVE_LZMA)
writer->compress_method = MZ_COMPRESS_METHOD_LZMA;
#else
writer->compress_method = MZ_COMPRESS_METHOD_STORE;
#endif
writer->compress_level = MZ_COMPRESS_LEVEL_BEST;
writer->progress_cb_interval_ms = MZ_DEFAULT_PROGRESS_INTERVAL;
}
if (handle != NULL)
*handle = writer;
return writer;
}
void mz_zip_writer_delete(void **handle) {
mz_zip_writer *writer = NULL;
if (handle == NULL)
return;
writer = (mz_zip_writer *)*handle;
if (writer != NULL) {
mz_zip_writer_close(writer);
if (writer->cert_data != NULL)
MZ_FREE(writer->cert_data);
writer->cert_data = NULL;
writer->cert_data_size = 0;
MZ_FREE(writer);
}
*handle = NULL;
}
/***************************************************************************/
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/mz_zip_rw.h 0000664 0000000 0000000 00000027126 14126475503 0024654 0 ustar 00root root 0000000 0000000 /* mz_zip_rw.h -- Zip reader/writer
part of the minizip-ng project
Copyright (C) 2010-2021 Nathan Moinvaziri
https://github.com/zlib-ng/minizip-ng
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_ZIP_RW_H
#define MZ_ZIP_RW_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
typedef int32_t (*mz_zip_reader_overwrite_cb)(void *handle, void *userdata, mz_zip_file *file_info, const char *path);
typedef int32_t (*mz_zip_reader_password_cb)(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password);
typedef int32_t (*mz_zip_reader_progress_cb)(void *handle, void *userdata, mz_zip_file *file_info, int64_t position);
typedef int32_t (*mz_zip_reader_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info, const char *path);
/***************************************************************************/
int32_t mz_zip_reader_is_open(void *handle);
/* Checks to see if the zip file is open */
int32_t mz_zip_reader_open(void *handle, void *stream);
/* Opens zip file from stream */
int32_t mz_zip_reader_open_file(void *handle, const char *path);
/* Opens zip file from a file path */
int32_t mz_zip_reader_open_file_in_memory(void *handle, const char *path);
/* Opens zip file from a file path into memory for faster access */
int32_t mz_zip_reader_open_buffer(void *handle, uint8_t *buf, int32_t len, uint8_t copy);
/* Opens zip file from memory buffer */
int32_t mz_zip_reader_close(void *handle);
/* Closes the zip file */
/***************************************************************************/
int32_t mz_zip_reader_unzip_cd(void *handle);
/* Unzip the central directory */
/***************************************************************************/
int32_t mz_zip_reader_goto_first_entry(void *handle);
/* Goto the first entry in the zip file that matches the pattern */
int32_t mz_zip_reader_goto_next_entry(void *handle);
/* Goto the next entry in the zip file that matches the pattern */
int32_t mz_zip_reader_locate_entry(void *handle, const char *filename, uint8_t ignore_case);
/* Locates an entry by filename */
int32_t mz_zip_reader_entry_open(void *handle);
/* Opens an entry for reading */
int32_t mz_zip_reader_entry_close(void *handle);
/* Closes an entry */
int32_t mz_zip_reader_entry_read(void *handle, void *buf, int32_t len);
/* Reads and entry after being opened */
int32_t mz_zip_reader_entry_has_sign(void *handle);
/* Checks to see if the entry has a signature */
int32_t mz_zip_reader_entry_sign_verify(void *handle);
/* Verifies a signature stored with the entry */
int32_t mz_zip_reader_entry_get_hash(void *handle, uint16_t algorithm, uint8_t *digest, int32_t digest_size);
/* Gets a hash algorithm from the entry's extra field */
int32_t mz_zip_reader_entry_get_first_hash(void *handle, uint16_t *algorithm, uint16_t *digest_size);
/* Gets the most secure hash algorithm from the entry's extra field */
int32_t mz_zip_reader_entry_get_info(void *handle, mz_zip_file **file_info);
/* Gets the current entry file info */
int32_t mz_zip_reader_entry_is_dir(void *handle);
/* Gets the current entry is a directory */
int32_t mz_zip_reader_entry_save(void *handle, void *stream, mz_stream_write_cb write_cb);
/* Save the current entry to a stream */
int32_t mz_zip_reader_entry_save_process(void *handle, void *stream, mz_stream_write_cb write_cb);
/* Saves a portion of the current entry to a stream callback */
int32_t mz_zip_reader_entry_save_file(void *handle, const char *path);
/* Save the current entry to a file */
int32_t mz_zip_reader_entry_save_buffer(void *handle, void *buf, int32_t len);
/* Save the current entry to a memory buffer */
int32_t mz_zip_reader_entry_save_buffer_length(void *handle);
/* Gets the length of the buffer required to save */
/***************************************************************************/
int32_t mz_zip_reader_save_all(void *handle, const char *destination_dir);
/* Save all files into a directory */
/***************************************************************************/
void mz_zip_reader_set_pattern(void *handle, const char *pattern, uint8_t ignore_case);
/* Sets the match pattern for entries in the zip file, if null all entries are matched */
void mz_zip_reader_set_password(void *handle, const char *password);
/* Sets the password required for extraction */
void mz_zip_reader_set_raw(void *handle, uint8_t raw);
/* Sets whether or not it should save the entry raw */
int32_t mz_zip_reader_get_raw(void *handle, uint8_t *raw);
/* Gets whether or not it should save the entry raw */
int32_t mz_zip_reader_get_zip_cd(void *handle, uint8_t *zip_cd);
/* Gets whether or not the archive has a zipped central directory */
int32_t mz_zip_reader_get_comment(void *handle, const char **comment);
/* Gets the comment for the central directory */
int32_t mz_zip_reader_set_recover(void *handle, uint8_t recover);
/* Sets the ability to recover the central dir by reading local file headers */
void mz_zip_reader_set_encoding(void *handle, int32_t encoding);
/* Sets whether or not it should support a special character encoding in zip file names. */
void mz_zip_reader_set_sign_required(void *handle, uint8_t sign_required);
/* Sets whether or not it a signature is required */
void mz_zip_reader_set_overwrite_cb(void *handle, void *userdata, mz_zip_reader_overwrite_cb cb);
/* Callback for what to do when a file is being overwritten */
void mz_zip_reader_set_password_cb(void *handle, void *userdata, mz_zip_reader_password_cb cb);
/* Callback for when a password is required and hasn't been set */
void mz_zip_reader_set_progress_cb(void *handle, void *userdata, mz_zip_reader_progress_cb cb);
/* Callback for extraction progress */
void mz_zip_reader_set_progress_interval(void *handle, uint32_t milliseconds);
/* Let at least milliseconds pass between calls to progress callback */
void mz_zip_reader_set_entry_cb(void *handle, void *userdata, mz_zip_reader_entry_cb cb);
/* Callback for zip file entries */
int32_t mz_zip_reader_get_zip_handle(void *handle, void **zip_handle);
/* Gets the underlying zip instance handle */
void* mz_zip_reader_create(void **handle);
/* Create new instance of zip reader */
void mz_zip_reader_delete(void **handle);
/* Delete instance of zip reader */
/***************************************************************************/
typedef int32_t (*mz_zip_writer_overwrite_cb)(void *handle, void *userdata, const char *path);
typedef int32_t (*mz_zip_writer_password_cb)(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password);
typedef int32_t (*mz_zip_writer_progress_cb)(void *handle, void *userdata, mz_zip_file *file_info, int64_t position);
typedef int32_t (*mz_zip_writer_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info);
/***************************************************************************/
int32_t mz_zip_writer_is_open(void *handle);
/* Checks to see if the zip file is open */
int32_t mz_zip_writer_open(void *handle, void *stream, uint8_t append);
/* Opens zip file from stream */
int32_t mz_zip_writer_open_file(void *handle, const char *path, int64_t disk_size, uint8_t append);
/* Opens zip file from a file path */
int32_t mz_zip_writer_open_file_in_memory(void *handle, const char *path);
/* Opens zip file from a file path into memory for faster access */
int32_t mz_zip_writer_close(void *handle);
/* Closes the zip file */
/***************************************************************************/
int32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info);
/* Opens an entry in the zip file for writing */
int32_t mz_zip_writer_entry_close(void *handle);
/* Closes entry in zip file */
int32_t mz_zip_writer_entry_write(void *handle, const void *buf, int32_t len);
/* Writes data into entry for zip */
/***************************************************************************/
int32_t mz_zip_writer_add(void *handle, void *stream, mz_stream_read_cb read_cb);
/* Writes all data to the currently open entry in the zip */
int32_t mz_zip_writer_add_process(void *handle, void *stream, mz_stream_read_cb read_cb);
/* Writes a portion of data to the currently open entry in the zip */
int32_t mz_zip_writer_add_info(void *handle, void *stream, mz_stream_read_cb read_cb, mz_zip_file *file_info);
/* Adds an entry to the zip based on the info */
int32_t mz_zip_writer_add_buffer(void *handle, void *buf, int32_t len, mz_zip_file *file_info);
/* Adds an entry to the zip with a memory buffer */
int32_t mz_zip_writer_add_file(void *handle, const char *path, const char *filename_in_zip);
/* Adds an entry to the zip from a file */
int32_t mz_zip_writer_add_path(void *handle, const char *path, const char *root_path, uint8_t include_path,
uint8_t recursive);
/* Enumerates a directory or pattern and adds entries to the zip */
int32_t mz_zip_writer_copy_from_reader(void *handle, void *reader);
/* Adds an entry from a zip reader instance */
/***************************************************************************/
void mz_zip_writer_set_password(void *handle, const char *password);
/* Password to use for encrypting files in the zip */
void mz_zip_writer_set_comment(void *handle, const char *comment);
/* Comment to use for the archive */
void mz_zip_writer_set_raw(void *handle, uint8_t raw);
/* Sets whether or not we should write the entry raw */
int32_t mz_zip_writer_get_raw(void *handle, uint8_t *raw);
/* Gets whether or not we should write the entry raw */
void mz_zip_writer_set_aes(void *handle, uint8_t aes);
/* Use aes encryption when adding files in zip */
void mz_zip_writer_set_compress_method(void *handle, uint16_t compress_method);
/* Sets the compression method when adding files in zip */
void mz_zip_writer_set_compress_level(void *handle, int16_t compress_level);
/* Sets the compression level when adding files in zip */
void mz_zip_writer_set_follow_links(void *handle, uint8_t follow_links);
/* Follow symbolic links when traversing directories and files to add */
void mz_zip_writer_set_store_links(void *handle, uint8_t store_links);
/* Store symbolic links in zip file */
void mz_zip_writer_set_zip_cd(void *handle, uint8_t zip_cd);
/* Sets whether or not central directory should be zipped */
int32_t mz_zip_writer_set_certificate(void *handle, const char *cert_path, const char *cert_pwd);
/* Sets the certificate and timestamp url to use for signing when adding files in zip */
void mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb);
/* Callback for what to do when zip file already exists */
void mz_zip_writer_set_password_cb(void *handle, void *userdata, mz_zip_writer_password_cb cb);
/* Callback for ask if a password is required for adding */
void mz_zip_writer_set_progress_cb(void *handle, void *userdata, mz_zip_writer_progress_cb cb);
/* Callback for compression progress */
void mz_zip_writer_set_progress_interval(void *handle, uint32_t milliseconds);
/* Let at least milliseconds pass between calls to progress callback */
void mz_zip_writer_set_entry_cb(void *handle, void *userdata, mz_zip_writer_entry_cb cb);
/* Callback for zip file entries */
int32_t mz_zip_writer_get_zip_handle(void *handle, void **zip_handle);
/* Gets the underlying zip handle */
void* mz_zip_writer_create(void **handle);
/* Create new instance of zip writer */
void mz_zip_writer_delete(void **handle);
/* Delete instance of zip writer */
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/test/ 0000775 0000000 0000000 00000000000 14126475503 0023432 5 ustar 00root root 0000000 0000000 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/test/empty.txt 0000664 0000000 0000000 00000000000 14126475503 0025317 0 ustar 00root root 0000000 0000000 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/test/fuzz/ 0000775 0000000 0000000 00000000000 14126475503 0024430 5 ustar 00root root 0000000 0000000 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/test/fuzz/standalone.c 0000664 0000000 0000000 00000004740 14126475503 0026731 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/test/fuzz/unzip_fuzzer.c 0000664 0000000 0000000 00000006407 14126475503 0027355 0 ustar 00root root 0000000 0000000 /* 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
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/test/fuzz/unzip_fuzzer.dict 0000664 0000000 0000000 00000000436 14126475503 0030052 0 ustar 00root root 0000000 0000000 # 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"
3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/test/fuzz/unzip_fuzzer_seed_corpus/ 0000775 0000000 0000000 00000000000 14126475503 0031575 5 ustar 00root root 0000000 0000000 as.zip 0000664 0000000 0000000 00000000351 14126475503 0032644 0 ustar 00root root 0000000 0000000 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/test/fuzz/unzip_fuzzer_seed_corpus PK zYKO ˙˙ AsUT õņđY÷ņđYux _ íÁ ļũĨŠ
PK zYKO ˙˙ AsUT õņđYux _ PK H bzip2.zip 0000664 0000000 0000000 00000500145 14126475503 0033275 0 ustar 00root root 0000000 0000000 3p-minizip-ng-7a1ea574f9503fb40738dad63605d4bf643f3378/minizip/test/fuzz/unzip_fuzzer_seed_corpus PK. xMÃ!É ņ vangogh.gifBZh91AY&SYžpÍž