updated zip (#5499)
* updated zip udated zip from version 1.15 to version 3.0.2 * Check for double defined macro * Update miniz.h * Update zip.c * Update zip.c --------- Co-authored-by: Kim Kulling <kimkulling@users.noreply.github.com>pull/5345/head^2
parent
329fee2f0b
commit
83d7216726
|
@ -0,0 +1 @@
|
||||||
|
*.h linguist-language=C
|
|
@ -0,0 +1,60 @@
|
||||||
|
/build/
|
||||||
|
/test/build/
|
||||||
|
/xcodeproj/
|
||||||
|
/infer-out/
|
||||||
|
.vscode/
|
||||||
|
Testing/
|
||||||
|
|
||||||
|
# Object files
|
||||||
|
*.o
|
||||||
|
*.ko
|
||||||
|
*.obj
|
||||||
|
*.elf
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# Shared objects (inc. Windows DLLs)
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
*.suo
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.i*86
|
||||||
|
*.x86_64
|
||||||
|
*.hex
|
||||||
|
|
||||||
|
# Temporary
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
CMakeScripts
|
||||||
|
*.cmake
|
||||||
|
|
||||||
|
# Xcode
|
||||||
|
*.build
|
||||||
|
*.xcodeproj
|
||||||
|
zip.sln
|
||||||
|
zip.vcxproj.filters
|
||||||
|
zip.vcxproj
|
||||||
|
ALL_BUILD.vcxproj.filters
|
||||||
|
ALL_BUILD.vcxproj
|
||||||
|
CMakeFiles/
|
||||||
|
zip.dir/
|
||||||
|
test/test.exe.vcxproj.filters
|
||||||
|
test/test.exe.vcxproj
|
||||||
|
test/test.exe.dir/
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Build script for travis-ci.org builds.
|
|
||||||
#
|
|
||||||
if [ $ANALYZE = "true" ] && [ "$CC" = "clang" ]; then
|
|
||||||
# scan-build -h
|
|
||||||
scan-build cmake -G "Unix Makefiles"
|
|
||||||
scan-build -enable-checker security.FloatLoopCounter \
|
|
||||||
-enable-checker security.insecureAPI.UncheckedReturn \
|
|
||||||
--status-bugs -v \
|
|
||||||
make -j 8 \
|
|
||||||
make -j 8 test
|
|
||||||
else
|
|
||||||
cmake -DCMAKE_BUILD_TYPE=Debug -DSANITIZE_ADDRESS=On -DCMAKE_INSTALL_PREFIX=_install
|
|
||||||
make -j 8
|
|
||||||
make install
|
|
||||||
ASAN_OPTIONS=detect_leaks=0 LSAN_OPTIONS=verbosity=1:log_threads=1 ctest -V
|
|
||||||
fi
|
|
|
@ -1,22 +0,0 @@
|
||||||
language: c
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages: &1
|
|
||||||
- lcov
|
|
||||||
# Compiler selection
|
|
||||||
compiler:
|
|
||||||
- clang
|
|
||||||
- gcc
|
|
||||||
env:
|
|
||||||
- ANALYZE=false
|
|
||||||
- ANALYZE=true
|
|
||||||
# Build steps
|
|
||||||
script:
|
|
||||||
- ./.travis.sh
|
|
||||||
after_success:
|
|
||||||
# Creating report
|
|
||||||
- cmake -DENABLE_COVERAGE=ON
|
|
||||||
- make
|
|
||||||
- make test
|
|
||||||
# Uploading report to CodeCov
|
|
||||||
- bash <(curl -s https://codecov.io/bash)
|
|
|
@ -1,27 +1,47 @@
|
||||||
cmake_minimum_required(VERSION 3.4)
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
|
||||||
project(zip
|
project(zip
|
||||||
LANGUAGES C
|
LANGUAGES C
|
||||||
VERSION "0.1.19")
|
VERSION "0.3.0")
|
||||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||||
option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
|
|
||||||
|
# Enable building tests only if the project is being built as a standalone one
|
||||||
|
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||||
|
option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
|
||||||
|
else ()
|
||||||
|
option(CMAKE_DISABLE_TESTING "Disable test creation" ON)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
option(CMAKE_ENABLE_SANITIZERS "Enable zip sanitizers" OFF)
|
||||||
|
option(ZIP_STATIC_PIC "Build static zip with PIC" ON)
|
||||||
|
option(ZIP_BUILD_DOCS "Generate API documentation with Doxygen" OFF)
|
||||||
|
|
||||||
|
if(ZIP_ENABLE_SHARABLE_FILE_OPEN)
|
||||||
|
add_definitions(-DZIP_ENABLE_SHARABLE_FILE_OPEN)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||||
|
# large file support
|
||||||
|
add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64)
|
||||||
|
endif()
|
||||||
|
|
||||||
# zip
|
# zip
|
||||||
set(SRC src/miniz.h src/zip.h src/zip.c)
|
set(SRC src/miniz.h src/zip.h src/zip.c)
|
||||||
|
|
||||||
# this is the "object library" target: compiles the sources only once
|
add_library(${PROJECT_NAME} ${SRC})
|
||||||
add_library(OBJLIB OBJECT ${SRC})
|
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||||
# shared libraries need PIC
|
|
||||||
set_property(TARGET OBJLIB PROPERTY POSITION_INDEPENDENT_CODE 1)
|
|
||||||
|
|
||||||
# static and shared libraries built from the same object files
|
if(ZIP_STATIC_PIC)
|
||||||
if (BUILD_SHARED_LIBS)
|
set_property(TARGET ${PROJECT_NAME} PROPERTY POSITION_INDEPENDENT_CODE 1)
|
||||||
add_library(${PROJECT_NAME} SHARED $<TARGET_OBJECTS:OBJLIB>)
|
endif()
|
||||||
include(GenerateExportHeader)
|
|
||||||
generate_export_header(${PROJECT_NAME})
|
set_property(TARGET ${PROJECT_NAME} PROPERTY C_VISIBILITY_PRESET hidden)
|
||||||
else()
|
if(BUILD_SHARED_LIBS)
|
||||||
add_library(${PROJECT_NAME} STATIC $<TARGET_OBJECTS:OBJLIB>)
|
target_compile_definitions(${PROJECT_NAME}
|
||||||
|
PUBLIC ZIP_SHARED
|
||||||
|
PRIVATE ZIP_BUILD_SHARED
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||||
|
@ -33,24 +53,26 @@ target_include_directories(${PROJECT_NAME} PUBLIC
|
||||||
if (NOT CMAKE_DISABLE_TESTING)
|
if (NOT CMAKE_DISABLE_TESTING)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
if (CMAKE_ENABLE_SANITIZERS)
|
||||||
find_package(Sanitizers)
|
find_package(Sanitizers)
|
||||||
add_sanitizers(${PROJECT_NAME} ${test_out})
|
add_sanitizers(${PROJECT_NAME})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 90)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
# Use secure functions by default and suppress warnings about "deprecated" functions
|
# Use secure functions by default and suppress warnings about "deprecated" functions
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
|
||||||
|
|
||||||
elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
|
elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
|
||||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
|
"${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
|
||||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
|
"${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -Werror -pedantic -Wno-deprecated")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic")
|
||||||
endif (MSVC)
|
endif (MSVC)
|
||||||
|
|
||||||
####
|
####
|
||||||
# Installation (https://github.com/forexample/package-example) {
|
|
||||||
|
|
||||||
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
|
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
|
||||||
set(INCLUDE_INSTALL_DIR "include")
|
set(INCLUDE_INSTALL_DIR "include")
|
||||||
|
|
||||||
|
@ -62,7 +84,7 @@ set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
|
||||||
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
|
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
|
||||||
set(NAMESPACE "${PROJECT_NAME}::")
|
set(NAMESPACE "${PROJECT_NAME}::")
|
||||||
|
|
||||||
# Include module with fuction 'write_basic_package_version_file'
|
# Include module with function 'write_basic_package_version_file'
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
# Note: PROJECT_VERSION is used as a VERSION
|
# Note: PROJECT_VERSION is used as a VERSION
|
||||||
|
@ -90,8 +112,6 @@ install(
|
||||||
DESTINATION "${CONFIG_INSTALL_DIR}"
|
DESTINATION "${CONFIG_INSTALL_DIR}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# }
|
|
||||||
|
|
||||||
install(TARGETS ${PROJECT_NAME}
|
install(TARGETS ${PROJECT_NAME}
|
||||||
EXPORT ${TARGETS_EXPORT_NAME}
|
EXPORT ${TARGETS_EXPORT_NAME}
|
||||||
RUNTIME DESTINATION bin
|
RUNTIME DESTINATION bin
|
||||||
|
@ -112,8 +132,8 @@ if(NOT TARGET uninstall)
|
||||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
|
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Doxygen)
|
if(ZIP_BUILD_DOCS)
|
||||||
if(DOXYGEN_FOUND)
|
find_package(Doxygen REQUIRED)
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
|
||||||
add_custom_target(doc
|
add_custom_target(doc
|
||||||
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Contribution Rules/Coding Standards
|
||||||
|
No need to throw away your coding style, just do your best to follow default clang-format style.
|
||||||
|
Apply `clang-format` to the source files before commit:
|
||||||
|
```sh
|
||||||
|
for file in $(git ls-files | \grep -E '\.(c|h)$' | \grep -v -- '#')
|
||||||
|
do
|
||||||
|
clang-format -i $file
|
||||||
|
done
|
||||||
|
```
|
File diff suppressed because it is too large
Load Diff
|
@ -1,23 +1,25 @@
|
||||||
### A portable (OSX/Linux/Windows), simple zip library written in C
|
## A portable (OSX/Linux/Windows/Android/iOS), simple zip library written in C
|
||||||
This is done by hacking awesome [miniz](https://code.google.com/p/miniz) library and layering functions on top of the miniz v1.15 API.
|
|
||||||
|
This is done by hacking awesome [miniz](https://github.com/richgel999/miniz) library and layering functions on top of the miniz v3.0.2 API.
|
||||||
|
|
||||||
[![Build](https://github.com/kuba--/zip/workflows/build/badge.svg)](https://github.com/kuba--/zip/actions?query=workflow%3Abuild)
|
[![Build](https://github.com/kuba--/zip/workflows/build/badge.svg)](https://github.com/kuba--/zip/actions?query=workflow%3Abuild)
|
||||||
|
|
||||||
|
### The Idea
|
||||||
|
|
||||||
# The Idea
|
|
||||||
<img src="zip.png" name="zip" />
|
<img src="zip.png" name="zip" />
|
||||||
... Some day, I was looking for zip library written in C for my project, but I could not find anything simple enough and lightweight.
|
... Some day, I was looking for zip library written in C for my project, but I could not find anything simple enough and lightweight.
|
||||||
Everything what I tried required 'crazy mental gymnastics' to integrate or had some limitations or was too heavy.
|
Everything what I tried required 'crazy mental gymnastics' to integrate or had some limitations or was too heavy.
|
||||||
I hate frameworks, factories and adding new dependencies. If I must to install all those dependencies and link new library, I'm getting almost sick.
|
I hate frameworks, factories and adding new dependencies. If I must to install all those dependencies and link new library, I'm getting almost sick.
|
||||||
I wanted something powerfull and small enough, so I could add just a few files and compile them into my project.
|
I wanted something powerful and small enough, so I could add just a few files and compile them into my project.
|
||||||
And finally I found miniz.
|
And finally I found miniz.
|
||||||
Miniz is a lossless, high performance data compression library in a single source file. I only needed simple interface to append buffers or files to the current zip-entry. Thanks to this feature I'm able to merge many files/buffers and compress them on-the-fly.
|
Miniz is a lossless, high performance data compression library in a single source file. I only needed simple interface to append buffers or files to the current zip-entry. Thanks to this feature I'm able to merge many files/buffers and compress them on-the-fly.
|
||||||
|
|
||||||
It was the reason, why I decided to write zip module on top of the miniz. It required a little bit hacking and wrapping some functions, but I kept simplicity. So, you can grab these 3 files and compile them into your project. I hope that interface is also extremely simple, so you will not have any problems to understand it.
|
It was the reason, why I decided to write zip module on top of the miniz. It required a little bit hacking and wrapping some functions, but I kept simplicity. So, you can grab these 3 files and compile them into your project. I hope that interface is also extremely simple, so you will not have any problems to understand it.
|
||||||
|
|
||||||
# Examples
|
### Examples
|
||||||
|
|
||||||
* Create a new zip archive with default compression level.
|
* Create a new zip archive with default compression level.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
{
|
{
|
||||||
|
@ -41,6 +43,7 @@ zip_close(zip);
|
||||||
```
|
```
|
||||||
|
|
||||||
* Append to the existing zip archive.
|
* Append to the existing zip archive.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
||||||
{
|
{
|
||||||
|
@ -55,6 +58,7 @@ zip_close(zip);
|
||||||
```
|
```
|
||||||
|
|
||||||
* Extract a zip archive into a folder.
|
* Extract a zip archive into a folder.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int on_extract_entry(const char *filename, void *arg) {
|
int on_extract_entry(const char *filename, void *arg) {
|
||||||
static int i = 0;
|
static int i = 0;
|
||||||
|
@ -69,6 +73,7 @@ zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
|
||||||
```
|
```
|
||||||
|
|
||||||
* Extract a zip entry into memory.
|
* Extract a zip entry into memory.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
void *buf = NULL;
|
void *buf = NULL;
|
||||||
size_t bufsize;
|
size_t bufsize;
|
||||||
|
@ -87,6 +92,7 @@ free(buf);
|
||||||
```
|
```
|
||||||
|
|
||||||
* Extract a zip entry into memory (no internal allocation).
|
* Extract a zip entry into memory (no internal allocation).
|
||||||
|
|
||||||
```c
|
```c
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
size_t bufsize;
|
size_t bufsize;
|
||||||
|
@ -108,6 +114,7 @@ free(buf);
|
||||||
```
|
```
|
||||||
|
|
||||||
* Extract a zip entry into memory using callback.
|
* Extract a zip entry into memory using callback.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
struct buffer_t {
|
struct buffer_t {
|
||||||
char *data;
|
char *data;
|
||||||
|
@ -140,8 +147,8 @@ zip_close(zip);
|
||||||
free(buf.data);
|
free(buf.data);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
* Extract a zip entry into a file.
|
* Extract a zip entry into a file.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
||||||
{
|
{
|
||||||
|
@ -181,7 +188,7 @@ free(outbuf);
|
||||||
|
|
||||||
```c
|
```c
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
ssize_t bufsize = 0;
|
size_t bufsize = 0;
|
||||||
|
|
||||||
struct zip_t *zip = zip_stream_open(zipstream, zipstreamsize, 0, 'r');
|
struct zip_t *zip = zip_stream_open(zipstream, zipstreamsize, 0, 'r');
|
||||||
{
|
{
|
||||||
|
@ -197,6 +204,7 @@ free(buf);
|
||||||
```
|
```
|
||||||
|
|
||||||
* List of all zip entries
|
* List of all zip entries
|
||||||
|
|
||||||
```c
|
```c
|
||||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
||||||
int i, n = zip_entries_total(zip);
|
int i, n = zip_entries_total(zip);
|
||||||
|
@ -214,6 +222,7 @@ zip_close(zip);
|
||||||
```
|
```
|
||||||
|
|
||||||
* Compress folder (recursively)
|
* Compress folder (recursively)
|
||||||
|
|
||||||
```c
|
```c
|
||||||
void zip_walk(struct zip_t *zip, const char *path) {
|
void zip_walk(struct zip_t *zip, const char *path) {
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
@ -245,27 +254,36 @@ void zip_walk(struct zip_t *zip, const char *path) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
* Deletes zip archive entries.
|
* Delete zip archive entries.
|
||||||
|
|
||||||
```c
|
```c
|
||||||
char *entries[] = {"unused.txt", "remove.ini", "delete.me"};
|
char *entries[] = {"unused.txt", "remove.ini", "delete.me"};
|
||||||
|
// size_t indices[] = {0, 1, 2};
|
||||||
|
|
||||||
struct zip_t *zip = zip_open("foo.zip", 0, 'd');
|
struct zip_t *zip = zip_open("foo.zip", 0, 'd');
|
||||||
{
|
{
|
||||||
zip_entries_delete(zip, entries, 3);
|
zip_entries_delete(zip, entries, 3);
|
||||||
|
|
||||||
|
// you can also delete by index, instead of by name
|
||||||
|
// zip_entries_deletebyindex(zip, indices, 3);
|
||||||
}
|
}
|
||||||
zip_close(zip);
|
zip_close(zip);
|
||||||
```
|
```
|
||||||
|
|
||||||
# Bindings
|
### Bindings
|
||||||
|
|
||||||
Compile zip library as a dynamic library.
|
Compile zip library as a dynamic library.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ mkdir build
|
$ mkdir build
|
||||||
$ cd build
|
$ cd build
|
||||||
$ cmake -DBUILD_SHARED_LIBS=true ..
|
$ cmake -DBUILD_SHARED_LIBS=true ..
|
||||||
$ make
|
$ cmake --build .
|
||||||
```
|
```
|
||||||
|
|
||||||
### [Go](https://golang.org) (cgo)
|
#### [Go](https://golang.org) (cgo)
|
||||||
|
> Third party binding: [kuba--/c-go-zip](https://github.com/kuba--/c-go-zip)
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
@ -295,7 +313,8 @@ func main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### [Rust](https://www.rust-lang.org) (ffi)
|
#### [Rust](https://www.rust-lang.org) (ffi)
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
@ -342,13 +361,16 @@ fn main() {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### [Ruby](http://www.ruby-lang.org) (ffi)
|
#### [Ruby](http://www.ruby-lang.org) (ffi)
|
||||||
|
|
||||||
Install _ffi_ gem.
|
Install _ffi_ gem.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ gem install ffi
|
$ gem install ffi
|
||||||
```
|
```
|
||||||
|
|
||||||
Bind in your module.
|
Bind in your module.
|
||||||
|
|
||||||
```ruby
|
```ruby
|
||||||
require 'ffi'
|
require 'ffi'
|
||||||
|
|
||||||
|
@ -375,13 +397,16 @@ Zip.zip_entry_close(ptr)
|
||||||
Zip.zip_close(ptr)
|
Zip.zip_close(ptr)
|
||||||
```
|
```
|
||||||
|
|
||||||
### [Python](https://www.python.org) (cffi)
|
#### [Python](https://www.python.org) (cffi)
|
||||||
|
|
||||||
Install _cffi_ package
|
Install _cffi_ package
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ pip install cffi
|
$ pip install cffi
|
||||||
```
|
```
|
||||||
|
|
||||||
Bind in your package.
|
Bind in your package.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import ctypes.util
|
import ctypes.util
|
||||||
from cffi import FFI
|
from cffi import FFI
|
||||||
|
@ -409,7 +434,8 @@ Zip.zip_entry_close(ptr)
|
||||||
Zip.zip_close(ptr)
|
Zip.zip_close(ptr)
|
||||||
```
|
```
|
||||||
|
|
||||||
### [Never](https://never-lang.readthedocs.io/) (ffi)
|
#### [Never](https://never-lang.readthedocs.io/) (ffi)
|
||||||
|
|
||||||
```never
|
```never
|
||||||
extern "libzip.so" func zip_open(zipname: string, level: int, mode: char) -> c_ptr
|
extern "libzip.so" func zip_open(zipname: string, level: int, mode: char) -> c_ptr
|
||||||
extern "libzip.so" func zip_close(zip: c_ptr) -> void
|
extern "libzip.so" func zip_close(zip: c_ptr) -> void
|
||||||
|
@ -438,8 +464,10 @@ func main() -> int
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### [Ring](http://ring-lang.net)
|
#### [Ring](http://ring-lang.net)
|
||||||
|
|
||||||
The language comes with RingZip based on this library
|
The language comes with RingZip based on this library
|
||||||
|
|
||||||
```ring
|
```ring
|
||||||
load "ziplib.ring"
|
load "ziplib.ring"
|
||||||
|
|
||||||
|
@ -455,15 +483,159 @@ new Zip {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# Check out more cool projects which use this library:
|
#### [Zig](https://ziglang.org)
|
||||||
- [Filament](https://github.com/google/filament): Filament is a real-time physically based rendering engine for Android, iOS, Linux, macOS, Windows, and WebGL. It is designed to be as small as possible and as efficient as possible on Android.
|
|
||||||
- [Hermes JS Engine](https://github.com/facebook/hermes): Hermes is a JavaScript engine optimized for fast start-up of React Native apps on Android. It features ahead-of-time static optimization and compact bytecode.
|
|
||||||
- [Open Asset Import Library](https://github.com/assimp/assimp): A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
|
|
||||||
- [PowerToys](https://github.com/microsoft/PowerToys): Set of utilities for power users to tune and streamline their Windows 10 experience for greater productivity.
|
|
||||||
- [The Ring Programming Language](https://ring-lang.github.io): Innovative and practical general-purpose multi-paradigm language.
|
|
||||||
- [The V Programming Language](https://github.com/vlang/v): Simple, fast, safe, compiled. For developing maintainable software.
|
|
||||||
- [TIC-80](https://github.com/nesbox/TIC-80): TIC-80 is a FREE and OPEN SOURCE fantasy computer for making, playing and sharing tiny games.
|
|
||||||
- [Urho3D](https://github.com/urho3d/Urho3D): Urho3D is a free lightweight, cross-platform 2D and 3D game engine implemented in C++ and released under the MIT license. Greatly inspired by OGRE and Horde3D.
|
|
||||||
- [Vcpkg](https://github.com/microsoft/vcpkg): Vcpkg helps you manage C and C++ libraries on Windows, Linux and MacOS.
|
|
||||||
- [and more...](https://grep.app/search?q=kuba--/zip)
|
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ zig build-exe main.zig -lc -lzip
|
||||||
|
```
|
||||||
|
|
||||||
|
```zig
|
||||||
|
const c = @cImport({
|
||||||
|
@cInclude("zip.h");
|
||||||
|
});
|
||||||
|
|
||||||
|
pub fn main() void {
|
||||||
|
var zip = c.zip_open("/tmp/zig.zip", 6, 'w');
|
||||||
|
defer c.zip_close(zip);
|
||||||
|
|
||||||
|
_ = c.zip_entry_open(zip, "test");
|
||||||
|
defer _ = c.zip_entry_close(zip);
|
||||||
|
|
||||||
|
const content = "test content";
|
||||||
|
_ = c.zip_entry_write(zip, content, content.len);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### [Odin](https://odin-lang.org)
|
||||||
|
> Third party binding: [thechampagne/zip-odin](https://github.com/thechampagne/zip-odin)
|
||||||
|
|
||||||
|
```odin
|
||||||
|
package main
|
||||||
|
|
||||||
|
foreign import lib "system:zip"
|
||||||
|
|
||||||
|
import "core:c"
|
||||||
|
|
||||||
|
foreign lib {
|
||||||
|
zip_open :: proc(zipname : cstring, level : c.int, mode : c.char) -> rawptr ---
|
||||||
|
|
||||||
|
zip_close :: proc(zip : rawptr) ---
|
||||||
|
|
||||||
|
zip_entry_open :: proc(zip : rawptr, entryname : cstring) -> c.int ---
|
||||||
|
|
||||||
|
zip_entry_close :: proc(zip : rawptr) -> c.int ---
|
||||||
|
|
||||||
|
zip_entry_write :: proc(zip : rawptr, buf : rawptr, bufsize : c.size_t) -> c.int ---
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
zip_file := zip_open("odin.zip", 6, 'w')
|
||||||
|
defer zip_close(zip_file)
|
||||||
|
|
||||||
|
zip_entry_open(zip_file, "test")
|
||||||
|
defer zip_entry_close(zip_file)
|
||||||
|
|
||||||
|
content := "test content"
|
||||||
|
zip_entry_write(zip_file, &content, len(content))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### [Nim](https://nim-lang.org)
|
||||||
|
> Third party binding: [thechampagne/nimzip](https://github.com/thechampagne/nimzip)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ nim c --passL:-lzip main.nim
|
||||||
|
```
|
||||||
|
|
||||||
|
```nim
|
||||||
|
proc zip_open(zipname: cstring, level: cint, mode: char): pointer {.importc.}
|
||||||
|
proc zip_close(zip: pointer) {.importc.}
|
||||||
|
proc zip_entry_open(zip: pointer, entryname: cstring): cint {.importc.}
|
||||||
|
proc zip_entry_close(zip: pointer): cint {.importc.}
|
||||||
|
proc zip_entry_write(zip: pointer, buf: pointer, bufsize: csize_t): cint {.importc.}
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
var zip = zip_open("/tmp/nim.zip", 6, 'w')
|
||||||
|
|
||||||
|
discard zip_entry_open(zip, "test")
|
||||||
|
|
||||||
|
let content: cstring = "test content"
|
||||||
|
discard zip_entry_write(zip, content, csize_t(len(content)))
|
||||||
|
|
||||||
|
discard zip_entry_close(zip)
|
||||||
|
zip_close(zip)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### [D](https://dlang.org)
|
||||||
|
> Third party binding: [thechampagne/zip-d](https://github.com/thechampagne/zip-d)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ dmd -L-lzip main.d
|
||||||
|
```
|
||||||
|
|
||||||
|
```d
|
||||||
|
extern(C) void* zip_open(const(char)* zipname, int level, char mode);
|
||||||
|
extern(C) void zip_close(void* zip);
|
||||||
|
extern(C) int zip_entry_open(void* zip, const(char)* entryname);
|
||||||
|
extern(C) int zip_entry_close(void* zip);
|
||||||
|
extern(C) int zip_entry_write(void* zip, const(void)* buf, size_t bufsize);
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
void* zip = zip_open("/tmp/d.zip", 6, 'w');
|
||||||
|
scope(exit) zip_close(zip);
|
||||||
|
|
||||||
|
zip_entry_open(zip, "test");
|
||||||
|
scope(exit) zip_entry_close(zip);
|
||||||
|
|
||||||
|
string content = "test content";
|
||||||
|
zip_entry_write(zip, content.ptr, content.length);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
|
||||||
|
> Third party binding: [thechampagne/zip-pascal](https://github.com/thechampagne/zip-pascal)
|
||||||
|
|
||||||
|
```pas
|
||||||
|
program main;
|
||||||
|
|
||||||
|
{$linklib c}
|
||||||
|
{$linklib zip}
|
||||||
|
|
||||||
|
uses ctypes;
|
||||||
|
|
||||||
|
function zip_open(zipname:Pchar; level:longint; mode:char):pointer;cdecl;external;
|
||||||
|
procedure zip_close(zip:pointer);cdecl;external;
|
||||||
|
function zip_entry_open(zip:pointer; entryname:Pchar):longint;cdecl;external;
|
||||||
|
function zip_entry_close(zip:pointer):longint;cdecl;external;
|
||||||
|
function zip_entry_write(zip:pointer; buf:pointer; bufsize:csize_t):longint;cdecl;external;
|
||||||
|
|
||||||
|
const
|
||||||
|
content: Pchar = 'test content';
|
||||||
|
var
|
||||||
|
zip : pointer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
zip := zip_open('/tmp/pascal.zip', 6, 'w');
|
||||||
|
|
||||||
|
zip_entry_open(zip, 'test');
|
||||||
|
|
||||||
|
zip_entry_write(zip, content, strlen(content));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
zip_close(zip);
|
||||||
|
end.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check out more cool projects which use this library
|
||||||
|
|
||||||
|
* [Filament](https://github.com/google/filament): Filament is a real-time physically based rendering engine for Android, iOS, Linux, macOS, Windows, and WebGL. It is designed to be as small as possible and as efficient as possible on Android.
|
||||||
|
* [Hermes JS Engine](https://github.com/facebook/hermes): Hermes is a JavaScript engine optimized for fast start-up of React Native apps on Android. It features ahead-of-time static optimization and compact bytecode.
|
||||||
|
* [Monster Mash](https://github.com/google/monster-mash): New Sketch-Based Modeling and Animation Tool.
|
||||||
|
* [Object-Oriented Graphics Rendering Engine](https://github.com/OGRECave/ogre): OGRE is a scene-oriented, flexible 3D engine written in C++ designed to make it easier and more intuitive for developers to produce games and demos utilising 3D hardware.
|
||||||
|
* [Open Asset Import Library](https://github.com/assimp/assimp): A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
|
||||||
|
* [PowerToys](https://github.com/microsoft/PowerToys): Set of utilities for power users to tune and streamline their Windows 10 experience for greater productivity.
|
||||||
|
* [The Ring Programming Language](https://ring-lang.github.io): Innovative and practical general-purpose multi-paradigm language.
|
||||||
|
* [The V Programming Language](https://github.com/vlang/v): Simple, fast, safe, compiled. For developing maintainable software.
|
||||||
|
* [TIC-80](https://github.com/nesbox/TIC-80): TIC-80 is a FREE and OPEN SOURCE fantasy computer for making, playing and sharing tiny games.
|
||||||
|
* [Urho3D](https://github.com/urho3d/Urho3D): Urho3D is a free lightweight, cross-platform 2D and 3D game engine implemented in C++ and released under the MIT license. Greatly inspired by OGRE and Horde3D.
|
||||||
|
* [and more...](https://grep.app/search?q=kuba--/zip)
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
version: zip-0.1.15.{build}
|
|
||||||
build_script:
|
|
||||||
- cmd: >-
|
|
||||||
cd c:\projects\zip
|
|
||||||
|
|
||||||
mkdir build
|
|
||||||
|
|
||||||
cd build
|
|
||||||
|
|
||||||
cmake -G"Visual Studio 14" -DCMAKE_BUILD_TYPE=Debug ..
|
|
||||||
|
|
||||||
cmake --build . --config %CMAKE_BUILD_TYPE%
|
|
||||||
|
|
||||||
ctest --verbose -C "Debug"
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake")
|
||||||
|
check_required_components("@PROJECT_NAME@")
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -12,9 +12,24 @@
|
||||||
#ifndef ZIP_H
|
#ifndef ZIP_H
|
||||||
#define ZIP_H
|
#define ZIP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#ifndef ZIP_SHARED
|
||||||
|
#define ZIP_EXPORT
|
||||||
|
#else
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifdef ZIP_BUILD_SHARED
|
||||||
|
#define ZIP_EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define ZIP_EXPORT __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define ZIP_EXPORT __attribute__((visibility("default")))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,14 +44,10 @@ typedef long ssize_t; /* byte count or error */
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MAX_PATH
|
|
||||||
#define MAX_PATH 32767 /* # chars in a path name including NULL */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @mainpage
|
* @mainpage
|
||||||
*
|
*
|
||||||
* Documenation for @ref zip.
|
* Documentation for @ref zip.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,6 +92,9 @@ typedef long ssize_t; /* byte count or error */
|
||||||
#define ZIP_EFSEEK -27 // fseek error
|
#define ZIP_EFSEEK -27 // fseek error
|
||||||
#define ZIP_EFREAD -28 // fread error
|
#define ZIP_EFREAD -28 // fread error
|
||||||
#define ZIP_EFWRITE -29 // fwrite error
|
#define ZIP_EFWRITE -29 // fwrite error
|
||||||
|
#define ZIP_ERINIT -30 // cannot initialize reader
|
||||||
|
#define ZIP_EWINIT -31 // cannot initialize writer
|
||||||
|
#define ZIP_EWRINIT -32 // cannot initialize writer from reader
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up the error message string corresponding to an error number.
|
* Looks up the error message string corresponding to an error number.
|
||||||
|
@ -88,7 +102,7 @@ typedef long ssize_t; /* byte count or error */
|
||||||
* @return error message string corresponding to errnum or NULL if error is not
|
* @return error message string corresponding to errnum or NULL if error is not
|
||||||
* found.
|
* found.
|
||||||
*/
|
*/
|
||||||
extern const char *zip_strerror(int errnum);
|
extern ZIP_EXPORT const char *zip_strerror(int errnum);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct zip_t
|
* @struct zip_t
|
||||||
|
@ -110,14 +124,32 @@ struct zip_t;
|
||||||
*
|
*
|
||||||
* @return the zip archive handler or NULL on error
|
* @return the zip archive handler or NULL on error
|
||||||
*/
|
*/
|
||||||
extern struct zip_t *zip_open(const char *zipname, int level, char mode);
|
extern ZIP_EXPORT struct zip_t *zip_open(const char *zipname, int level,
|
||||||
|
char mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens zip archive with compression level using the given mode.
|
||||||
|
* The function additionally returns @param errnum -
|
||||||
|
*
|
||||||
|
* @param zipname zip archive file name.
|
||||||
|
* @param level compression level (0-9 are the standard zlib-style levels).
|
||||||
|
* @param mode file access mode.
|
||||||
|
* - 'r': opens a file for reading/extracting (the file must exists).
|
||||||
|
* - 'w': creates an empty file for writing.
|
||||||
|
* - 'a': appends to an existing archive.
|
||||||
|
* @param errnum 0 on success, negative number (< 0) on error.
|
||||||
|
*
|
||||||
|
* @return the zip archive handler or NULL on error
|
||||||
|
*/
|
||||||
|
extern ZIP_EXPORT struct zip_t *
|
||||||
|
zip_openwitherror(const char *zipname, int level, char mode, int *errnum);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the zip archive, releases resources - always finalize.
|
* Closes the zip archive, releases resources - always finalize.
|
||||||
*
|
*
|
||||||
* @param zip zip archive handler.
|
* @param zip zip archive handler.
|
||||||
*/
|
*/
|
||||||
extern void zip_close(struct zip_t *zip);
|
extern ZIP_EXPORT void zip_close(struct zip_t *zip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the archive has a zip64 end of central directory headers.
|
* Determines if the archive has a zip64 end of central directory headers.
|
||||||
|
@ -127,7 +159,7 @@ extern void zip_close(struct zip_t *zip);
|
||||||
* @return the return code - 1 (true), 0 (false), negative number (< 0) on
|
* @return the return code - 1 (true), 0 (false), negative number (< 0) on
|
||||||
* error.
|
* error.
|
||||||
*/
|
*/
|
||||||
extern int zip_is64(struct zip_t *zip);
|
extern ZIP_EXPORT int zip_is64(struct zip_t *zip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens an entry by name in the zip archive.
|
* Opens an entry by name in the zip archive.
|
||||||
|
@ -141,7 +173,22 @@ extern int zip_is64(struct zip_t *zip);
|
||||||
*
|
*
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_entry_open(struct zip_t *zip, const char *entryname);
|
extern ZIP_EXPORT int zip_entry_open(struct zip_t *zip, const char *entryname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens an entry by name in the zip archive.
|
||||||
|
*
|
||||||
|
* For zip archive opened in 'w' or 'a' mode the function will append
|
||||||
|
* a new entry. In readonly mode the function tries to locate the entry
|
||||||
|
* in global dictionary (case sensitive).
|
||||||
|
*
|
||||||
|
* @param zip zip archive handler.
|
||||||
|
* @param entryname an entry name in local dictionary (case sensitive).
|
||||||
|
*
|
||||||
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
|
*/
|
||||||
|
extern ZIP_EXPORT int zip_entry_opencasesensitive(struct zip_t *zip,
|
||||||
|
const char *entryname);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a new entry by index in the zip archive.
|
* Opens a new entry by index in the zip archive.
|
||||||
|
@ -153,7 +200,7 @@ extern int zip_entry_open(struct zip_t *zip, const char *entryname);
|
||||||
*
|
*
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_entry_openbyindex(struct zip_t *zip, int index);
|
extern ZIP_EXPORT int zip_entry_openbyindex(struct zip_t *zip, size_t index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes a zip entry, flushes buffer and releases resources.
|
* Closes a zip entry, flushes buffer and releases resources.
|
||||||
|
@ -162,7 +209,7 @@ extern int zip_entry_openbyindex(struct zip_t *zip, int index);
|
||||||
*
|
*
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_entry_close(struct zip_t *zip);
|
extern ZIP_EXPORT int zip_entry_close(struct zip_t *zip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a local name of the current zip entry.
|
* Returns a local name of the current zip entry.
|
||||||
|
@ -178,7 +225,7 @@ extern int zip_entry_close(struct zip_t *zip);
|
||||||
*
|
*
|
||||||
* @return the pointer to the current zip entry name, or NULL on error.
|
* @return the pointer to the current zip entry name, or NULL on error.
|
||||||
*/
|
*/
|
||||||
extern const char *zip_entry_name(struct zip_t *zip);
|
extern ZIP_EXPORT const char *zip_entry_name(struct zip_t *zip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an index of the current zip entry.
|
* Returns an index of the current zip entry.
|
||||||
|
@ -187,7 +234,7 @@ extern const char *zip_entry_name(struct zip_t *zip);
|
||||||
*
|
*
|
||||||
* @return the index on success, negative number (< 0) on error.
|
* @return the index on success, negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_entry_index(struct zip_t *zip);
|
extern ZIP_EXPORT ssize_t zip_entry_index(struct zip_t *zip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the current zip entry is a directory entry.
|
* Determines if the current zip entry is a directory entry.
|
||||||
|
@ -197,16 +244,35 @@ extern int zip_entry_index(struct zip_t *zip);
|
||||||
* @return the return code - 1 (true), 0 (false), negative number (< 0) on
|
* @return the return code - 1 (true), 0 (false), negative number (< 0) on
|
||||||
* error.
|
* error.
|
||||||
*/
|
*/
|
||||||
extern int zip_entry_isdir(struct zip_t *zip);
|
extern ZIP_EXPORT int zip_entry_isdir(struct zip_t *zip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an uncompressed size of the current zip entry.
|
* Returns the uncompressed size of the current zip entry.
|
||||||
|
* Alias for zip_entry_uncomp_size (for backward compatibility).
|
||||||
*
|
*
|
||||||
* @param zip zip archive handler.
|
* @param zip zip archive handler.
|
||||||
*
|
*
|
||||||
* @return the uncompressed size in bytes.
|
* @return the uncompressed size in bytes.
|
||||||
*/
|
*/
|
||||||
extern unsigned long long zip_entry_size(struct zip_t *zip);
|
extern ZIP_EXPORT unsigned long long zip_entry_size(struct zip_t *zip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the uncompressed size of the current zip entry.
|
||||||
|
*
|
||||||
|
* @param zip zip archive handler.
|
||||||
|
*
|
||||||
|
* @return the uncompressed size in bytes.
|
||||||
|
*/
|
||||||
|
extern ZIP_EXPORT unsigned long long zip_entry_uncomp_size(struct zip_t *zip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the compressed size of the current zip entry.
|
||||||
|
*
|
||||||
|
* @param zip zip archive handler.
|
||||||
|
*
|
||||||
|
* @return the compressed size in bytes.
|
||||||
|
*/
|
||||||
|
extern ZIP_EXPORT unsigned long long zip_entry_comp_size(struct zip_t *zip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns CRC-32 checksum of the current zip entry.
|
* Returns CRC-32 checksum of the current zip entry.
|
||||||
|
@ -215,7 +281,26 @@ extern unsigned long long zip_entry_size(struct zip_t *zip);
|
||||||
*
|
*
|
||||||
* @return the CRC-32 checksum.
|
* @return the CRC-32 checksum.
|
||||||
*/
|
*/
|
||||||
extern unsigned int zip_entry_crc32(struct zip_t *zip);
|
extern ZIP_EXPORT unsigned int zip_entry_crc32(struct zip_t *zip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns byte offset of the current zip entry
|
||||||
|
* in the archive's central directory.
|
||||||
|
*
|
||||||
|
* @param zip zip archive handler.
|
||||||
|
*
|
||||||
|
* @return the offset in bytes.
|
||||||
|
*/
|
||||||
|
extern ZIP_EXPORT unsigned long long zip_entry_dir_offset(struct zip_t *zip);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current zip entry's local header file offset in bytes.
|
||||||
|
*
|
||||||
|
* @param zip zip archive handler.
|
||||||
|
*
|
||||||
|
* @return the entry's local header file offset in bytes.
|
||||||
|
*/
|
||||||
|
extern ZIP_EXPORT unsigned long long zip_entry_header_offset(struct zip_t *zip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compresses an input buffer for the current zip entry.
|
* Compresses an input buffer for the current zip entry.
|
||||||
|
@ -226,7 +311,8 @@ extern unsigned int zip_entry_crc32(struct zip_t *zip);
|
||||||
*
|
*
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
|
extern ZIP_EXPORT int zip_entry_write(struct zip_t *zip, const void *buf,
|
||||||
|
size_t bufsize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compresses a file for the current zip entry.
|
* Compresses a file for the current zip entry.
|
||||||
|
@ -236,7 +322,7 @@ extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
|
||||||
*
|
*
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
|
extern ZIP_EXPORT int zip_entry_fwrite(struct zip_t *zip, const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the current zip entry into output buffer.
|
* Extracts the current zip entry into output buffer.
|
||||||
|
@ -251,9 +337,10 @@ extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
|
||||||
* for large entries, please take a look at zip_entry_extract function.
|
* for large entries, please take a look at zip_entry_extract function.
|
||||||
*
|
*
|
||||||
* @return the return code - the number of bytes actually read on success.
|
* @return the return code - the number of bytes actually read on success.
|
||||||
* Otherwise a -1 on error.
|
* Otherwise a negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
|
extern ZIP_EXPORT ssize_t zip_entry_read(struct zip_t *zip, void **buf,
|
||||||
|
size_t *bufsize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the current zip entry into a memory buffer using no memory
|
* Extracts the current zip entry into a memory buffer using no memory
|
||||||
|
@ -269,9 +356,10 @@ extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
|
||||||
* For large entries, please take a look at zip_entry_extract function.
|
* For large entries, please take a look at zip_entry_extract function.
|
||||||
*
|
*
|
||||||
* @return the return code - the number of bytes actually read on success.
|
* @return the return code - the number of bytes actually read on success.
|
||||||
* Otherwise a -1 on error (e.g. bufsize is not large enough).
|
* Otherwise a negative number (< 0) on error (e.g. bufsize is not large
|
||||||
|
* enough).
|
||||||
*/
|
*/
|
||||||
extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
|
extern ZIP_EXPORT ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
|
||||||
size_t bufsize);
|
size_t bufsize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -282,7 +370,7 @@ extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
|
||||||
*
|
*
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_entry_fread(struct zip_t *zip, const char *filename);
|
extern ZIP_EXPORT int zip_entry_fread(struct zip_t *zip, const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the current zip entry using a callback function (on_extract).
|
* Extracts the current zip entry using a callback function (on_extract).
|
||||||
|
@ -294,9 +382,9 @@ extern int zip_entry_fread(struct zip_t *zip, const char *filename);
|
||||||
*
|
*
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int
|
extern ZIP_EXPORT int
|
||||||
zip_entry_extract(struct zip_t *zip,
|
zip_entry_extract(struct zip_t *zip,
|
||||||
size_t (*on_extract)(void *arg, unsigned long long offset,
|
size_t (*on_extract)(void *arg, uint64_t offset,
|
||||||
const void *data, size_t size),
|
const void *data, size_t size),
|
||||||
void *arg);
|
void *arg);
|
||||||
|
|
||||||
|
@ -308,7 +396,7 @@ zip_entry_extract(struct zip_t *zip,
|
||||||
* @return the return code - the number of entries on success, negative number
|
* @return the return code - the number of entries on success, negative number
|
||||||
* (< 0) on error.
|
* (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_entries_total(struct zip_t *zip);
|
extern ZIP_EXPORT ssize_t zip_entries_total(struct zip_t *zip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes zip archive entries.
|
* Deletes zip archive entries.
|
||||||
|
@ -318,7 +406,19 @@ extern int zip_entries_total(struct zip_t *zip);
|
||||||
* @param len the number of entries to be deleted.
|
* @param len the number of entries to be deleted.
|
||||||
* @return the number of deleted entries, or negative number (< 0) on error.
|
* @return the number of deleted entries, or negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_entries_delete(struct zip_t *zip, char *const entries[],
|
extern ZIP_EXPORT ssize_t zip_entries_delete(struct zip_t *zip,
|
||||||
|
char *const entries[], size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes zip archive entries.
|
||||||
|
*
|
||||||
|
* @param zip zip archive handler.
|
||||||
|
* @param entries array of zip archive entries indices to be deleted.
|
||||||
|
* @param len the number of entries to be deleted.
|
||||||
|
* @return the number of deleted entries, or negative number (< 0) on error.
|
||||||
|
*/
|
||||||
|
extern ZIP_EXPORT ssize_t zip_entries_deletebyindex(struct zip_t *zip,
|
||||||
|
size_t entries[],
|
||||||
size_t len);
|
size_t len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -338,9 +438,9 @@ extern int zip_entries_delete(struct zip_t *zip, char *const entries[],
|
||||||
*
|
*
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_stream_extract(const char *stream, size_t size, const char *dir,
|
extern ZIP_EXPORT int
|
||||||
int (*on_extract)(const char *filename,
|
zip_stream_extract(const char *stream, size_t size, const char *dir,
|
||||||
void *arg),
|
int (*on_extract)(const char *filename, void *arg),
|
||||||
void *arg);
|
void *arg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -348,11 +448,36 @@ extern int zip_stream_extract(const char *stream, size_t size, const char *dir,
|
||||||
*
|
*
|
||||||
* @param stream zip archive stream.
|
* @param stream zip archive stream.
|
||||||
* @param size stream size.
|
* @param size stream size.
|
||||||
|
* @param level compression level (0-9 are the standard zlib-style levels).
|
||||||
|
* @param mode file access mode.
|
||||||
|
* - 'r': opens a file for reading/extracting (the file must exists).
|
||||||
|
* - 'w': creates an empty file for writing.
|
||||||
|
* - 'a': appends to an existing archive.
|
||||||
*
|
*
|
||||||
* @return the zip archive handler or NULL on error
|
* @return the zip archive handler or NULL on error
|
||||||
*/
|
*/
|
||||||
extern struct zip_t *zip_stream_open(const char *stream, size_t size, int level,
|
extern ZIP_EXPORT struct zip_t *zip_stream_open(const char *stream, size_t size,
|
||||||
char mode);
|
int level, char mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens zip archive stream into memory.
|
||||||
|
* The function additionally returns @param errnum -
|
||||||
|
*
|
||||||
|
* @param stream zip archive stream.
|
||||||
|
* @param size stream size.*
|
||||||
|
* @param level compression level (0-9 are the standard zlib-style levels).
|
||||||
|
* @param mode file access mode.
|
||||||
|
* - 'r': opens a file for reading/extracting (the file must exists).
|
||||||
|
* - 'w': creates an empty file for writing.
|
||||||
|
* - 'a': appends to an existing archive.
|
||||||
|
* @param errnum 0 on success, negative number (< 0) on error.
|
||||||
|
*
|
||||||
|
* @return the zip archive handler or NULL on error
|
||||||
|
*/
|
||||||
|
extern ZIP_EXPORT struct zip_t *zip_stream_openwitherror(const char *stream,
|
||||||
|
size_t size, int level,
|
||||||
|
char mode,
|
||||||
|
int *errnum);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy zip archive stream output buffer.
|
* Copy zip archive stream output buffer.
|
||||||
|
@ -363,7 +488,8 @@ extern struct zip_t *zip_stream_open(const char *stream, size_t size, int level,
|
||||||
*
|
*
|
||||||
* @return copy size
|
* @return copy size
|
||||||
*/
|
*/
|
||||||
extern ssize_t zip_stream_copy(struct zip_t *zip, void **buf, ssize_t *bufsize);
|
extern ZIP_EXPORT ssize_t zip_stream_copy(struct zip_t *zip, void **buf,
|
||||||
|
size_t *bufsize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close zip archive releases resources.
|
* Close zip archive releases resources.
|
||||||
|
@ -372,7 +498,7 @@ extern ssize_t zip_stream_copy(struct zip_t *zip, void **buf, ssize_t *bufsize);
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
extern void zip_stream_close(struct zip_t *zip);
|
extern ZIP_EXPORT void zip_stream_close(struct zip_t *zip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new archive and puts files into a single zip archive.
|
* Creates a new archive and puts files into a single zip archive.
|
||||||
|
@ -383,7 +509,8 @@ extern void zip_stream_close(struct zip_t *zip);
|
||||||
*
|
*
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_create(const char *zipname, const char *filenames[], size_t len);
|
extern ZIP_EXPORT int zip_create(const char *zipname, const char *filenames[],
|
||||||
|
size_t len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts a zip archive file into directory.
|
* Extracts a zip archive file into directory.
|
||||||
|
@ -401,10 +528,10 @@ extern int zip_create(const char *zipname, const char *filenames[], size_t len);
|
||||||
*
|
*
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
*/
|
*/
|
||||||
extern int zip_extract(const char *zipname, const char *dir,
|
extern ZIP_EXPORT int zip_extract(const char *zipname, const char *dir,
|
||||||
int (*on_extract_entry)(const char *filename, void *arg),
|
int (*on_extract_entry)(const char *filename,
|
||||||
|
void *arg),
|
||||||
void *arg);
|
void *arg);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,46 @@
|
||||||
cmake_minimum_required(VERSION 3.4)
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
|
||||||
|
find_package(Sanitizers)
|
||||||
|
|
||||||
# tests
|
# tests
|
||||||
set(test_write_out test_write.out)
|
set(test_write_out test_write.out)
|
||||||
add_executable(${test_write_out} test_write.c)
|
add_executable(${test_write_out} test_write.c)
|
||||||
target_link_libraries(${test_write_out} zip)
|
target_link_libraries(${test_write_out} zip)
|
||||||
add_test(NAME ${test_write_out} COMMAND ${test_write_out})
|
add_test(NAME ${test_write_out} COMMAND ${test_write_out})
|
||||||
set(test_write_out ${test_write_out} PARENT_SCOPE)
|
add_sanitizers(${test_write_out})
|
||||||
|
|
||||||
set(test_append_out test_append.out)
|
set(test_append_out test_append.out)
|
||||||
add_executable(${test_append_out} test_append.c)
|
add_executable(${test_append_out} test_append.c)
|
||||||
target_link_libraries(${test_append_out} zip)
|
target_link_libraries(${test_append_out} zip)
|
||||||
add_test(NAME ${test_append_out} COMMAND ${test_append_out})
|
add_test(NAME ${test_append_out} COMMAND ${test_append_out})
|
||||||
set(test_append_out ${test_append_out} PARENT_SCOPE)
|
add_sanitizers(${test_append_out})
|
||||||
|
|
||||||
set(test_read_out test_read.out)
|
set(test_read_out test_read.out)
|
||||||
add_executable(${test_read_out} test_read.c)
|
add_executable(${test_read_out} test_read.c)
|
||||||
target_link_libraries(${test_read_out} zip)
|
target_link_libraries(${test_read_out} zip)
|
||||||
add_test(NAME ${test_read_out} COMMAND ${test_read_out})
|
add_test(NAME ${test_read_out} COMMAND ${test_read_out})
|
||||||
set(test_read_out ${test_read_out} PARENT_SCOPE)
|
add_sanitizers(${test_read_out})
|
||||||
|
|
||||||
set(test_extract_out test_extract.out)
|
set(test_extract_out test_extract.out)
|
||||||
add_executable(${test_extract_out} test_extract.c)
|
add_executable(${test_extract_out} test_extract.c)
|
||||||
target_link_libraries(${test_extract_out} zip)
|
target_link_libraries(${test_extract_out} zip)
|
||||||
add_test(NAME ${test_extract_out} COMMAND ${test_extract_out})
|
add_test(NAME ${test_extract_out} COMMAND ${test_extract_out})
|
||||||
set(test_extract_out ${test_extract_out} PARENT_SCOPE)
|
add_sanitizers(${test_extract_out})
|
||||||
|
|
||||||
set(test_entry_out test_entry.out)
|
set(test_entry_out test_entry.out)
|
||||||
add_executable(${test_entry_out} test_entry.c)
|
add_executable(${test_entry_out} test_entry.c)
|
||||||
target_link_libraries(${test_entry_out} zip)
|
target_link_libraries(${test_entry_out} zip)
|
||||||
add_test(NAME ${test_entry_out} COMMAND ${test_entry_out})
|
add_test(NAME ${test_entry_out} COMMAND ${test_entry_out})
|
||||||
set(test_entry_out ${test_entry_out} PARENT_SCOPE)
|
add_sanitizers(${test_entry_out})
|
||||||
|
|
||||||
set(test_permissions_out test_permissions.out)
|
set(test_permissions_out test_permissions.out)
|
||||||
add_executable(${test_permissions_out} test_permissions.c)
|
add_executable(${test_permissions_out} test_permissions.c)
|
||||||
target_link_libraries(${test_permissions_out} zip)
|
target_link_libraries(${test_permissions_out} zip)
|
||||||
add_test(NAME ${test_permissions_out} COMMAND ${test_permissions_out})
|
add_test(NAME ${test_permissions_out} COMMAND ${test_permissions_out})
|
||||||
set(test_permissions_out ${test_permissions_out} PARENT_SCOPE)
|
add_sanitizers(${test_permissions_out})
|
||||||
|
|
||||||
|
set(test_open_out test_open.out)
|
||||||
|
add_executable(${test_open_out} test_open.c)
|
||||||
|
target_link_libraries(${test_open_out} zip)
|
||||||
|
add_test(NAME ${test_open_out} COMMAND ${test_open_out})
|
||||||
|
add_sanitizers(${test_open_out})
|
||||||
|
|
|
@ -0,0 +1,370 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 David Siñuela Pastor, siu.4coders@gmail.com
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef MINUNIT_MINUNIT_H
|
||||||
|
#define MINUNIT_MINUNIT_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <Windows.h>
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define __func__ __FUNCTION__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(__unix__) || defined(__unix) || defined(unix) || \
|
||||||
|
(defined(__APPLE__) && defined(__MACH__))
|
||||||
|
|
||||||
|
/* Change POSIX C SOURCE version for pure c99 compilers */
|
||||||
|
#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200112L
|
||||||
|
#undef _POSIX_C_SOURCE
|
||||||
|
#define _POSIX_C_SOURCE 200112L
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <sys/time.h> /* gethrtime(), gettimeofday() */
|
||||||
|
#include <sys/times.h>
|
||||||
|
#include <time.h> /* clock_gettime(), time() */
|
||||||
|
#include <unistd.h> /* POSIX flags */
|
||||||
|
|
||||||
|
#if defined(__MACH__) && defined(__APPLE__)
|
||||||
|
#include <mach/mach.h>
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC__ >= 5 && !defined(__STDC_VERSION__)
|
||||||
|
#define __func__ __extension__ __FUNCTION__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unable to define timers for an unknown OS."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* Maximum length of last message */
|
||||||
|
#define MINUNIT_MESSAGE_LEN 1024
|
||||||
|
/* Accuracy with which floats are compared */
|
||||||
|
#define MINUNIT_EPSILON 1E-12
|
||||||
|
|
||||||
|
/* Misc. counters */
|
||||||
|
static int minunit_run = 0;
|
||||||
|
static int minunit_assert = 0;
|
||||||
|
static int minunit_fail = 0;
|
||||||
|
static int minunit_status = 0;
|
||||||
|
|
||||||
|
/* Timers */
|
||||||
|
static double minunit_real_timer = 0;
|
||||||
|
static double minunit_proc_timer = 0;
|
||||||
|
|
||||||
|
/* Last message */
|
||||||
|
static char minunit_last_message[MINUNIT_MESSAGE_LEN];
|
||||||
|
|
||||||
|
/* Test setup and teardown function pointers */
|
||||||
|
static void (*minunit_setup)(void) = NULL;
|
||||||
|
static void (*minunit_teardown)(void) = NULL;
|
||||||
|
|
||||||
|
/* Definitions */
|
||||||
|
#define MU_TEST(method_name) static void method_name(void)
|
||||||
|
#define MU_TEST_SUITE(suite_name) static void suite_name(void)
|
||||||
|
|
||||||
|
#define MU__SAFE_BLOCK(block) \
|
||||||
|
do { \
|
||||||
|
block \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* Run test suite and unset setup and teardown functions */
|
||||||
|
#define MU_RUN_SUITE(suite_name) \
|
||||||
|
MU__SAFE_BLOCK(suite_name(); minunit_setup = NULL; minunit_teardown = NULL;)
|
||||||
|
|
||||||
|
/* Configure setup and teardown functions */
|
||||||
|
#define MU_SUITE_CONFIGURE(setup_fun, teardown_fun) \
|
||||||
|
MU__SAFE_BLOCK(minunit_setup = setup_fun; minunit_teardown = teardown_fun;)
|
||||||
|
|
||||||
|
/* Test runner */
|
||||||
|
#define MU_RUN_TEST(test) \
|
||||||
|
MU__SAFE_BLOCK( \
|
||||||
|
if (minunit_real_timer == 0 && minunit_proc_timer == 0) { \
|
||||||
|
minunit_real_timer = mu_timer_real(); \
|
||||||
|
minunit_proc_timer = mu_timer_cpu(); \
|
||||||
|
} if (minunit_setup) (*minunit_setup)(); \
|
||||||
|
minunit_status = 0; test(); minunit_run++; if (minunit_status) { \
|
||||||
|
minunit_fail++; \
|
||||||
|
printf("F"); \
|
||||||
|
printf("\n%s\n", minunit_last_message); \
|
||||||
|
} fflush(stdout); \
|
||||||
|
if (minunit_teardown)(*minunit_teardown)();)
|
||||||
|
|
||||||
|
/* Report */
|
||||||
|
#define MU_REPORT() \
|
||||||
|
MU__SAFE_BLOCK( \
|
||||||
|
double minunit_end_real_timer; double minunit_end_proc_timer; \
|
||||||
|
printf("\n\n%d tests, %d assertions, %d failures\n", minunit_run, \
|
||||||
|
minunit_assert, minunit_fail); \
|
||||||
|
minunit_end_real_timer = mu_timer_real(); \
|
||||||
|
minunit_end_proc_timer = mu_timer_cpu(); \
|
||||||
|
printf("\nFinished in %.8f seconds (real) %.8f seconds (proc)\n\n", \
|
||||||
|
minunit_end_real_timer - minunit_real_timer, \
|
||||||
|
minunit_end_proc_timer - minunit_proc_timer);)
|
||||||
|
#define MU_EXIT_CODE minunit_fail
|
||||||
|
|
||||||
|
/* Assertions */
|
||||||
|
#define mu_check(test) \
|
||||||
|
MU__SAFE_BLOCK( \
|
||||||
|
minunit_assert++; if (!(test)) { \
|
||||||
|
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||||
|
"%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, \
|
||||||
|
#test); \
|
||||||
|
minunit_status = 1; \
|
||||||
|
return; \
|
||||||
|
} else { printf("."); })
|
||||||
|
|
||||||
|
#define mu_fail(message) \
|
||||||
|
MU__SAFE_BLOCK(minunit_assert++; \
|
||||||
|
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||||
|
"%s failed:\n\t%s:%d: %s", __func__, __FILE__, \
|
||||||
|
__LINE__, message); \
|
||||||
|
minunit_status = 1; return;)
|
||||||
|
|
||||||
|
#define mu_assert(test, message) \
|
||||||
|
MU__SAFE_BLOCK( \
|
||||||
|
minunit_assert++; if (!(test)) { \
|
||||||
|
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||||
|
"%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, \
|
||||||
|
message); \
|
||||||
|
minunit_status = 1; \
|
||||||
|
return; \
|
||||||
|
} else { printf("."); })
|
||||||
|
|
||||||
|
#define mu_assert_int_eq(expected, result) \
|
||||||
|
MU__SAFE_BLOCK( \
|
||||||
|
int minunit_tmp_e; int minunit_tmp_r; minunit_assert++; \
|
||||||
|
minunit_tmp_e = (expected); minunit_tmp_r = (result); \
|
||||||
|
if (minunit_tmp_e != minunit_tmp_r) { \
|
||||||
|
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||||
|
"%s failed:\n\t%s:%d: %d expected but was %d", __func__, \
|
||||||
|
__FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r); \
|
||||||
|
minunit_status = 1; \
|
||||||
|
return; \
|
||||||
|
} else { printf("."); })
|
||||||
|
|
||||||
|
#define mu_assert_double_eq(expected, result) \
|
||||||
|
MU__SAFE_BLOCK( \
|
||||||
|
double minunit_tmp_e; double minunit_tmp_r; minunit_assert++; \
|
||||||
|
minunit_tmp_e = (expected); minunit_tmp_r = (result); \
|
||||||
|
if (fabs(minunit_tmp_e - minunit_tmp_r) > MINUNIT_EPSILON) { \
|
||||||
|
int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON); \
|
||||||
|
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||||
|
"%s failed:\n\t%s:%d: %.*g expected but was %.*g", __func__, \
|
||||||
|
__FILE__, __LINE__, minunit_significant_figures, \
|
||||||
|
minunit_tmp_e, minunit_significant_figures, minunit_tmp_r); \
|
||||||
|
minunit_status = 1; \
|
||||||
|
return; \
|
||||||
|
} else { printf("."); })
|
||||||
|
|
||||||
|
#define mu_assert_string_eq(expected, result) \
|
||||||
|
MU__SAFE_BLOCK( \
|
||||||
|
const char *minunit_tmp_e = expected; \
|
||||||
|
const char *minunit_tmp_r = result; minunit_assert++; \
|
||||||
|
if (!minunit_tmp_e) { \
|
||||||
|
minunit_tmp_e = "<null pointer>"; \
|
||||||
|
} if (!minunit_tmp_r) { \
|
||||||
|
minunit_tmp_r = "<null pointer>"; \
|
||||||
|
} if (strcmp(minunit_tmp_e, minunit_tmp_r)) { \
|
||||||
|
snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \
|
||||||
|
"%s failed:\n\t%s:%d: '%s' expected but was '%s'", __func__, \
|
||||||
|
__FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r); \
|
||||||
|
minunit_status = 1; \
|
||||||
|
return; \
|
||||||
|
} else { printf("."); })
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following two functions were written by David Robert Nadeau
|
||||||
|
* from http://NadeauSoftware.com/ and distributed under the
|
||||||
|
* Creative Commons Attribution 3.0 Unported License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the real time, in seconds, or -1.0 if an error occurred.
|
||||||
|
*
|
||||||
|
* Time is measured since an arbitrary and OS-dependent start time.
|
||||||
|
* The returned real time is only useful for computing an elapsed time
|
||||||
|
* between two calls to this function.
|
||||||
|
*/
|
||||||
|
static double mu_timer_real(void) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
/* Windows 2000 and later. ---------------------------------- */
|
||||||
|
LARGE_INTEGER Time;
|
||||||
|
LARGE_INTEGER Frequency;
|
||||||
|
|
||||||
|
QueryPerformanceFrequency(&Frequency);
|
||||||
|
QueryPerformanceCounter(&Time);
|
||||||
|
|
||||||
|
Time.QuadPart *= 1000000;
|
||||||
|
Time.QuadPart /= Frequency.QuadPart;
|
||||||
|
|
||||||
|
return (double)Time.QuadPart / 1000000.0;
|
||||||
|
|
||||||
|
#elif (defined(__hpux) || defined(hpux)) || \
|
||||||
|
((defined(__sun__) || defined(__sun) || defined(sun)) && \
|
||||||
|
(defined(__SVR4) || defined(__svr4__)))
|
||||||
|
/* HP-UX, Solaris. ------------------------------------------ */
|
||||||
|
return (double)gethrtime() / 1000000000.0;
|
||||||
|
|
||||||
|
#elif defined(__MACH__) && defined(__APPLE__)
|
||||||
|
/* OSX. ----------------------------------------------------- */
|
||||||
|
static double timeConvert = 0.0;
|
||||||
|
if (timeConvert == 0.0) {
|
||||||
|
mach_timebase_info_data_t timeBase;
|
||||||
|
(void)mach_timebase_info(&timeBase);
|
||||||
|
timeConvert =
|
||||||
|
(double)timeBase.numer / (double)timeBase.denom / 1000000000.0;
|
||||||
|
}
|
||||||
|
return (double)mach_absolute_time() * timeConvert;
|
||||||
|
|
||||||
|
#elif defined(_POSIX_VERSION)
|
||||||
|
/* POSIX. --------------------------------------------------- */
|
||||||
|
struct timeval tm;
|
||||||
|
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
#if defined(CLOCK_MONOTONIC_PRECISE)
|
||||||
|
/* BSD. --------------------------------------------- */
|
||||||
|
const clockid_t id = CLOCK_MONOTONIC_PRECISE;
|
||||||
|
#elif defined(CLOCK_MONOTONIC_RAW)
|
||||||
|
/* Linux. ------------------------------------------- */
|
||||||
|
const clockid_t id = CLOCK_MONOTONIC_RAW;
|
||||||
|
#elif defined(CLOCK_HIGHRES)
|
||||||
|
/* Solaris. ----------------------------------------- */
|
||||||
|
const clockid_t id = CLOCK_HIGHRES;
|
||||||
|
#elif defined(CLOCK_MONOTONIC)
|
||||||
|
/* AIX, BSD, Linux, POSIX, Solaris. ----------------- */
|
||||||
|
const clockid_t id = CLOCK_MONOTONIC;
|
||||||
|
#elif defined(CLOCK_REALTIME)
|
||||||
|
/* AIX, BSD, HP-UX, Linux, POSIX. ------------------- */
|
||||||
|
const clockid_t id = CLOCK_REALTIME;
|
||||||
|
#else
|
||||||
|
const clockid_t id = (clockid_t)-1; /* Unknown. */
|
||||||
|
#endif /* CLOCK_* */
|
||||||
|
if (id != (clockid_t)-1 && clock_gettime(id, &ts) != -1)
|
||||||
|
return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0;
|
||||||
|
/* Fall thru. */
|
||||||
|
}
|
||||||
|
#endif /* _POSIX_TIMERS */
|
||||||
|
|
||||||
|
/* AIX, BSD, Cygwin, HP-UX, Linux, OSX, POSIX, Solaris. ----- */
|
||||||
|
gettimeofday(&tm, NULL);
|
||||||
|
return (double)tm.tv_sec + (double)tm.tv_usec / 1000000.0;
|
||||||
|
#else
|
||||||
|
return -1.0; /* Failed. */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the amount of CPU time used by the current process,
|
||||||
|
* in seconds, or -1.0 if an error occurred.
|
||||||
|
*/
|
||||||
|
static double mu_timer_cpu(void) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
/* Windows -------------------------------------------------- */
|
||||||
|
FILETIME createTime;
|
||||||
|
FILETIME exitTime;
|
||||||
|
FILETIME kernelTime;
|
||||||
|
FILETIME userTime;
|
||||||
|
|
||||||
|
/* This approach has a resolution of 1/64 second. Unfortunately, Windows' API
|
||||||
|
* does not offer better */
|
||||||
|
if (GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime,
|
||||||
|
&userTime) != 0) {
|
||||||
|
ULARGE_INTEGER userSystemTime;
|
||||||
|
memcpy(&userSystemTime, &userTime, sizeof(ULARGE_INTEGER));
|
||||||
|
return (double)userSystemTime.QuadPart / 10000000.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__unix__) || defined(__unix) || defined(unix) || \
|
||||||
|
(defined(__APPLE__) && defined(__MACH__))
|
||||||
|
/* AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris --------- */
|
||||||
|
|
||||||
|
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
|
||||||
|
/* Prefer high-res POSIX timers, when available. */
|
||||||
|
{
|
||||||
|
clockid_t id;
|
||||||
|
struct timespec ts;
|
||||||
|
#if _POSIX_CPUTIME > 0
|
||||||
|
/* Clock ids vary by OS. Query the id, if possible. */
|
||||||
|
if (clock_getcpuclockid(0, &id) == -1)
|
||||||
|
#endif
|
||||||
|
#if defined(CLOCK_PROCESS_CPUTIME_ID)
|
||||||
|
/* Use known clock id for AIX, Linux, or Solaris. */
|
||||||
|
id = CLOCK_PROCESS_CPUTIME_ID;
|
||||||
|
#elif defined(CLOCK_VIRTUAL)
|
||||||
|
/* Use known clock id for BSD or HP-UX. */
|
||||||
|
id = CLOCK_VIRTUAL;
|
||||||
|
#else
|
||||||
|
id = (clockid_t)-1;
|
||||||
|
#endif
|
||||||
|
if (id != (clockid_t)-1 && clock_gettime(id, &ts) != -1)
|
||||||
|
return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(RUSAGE_SELF)
|
||||||
|
{
|
||||||
|
struct rusage rusage;
|
||||||
|
if (getrusage(RUSAGE_SELF, &rusage) != -1)
|
||||||
|
return (double)rusage.ru_utime.tv_sec +
|
||||||
|
(double)rusage.ru_utime.tv_usec / 1000000.0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_SC_CLK_TCK)
|
||||||
|
{
|
||||||
|
const double ticks = (double)sysconf(_SC_CLK_TCK);
|
||||||
|
struct tms tms;
|
||||||
|
if (times(&tms) != (clock_t)-1)
|
||||||
|
return (double)tms.tms_utime / ticks;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CLOCKS_PER_SEC)
|
||||||
|
{
|
||||||
|
clock_t cl = clock();
|
||||||
|
if (cl != (clock_t)-1)
|
||||||
|
return (double)cl / (double)CLOCKS_PER_SEC;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return -1; /* Failed. */
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* MINUNIT_MINUNIT_H */
|
|
@ -1,495 +0,0 @@
|
||||||
#include <zip.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__)
|
|
||||||
#define MZ_FILE_STAT_STRUCT _stat
|
|
||||||
#define MZ_FILE_STAT _stat
|
|
||||||
#else
|
|
||||||
#define MZ_FILE_STAT_STRUCT stat
|
|
||||||
#define MZ_FILE_STAT stat
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ZIPNAME "test.zip\0"
|
|
||||||
#define TESTDATA1 "Some test data 1...\0"
|
|
||||||
#define CRC32DATA1 2220805626
|
|
||||||
#define TESTDATA2 "Some test data 2...\0"
|
|
||||||
#define CRC32DATA2 2532008468
|
|
||||||
|
|
||||||
#define RFILE "4.txt\0"
|
|
||||||
#define RMODE 0100444
|
|
||||||
|
|
||||||
#define WFILE "6.txt\0"
|
|
||||||
#define WMODE 0100666
|
|
||||||
|
|
||||||
#define XFILE "7.txt\0"
|
|
||||||
#define XMODE 0100777
|
|
||||||
|
|
||||||
#define UNIXMODE 0100644
|
|
||||||
|
|
||||||
#define UNUSED(x) (void)x
|
|
||||||
|
|
||||||
static int total_entries = 0;
|
|
||||||
|
|
||||||
static void test_write(void) {
|
|
||||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
|
||||||
assert(zip != NULL);
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test/test-1.txt"));
|
|
||||||
assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
|
||||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
|
||||||
assert(total_entries == zip_entry_index(zip));
|
|
||||||
assert(strlen(TESTDATA1) == zip_entry_size(zip));
|
|
||||||
assert(CRC32DATA1 == zip_entry_crc32(zip));
|
|
||||||
++total_entries;
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
assert(0 == zip_is64(zip));
|
|
||||||
zip_close(zip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_append(void) {
|
|
||||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
|
||||||
assert(zip != NULL);
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test\\test-2.txt"));
|
|
||||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
|
||||||
assert(total_entries == zip_entry_index(zip));
|
|
||||||
assert(0 == zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)));
|
|
||||||
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
|
||||||
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
|
||||||
|
|
||||||
++total_entries;
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test\\empty/"));
|
|
||||||
assert(0 == strcmp(zip_entry_name(zip), "test/empty/"));
|
|
||||||
assert(0 == zip_entry_size(zip));
|
|
||||||
assert(0 == zip_entry_crc32(zip));
|
|
||||||
|
|
||||||
assert(total_entries == zip_entry_index(zip));
|
|
||||||
++total_entries;
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "empty/"));
|
|
||||||
assert(0 == strcmp(zip_entry_name(zip), "empty/"));
|
|
||||||
assert(0 == zip_entry_size(zip));
|
|
||||||
assert(0 == zip_entry_crc32(zip));
|
|
||||||
|
|
||||||
assert(total_entries == zip_entry_index(zip));
|
|
||||||
++total_entries;
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
|
|
||||||
zip_close(zip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_read(void) {
|
|
||||||
char *buf = NULL;
|
|
||||||
ssize_t bufsize;
|
|
||||||
size_t buftmp;
|
|
||||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
|
||||||
assert(zip != NULL);
|
|
||||||
assert(0 == zip_is64(zip));
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test\\test-1.txt"));
|
|
||||||
assert(strlen(TESTDATA1) == zip_entry_size(zip));
|
|
||||||
assert(CRC32DATA1 == zip_entry_crc32(zip));
|
|
||||||
|
|
||||||
bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);
|
|
||||||
assert(bufsize == strlen(TESTDATA1));
|
|
||||||
assert((size_t)bufsize == buftmp);
|
|
||||||
assert(0 == strncmp(buf, TESTDATA1, bufsize));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
free(buf);
|
|
||||||
buf = NULL;
|
|
||||||
bufsize = 0;
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test/test-2.txt"));
|
|
||||||
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
|
||||||
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
|
||||||
|
|
||||||
bufsize = zip_entry_read(zip, (void **)&buf, NULL);
|
|
||||||
assert((size_t)bufsize == strlen(TESTDATA2));
|
|
||||||
assert(0 == strncmp(buf, TESTDATA2, (size_t)bufsize));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
free(buf);
|
|
||||||
buf = NULL;
|
|
||||||
bufsize = 0;
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test\\empty/"));
|
|
||||||
assert(0 == strcmp(zip_entry_name(zip), "test/empty/"));
|
|
||||||
assert(0 == zip_entry_size(zip));
|
|
||||||
assert(0 == zip_entry_crc32(zip));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
|
|
||||||
buftmp = strlen(TESTDATA2);
|
|
||||||
buf = calloc(buftmp, sizeof(char));
|
|
||||||
assert(0 == zip_entry_open(zip, "test/test-2.txt"));
|
|
||||||
|
|
||||||
bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp);
|
|
||||||
assert(buftmp == (size_t)bufsize);
|
|
||||||
assert(0 == strncmp(buf, TESTDATA2, buftmp));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
free(buf);
|
|
||||||
buf = NULL;
|
|
||||||
bufsize = 0;
|
|
||||||
|
|
||||||
buftmp = strlen(TESTDATA1);
|
|
||||||
buf = calloc(buftmp, sizeof(char));
|
|
||||||
assert(0 == zip_entry_open(zip, "test/test-1.txt"));
|
|
||||||
|
|
||||||
bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp);
|
|
||||||
assert(buftmp == (size_t)bufsize);
|
|
||||||
assert(0 == strncmp(buf, TESTDATA1, buftmp));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
free(buf);
|
|
||||||
buf = NULL;
|
|
||||||
bufsize = 0;
|
|
||||||
|
|
||||||
zip_close(zip);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct buffer_t {
|
|
||||||
char *data;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
static size_t on_extract(void *arg, unsigned long long offset, const void *data,
|
|
||||||
size_t size) {
|
|
||||||
UNUSED(offset);
|
|
||||||
|
|
||||||
struct buffer_t *buf = (struct buffer_t *)arg;
|
|
||||||
buf->data = realloc(buf->data, buf->size + size + 1);
|
|
||||||
assert(NULL != buf->data);
|
|
||||||
|
|
||||||
memcpy(&(buf->data[buf->size]), data, size);
|
|
||||||
buf->size += size;
|
|
||||||
buf->data[buf->size] = 0;
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_extract(void) {
|
|
||||||
struct buffer_t buf;
|
|
||||||
|
|
||||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
|
||||||
assert(zip != NULL);
|
|
||||||
memset((void *)&buf, 0, sizeof(struct buffer_t));
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test/test-1.txt"));
|
|
||||||
assert(0 == zip_entry_extract(zip, on_extract, &buf));
|
|
||||||
|
|
||||||
assert(buf.size == strlen(TESTDATA1));
|
|
||||||
assert(0 == strncmp(buf.data, TESTDATA1, buf.size));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
free(buf.data);
|
|
||||||
buf.data = NULL;
|
|
||||||
buf.size = 0;
|
|
||||||
|
|
||||||
zip_close(zip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_total_entries(void) {
|
|
||||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
|
||||||
assert(zip != NULL);
|
|
||||||
|
|
||||||
int n = zip_total_entries(zip);
|
|
||||||
zip_close(zip);
|
|
||||||
|
|
||||||
assert(n == total_entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_entry_name(void) {
|
|
||||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
|
||||||
assert(zip != NULL);
|
|
||||||
|
|
||||||
assert(zip_entry_name(zip) == NULL);
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test\\test-1.txt"));
|
|
||||||
assert(NULL != zip_entry_name(zip));
|
|
||||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
|
||||||
assert(strlen(TESTDATA1) == zip_entry_size(zip));
|
|
||||||
assert(CRC32DATA1 == zip_entry_crc32(zip));
|
|
||||||
assert(0 == zip_entry_index(zip));
|
|
||||||
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test/test-2.txt"));
|
|
||||||
assert(NULL != zip_entry_name(zip));
|
|
||||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
|
||||||
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
|
||||||
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
|
||||||
assert(1 == zip_entry_index(zip));
|
|
||||||
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
|
|
||||||
zip_close(zip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_entry_index(void) {
|
|
||||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
|
||||||
assert(zip != NULL);
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test\\test-1.txt"));
|
|
||||||
assert(0 == zip_entry_index(zip));
|
|
||||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
|
||||||
assert(strlen(TESTDATA1) == zip_entry_size(zip));
|
|
||||||
assert(CRC32DATA1 == zip_entry_crc32(zip));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test/test-2.txt"));
|
|
||||||
assert(1 == zip_entry_index(zip));
|
|
||||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
|
||||||
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
|
||||||
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
|
|
||||||
zip_close(zip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_entry_openbyindex(void) {
|
|
||||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
|
||||||
assert(zip != NULL);
|
|
||||||
|
|
||||||
assert(0 == zip_entry_openbyindex(zip, 1));
|
|
||||||
assert(1 == zip_entry_index(zip));
|
|
||||||
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
|
||||||
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
|
||||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
|
|
||||||
assert(0 == zip_entry_openbyindex(zip, 0));
|
|
||||||
assert(0 == zip_entry_index(zip));
|
|
||||||
assert(strlen(TESTDATA1) == zip_entry_size(zip));
|
|
||||||
assert(CRC32DATA1 == zip_entry_crc32(zip));
|
|
||||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
|
|
||||||
zip_close(zip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_list_entries(void) {
|
|
||||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
|
||||||
assert(zip != NULL);
|
|
||||||
|
|
||||||
int i = 0, n = zip_total_entries(zip);
|
|
||||||
for (; i < n; ++i) {
|
|
||||||
assert(0 == zip_entry_openbyindex(zip, i));
|
|
||||||
fprintf(stdout, "[%d]: %s", i, zip_entry_name(zip));
|
|
||||||
if (zip_entry_isdir(zip)) {
|
|
||||||
fprintf(stdout, " (DIR)");
|
|
||||||
}
|
|
||||||
fprintf(stdout, "\n");
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
}
|
|
||||||
|
|
||||||
zip_close(zip);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_fwrite(void) {
|
|
||||||
const char *filename = WFILE;
|
|
||||||
FILE *stream = NULL;
|
|
||||||
struct zip_t *zip = NULL;
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
if (0 != fopen_s(&stream, filename, "w+"))
|
|
||||||
#else
|
|
||||||
if (!(stream = fopen(filename, "w+")))
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// Cannot open filename
|
|
||||||
fprintf(stdout, "Cannot open filename\n");
|
|
||||||
assert(0 == -1);
|
|
||||||
}
|
|
||||||
fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream);
|
|
||||||
assert(0 == fclose(stream));
|
|
||||||
|
|
||||||
zip = zip_open(ZIPNAME, 9, 'w');
|
|
||||||
assert(zip != NULL);
|
|
||||||
assert(0 == zip_entry_open(zip, WFILE));
|
|
||||||
assert(0 == zip_entry_fwrite(zip, WFILE));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
assert(0 == zip_is64(zip));
|
|
||||||
|
|
||||||
zip_close(zip);
|
|
||||||
remove(WFILE);
|
|
||||||
remove(ZIPNAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_exe_permissions(void) {
|
|
||||||
#if defined(_WIN32) || defined(__WIN32__)
|
|
||||||
#else
|
|
||||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
|
||||||
const char *filenames[] = {XFILE};
|
|
||||||
FILE *f = fopen(XFILE, "w");
|
|
||||||
fclose(f);
|
|
||||||
chmod(XFILE, XMODE);
|
|
||||||
|
|
||||||
remove(ZIPNAME);
|
|
||||||
|
|
||||||
assert(0 == zip_create(ZIPNAME, filenames, 1));
|
|
||||||
|
|
||||||
remove(XFILE);
|
|
||||||
|
|
||||||
assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
|
|
||||||
|
|
||||||
assert(0 == MZ_FILE_STAT(XFILE, &file_stats));
|
|
||||||
assert(XMODE == file_stats.st_mode);
|
|
||||||
|
|
||||||
remove(XFILE);
|
|
||||||
remove(ZIPNAME);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_read_permissions(void) {
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#else
|
|
||||||
|
|
||||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
|
||||||
const char *filenames[] = {RFILE};
|
|
||||||
FILE *f = fopen(RFILE, "w");
|
|
||||||
fclose(f);
|
|
||||||
chmod(RFILE, RMODE);
|
|
||||||
|
|
||||||
remove(ZIPNAME);
|
|
||||||
|
|
||||||
assert(0 == zip_create(ZIPNAME, filenames, 1));
|
|
||||||
|
|
||||||
// chmod from 444 to 666 to be able delete the file on windows
|
|
||||||
chmod(RFILE, WMODE);
|
|
||||||
remove(RFILE);
|
|
||||||
|
|
||||||
assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
|
|
||||||
|
|
||||||
assert(0 == MZ_FILE_STAT(RFILE, &file_stats));
|
|
||||||
assert(RMODE == file_stats.st_mode);
|
|
||||||
|
|
||||||
chmod(RFILE, WMODE);
|
|
||||||
remove(RFILE);
|
|
||||||
remove(ZIPNAME);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_write_permissions(void) {
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#else
|
|
||||||
|
|
||||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
|
||||||
const char *filenames[] = {WFILE};
|
|
||||||
FILE *f = fopen(WFILE, "w");
|
|
||||||
fclose(f);
|
|
||||||
chmod(WFILE, WMODE);
|
|
||||||
|
|
||||||
remove(ZIPNAME);
|
|
||||||
|
|
||||||
assert(0 == zip_create(ZIPNAME, filenames, 1));
|
|
||||||
|
|
||||||
remove(WFILE);
|
|
||||||
|
|
||||||
assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
|
|
||||||
|
|
||||||
assert(0 == MZ_FILE_STAT(WFILE, &file_stats));
|
|
||||||
assert(WMODE == file_stats.st_mode);
|
|
||||||
|
|
||||||
remove(WFILE);
|
|
||||||
remove(ZIPNAME);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_mtime(void) {
|
|
||||||
struct MZ_FILE_STAT_STRUCT file_stat1, file_stat2;
|
|
||||||
|
|
||||||
const char *filename = WFILE;
|
|
||||||
FILE *stream = NULL;
|
|
||||||
struct zip_t *zip = NULL;
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
if (0 != fopen_s(&stream, filename, "w+"))
|
|
||||||
#else
|
|
||||||
if (!(stream = fopen(filename, "w+")))
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// Cannot open filename
|
|
||||||
fprintf(stdout, "Cannot open filename\n");
|
|
||||||
assert(0 == -1);
|
|
||||||
}
|
|
||||||
fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream);
|
|
||||||
assert(0 == fclose(stream));
|
|
||||||
|
|
||||||
memset(&file_stat1, 0, sizeof(file_stat1));
|
|
||||||
memset(&file_stat2, 0, sizeof(file_stat2));
|
|
||||||
zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
|
||||||
assert(zip != NULL);
|
|
||||||
assert(0 == zip_entry_open(zip, filename));
|
|
||||||
assert(0 == zip_entry_fwrite(zip, filename));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
zip_close(zip);
|
|
||||||
|
|
||||||
assert(0 == MZ_FILE_STAT(filename, &file_stat1));
|
|
||||||
|
|
||||||
remove(filename);
|
|
||||||
assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
|
|
||||||
assert(0 == MZ_FILE_STAT(filename, &file_stat2));
|
|
||||||
fprintf(stdout, "file_stat1.st_mtime: %lu\n", file_stat1.st_mtime);
|
|
||||||
fprintf(stdout, "file_stat2.st_mtime: %lu\n", file_stat2.st_mtime);
|
|
||||||
assert(labs(file_stat1.st_mtime - file_stat2.st_mtime) <= 1);
|
|
||||||
|
|
||||||
remove(filename);
|
|
||||||
remove(ZIPNAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_unix_permissions(void) {
|
|
||||||
#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__)
|
|
||||||
#else
|
|
||||||
// UNIX or APPLE
|
|
||||||
struct MZ_FILE_STAT_STRUCT file_stats;
|
|
||||||
|
|
||||||
remove(ZIPNAME);
|
|
||||||
|
|
||||||
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
|
||||||
assert(zip != NULL);
|
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, RFILE));
|
|
||||||
assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
|
||||||
assert(0 == zip_entry_close(zip));
|
|
||||||
|
|
||||||
zip_close(zip);
|
|
||||||
|
|
||||||
remove(RFILE);
|
|
||||||
|
|
||||||
assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
|
|
||||||
|
|
||||||
assert(0 == MZ_FILE_STAT(RFILE, &file_stats));
|
|
||||||
assert(UNIXMODE == file_stats.st_mode);
|
|
||||||
|
|
||||||
remove(RFILE);
|
|
||||||
remove(ZIPNAME);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
UNUSED(argc);
|
|
||||||
UNUSED(argv);
|
|
||||||
|
|
||||||
remove(ZIPNAME);
|
|
||||||
|
|
||||||
test_write();
|
|
||||||
test_append();
|
|
||||||
test_read();
|
|
||||||
test_extract();
|
|
||||||
test_total_entries();
|
|
||||||
test_entry_name();
|
|
||||||
test_entry_index();
|
|
||||||
test_entry_openbyindex();
|
|
||||||
test_list_entries();
|
|
||||||
test_fwrite();
|
|
||||||
test_read_permissions();
|
|
||||||
test_write_permissions();
|
|
||||||
test_exe_permissions();
|
|
||||||
test_mtime();
|
|
||||||
test_unix_permissions();
|
|
||||||
|
|
||||||
remove(ZIPNAME);
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <zip.h>
|
||||||
|
|
||||||
|
#include "minunit.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#define MKTEMP _mktemp
|
||||||
|
#define UNLINK _unlink
|
||||||
|
#else
|
||||||
|
#define MKTEMP mkstemp
|
||||||
|
#define UNLINK unlink
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||||
|
static int total_entries = 0;
|
||||||
|
|
||||||
|
#define TESTDATA1 "Some test data 1...\0"
|
||||||
|
|
||||||
|
void test_setup(void) {
|
||||||
|
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||||
|
MKTEMP(ZIPNAME);
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
|
|
||||||
|
zip_entry_open(zip, "test/test-1.txt");
|
||||||
|
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_teardown(void) { UNLINK(ZIPNAME); }
|
||||||
|
|
||||||
|
#define TESTDATA2 "Some test data 2...\0"
|
||||||
|
#define CRC32DATA2 2532008468
|
||||||
|
|
||||||
|
MU_TEST(test_append) {
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test\\test-2.txt"));
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||||
|
mu_assert_int_eq(total_entries, zip_entry_index(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
++total_entries;
|
||||||
|
zip_close(zip);
|
||||||
|
|
||||||
|
zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test\\empty/"));
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/empty/"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_size(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(total_entries, zip_entry_index(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
++total_entries;
|
||||||
|
zip_close(zip);
|
||||||
|
|
||||||
|
zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "empty/"));
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "empty/"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_size(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(total_entries, zip_entry_index(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "dotfiles/.test"));
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "dotfiles/.test"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_size(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(total_entries, zip_entry_index(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
mu_assert_int_eq(total_entries, zip_entries_total(zip));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(test_append_suite) {
|
||||||
|
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||||
|
|
||||||
|
MU_RUN_TEST(test_append);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNUSED(x) (void)x
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
UNUSED(argc);
|
||||||
|
UNUSED(argv);
|
||||||
|
|
||||||
|
MU_RUN_SUITE(test_append_suite);
|
||||||
|
MU_REPORT();
|
||||||
|
return MU_EXIT_CODE;
|
||||||
|
}
|
|
@ -0,0 +1,438 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <zip.h>
|
||||||
|
|
||||||
|
#include "minunit.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#define MKTEMP _mktemp
|
||||||
|
#define UNLINK _unlink
|
||||||
|
#else
|
||||||
|
#define MKTEMP mkstemp
|
||||||
|
#define UNLINK unlink
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE \
|
||||||
|
(sizeof(unsigned short) * 2 + sizeof(unsigned long long) * 3)
|
||||||
|
#define MZ_ZIP_LOCAL_DIR_HEADER_SIZE 30
|
||||||
|
|
||||||
|
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||||
|
|
||||||
|
#define CRC32DATA1 2220805626
|
||||||
|
#define TESTDATA1 "Some test data 1...\0"
|
||||||
|
|
||||||
|
#define TESTDATA2 "Some test data 2...\0"
|
||||||
|
#define CRC32DATA2 2532008468
|
||||||
|
|
||||||
|
static int total_entries = 0;
|
||||||
|
|
||||||
|
void test_setup(void) {
|
||||||
|
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||||
|
MKTEMP(ZIPNAME);
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
|
|
||||||
|
zip_entry_open(zip, "test/test-1.txt");
|
||||||
|
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_entry_open(zip, "test\\test-2.txt");
|
||||||
|
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_entry_open(zip, "test\\empty/");
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_entry_open(zip, "empty/");
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_entry_open(zip, "dotfiles/.test");
|
||||||
|
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_entry_open(zip, "delete.me");
|
||||||
|
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_entry_open(zip, "_");
|
||||||
|
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_entry_open(zip, "delete/file.1");
|
||||||
|
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_entry_open(zip, "delete/file.2");
|
||||||
|
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_entry_open(zip, "deleteme/file.3");
|
||||||
|
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_entry_open(zip, "delete/file.4");
|
||||||
|
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
++total_entries;
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_teardown(void) {
|
||||||
|
total_entries = 0;
|
||||||
|
|
||||||
|
UNLINK(ZIPNAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_entry_name) {
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_check(zip_entry_name(zip) == NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test\\test-1.txt"));
|
||||||
|
mu_check(NULL != zip_entry_name(zip));
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_index(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt"));
|
||||||
|
mu_check(NULL != zip_entry_name(zip));
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(1, zip_entry_index(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_entry_opencasesensitive) {
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_check(zip_entry_name(zip) == NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test/TEST-1.TXT"));
|
||||||
|
mu_check(NULL != zip_entry_name(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(ZIP_ENOENT,
|
||||||
|
zip_entry_opencasesensitive(zip, "test/TEST-1.TXT"));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_entry_index) {
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test\\test-1.txt"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_index(zip));
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt"));
|
||||||
|
mu_assert_int_eq(1, zip_entry_index(zip));
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_entry_openbyindex) {
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_openbyindex(zip, 1));
|
||||||
|
mu_assert_int_eq(1, zip_entry_index(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_openbyindex(zip, 0));
|
||||||
|
mu_assert_int_eq(0, zip_entry_index(zip));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_entry_read) {
|
||||||
|
char *bufencode1 = NULL;
|
||||||
|
char *bufencode2 = NULL;
|
||||||
|
char *buf = NULL;
|
||||||
|
size_t bufsize;
|
||||||
|
|
||||||
|
struct zip_t *zip =
|
||||||
|
zip_stream_open(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
ssize_t n = zip_stream_copy(zip, (void **)&bufencode1, NULL);
|
||||||
|
zip_stream_copy(zip, (void **)&bufencode2, &bufsize);
|
||||||
|
mu_assert_int_eq(0, strncmp(bufencode1, bufencode2, bufsize));
|
||||||
|
|
||||||
|
zip_stream_close(zip);
|
||||||
|
|
||||||
|
struct zip_t *zipstream = zip_stream_open(bufencode1, n, 0, 'r');
|
||||||
|
mu_check(zipstream != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zipstream, "test/test-1.txt"));
|
||||||
|
n = zip_entry_read(zipstream, (void **)&buf, NULL);
|
||||||
|
mu_assert_int_eq(0, strncmp(buf, TESTDATA1, (size_t)n));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zipstream));
|
||||||
|
|
||||||
|
zip_stream_close(zipstream);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
free(bufencode1);
|
||||||
|
free(bufencode2);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_list_entries) {
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
int i = 0, n = zip_entries_total(zip);
|
||||||
|
for (; i < n; ++i) {
|
||||||
|
mu_assert_int_eq(0, zip_entry_openbyindex(zip, i));
|
||||||
|
fprintf(stdout, "[%d]: %s", i, zip_entry_name(zip));
|
||||||
|
if (zip_entry_isdir(zip)) {
|
||||||
|
fprintf(stdout, " (DIR)");
|
||||||
|
}
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
}
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_entries_deletebyindex) {
|
||||||
|
size_t entries[] = {5, 6, 7, 9, 8};
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'd');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(5, zip_entries_deletebyindex(zip, entries, 5));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
|
||||||
|
zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete.me"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
fprintf(stdout, "delete.me: %s\n", zip_strerror(ZIP_ENOENT));
|
||||||
|
|
||||||
|
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "_"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
fprintf(stdout, "_: %s\n", zip_strerror(ZIP_ENOENT));
|
||||||
|
|
||||||
|
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.1"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
fprintf(stdout, "delete/file.1: %s\n", zip_strerror(ZIP_ENOENT));
|
||||||
|
|
||||||
|
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "deleteme/file.3"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
fprintf(stdout, "delete/file.3: %s\n", zip_strerror(ZIP_ENOENT));
|
||||||
|
|
||||||
|
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.2"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
fprintf(stdout, "delete/file.2: %s\n", zip_strerror(ZIP_ENOENT));
|
||||||
|
|
||||||
|
mu_assert_int_eq(total_entries - 5, zip_entries_total(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.4"));
|
||||||
|
|
||||||
|
size_t buftmp = 0;
|
||||||
|
char *buf = NULL;
|
||||||
|
ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);
|
||||||
|
|
||||||
|
mu_assert_int_eq(bufsize, strlen(TESTDATA2));
|
||||||
|
mu_assert_int_eq((size_t)bufsize, buftmp);
|
||||||
|
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, bufsize));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_entries_deleteinvalid) {
|
||||||
|
size_t entries[] = {111, 222, 333, 444};
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'd');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entries_deletebyindex(zip, entries, 4));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
|
||||||
|
zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "delete.me"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "_"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.1"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "deleteme/file.3"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.2"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(total_entries, zip_entries_total(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.4"));
|
||||||
|
|
||||||
|
size_t buftmp = 0;
|
||||||
|
char *buf = NULL;
|
||||||
|
ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);
|
||||||
|
|
||||||
|
mu_assert_int_eq(bufsize, strlen(TESTDATA2));
|
||||||
|
mu_assert_int_eq((size_t)bufsize, buftmp);
|
||||||
|
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, bufsize));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_entries_delete) {
|
||||||
|
char *entries[] = {"delete.me", "_", "delete/file.1", "deleteme/file.3",
|
||||||
|
"delete/file.2"};
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'd');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(5, zip_entries_delete(zip, entries, 5));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
|
||||||
|
zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete.me"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
fprintf(stdout, "delete.me: %s\n", zip_strerror(ZIP_ENOENT));
|
||||||
|
|
||||||
|
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "_"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
fprintf(stdout, "_: %s\n", zip_strerror(ZIP_ENOENT));
|
||||||
|
|
||||||
|
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.1"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
fprintf(stdout, "delete/file.1: %s\n", zip_strerror(ZIP_ENOENT));
|
||||||
|
|
||||||
|
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "deleteme/file.3"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
fprintf(stdout, "delete/file.3: %s\n", zip_strerror(ZIP_ENOENT));
|
||||||
|
|
||||||
|
mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.2"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
fprintf(stdout, "delete/file.2: %s\n", zip_strerror(ZIP_ENOENT));
|
||||||
|
|
||||||
|
mu_assert_int_eq(total_entries - 5, zip_entries_total(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.4"));
|
||||||
|
|
||||||
|
size_t buftmp = 0;
|
||||||
|
char *buf = NULL;
|
||||||
|
ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);
|
||||||
|
|
||||||
|
mu_assert_int_eq(bufsize, strlen(TESTDATA2));
|
||||||
|
mu_assert_int_eq((size_t)bufsize, buftmp);
|
||||||
|
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, bufsize));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_entry_offset) {
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
unsigned long long off = 0ULL;
|
||||||
|
int i = 0, n = zip_entries_total(zip);
|
||||||
|
for (; i < n; i++) {
|
||||||
|
mu_assert_int_eq(0, zip_entry_openbyindex(zip, i));
|
||||||
|
mu_assert_int_eq(i, zip_entry_index(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(off, zip_entry_header_offset(zip));
|
||||||
|
|
||||||
|
off = zip_entry_header_offset(zip) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
|
||||||
|
strlen(zip_entry_name(zip)) + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE +
|
||||||
|
zip_entry_comp_size(zip);
|
||||||
|
fprintf(stdout, "\n[%d: %s]: header: %llu, dir: %llu, size: %llu (%llu)\n",
|
||||||
|
i, zip_entry_name(zip), zip_entry_header_offset(zip),
|
||||||
|
zip_entry_dir_offset(zip), zip_entry_comp_size(zip), off);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
}
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(test_entry_suite) {
|
||||||
|
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||||
|
|
||||||
|
MU_RUN_TEST(test_entry_name);
|
||||||
|
MU_RUN_TEST(test_entry_opencasesensitive);
|
||||||
|
MU_RUN_TEST(test_entry_index);
|
||||||
|
MU_RUN_TEST(test_entry_openbyindex);
|
||||||
|
MU_RUN_TEST(test_entry_read);
|
||||||
|
MU_RUN_TEST(test_list_entries);
|
||||||
|
MU_RUN_TEST(test_entries_deletebyindex);
|
||||||
|
MU_RUN_TEST(test_entries_delete);
|
||||||
|
MU_RUN_TEST(test_entry_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNUSED(x) (void)x
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
UNUSED(argc);
|
||||||
|
UNUSED(argv);
|
||||||
|
|
||||||
|
MU_RUN_SUITE(test_entry_suite);
|
||||||
|
MU_REPORT();
|
||||||
|
return MU_EXIT_CODE;
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <zip.h>
|
||||||
|
|
||||||
|
#include "minunit.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#define MKTEMP _mktemp
|
||||||
|
#define UNLINK _unlink
|
||||||
|
#else
|
||||||
|
#define MKTEMP mkstemp
|
||||||
|
#define UNLINK unlink
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||||
|
|
||||||
|
#define TESTDATA1 "Some test data 1...\0"
|
||||||
|
#define TESTDATA2 "Some test data 2...\0"
|
||||||
|
|
||||||
|
void test_setup(void) {
|
||||||
|
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||||
|
MKTEMP(ZIPNAME);
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
|
|
||||||
|
zip_entry_open(zip, "test/test-1.txt");
|
||||||
|
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
|
||||||
|
zip_entry_open(zip, "test\\test-2.txt");
|
||||||
|
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
|
||||||
|
zip_entry_open(zip, "test\\empty/");
|
||||||
|
zip_entry_close(zip);
|
||||||
|
|
||||||
|
zip_entry_open(zip, "empty/");
|
||||||
|
zip_entry_close(zip);
|
||||||
|
|
||||||
|
zip_entry_open(zip, "dotfiles/.test");
|
||||||
|
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_teardown(void) {
|
||||||
|
UNLINK("test/test-1.txt");
|
||||||
|
UNLINK("test/test-2.txt");
|
||||||
|
UNLINK("test/empty");
|
||||||
|
UNLINK("test");
|
||||||
|
UNLINK("empty");
|
||||||
|
UNLINK("dotfiles/.test");
|
||||||
|
UNLINK("dotfiles");
|
||||||
|
UNLINK(ZIPNAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNUSED(x) (void)x
|
||||||
|
|
||||||
|
struct buffer_t {
|
||||||
|
char *data;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t on_extract(void *arg, uint64_t offset, const void *data,
|
||||||
|
size_t size) {
|
||||||
|
UNUSED(offset);
|
||||||
|
|
||||||
|
struct buffer_t *buf = (struct buffer_t *)arg;
|
||||||
|
buf->data = realloc(buf->data, buf->size + size + 1);
|
||||||
|
|
||||||
|
memcpy(&(buf->data[buf->size]), data, size);
|
||||||
|
buf->size += size;
|
||||||
|
buf->data[buf->size] = 0;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_extract) {
|
||||||
|
struct buffer_t buf;
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
memset((void *)&buf, 0, sizeof(struct buffer_t));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_extract(zip, on_extract, &buf));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA1), buf.size);
|
||||||
|
mu_assert_int_eq(0, strncmp(buf.data, TESTDATA1, buf.size));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
free(buf.data);
|
||||||
|
buf.data = NULL;
|
||||||
|
buf.size = 0;
|
||||||
|
|
||||||
|
memset((void *)&buf, 0, sizeof(struct buffer_t));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "dotfiles/.test"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_extract(zip, on_extract, &buf));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA2), buf.size);
|
||||||
|
mu_assert_int_eq(0, strncmp(buf.data, TESTDATA2, buf.size));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
free(buf.data);
|
||||||
|
buf.data = NULL;
|
||||||
|
buf.size = 0;
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_extract_stream) {
|
||||||
|
mu_assert_int_eq(
|
||||||
|
ZIP_ENOINIT,
|
||||||
|
zip_extract("non_existing_directory/non_existing_archive.zip", ".", NULL,
|
||||||
|
NULL));
|
||||||
|
mu_assert_int_eq(ZIP_ENOINIT, zip_stream_extract("", 0, ".", NULL, NULL));
|
||||||
|
fprintf(stdout, "zip_stream_extract: %s\n", zip_strerror(ZIP_ENOINIT));
|
||||||
|
|
||||||
|
FILE *fp = NULL;
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
if (0 != fopen_s(&fp, ZIPNAME, "rb+"))
|
||||||
|
#else
|
||||||
|
if (!(fp = fopen(ZIPNAME, "rb+")))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
mu_fail("Cannot open filename\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fp, 0L, SEEK_END);
|
||||||
|
size_t filesize = ftell(fp);
|
||||||
|
fseek(fp, 0L, SEEK_SET);
|
||||||
|
|
||||||
|
char *stream = (char *)malloc(filesize * sizeof(char));
|
||||||
|
memset(stream, 0, filesize);
|
||||||
|
|
||||||
|
size_t size = fread(stream, sizeof(char), filesize, fp);
|
||||||
|
mu_assert_int_eq(filesize, size);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_stream_extract(stream, size, ".", NULL, NULL));
|
||||||
|
|
||||||
|
free(stream);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(test_extract_suite) {
|
||||||
|
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||||
|
|
||||||
|
MU_RUN_TEST(test_extract);
|
||||||
|
MU_RUN_TEST(test_extract_stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
UNUSED(argc);
|
||||||
|
UNUSED(argv);
|
||||||
|
|
||||||
|
MU_RUN_SUITE(test_extract_suite);
|
||||||
|
MU_REPORT();
|
||||||
|
return MU_EXIT_CODE;
|
||||||
|
}
|
|
@ -1,127 +0,0 @@
|
||||||
// Demonstrates miniz.c's compress() and uncompress() functions
|
|
||||||
// (same as zlib's). Public domain, May 15 2011, Rich Geldreich,
|
|
||||||
// richgel99@gmail.com. See "unlicense" statement at the end of tinfl.c.
|
|
||||||
|
|
||||||
#include <miniz.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
typedef unsigned char uint8;
|
|
||||||
typedef unsigned short uint16;
|
|
||||||
typedef unsigned int uint;
|
|
||||||
|
|
||||||
// The string to compress.
|
|
||||||
static const char *s_pStr =
|
|
||||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
|
||||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
|
||||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
|
||||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
|
||||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
|
||||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."
|
|
||||||
"Good morning Dr. Chandra. This is Hal. I am ready for my first lesson.";
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
uint step = 0;
|
|
||||||
int cmp_status;
|
|
||||||
uLong src_len = (uLong)strlen(s_pStr);
|
|
||||||
uLong uncomp_len = src_len;
|
|
||||||
uLong cmp_len;
|
|
||||||
uint8 *pCmp, *pUncomp;
|
|
||||||
size_t sz;
|
|
||||||
uint total_succeeded = 0;
|
|
||||||
(void)argc, (void)argv;
|
|
||||||
|
|
||||||
printf("miniz.c version: %s\n", MZ_VERSION);
|
|
||||||
|
|
||||||
do {
|
|
||||||
pCmp = (uint8 *)tdefl_compress_mem_to_heap(s_pStr, src_len, &cmp_len, 0);
|
|
||||||
if (!pCmp) {
|
|
||||||
printf("tdefl_compress_mem_to_heap failed\n");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
if (src_len <= cmp_len) {
|
|
||||||
printf("tdefl_compress_mem_to_heap failed: from %u to %u bytes\n",
|
|
||||||
(mz_uint32)uncomp_len, (mz_uint32)cmp_len);
|
|
||||||
free(pCmp);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
sz = tdefl_compress_mem_to_mem(pCmp, cmp_len, s_pStr, src_len, 0);
|
|
||||||
if (sz != cmp_len) {
|
|
||||||
printf("tdefl_compress_mem_to_mem failed: expected %u, got %u\n",
|
|
||||||
(mz_uint32)cmp_len, (mz_uint32)sz);
|
|
||||||
free(pCmp);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate buffers to hold compressed and uncompressed data.
|
|
||||||
free(pCmp);
|
|
||||||
cmp_len = compressBound(src_len);
|
|
||||||
pCmp = (mz_uint8 *)malloc((size_t)cmp_len);
|
|
||||||
pUncomp = (mz_uint8 *)malloc((size_t)src_len);
|
|
||||||
if ((!pCmp) || (!pUncomp)) {
|
|
||||||
printf("Out of memory!\n");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compress the string.
|
|
||||||
cmp_status =
|
|
||||||
compress(pCmp, &cmp_len, (const unsigned char *)s_pStr, src_len);
|
|
||||||
if (cmp_status != Z_OK) {
|
|
||||||
printf("compress() failed!\n");
|
|
||||||
free(pCmp);
|
|
||||||
free(pUncomp);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Compressed from %u to %u bytes\n", (mz_uint32)src_len,
|
|
||||||
(mz_uint32)cmp_len);
|
|
||||||
|
|
||||||
if (step) {
|
|
||||||
// Purposely corrupt the compressed data if fuzzy testing (this is a
|
|
||||||
// very crude fuzzy test).
|
|
||||||
uint n = 1 + (rand() % 3);
|
|
||||||
while (n--) {
|
|
||||||
uint i = rand() % cmp_len;
|
|
||||||
pCmp[i] ^= (rand() & 0xFF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decompress.
|
|
||||||
cmp_status = uncompress(pUncomp, &uncomp_len, pCmp, cmp_len);
|
|
||||||
total_succeeded += (cmp_status == Z_OK);
|
|
||||||
|
|
||||||
if (step) {
|
|
||||||
printf("Simple fuzzy test: step %u total_succeeded: %u\n", step,
|
|
||||||
total_succeeded);
|
|
||||||
} else {
|
|
||||||
if (cmp_status != Z_OK) {
|
|
||||||
printf("uncompress failed!\n");
|
|
||||||
free(pCmp);
|
|
||||||
free(pUncomp);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Decompressed from %u to %u bytes\n", (mz_uint32)cmp_len,
|
|
||||||
(mz_uint32)uncomp_len);
|
|
||||||
|
|
||||||
// Ensure uncompress() returned the expected data.
|
|
||||||
if ((uncomp_len != src_len) ||
|
|
||||||
(memcmp(pUncomp, s_pStr, (size_t)src_len))) {
|
|
||||||
printf("Decompression failed!\n");
|
|
||||||
free(pCmp);
|
|
||||||
free(pUncomp);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(pCmp);
|
|
||||||
free(pUncomp);
|
|
||||||
|
|
||||||
step++;
|
|
||||||
|
|
||||||
// Keep on fuzzy testing if there's a non-empty command line.
|
|
||||||
} while (argc >= 2);
|
|
||||||
|
|
||||||
printf("Success.\n");
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <zip.h>
|
||||||
|
|
||||||
|
#include "minunit.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#define MKTEMP _mktemp
|
||||||
|
#else
|
||||||
|
#define MKTEMP mkstemp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||||
|
|
||||||
|
void test_setup(void) {
|
||||||
|
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||||
|
MKTEMP(ZIPNAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_teardown(void) { remove(ZIPNAME); }
|
||||||
|
|
||||||
|
MU_TEST(test_openwitherror) {
|
||||||
|
int errnum;
|
||||||
|
struct zip_t *zip =
|
||||||
|
zip_openwitherror(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'r', &errnum);
|
||||||
|
mu_check(zip == NULL);
|
||||||
|
mu_assert_int_eq(ZIP_ERINIT, errnum);
|
||||||
|
|
||||||
|
zip = zip_openwitherror(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w', &errnum);
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
mu_assert_int_eq(0, errnum);
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_stream_openwitherror) {
|
||||||
|
int errnum;
|
||||||
|
struct zip_t *zip = zip_stream_openwitherror(
|
||||||
|
NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'r', &errnum);
|
||||||
|
mu_check(zip == NULL);
|
||||||
|
mu_assert_int_eq(ZIP_EINVMODE, errnum);
|
||||||
|
|
||||||
|
zip = zip_stream_openwitherror(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w',
|
||||||
|
&errnum);
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
mu_assert_int_eq(0, errnum);
|
||||||
|
|
||||||
|
zip_stream_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(test_entry_suite) {
|
||||||
|
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||||
|
|
||||||
|
MU_RUN_TEST(test_openwitherror);
|
||||||
|
MU_RUN_TEST(test_stream_openwitherror);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNUSED(x) (void)x
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
UNUSED(argc);
|
||||||
|
UNUSED(argv);
|
||||||
|
|
||||||
|
MU_RUN_SUITE(test_entry_suite);
|
||||||
|
MU_REPORT();
|
||||||
|
return MU_EXIT_CODE;
|
||||||
|
}
|
|
@ -0,0 +1,191 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <zip.h>
|
||||||
|
|
||||||
|
#include "minunit.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#define MKTEMP _mktemp
|
||||||
|
#define UNLINK _unlink
|
||||||
|
#else
|
||||||
|
#define MKTEMP mkstemp
|
||||||
|
#define UNLINK unlink
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||||
|
static char XFILE[L_tmpnam + 1] = {0};
|
||||||
|
static char RFILE[L_tmpnam + 1] = {0};
|
||||||
|
static char WFILE[L_tmpnam + 1] = {0};
|
||||||
|
|
||||||
|
void test_setup(void) {
|
||||||
|
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||||
|
strncpy(XFILE, "x-XXXXXX\0", L_tmpnam);
|
||||||
|
strncpy(RFILE, "r-XXXXXX\0", L_tmpnam);
|
||||||
|
strncpy(WFILE, "w-XXXXXX\0", L_tmpnam);
|
||||||
|
|
||||||
|
MKTEMP(ZIPNAME);
|
||||||
|
MKTEMP(XFILE);
|
||||||
|
MKTEMP(RFILE);
|
||||||
|
MKTEMP(WFILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_teardown(void) {
|
||||||
|
UNLINK(WFILE);
|
||||||
|
UNLINK(RFILE);
|
||||||
|
UNLINK(XFILE);
|
||||||
|
UNLINK(ZIPNAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
|
#define MZ_FILE_STAT_STRUCT _stat
|
||||||
|
#define MZ_FILE_STAT _stat
|
||||||
|
#else
|
||||||
|
#define MZ_FILE_STAT_STRUCT stat
|
||||||
|
#define MZ_FILE_STAT stat
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define XMODE 0100777
|
||||||
|
#define RMODE 0100444
|
||||||
|
#define WMODE 0100666
|
||||||
|
#define UNIXMODE 0100600
|
||||||
|
|
||||||
|
MU_TEST(test_exe_permissions) {
|
||||||
|
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||||
|
|
||||||
|
const char *filenames[] = {XFILE};
|
||||||
|
FILE *f = fopen(XFILE, "w");
|
||||||
|
fclose(f);
|
||||||
|
chmod(XFILE, XMODE);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_create(ZIPNAME, filenames, 1));
|
||||||
|
remove(XFILE);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, MZ_FILE_STAT(XFILE, &file_stats));
|
||||||
|
mu_assert_int_eq(XMODE, file_stats.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_read_permissions) {
|
||||||
|
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||||
|
|
||||||
|
const char *filenames[] = {RFILE};
|
||||||
|
FILE *f = fopen(RFILE, "w");
|
||||||
|
fclose(f);
|
||||||
|
chmod(RFILE, RMODE);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_create(ZIPNAME, filenames, 1));
|
||||||
|
remove(RFILE);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||||
|
mu_assert_int_eq(0, MZ_FILE_STAT(RFILE, &file_stats));
|
||||||
|
mu_assert_int_eq(RMODE, file_stats.st_mode);
|
||||||
|
|
||||||
|
// chmod from 444 to 666 to be able delete the file on windows
|
||||||
|
chmod(RFILE, WMODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_write_permissions) {
|
||||||
|
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||||
|
|
||||||
|
const char *filenames[] = {WFILE};
|
||||||
|
FILE *f = fopen(WFILE, "w");
|
||||||
|
fclose(f);
|
||||||
|
chmod(WFILE, WMODE);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_create(ZIPNAME, filenames, 1));
|
||||||
|
remove(WFILE);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||||
|
mu_assert_int_eq(0, MZ_FILE_STAT(WFILE, &file_stats));
|
||||||
|
mu_assert_int_eq(WMODE, file_stats.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TESTDATA1 "Some test data 1...\0"
|
||||||
|
|
||||||
|
MU_TEST(test_unix_permissions) {
|
||||||
|
// UNIX or APPLE
|
||||||
|
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, RFILE));
|
||||||
|
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, MZ_FILE_STAT(RFILE, &file_stats));
|
||||||
|
|
||||||
|
mu_assert_int_eq(UNIXMODE, file_stats.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_mtime) {
|
||||||
|
struct MZ_FILE_STAT_STRUCT file_stat1, file_stat2;
|
||||||
|
|
||||||
|
const char *filename = "test.data";
|
||||||
|
FILE *stream = NULL;
|
||||||
|
struct zip_t *zip = NULL;
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
if (0 != fopen_s(&stream, filename, "w+"))
|
||||||
|
#else
|
||||||
|
if (!(stream = fopen(filename, "w+")))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
mu_fail("Cannot open filename\n");
|
||||||
|
}
|
||||||
|
fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream);
|
||||||
|
mu_assert_int_eq(0, fclose(stream));
|
||||||
|
|
||||||
|
memset(&file_stat1, 0, sizeof(file_stat1));
|
||||||
|
memset(&file_stat2, 0, sizeof(file_stat2));
|
||||||
|
|
||||||
|
zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, filename));
|
||||||
|
mu_assert_int_eq(0, zip_entry_fwrite(zip, filename));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, MZ_FILE_STAT(filename, &file_stat1));
|
||||||
|
remove(filename);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||||
|
mu_assert_int_eq(0, MZ_FILE_STAT(filename, &file_stat2));
|
||||||
|
remove(filename);
|
||||||
|
|
||||||
|
fprintf(stdout, "file_stat1.st_mtime: %lu\n", file_stat1.st_mtime);
|
||||||
|
fprintf(stdout, "file_stat2.st_mtime: %lu\n", file_stat2.st_mtime);
|
||||||
|
mu_check(labs(file_stat1.st_mtime - file_stat2.st_mtime) <= 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(test_permissions_suite) {
|
||||||
|
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__WIN32__)
|
||||||
|
#else
|
||||||
|
MU_RUN_TEST(test_exe_permissions);
|
||||||
|
MU_RUN_TEST(test_read_permissions);
|
||||||
|
MU_RUN_TEST(test_write_permissions);
|
||||||
|
MU_RUN_TEST(test_unix_permissions);
|
||||||
|
#endif
|
||||||
|
MU_RUN_TEST(test_mtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNUSED(x) (void)x
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
UNUSED(argc);
|
||||||
|
UNUSED(argv);
|
||||||
|
|
||||||
|
MU_RUN_SUITE(test_permissions_suite);
|
||||||
|
MU_REPORT();
|
||||||
|
return MU_EXIT_CODE;
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <zip.h>
|
||||||
|
|
||||||
|
#include "minunit.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#define MKTEMP _mktemp
|
||||||
|
#else
|
||||||
|
#define MKTEMP mkstemp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||||
|
|
||||||
|
#define CRC32DATA1 2220805626
|
||||||
|
#define TESTDATA1 "Some test data 1...\0"
|
||||||
|
|
||||||
|
#define TESTDATA2 "Some test data 2...\0"
|
||||||
|
#define CRC32DATA2 2532008468
|
||||||
|
|
||||||
|
void test_setup(void) {
|
||||||
|
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||||
|
MKTEMP(ZIPNAME);
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
|
|
||||||
|
zip_entry_open(zip, "test/test-1.txt");
|
||||||
|
zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
|
||||||
|
zip_entry_open(zip, "test\\test-2.txt");
|
||||||
|
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
|
||||||
|
zip_entry_open(zip, "test\\empty/");
|
||||||
|
zip_entry_close(zip);
|
||||||
|
|
||||||
|
zip_entry_open(zip, "empty/");
|
||||||
|
zip_entry_close(zip);
|
||||||
|
|
||||||
|
zip_entry_open(zip, "dotfiles/.test");
|
||||||
|
zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2));
|
||||||
|
zip_entry_close(zip);
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_teardown(void) { remove(ZIPNAME); }
|
||||||
|
|
||||||
|
MU_TEST(test_read) {
|
||||||
|
char *buf = NULL;
|
||||||
|
ssize_t bufsize;
|
||||||
|
size_t buftmp;
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
mu_assert_int_eq(1, zip_is64(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test\\test-1.txt"));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||||
|
bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA1), bufsize);
|
||||||
|
mu_assert_int_eq((size_t)bufsize, buftmp);
|
||||||
|
mu_assert_int_eq(0, strncmp(buf, TESTDATA1, bufsize));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt"));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
|
||||||
|
bufsize = zip_entry_read(zip, (void **)&buf, NULL);
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA2), (size_t)bufsize);
|
||||||
|
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, (size_t)bufsize));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test\\empty/"));
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/empty/"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_size(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_noallocread) {
|
||||||
|
ssize_t bufsize;
|
||||||
|
size_t buftmp = strlen(TESTDATA2);
|
||||||
|
char *buf = calloc(buftmp, sizeof(char));
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
mu_assert_int_eq(1, zip_is64(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt"));
|
||||||
|
bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp);
|
||||||
|
mu_assert_int_eq(buftmp, (size_t)bufsize);
|
||||||
|
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, buftmp));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
buftmp = strlen(TESTDATA1);
|
||||||
|
buf = calloc(buftmp, sizeof(char));
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt"));
|
||||||
|
bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp);
|
||||||
|
mu_assert_int_eq(buftmp, (size_t)bufsize);
|
||||||
|
mu_assert_int_eq(0, strncmp(buf, TESTDATA1, buftmp));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
buftmp = strlen(TESTDATA2);
|
||||||
|
buf = calloc(buftmp, sizeof(char));
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "dotfiles/.test"));
|
||||||
|
bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp);
|
||||||
|
mu_assert_int_eq(buftmp, (size_t)bufsize);
|
||||||
|
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, buftmp));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
free(buf);
|
||||||
|
buf = NULL;
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(test_read_suite) {
|
||||||
|
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||||
|
|
||||||
|
MU_RUN_TEST(test_read);
|
||||||
|
MU_RUN_TEST(test_noallocread);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNUSED(x) (void)x
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
UNUSED(argc);
|
||||||
|
UNUSED(argv);
|
||||||
|
|
||||||
|
MU_RUN_SUITE(test_read_suite);
|
||||||
|
MU_REPORT();
|
||||||
|
return MU_EXIT_CODE;
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <zip.h>
|
||||||
|
|
||||||
|
#include "minunit.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#define MKTEMP _mktemp
|
||||||
|
#define UNLINK _unlink
|
||||||
|
#else
|
||||||
|
#define MKTEMP mkstemp
|
||||||
|
#define UNLINK unlink
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char ZIPNAME[L_tmpnam + 1] = {0};
|
||||||
|
static char WFILE[L_tmpnam + 1] = {0};
|
||||||
|
|
||||||
|
void test_setup(void) {
|
||||||
|
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
|
||||||
|
strncpy(WFILE, "w-XXXXXX\0", L_tmpnam);
|
||||||
|
|
||||||
|
MKTEMP(ZIPNAME);
|
||||||
|
MKTEMP(WFILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_teardown(void) {
|
||||||
|
UNLINK(WFILE);
|
||||||
|
UNLINK(ZIPNAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CRC32DATA1 2220805626
|
||||||
|
#define TESTDATA1 "Some test data 1...\0"
|
||||||
|
|
||||||
|
MU_TEST(test_write) {
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
||||||
|
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_index(zip));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(1, zip_is64(zip));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_write_utf) {
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, "тест/Если-б-не-было-войны.txt"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
||||||
|
mu_assert_int_eq(
|
||||||
|
0, strcmp(zip_entry_name(zip), "тест/Если-б-не-было-войны.txt"));
|
||||||
|
mu_assert_int_eq(0, zip_entry_index(zip));
|
||||||
|
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
|
||||||
|
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
|
||||||
|
mu_assert_int_eq(1, zip_is64(zip));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(test_fwrite) {
|
||||||
|
const char *filename = WFILE;
|
||||||
|
FILE *stream = NULL;
|
||||||
|
struct zip_t *zip = NULL;
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
if (0 != fopen_s(&stream, filename, "w+"))
|
||||||
|
#else
|
||||||
|
if (!(stream = fopen(filename, "w+")))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// Cannot open filename
|
||||||
|
mu_fail("Cannot open filename\n");
|
||||||
|
}
|
||||||
|
fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream);
|
||||||
|
mu_assert_int_eq(0, fclose(stream));
|
||||||
|
|
||||||
|
zip = zip_open(ZIPNAME, 9, 'w');
|
||||||
|
mu_check(zip != NULL);
|
||||||
|
mu_assert_int_eq(0, zip_entry_open(zip, WFILE));
|
||||||
|
mu_assert_int_eq(0, zip_entry_fwrite(zip, WFILE));
|
||||||
|
mu_assert_int_eq(0, zip_entry_close(zip));
|
||||||
|
mu_assert_int_eq(1, zip_is64(zip));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(test_write_suite) {
|
||||||
|
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
|
||||||
|
|
||||||
|
MU_RUN_TEST(test_write);
|
||||||
|
MU_RUN_TEST(test_write_utf);
|
||||||
|
MU_RUN_TEST(test_fwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define UNUSED(x) (void)x
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
UNUSED(argc);
|
||||||
|
UNUSED(argv);
|
||||||
|
|
||||||
|
MU_RUN_SUITE(test_write_suite);
|
||||||
|
MU_REPORT();
|
||||||
|
return MU_EXIT_CODE;
|
||||||
|
}
|
Loading…
Reference in New Issue