Remove zip lib as code
parent
97d7f685ba
commit
62e1ea7e3c
|
@ -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,122 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.4)
|
|
||||||
|
|
||||||
project(zip
|
|
||||||
LANGUAGES C
|
|
||||||
VERSION "0.1.19")
|
|
||||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
|
||||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
|
||||||
option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
|
|
||||||
|
|
||||||
# zip
|
|
||||||
set(SRC src/miniz.h src/zip.h src/zip.c)
|
|
||||||
|
|
||||||
# this is the "object library" target: compiles the sources only once
|
|
||||||
add_library(OBJLIB OBJECT ${SRC})
|
|
||||||
# shared libraries need PIC
|
|
||||||
set_property(TARGET OBJLIB PROPERTY POSITION_INDEPENDENT_CODE 1)
|
|
||||||
|
|
||||||
# static and shared libraries built from the same object files
|
|
||||||
if (BUILD_SHARED_LIBS)
|
|
||||||
add_library(${PROJECT_NAME} SHARED $<TARGET_OBJECTS:OBJLIB>)
|
|
||||||
include(GenerateExportHeader)
|
|
||||||
generate_export_header(${PROJECT_NAME})
|
|
||||||
else()
|
|
||||||
add_library(${PROJECT_NAME} STATIC $<TARGET_OBJECTS:OBJLIB>)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
|
||||||
$<INSTALL_INTERFACE:include>
|
|
||||||
)
|
|
||||||
|
|
||||||
# test
|
|
||||||
if (NOT CMAKE_DISABLE_TESTING)
|
|
||||||
enable_testing()
|
|
||||||
add_subdirectory(test)
|
|
||||||
find_package(Sanitizers)
|
|
||||||
add_sanitizers(${PROJECT_NAME} ${test_out})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (MSVC)
|
|
||||||
# Use secure functions by default and suppress warnings about "deprecated" functions
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
|
|
||||||
elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
|
|
||||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
|
|
||||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -Werror -pedantic -Wno-deprecated")
|
|
||||||
endif (MSVC)
|
|
||||||
|
|
||||||
####
|
|
||||||
# Installation (https://github.com/forexample/package-example) {
|
|
||||||
|
|
||||||
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
|
|
||||||
set(INCLUDE_INSTALL_DIR "include")
|
|
||||||
|
|
||||||
set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
|
|
||||||
set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
|
|
||||||
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
|
|
||||||
set(NAMESPACE "${PROJECT_NAME}::")
|
|
||||||
|
|
||||||
# Include module with fuction 'write_basic_package_version_file'
|
|
||||||
include(CMakePackageConfigHelpers)
|
|
||||||
|
|
||||||
# Note: PROJECT_VERSION is used as a VERSION
|
|
||||||
write_basic_package_version_file(
|
|
||||||
"${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion
|
|
||||||
)
|
|
||||||
|
|
||||||
# Use variables:
|
|
||||||
# * TARGETS_EXPORT_NAME
|
|
||||||
# * PROJECT_NAME
|
|
||||||
configure_package_config_file(
|
|
||||||
"cmake/Config.cmake.in"
|
|
||||||
"${PROJECT_CONFIG}"
|
|
||||||
INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
|
|
||||||
)
|
|
||||||
|
|
||||||
install(
|
|
||||||
FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
|
|
||||||
DESTINATION "${CONFIG_INSTALL_DIR}"
|
|
||||||
)
|
|
||||||
|
|
||||||
install(
|
|
||||||
EXPORT "${TARGETS_EXPORT_NAME}"
|
|
||||||
NAMESPACE "${NAMESPACE}"
|
|
||||||
DESTINATION "${CONFIG_INSTALL_DIR}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# }
|
|
||||||
|
|
||||||
install(TARGETS ${PROJECT_NAME}
|
|
||||||
EXPORT ${TARGETS_EXPORT_NAME}
|
|
||||||
RUNTIME DESTINATION bin
|
|
||||||
ARCHIVE DESTINATION lib
|
|
||||||
LIBRARY DESTINATION lib
|
|
||||||
INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR}
|
|
||||||
)
|
|
||||||
install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION ${INCLUDE_INSTALL_DIR}/zip)
|
|
||||||
|
|
||||||
# uninstall target (https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake)
|
|
||||||
if(NOT TARGET uninstall)
|
|
||||||
configure_file(
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake"
|
|
||||||
IMMEDIATE @ONLY)
|
|
||||||
|
|
||||||
add_custom_target(uninstall
|
|
||||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(Doxygen)
|
|
||||||
if(DOXYGEN_FOUND)
|
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
|
|
||||||
add_custom_target(doc
|
|
||||||
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
|
||||||
COMMENT "Generating API documentation with Doxygen" VERBATIM)
|
|
||||||
endif()
|
|
|
@ -1,469 +0,0 @@
|
||||||
### A portable (OSX/Linux/Windows), simple zip library written in C
|
|
||||||
This is done by hacking awesome [miniz](https://code.google.com/p/miniz) library and layering functions on top of the miniz v1.15 API.
|
|
||||||
|
|
||||||
[![Build](https://github.com/kuba--/zip/workflows/build/badge.svg)](https://github.com/kuba--/zip/actions?query=workflow%3Abuild)
|
|
||||||
|
|
||||||
|
|
||||||
# The Idea
|
|
||||||
<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.
|
|
||||||
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 wanted something powerfull and small enough, so I could add just a few files and compile them into my project.
|
|
||||||
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.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
* Create a new zip archive with default compression level.
|
|
||||||
```c
|
|
||||||
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
|
||||||
{
|
|
||||||
zip_entry_open(zip, "foo-1.txt");
|
|
||||||
{
|
|
||||||
const char *buf = "Some data here...\0";
|
|
||||||
zip_entry_write(zip, buf, strlen(buf));
|
|
||||||
}
|
|
||||||
zip_entry_close(zip);
|
|
||||||
|
|
||||||
zip_entry_open(zip, "foo-2.txt");
|
|
||||||
{
|
|
||||||
// merge 3 files into one entry and compress them on-the-fly.
|
|
||||||
zip_entry_fwrite(zip, "foo-2.1.txt");
|
|
||||||
zip_entry_fwrite(zip, "foo-2.2.txt");
|
|
||||||
zip_entry_fwrite(zip, "foo-2.3.txt");
|
|
||||||
}
|
|
||||||
zip_entry_close(zip);
|
|
||||||
}
|
|
||||||
zip_close(zip);
|
|
||||||
```
|
|
||||||
|
|
||||||
* Append to the existing zip archive.
|
|
||||||
```c
|
|
||||||
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
|
|
||||||
{
|
|
||||||
zip_entry_open(zip, "foo-3.txt");
|
|
||||||
{
|
|
||||||
const char *buf = "Append some data here...\0";
|
|
||||||
zip_entry_write(zip, buf, strlen(buf));
|
|
||||||
}
|
|
||||||
zip_entry_close(zip);
|
|
||||||
}
|
|
||||||
zip_close(zip);
|
|
||||||
```
|
|
||||||
|
|
||||||
* Extract a zip archive into a folder.
|
|
||||||
```c
|
|
||||||
int on_extract_entry(const char *filename, void *arg) {
|
|
||||||
static int i = 0;
|
|
||||||
int n = *(int *)arg;
|
|
||||||
printf("Extracted: %s (%d of %d)\n", filename, ++i, n);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int arg = 2;
|
|
||||||
zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
|
|
||||||
```
|
|
||||||
|
|
||||||
* Extract a zip entry into memory.
|
|
||||||
```c
|
|
||||||
void *buf = NULL;
|
|
||||||
size_t bufsize;
|
|
||||||
|
|
||||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
|
||||||
{
|
|
||||||
zip_entry_open(zip, "foo-1.txt");
|
|
||||||
{
|
|
||||||
zip_entry_read(zip, &buf, &bufsize);
|
|
||||||
}
|
|
||||||
zip_entry_close(zip);
|
|
||||||
}
|
|
||||||
zip_close(zip);
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
```
|
|
||||||
|
|
||||||
* Extract a zip entry into memory (no internal allocation).
|
|
||||||
```c
|
|
||||||
unsigned char *buf;
|
|
||||||
size_t bufsize;
|
|
||||||
|
|
||||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
|
||||||
{
|
|
||||||
zip_entry_open(zip, "foo-1.txt");
|
|
||||||
{
|
|
||||||
bufsize = zip_entry_size(zip);
|
|
||||||
buf = calloc(sizeof(unsigned char), bufsize);
|
|
||||||
|
|
||||||
zip_entry_noallocread(zip, (void *)buf, bufsize);
|
|
||||||
}
|
|
||||||
zip_entry_close(zip);
|
|
||||||
}
|
|
||||||
zip_close(zip);
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
```
|
|
||||||
|
|
||||||
* Extract a zip entry into memory using callback.
|
|
||||||
```c
|
|
||||||
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) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct buffer_t buf = {0};
|
|
||||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
|
||||||
{
|
|
||||||
zip_entry_open(zip, "foo-1.txt");
|
|
||||||
{
|
|
||||||
zip_entry_extract(zip, on_extract, &buf);
|
|
||||||
}
|
|
||||||
zip_entry_close(zip);
|
|
||||||
}
|
|
||||||
zip_close(zip);
|
|
||||||
|
|
||||||
free(buf.data);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
* Extract a zip entry into a file.
|
|
||||||
```c
|
|
||||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
|
||||||
{
|
|
||||||
zip_entry_open(zip, "foo-2.txt");
|
|
||||||
{
|
|
||||||
zip_entry_fread(zip, "foo-2.txt");
|
|
||||||
}
|
|
||||||
zip_entry_close(zip);
|
|
||||||
}
|
|
||||||
zip_close(zip);
|
|
||||||
```
|
|
||||||
|
|
||||||
* Create a new zip archive in memory (stream API).
|
|
||||||
|
|
||||||
```c
|
|
||||||
char *outbuf = NULL;
|
|
||||||
size_t outbufsize = 0;
|
|
||||||
|
|
||||||
const char *inbuf = "Append some data here...\0";
|
|
||||||
struct zip_t *zip = zip_stream_open(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
|
||||||
{
|
|
||||||
zip_entry_open(zip, "foo-1.txt");
|
|
||||||
{
|
|
||||||
zip_entry_write(zip, inbuf, strlen(inbuf));
|
|
||||||
}
|
|
||||||
zip_entry_close(zip);
|
|
||||||
|
|
||||||
/* copy compressed stream into outbuf */
|
|
||||||
zip_stream_copy(zip, (void **)&outbuf, &outbufsize);
|
|
||||||
}
|
|
||||||
zip_stream_close(zip);
|
|
||||||
|
|
||||||
free(outbuf);
|
|
||||||
```
|
|
||||||
|
|
||||||
* Extract a zip entry into a memory (stream API).
|
|
||||||
|
|
||||||
```c
|
|
||||||
char *buf = NULL;
|
|
||||||
ssize_t bufsize = 0;
|
|
||||||
|
|
||||||
struct zip_t *zip = zip_stream_open(zipstream, zipstreamsize, 0, 'r');
|
|
||||||
{
|
|
||||||
zip_entry_open(zip, "foo-1.txt");
|
|
||||||
{
|
|
||||||
zip_entry_read(zip, (void **)&buf, &bufsize);
|
|
||||||
}
|
|
||||||
zip_entry_close(zip);
|
|
||||||
}
|
|
||||||
zip_stream_close(zip);
|
|
||||||
|
|
||||||
free(buf);
|
|
||||||
```
|
|
||||||
|
|
||||||
* List of all zip entries
|
|
||||||
```c
|
|
||||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
|
||||||
int i, n = zip_entries_total(zip);
|
|
||||||
for (i = 0; i < n; ++i) {
|
|
||||||
zip_entry_openbyindex(zip, i);
|
|
||||||
{
|
|
||||||
const char *name = zip_entry_name(zip);
|
|
||||||
int isdir = zip_entry_isdir(zip);
|
|
||||||
unsigned long long size = zip_entry_size(zip);
|
|
||||||
unsigned int crc32 = zip_entry_crc32(zip);
|
|
||||||
}
|
|
||||||
zip_entry_close(zip);
|
|
||||||
}
|
|
||||||
zip_close(zip);
|
|
||||||
```
|
|
||||||
|
|
||||||
* Compress folder (recursively)
|
|
||||||
```c
|
|
||||||
void zip_walk(struct zip_t *zip, const char *path) {
|
|
||||||
DIR *dir;
|
|
||||||
struct dirent *entry;
|
|
||||||
char fullpath[MAX_PATH];
|
|
||||||
struct stat s;
|
|
||||||
|
|
||||||
memset(fullpath, 0, MAX_PATH);
|
|
||||||
dir = opendir(path);
|
|
||||||
assert(dir);
|
|
||||||
|
|
||||||
while ((entry = readdir(dir))) {
|
|
||||||
// skip "." and ".."
|
|
||||||
if (!strcmp(entry->d_name, ".\0") || !strcmp(entry->d_name, "..\0"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entry->d_name);
|
|
||||||
stat(fullpath, &s);
|
|
||||||
if (S_ISDIR(s.st_mode))
|
|
||||||
zip_walk(zip, fullpath);
|
|
||||||
else {
|
|
||||||
zip_entry_open(zip, fullpath);
|
|
||||||
zip_entry_fwrite(zip, fullpath);
|
|
||||||
zip_entry_close(zip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
* Deletes zip archive entries.
|
|
||||||
```c
|
|
||||||
char *entries[] = {"unused.txt", "remove.ini", "delete.me"};
|
|
||||||
|
|
||||||
struct zip_t *zip = zip_open("foo.zip", 0, 'd');
|
|
||||||
{
|
|
||||||
zip_entries_delete(zip, entries, 3);
|
|
||||||
}
|
|
||||||
zip_close(zip);
|
|
||||||
```
|
|
||||||
|
|
||||||
# Bindings
|
|
||||||
Compile zip library as a dynamic library.
|
|
||||||
```shell
|
|
||||||
$ mkdir build
|
|
||||||
$ cd build
|
|
||||||
$ cmake -DBUILD_SHARED_LIBS=true ..
|
|
||||||
$ make
|
|
||||||
```
|
|
||||||
|
|
||||||
### [Go](https://golang.org) (cgo)
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo CFLAGS: -I../src
|
|
||||||
#cgo LDFLAGS: -L. -lzip
|
|
||||||
#include <zip.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
path := C.CString("/tmp/go.zip")
|
|
||||||
zip := C.zip_open(path, 6, 'w')
|
|
||||||
|
|
||||||
entryname := C.CString("test")
|
|
||||||
C.zip_entry_open(zip, entryname)
|
|
||||||
|
|
||||||
content := "test content"
|
|
||||||
buf := unsafe.Pointer(C.CString(content))
|
|
||||||
bufsize := C.size_t(len(content))
|
|
||||||
C.zip_entry_write(zip, buf, bufsize)
|
|
||||||
|
|
||||||
C.zip_entry_close(zip)
|
|
||||||
|
|
||||||
C.zip_close(zip)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### [Rust](https://www.rust-lang.org) (ffi)
|
|
||||||
```rust
|
|
||||||
extern crate libc;
|
|
||||||
use std::ffi::CString;
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Zip {
|
|
||||||
_private: [u8; 0],
|
|
||||||
}
|
|
||||||
|
|
||||||
#[link(name = "zip")]
|
|
||||||
extern "C" {
|
|
||||||
fn zip_open(path: *const libc::c_char, level: libc::c_int, mode: libc::c_char) -> *mut Zip;
|
|
||||||
fn zip_close(zip: *mut Zip) -> libc::c_void;
|
|
||||||
|
|
||||||
fn zip_entry_open(zip: *mut Zip, entryname: *const libc::c_char) -> libc::c_int;
|
|
||||||
fn zip_entry_close(zip: *mut Zip) -> libc::c_int;
|
|
||||||
fn zip_entry_write(
|
|
||||||
zip: *mut Zip,
|
|
||||||
buf: *const libc::c_void,
|
|
||||||
bufsize: libc::size_t,
|
|
||||||
) -> libc::c_int;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let path = CString::new("/tmp/rust.zip").unwrap();
|
|
||||||
let mode: libc::c_char = 'w' as libc::c_char;
|
|
||||||
|
|
||||||
let entryname = CString::new("test.txt").unwrap();
|
|
||||||
let content = "test content\0";
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let zip: *mut Zip = zip_open(path.as_ptr(), 5, mode);
|
|
||||||
{
|
|
||||||
zip_entry_open(zip, entryname.as_ptr());
|
|
||||||
{
|
|
||||||
let buf = content.as_ptr() as *const libc::c_void;
|
|
||||||
let bufsize = content.len() as libc::size_t;
|
|
||||||
zip_entry_write(zip, buf, bufsize);
|
|
||||||
}
|
|
||||||
zip_entry_close(zip);
|
|
||||||
}
|
|
||||||
zip_close(zip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### [Ruby](http://www.ruby-lang.org) (ffi)
|
|
||||||
Install _ffi_ gem.
|
|
||||||
```shell
|
|
||||||
$ gem install ffi
|
|
||||||
```
|
|
||||||
|
|
||||||
Bind in your module.
|
|
||||||
```ruby
|
|
||||||
require 'ffi'
|
|
||||||
|
|
||||||
module Zip
|
|
||||||
extend FFI::Library
|
|
||||||
ffi_lib "./libzip.#{::FFI::Platform::LIBSUFFIX}"
|
|
||||||
|
|
||||||
attach_function :zip_open, [:string, :int, :char], :pointer
|
|
||||||
attach_function :zip_close, [:pointer], :void
|
|
||||||
|
|
||||||
attach_function :zip_entry_open, [:pointer, :string], :int
|
|
||||||
attach_function :zip_entry_close, [:pointer], :void
|
|
||||||
attach_function :zip_entry_write, [:pointer, :string, :int], :int
|
|
||||||
end
|
|
||||||
|
|
||||||
ptr = Zip.zip_open("/tmp/ruby.zip", 6, "w".bytes()[0])
|
|
||||||
|
|
||||||
status = Zip.zip_entry_open(ptr, "test")
|
|
||||||
|
|
||||||
content = "test content"
|
|
||||||
status = Zip.zip_entry_write(ptr, content, content.size())
|
|
||||||
|
|
||||||
Zip.zip_entry_close(ptr)
|
|
||||||
Zip.zip_close(ptr)
|
|
||||||
```
|
|
||||||
|
|
||||||
### [Python](https://www.python.org) (cffi)
|
|
||||||
Install _cffi_ package
|
|
||||||
```shell
|
|
||||||
$ pip install cffi
|
|
||||||
```
|
|
||||||
|
|
||||||
Bind in your package.
|
|
||||||
```python
|
|
||||||
import ctypes.util
|
|
||||||
from cffi import FFI
|
|
||||||
|
|
||||||
ffi = FFI()
|
|
||||||
ffi.cdef("""
|
|
||||||
struct zip_t *zip_open(const char *zipname, int level, char mode);
|
|
||||||
void zip_close(struct zip_t *zip);
|
|
||||||
|
|
||||||
int zip_entry_open(struct zip_t *zip, const char *entryname);
|
|
||||||
int zip_entry_close(struct zip_t *zip);
|
|
||||||
int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
|
|
||||||
""")
|
|
||||||
|
|
||||||
Zip = ffi.dlopen(ctypes.util.find_library("zip"))
|
|
||||||
|
|
||||||
ptr = Zip.zip_open("/tmp/python.zip", 6, 'w')
|
|
||||||
|
|
||||||
status = Zip.zip_entry_open(ptr, "test")
|
|
||||||
|
|
||||||
content = "test content"
|
|
||||||
status = Zip.zip_entry_write(ptr, content, len(content))
|
|
||||||
|
|
||||||
Zip.zip_entry_close(ptr)
|
|
||||||
Zip.zip_close(ptr)
|
|
||||||
```
|
|
||||||
|
|
||||||
### [Never](https://never-lang.readthedocs.io/) (ffi)
|
|
||||||
```never
|
|
||||||
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_entry_open(zip: c_ptr, entryname: string) -> int
|
|
||||||
extern "libzip.so" func zip_entry_close(zip: c_ptr) -> int
|
|
||||||
extern "libzip.so" func zip_entry_write(zip: c_ptr, buf: string, bufsize: int) -> int
|
|
||||||
extern "libzip.so" func zip_entry_fwrite(zip: c_ptr, filename: string) -> int
|
|
||||||
|
|
||||||
func main() -> int
|
|
||||||
{
|
|
||||||
let content = "Test content"
|
|
||||||
|
|
||||||
let zip = zip_open("/tmp/never.zip", 6, 'w');
|
|
||||||
|
|
||||||
zip_entry_open(zip, "test.file");
|
|
||||||
zip_entry_fwrite(zip, "/tmp/test.txt");
|
|
||||||
zip_entry_close(zip);
|
|
||||||
|
|
||||||
zip_entry_open(zip, "test.content");
|
|
||||||
zip_entry_write(zip, content, length(content));
|
|
||||||
zip_entry_close(zip);
|
|
||||||
|
|
||||||
zip_close(zip);
|
|
||||||
0
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### [Ring](http://ring-lang.net)
|
|
||||||
The language comes with RingZip based on this library
|
|
||||||
```ring
|
|
||||||
load "ziplib.ring"
|
|
||||||
|
|
||||||
new Zip {
|
|
||||||
setFileName("myfile.zip")
|
|
||||||
open("w")
|
|
||||||
newEntry() {
|
|
||||||
open("test.c")
|
|
||||||
writefile("test.c")
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
- [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)
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
This is free and unencumbered software released into the public domain.
|
|
||||||
|
|
||||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
||||||
distribute this software, either in source code form or as a compiled
|
|
||||||
binary, for any purpose, commercial or non-commercial, and by any
|
|
||||||
means.
|
|
||||||
|
|
||||||
In jurisdictions that recognize copyright laws, the author or authors
|
|
||||||
of this software dedicate any and all copyright interest in the
|
|
||||||
software to the public domain. We make this dedication for the benefit
|
|
||||||
of the public at large and to the detriment of our heirs and
|
|
||||||
successors. We intend this dedication to be an overt act of
|
|
||||||
relinquishment in perpetuity of all present and future rights to this
|
|
||||||
software under copyright law.
|
|
||||||
|
|
||||||
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 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.
|
|
||||||
|
|
||||||
For more information, please refer to <http://unlicense.org/>
|
|
||||||
*/
|
|
|
@ -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"
|
|
|
@ -1,55 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# The MIT License (MIT)
|
|
||||||
#
|
|
||||||
# Copyright (c)
|
|
||||||
# 2013 Matthew Arsenault
|
|
||||||
# 2015-2016 RWTH Aachen University, Federal Republic of Germany
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
# This script is a wrapper for AddressSanitizer. In some special cases you need
|
|
||||||
# to preload AddressSanitizer to avoid error messages - e.g. if you're
|
|
||||||
# preloading another library to your application. At the moment this script will
|
|
||||||
# only do something, if we're running on a Linux platform. OSX might not be
|
|
||||||
# affected.
|
|
||||||
|
|
||||||
|
|
||||||
# Exit immediately, if platform is not Linux.
|
|
||||||
if [ "$(uname)" != "Linux" ]
|
|
||||||
then
|
|
||||||
exec $@
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# Get the used libasan of the application ($1). If a libasan was found, it will
|
|
||||||
# be prepended to LD_PRELOAD.
|
|
||||||
libasan=$(ldd $1 | grep libasan | sed "s/^[[:space:]]//" | cut -d' ' -f1)
|
|
||||||
if [ -n "$libasan" ]
|
|
||||||
then
|
|
||||||
if [ -n "$LD_PRELOAD" ]
|
|
||||||
then
|
|
||||||
export LD_PRELOAD="$libasan:$LD_PRELOAD"
|
|
||||||
else
|
|
||||||
export LD_PRELOAD="$libasan"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Execute the application.
|
|
||||||
exec $@
|
|
|
@ -1,23 +0,0 @@
|
||||||
# copied from https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake
|
|
||||||
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
|
|
||||||
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
|
|
||||||
endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
|
|
||||||
|
|
||||||
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
|
|
||||||
string(REGEX REPLACE "\n" ";" files "${files}")
|
|
||||||
foreach(file ${files})
|
|
||||||
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
|
|
||||||
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
|
||||||
exec_program(
|
|
||||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
|
||||||
OUTPUT_VARIABLE rm_out
|
|
||||||
RETURN_VALUE rm_retval
|
|
||||||
)
|
|
||||||
if(NOT "${rm_retval}" STREQUAL 0)
|
|
||||||
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
|
|
||||||
endif(NOT "${rm_retval}" STREQUAL 0)
|
|
||||||
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
|
||||||
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
|
|
||||||
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
|
||||||
endforeach(file)
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,413 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#ifndef ZIP_H
|
|
||||||
#define ZIP_H
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(_POSIX_C_SOURCE) && defined(_MSC_VER)
|
|
||||||
// 64-bit Windows is the only mainstream platform
|
|
||||||
// where sizeof(long) != sizeof(void*)
|
|
||||||
#ifdef _WIN64
|
|
||||||
typedef long long ssize_t; /* byte count or error */
|
|
||||||
#else
|
|
||||||
typedef long ssize_t; /* byte count or error */
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MAX_PATH
|
|
||||||
#define MAX_PATH 32767 /* # chars in a path name including NULL */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @mainpage
|
|
||||||
*
|
|
||||||
* Documenation for @ref zip.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @addtogroup zip
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default zip compression level.
|
|
||||||
*/
|
|
||||||
#define ZIP_DEFAULT_COMPRESSION_LEVEL 6
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error codes
|
|
||||||
*/
|
|
||||||
#define ZIP_ENOINIT -1 // not initialized
|
|
||||||
#define ZIP_EINVENTNAME -2 // invalid entry name
|
|
||||||
#define ZIP_ENOENT -3 // entry not found
|
|
||||||
#define ZIP_EINVMODE -4 // invalid zip mode
|
|
||||||
#define ZIP_EINVLVL -5 // invalid compression level
|
|
||||||
#define ZIP_ENOSUP64 -6 // no zip 64 support
|
|
||||||
#define ZIP_EMEMSET -7 // memset error
|
|
||||||
#define ZIP_EWRTENT -8 // cannot write data to entry
|
|
||||||
#define ZIP_ETDEFLINIT -9 // cannot initialize tdefl compressor
|
|
||||||
#define ZIP_EINVIDX -10 // invalid index
|
|
||||||
#define ZIP_ENOHDR -11 // header not found
|
|
||||||
#define ZIP_ETDEFLBUF -12 // cannot flush tdefl buffer
|
|
||||||
#define ZIP_ECRTHDR -13 // cannot create entry header
|
|
||||||
#define ZIP_EWRTHDR -14 // cannot write entry header
|
|
||||||
#define ZIP_EWRTDIR -15 // cannot write to central dir
|
|
||||||
#define ZIP_EOPNFILE -16 // cannot open file
|
|
||||||
#define ZIP_EINVENTTYPE -17 // invalid entry type
|
|
||||||
#define ZIP_EMEMNOALLOC -18 // extracting data using no memory allocation
|
|
||||||
#define ZIP_ENOFILE -19 // file not found
|
|
||||||
#define ZIP_ENOPERM -20 // no permission
|
|
||||||
#define ZIP_EOOMEM -21 // out of memory
|
|
||||||
#define ZIP_EINVZIPNAME -22 // invalid zip archive name
|
|
||||||
#define ZIP_EMKDIR -23 // make dir error
|
|
||||||
#define ZIP_ESYMLINK -24 // symlink error
|
|
||||||
#define ZIP_ECLSZIP -25 // close archive error
|
|
||||||
#define ZIP_ECAPSIZE -26 // capacity size too small
|
|
||||||
#define ZIP_EFSEEK -27 // fseek error
|
|
||||||
#define ZIP_EFREAD -28 // fread error
|
|
||||||
#define ZIP_EFWRITE -29 // fwrite error
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Looks up the error message string coresponding to an error number.
|
|
||||||
* @param errnum error number
|
|
||||||
* @return error message string coresponding to errnum or NULL if error is not
|
|
||||||
* found.
|
|
||||||
*/
|
|
||||||
extern const char *zip_strerror(int errnum);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @struct zip_t
|
|
||||||
*
|
|
||||||
* This data structure is used throughout the library to represent zip archive -
|
|
||||||
* forward declaration.
|
|
||||||
*/
|
|
||||||
struct zip_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens zip archive with compression level using the given mode.
|
|
||||||
*
|
|
||||||
* @param zipname zip archive file name.
|
|
||||||
* @param level compression level (0-9 are the standard zlib-style levels).
|
|
||||||
* @param mode file access mode.
|
|
||||||
* - 'r': opens a file for reading/extracting (the file must exists).
|
|
||||||
* - 'w': creates an empty file for writing.
|
|
||||||
* - 'a': appends to an existing archive.
|
|
||||||
*
|
|
||||||
* @return the zip archive handler or NULL on error
|
|
||||||
*/
|
|
||||||
extern struct zip_t *zip_open(const char *zipname, int level, char mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the zip archive, releases resources - always finalize.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
*/
|
|
||||||
extern void zip_close(struct zip_t *zip);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the archive has a zip64 end of central directory headers.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
*
|
|
||||||
* @return the return code - 1 (true), 0 (false), negative number (< 0) on
|
|
||||||
* error.
|
|
||||||
*/
|
|
||||||
extern int zip_is64(struct zip_t *zip);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens an entry by name in the zip archive.
|
|
||||||
*
|
|
||||||
* For zip archive opened in 'w' or 'a' mode the function will append
|
|
||||||
* a new entry. In readonly mode the function tries to locate the entry
|
|
||||||
* in global dictionary.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
* @param entryname an entry name in local dictionary.
|
|
||||||
*
|
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_open(struct zip_t *zip, const char *entryname);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a new entry by index in the zip archive.
|
|
||||||
*
|
|
||||||
* This function is only valid if zip archive was opened in 'r' (readonly) mode.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
* @param index index in local dictionary.
|
|
||||||
*
|
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_openbyindex(struct zip_t *zip, int index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes a zip entry, flushes buffer and releases resources.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
*
|
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_close(struct zip_t *zip);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a local name of the current zip entry.
|
|
||||||
*
|
|
||||||
* The main difference between user's entry name and local entry name
|
|
||||||
* is optional relative path.
|
|
||||||
* Following .ZIP File Format Specification - the path stored MUST not contain
|
|
||||||
* a drive or device letter, or a leading slash.
|
|
||||||
* All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
|
|
||||||
* for compatibility with Amiga and UNIX file systems etc.
|
|
||||||
*
|
|
||||||
* @param zip: zip archive handler.
|
|
||||||
*
|
|
||||||
* @return the pointer to the current zip entry name, or NULL on error.
|
|
||||||
*/
|
|
||||||
extern const char *zip_entry_name(struct zip_t *zip);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an index of the current zip entry.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
*
|
|
||||||
* @return the index on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_index(struct zip_t *zip);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the current zip entry is a directory entry.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
*
|
|
||||||
* @return the return code - 1 (true), 0 (false), negative number (< 0) on
|
|
||||||
* error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_isdir(struct zip_t *zip);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an uncompressed size of the current zip entry.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
*
|
|
||||||
* @return the uncompressed size in bytes.
|
|
||||||
*/
|
|
||||||
extern unsigned long long zip_entry_size(struct zip_t *zip);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns CRC-32 checksum of the current zip entry.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
*
|
|
||||||
* @return the CRC-32 checksum.
|
|
||||||
*/
|
|
||||||
extern unsigned int zip_entry_crc32(struct zip_t *zip);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compresses an input buffer for the current zip entry.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
* @param buf input buffer.
|
|
||||||
* @param bufsize input buffer size (in bytes).
|
|
||||||
*
|
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compresses a file for the current zip entry.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
* @param filename input file.
|
|
||||||
*
|
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the current zip entry into output buffer.
|
|
||||||
*
|
|
||||||
* The function allocates sufficient memory for a output buffer.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
* @param buf output buffer.
|
|
||||||
* @param bufsize output buffer size (in bytes).
|
|
||||||
*
|
|
||||||
* @note remember to release memory allocated for a output buffer.
|
|
||||||
* for large entries, please take a look at zip_entry_extract function.
|
|
||||||
*
|
|
||||||
* @return the return code - the number of bytes actually read on success.
|
|
||||||
* Otherwise a -1 on error.
|
|
||||||
*/
|
|
||||||
extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the current zip entry into a memory buffer using no memory
|
|
||||||
* allocation.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
* @param buf preallocated output buffer.
|
|
||||||
* @param bufsize output buffer size (in bytes).
|
|
||||||
*
|
|
||||||
* @note ensure supplied output buffer is large enough.
|
|
||||||
* zip_entry_size function (returns uncompressed size for the current
|
|
||||||
* entry) can be handy to estimate how big buffer is needed.
|
|
||||||
* For large entries, please take a look at zip_entry_extract function.
|
|
||||||
*
|
|
||||||
* @return the return code - the number of bytes actually read on success.
|
|
||||||
* Otherwise a -1 on error (e.g. bufsize is not large enough).
|
|
||||||
*/
|
|
||||||
extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
|
|
||||||
size_t bufsize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the current zip entry into output file.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
* @param filename output file.
|
|
||||||
*
|
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_fread(struct zip_t *zip, const char *filename);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the current zip entry using a callback function (on_extract).
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
* @param on_extract callback function.
|
|
||||||
* @param arg opaque pointer (optional argument, which you can pass to the
|
|
||||||
* on_extract callback)
|
|
||||||
*
|
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int
|
|
||||||
zip_entry_extract(struct zip_t *zip,
|
|
||||||
size_t (*on_extract)(void *arg, unsigned long long offset,
|
|
||||||
const void *data, size_t size),
|
|
||||||
void *arg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of all entries (files and directories) in the zip archive.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
*
|
|
||||||
* @return the return code - the number of entries on success, negative number
|
|
||||||
* (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entries_total(struct zip_t *zip);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes zip archive entries.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
* @param entries array of zip archive 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.
|
|
||||||
*/
|
|
||||||
extern int zip_entries_delete(struct zip_t *zip, char *const entries[],
|
|
||||||
size_t len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts a zip archive stream into directory.
|
|
||||||
*
|
|
||||||
* If on_extract is not NULL, the callback will be called after
|
|
||||||
* successfully extracted each zip entry.
|
|
||||||
* Returning a negative value from the callback will cause abort and return an
|
|
||||||
* error. The last argument (void *arg) is optional, which you can use to pass
|
|
||||||
* data to the on_extract callback.
|
|
||||||
*
|
|
||||||
* @param stream zip archive stream.
|
|
||||||
* @param size stream size.
|
|
||||||
* @param dir output directory.
|
|
||||||
* @param on_extract on extract callback.
|
|
||||||
* @param arg opaque pointer.
|
|
||||||
*
|
|
||||||
* @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,
|
|
||||||
int (*on_extract)(const char *filename,
|
|
||||||
void *arg),
|
|
||||||
void *arg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens zip archive stream into memory.
|
|
||||||
*
|
|
||||||
* @param stream zip archive stream.
|
|
||||||
* @param size stream size.
|
|
||||||
*
|
|
||||||
* @return the zip archive handler or NULL on error
|
|
||||||
*/
|
|
||||||
extern struct zip_t *zip_stream_open(const char *stream, size_t size, int level,
|
|
||||||
char mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy zip archive stream output buffer.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
* @param buf output buffer. User should free buf.
|
|
||||||
* @param bufsize output buffer size (in bytes).
|
|
||||||
*
|
|
||||||
* @return copy size
|
|
||||||
*/
|
|
||||||
extern ssize_t zip_stream_copy(struct zip_t *zip, void **buf, ssize_t *bufsize);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close zip archive releases resources.
|
|
||||||
*
|
|
||||||
* @param zip zip archive handler.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
extern void zip_stream_close(struct zip_t *zip);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new archive and puts files into a single zip archive.
|
|
||||||
*
|
|
||||||
* @param zipname zip archive file.
|
|
||||||
* @param filenames input files.
|
|
||||||
* @param len: number of input files.
|
|
||||||
*
|
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_create(const char *zipname, const char *filenames[], size_t len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts a zip archive file into directory.
|
|
||||||
*
|
|
||||||
* If on_extract_entry is not NULL, the callback will be called after
|
|
||||||
* successfully extracted each zip entry.
|
|
||||||
* Returning a negative value from the callback will cause abort and return an
|
|
||||||
* error. The last argument (void *arg) is optional, which you can use to pass
|
|
||||||
* data to the on_extract_entry callback.
|
|
||||||
*
|
|
||||||
* @param zipname zip archive file.
|
|
||||||
* @param dir output directory.
|
|
||||||
* @param on_extract_entry on extract callback.
|
|
||||||
* @param arg opaque pointer.
|
|
||||||
*
|
|
||||||
* @return the return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_extract(const char *zipname, const char *dir,
|
|
||||||
int (*on_extract_entry)(const char *filename, void *arg),
|
|
||||||
void *arg);
|
|
||||||
|
|
||||||
/** @} */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,38 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.4)
|
|
||||||
|
|
||||||
# tests
|
|
||||||
set(test_write_out test_write.out)
|
|
||||||
add_executable(${test_write_out} test_write.c)
|
|
||||||
target_link_libraries(${test_write_out} zip)
|
|
||||||
add_test(NAME ${test_write_out} COMMAND ${test_write_out})
|
|
||||||
set(test_write_out ${test_write_out} PARENT_SCOPE)
|
|
||||||
|
|
||||||
set(test_append_out test_append.out)
|
|
||||||
add_executable(${test_append_out} test_append.c)
|
|
||||||
target_link_libraries(${test_append_out} zip)
|
|
||||||
add_test(NAME ${test_append_out} COMMAND ${test_append_out})
|
|
||||||
set(test_append_out ${test_append_out} PARENT_SCOPE)
|
|
||||||
|
|
||||||
set(test_read_out test_read.out)
|
|
||||||
add_executable(${test_read_out} test_read.c)
|
|
||||||
target_link_libraries(${test_read_out} zip)
|
|
||||||
add_test(NAME ${test_read_out} COMMAND ${test_read_out})
|
|
||||||
set(test_read_out ${test_read_out} PARENT_SCOPE)
|
|
||||||
|
|
||||||
set(test_extract_out test_extract.out)
|
|
||||||
add_executable(${test_extract_out} test_extract.c)
|
|
||||||
target_link_libraries(${test_extract_out} zip)
|
|
||||||
add_test(NAME ${test_extract_out} COMMAND ${test_extract_out})
|
|
||||||
set(test_extract_out ${test_extract_out} PARENT_SCOPE)
|
|
||||||
|
|
||||||
set(test_entry_out test_entry.out)
|
|
||||||
add_executable(${test_entry_out} test_entry.c)
|
|
||||||
target_link_libraries(${test_entry_out} zip)
|
|
||||||
add_test(NAME ${test_entry_out} COMMAND ${test_entry_out})
|
|
||||||
set(test_entry_out ${test_entry_out} PARENT_SCOPE)
|
|
||||||
|
|
||||||
set(test_permissions_out test_permissions.out)
|
|
||||||
add_executable(${test_permissions_out} test_permissions.c)
|
|
||||||
target_link_libraries(${test_permissions_out} zip)
|
|
||||||
add_test(NAME ${test_permissions_out} COMMAND ${test_permissions_out})
|
|
||||||
set(test_permissions_out ${test_permissions_out} PARENT_SCOPE)
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 5.2 KiB |
Loading…
Reference in New Issue