Merge branch 'master' into UnitTestBlenderSubdivision

pull/5345/head
Kim Kulling 2024-05-30 09:03:03 +02:00 committed by GitHub
commit 19797afa49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 11315 additions and 3727 deletions

View File

@ -55,7 +55,7 @@ IF(ASSIMP_HUNTER_ENABLED)
add_definitions(-DASSIMP_USE_HUNTER) add_definitions(-DASSIMP_USE_HUNTER)
ENDIF() ENDIF()
PROJECT(Assimp VERSION 5.4.0) PROJECT(Assimp VERSION 5.4.1)
# All supported options ############################################### # All supported options ###############################################

View File

@ -63,7 +63,6 @@ class Scope;
class Parser; class Parser;
class Element; class Element;
// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03
using ScopeList = std::vector<Scope*>; using ScopeList = std::vector<Scope*>;
using ElementMap = std::fbx_unordered_multimap< std::string, Element*>; using ElementMap = std::fbx_unordered_multimap< std::string, Element*>;
using ElementCollection = std::pair<ElementMap::const_iterator,ElementMap::const_iterator>; using ElementCollection = std::pair<ElementMap::const_iterator,ElementMap::const_iterator>;

View File

@ -243,7 +243,6 @@ DirectPropertyMap PropertyTable::GetUnparsedProperties() const
// Read the element's value. // Read the element's value.
// Wrap the naked pointer (since the call site is required to acquire ownership) // Wrap the naked pointer (since the call site is required to acquire ownership)
// std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
std::shared_ptr<Property> prop = std::shared_ptr<Property>(ReadTypedProperty(*currentElement.second)); std::shared_ptr<Property> prop = std::shared_ptr<Property>(ReadTypedProperty(*currentElement.second));
// Element could not be read. Skip it. // Element could not be read. Skip it.

View File

@ -582,10 +582,12 @@ void ObjFileParser::getMaterialDesc() {
skip = true; skip = true;
} }
// If the current mesh has the same material, we simply ignore that 'usemtl' command // If the current mesh has the same material, we will ignore that 'usemtl' command
// There is no need to create another object or even mesh here // There is no need to create another object or even mesh here
if (m_pModel->mCurrentMaterial && m_pModel->mCurrentMaterial->MaterialName == aiString(strName)) { if (!skip) {
skip = true; if (m_pModel->mCurrentMaterial && m_pModel->mCurrentMaterial->MaterialName == aiString(strName)) {
skip = true;
}
} }
if (!skip) { if (!skip) {

View File

@ -92,7 +92,7 @@ static constexpr aiImporterDesc desc = {
0, 0,
0, 0,
0, 0,
"gltf glb" "gltf glb vrm"
}; };
glTF2Importer::glTF2Importer() : glTF2Importer::glTF2Importer() :
@ -106,7 +106,7 @@ const aiImporterDesc *glTF2Importer::GetInfo() const {
bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const { bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
const std::string extension = GetExtension(filename); const std::string extension = GetExtension(filename);
if (!checkSig && (extension != "gltf") && (extension != "glb")) { if (!checkSig && (extension != "gltf") && (extension != "glb") && (extension != "vrm")) {
return false; return false;
} }

View File

@ -471,6 +471,14 @@ ADD_ASSIMP_IMPORTER( MDL
AssetLib/MDL/HalfLife/UniqueNameGenerator.h AssetLib/MDL/HalfLife/UniqueNameGenerator.h
) )
IF(((CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND NOT MINGW AND NOT HAIKU) AND CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 13)
message(STATUS "GCC13 detected disabling \"-Warray-bounds and -Wstringop-overflow\" for"
" AssetLib/MDL/MDLLoader.cpp as it appears to be a false positive")
set_source_files_properties(AssetLib/MDL/MDLLoader.cpp PROPERTIES
COMPILE_FLAGS "-Wno-array-bounds -Wno-stringop-overflow"
)
endif()
SET( MaterialSystem_SRCS SET( MaterialSystem_SRCS
Material/MaterialSystem.cpp Material/MaterialSystem.cpp
Material/MaterialSystem.h Material/MaterialSystem.h
@ -503,6 +511,14 @@ ADD_ASSIMP_IMPORTER( OBJ
AssetLib/Obj/ObjTools.h AssetLib/Obj/ObjTools.h
) )
IF(((CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND NOT MINGW AND NOT HAIKU) AND CMAKE_CXX_COMPILER_VERSION EQUAL 14)
message(STATUS "GCC14 detected disabling \"-Wmaybe-uninitialized\" for"
" AssetLib/Obj/ObjFileParser.cpp as it appears to be a false positive")
set_source_files_properties(AssetLib/Obj/ObjFileParser.cpp PROPERTIES
COMPILE_FLAGS "-Wno-maybe-uninitialized"
)
endif()
ADD_ASSIMP_IMPORTER( OGRE ADD_ASSIMP_IMPORTER( OGRE
AssetLib/Ogre/OgreImporter.h AssetLib/Ogre/OgreImporter.h
AssetLib/Ogre/OgreStructs.h AssetLib/Ogre/OgreStructs.h

View File

@ -233,8 +233,13 @@ const aiScene *aiImportFileFromMemoryWithProperties(
unsigned int pFlags, unsigned int pFlags,
const char *pHint, const char *pHint,
const aiPropertyStore *props) { const aiPropertyStore *props) {
ai_assert(nullptr != pBuffer); if (pBuffer == nullptr) {
ai_assert(0 != pLength); return nullptr;
}
if (pLength == 0u) {
return nullptr;
}
const aiScene *scene = nullptr; const aiScene *scene = nullptr;
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();

View File

@ -148,8 +148,10 @@ void Bitmap::WriteData(aiTexture *texture, IOStream *file) {
file->Write(pixel, mBytesPerPixel, 1); file->Write(pixel, mBytesPerPixel, 1);
} }
// When padding is 0, passing it as an argument will cause an assertion failure in DefaultIOStream::Write.
file->Write(padding_data, padding, 1); if (padding) {
file->Write(padding_data, padding, 1);
}
} }
} }

View File

@ -524,6 +524,10 @@ void CatmullClarkSubdivider::InternSubdivide(
} }
} }
if (mp == nullptr) {
continue;
}
ai_assert(adj[o] - moffsets[nidx].first < mp->mNumFaces); ai_assert(adj[o] - moffsets[nidx].first < mp->mNumFaces);
const aiFace &f = mp->mFaces[adj[o] - moffsets[nidx].first]; const aiFace &f = mp->mFaces[adj[o] - moffsets[nidx].first];
bool haveit = false; bool haveit = false;

View File

@ -1,21 +1,23 @@
_**Contents**_ _**Contents**_
* [CMake Basics](#cmake-basics) - [Building](#building)
* [Mac OS X](#mac-os-x) - [CMake Basics](#cmake-basics)
* [Windows](#windows) - [Mac OS X](#mac-os-x)
* [CMake Build Configuration](#cmake-build-configuration) - [Windows](#windows)
* [Transcoder](#transcoder) - [CMake Build Configuration](#cmake-build-configuration)
* [Debugging and Optimization](#debugging-and-optimization) - [Transcoder](#transcoder)
* [Googletest Integration](#googletest-integration) - [Debugging and Optimization](#debugging-and-optimization)
* [Third Party Libraries](#third-party-libraries) - [Googletest Integration](#googletest-integration)
* [Javascript Encoder/Decoder](#javascript-encoderdecoder) - [Third Party Libraries](#third-party-libraries)
* [WebAssembly Decoder](#webassembly-decoder) - [WebAssembly Decoder](#webassembly-decoder)
* [WebAssembly Mesh Only Decoder](#webassembly-mesh-only-decoder) - [WebAssembly Mesh Only Decoder](#webassembly-mesh-only-decoder)
* [WebAssembly Point Cloud Only Decoder](#webassembly-point-cloud-only-decoder) - [WebAssembly Point Cloud Only Decoder](#webassembly-point-cloud-only-decoder)
* [iOS Builds](#ios-builds) - [Javascript Encoder/Decoder](#javascript-encoderdecoder)
* [Android Studio Project Integration](#android-studio-project-integration) - [iOS Builds](#ios-builds)
* [Native Android Builds](#native-android-builds) - [Native Android Builds](#native-android-builds)
* [vcpkg](#vcpkg) - [Android Studio Project Integration](#android-studio-project-integration)
- [Draco - Static Library](#draco---static-library)
- [vcpkg](#vcpkg)
Building Building
======== ========
@ -325,7 +327,7 @@ Draco - Static Library
To include Draco in an existing or new Android Studio project, reference it To include Draco in an existing or new Android Studio project, reference it
from the `cmake` file of an existing native project that has a minimum SDK from the `cmake` file of an existing native project that has a minimum SDK
version of 18 or higher. The project must support C++11. version of 18 or higher. The project must support C++11 at least.
To add Draco to your project: To add Draco to your project:
1. Create a new "Native C++" project. 1. Create a new "Native C++" project.

1
contrib/zip/.gitattributes vendored 100644
View File

@ -0,0 +1 @@
*.h linguist-language=C

60
contrib/zip/.gitignore vendored 100644
View File

@ -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/

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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
@ -278,24 +296,25 @@ import "C"
import "unsafe" import "unsafe"
func main() { func main() {
path := C.CString("/tmp/go.zip") path := C.CString("/tmp/go.zip")
zip := C.zip_open(path, 6, 'w') zip := C.zip_open(path, 6, 'w')
entryname := C.CString("test") entryname := C.CString("test")
C.zip_entry_open(zip, entryname) C.zip_entry_open(zip, entryname)
content := "test content" content := "test content"
buf := unsafe.Pointer(C.CString(content)) buf := unsafe.Pointer(C.CString(content))
bufsize := C.size_t(len(content)) bufsize := C.size_t(len(content))
C.zip_entry_write(zip, buf, bufsize) C.zip_entry_write(zip, buf, bufsize)
C.zip_entry_close(zip) C.zip_entry_close(zip)
C.zip_close(zip) C.zip_close(zip)
} }
``` ```
### [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)

View File

@ -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"

View File

@ -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

View File

@ -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,10 +356,11 @@ 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);
/** /**
* Extracts the current zip entry into output file. * Extracts the current zip entry into output file.
@ -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,8 +406,20 @@ 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,
size_t len); 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);
/** /**
* Extracts a zip archive stream into directory. * Extracts a zip archive stream into directory.
@ -338,21 +438,46 @@ 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);
/** /**
* Opens zip archive stream into memory. * Opens zip archive stream into memory.
* *
* @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
} }

View File

@ -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})

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -150,7 +150,7 @@ inline uint8_t HexOctetToDecimal(const char* in) {
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
// signed variant of strtoul10 // signed variant of strtoul10
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
inline int strtol10( const char* in, const char** out=0) { inline int strtol10( const char* in, const char** out = 0) {
bool inv = (*in=='-'); bool inv = (*in=='-');
if ( inv || *in == '+' ) { if ( inv || *in == '+' ) {
++in; ++in;
@ -158,7 +158,7 @@ inline int strtol10( const char* in, const char** out=0) {
int value = strtoul10(in,out); int value = strtoul10(in,out);
if (inv) { if (inv) {
if (value < INT_MAX) { if (value < INT_MAX && value > INT_MIN) {
value = -value; value = -value;
} else { } else {
ASSIMP_LOG_WARN( "Converting the string \"", in, "\" into an inverted value resulted in overflow." ); ASSIMP_LOG_WARN( "Converting the string \"", in, "\" into an inverted value resulted in overflow." );

View File

@ -334,7 +334,12 @@ enum aiTextureType {
#define AI_TEXTURE_TYPE_MAX aiTextureType_TRANSMISSION #define AI_TEXTURE_TYPE_MAX aiTextureType_TRANSMISSION
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
// Get a string for a given aiTextureType /**
* @brief Get a string for a given aiTextureType
*
* @param in The texture type
* @return The description string for the texture type.
*/
ASSIMP_API const char *aiTextureTypeToString(enum aiTextureType in); ASSIMP_API const char *aiTextureTypeToString(enum aiTextureType in);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -425,7 +430,8 @@ enum aiShadingMode {
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Defines some mixed flags for a particular texture. /**
* @brief Defines some mixed flags for a particular texture.
* *
* Usually you'll instruct your cg artists how textures have to look like ... * Usually you'll instruct your cg artists how textures have to look like ...
* and how they will be processed in your application. However, if you use * and how they will be processed in your application. However, if you use
@ -464,7 +470,8 @@ enum aiTextureFlags {
}; };
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Defines alpha-blend flags. /**
* @brief Defines alpha-blend flags.
* *
* If you're familiar with OpenGL or D3D, these flags aren't new to you. * If you're familiar with OpenGL or D3D, these flags aren't new to you.
* They define *how* the final color value of a pixel is computed, basing * They define *how* the final color value of a pixel is computed, basing
@ -508,7 +515,8 @@ enum aiBlendMode {
#include "./Compiler/pushpack1.h" #include "./Compiler/pushpack1.h"
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief Defines how an UV channel is transformed. /**
* @brief Defines how an UV channel is transformed.
* *
* This is just a helper structure for the #AI_MATKEY_UVTRANSFORM key. * This is just a helper structure for the #AI_MATKEY_UVTRANSFORM key.
* See its documentation for more details. * See its documentation for more details.
@ -552,8 +560,8 @@ struct aiUVTransform {
//! @cond AI_DOX_INCLUDE_INTERNAL //! @cond AI_DOX_INCLUDE_INTERNAL
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** @brief A very primitive RTTI system for the contents of material /**
* properties. * @brief A very primitive RTTI system for the contents of material properties.
*/ */
enum aiPropertyTypeInfo { enum aiPropertyTypeInfo {
/** Array of single-precision (32 Bit) floats /** Array of single-precision (32 Bit) floats
@ -698,7 +706,14 @@ struct aiMaterial
#ifdef __cplusplus #ifdef __cplusplus
public: public:
/**
* @brief The class constructor.
*/
aiMaterial(); aiMaterial();
/**
* @brief The class destructor.
*/
~aiMaterial(); ~aiMaterial();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -1016,7 +1031,7 @@ extern "C" {
// Clearcoat // Clearcoat
// --------- // ---------
// Clearcoat layer intensity. 0.0 = none (disabled) // Clearcoat layer intensity. 0.0 = none (disabled)
#define AI_MATKEY_CLEARCOAT_FACTOR "$mat.clearcoat.factor", 0, 0 #define AI_MATKEY_CLEARCOAT_FACTOR "$mat.clearcoat.factor", 0, 0
#define AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR "$mat.clearcoat.roughnessFactor", 0, 0 #define AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR "$mat.clearcoat.roughnessFactor", 0, 0
#define AI_MATKEY_CLEARCOAT_TEXTURE aiTextureType_CLEARCOAT, 0 #define AI_MATKEY_CLEARCOAT_TEXTURE aiTextureType_CLEARCOAT, 0
#define AI_MATKEY_CLEARCOAT_ROUGHNESS_TEXTURE aiTextureType_CLEARCOAT, 1 #define AI_MATKEY_CLEARCOAT_ROUGHNESS_TEXTURE aiTextureType_CLEARCOAT, 1
@ -1046,23 +1061,23 @@ extern "C" {
// Emissive // Emissive
// -------- // --------
#define AI_MATKEY_USE_EMISSIVE_MAP "$mat.useEmissiveMap", 0, 0 #define AI_MATKEY_USE_EMISSIVE_MAP "$mat.useEmissiveMap", 0, 0
#define AI_MATKEY_EMISSIVE_INTENSITY "$mat.emissiveIntensity", 0, 0 #define AI_MATKEY_EMISSIVE_INTENSITY "$mat.emissiveIntensity", 0, 0
#define AI_MATKEY_USE_AO_MAP "$mat.useAOMap", 0, 0 #define AI_MATKEY_USE_AO_MAP "$mat.useAOMap", 0, 0
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Pure key names for all texture-related properties // Pure key names for all texture-related properties
//! @cond MATS_DOC_FULL //! @cond MATS_DOC_FULL
#define _AI_MATKEY_TEXTURE_BASE "$tex.file" #define _AI_MATKEY_TEXTURE_BASE "$tex.file"
#define _AI_MATKEY_UVWSRC_BASE "$tex.uvwsrc" #define _AI_MATKEY_UVWSRC_BASE "$tex.uvwsrc"
#define _AI_MATKEY_TEXOP_BASE "$tex.op" #define _AI_MATKEY_TEXOP_BASE "$tex.op"
#define _AI_MATKEY_MAPPING_BASE "$tex.mapping" #define _AI_MATKEY_MAPPING_BASE "$tex.mapping"
#define _AI_MATKEY_TEXBLEND_BASE "$tex.blend" #define _AI_MATKEY_TEXBLEND_BASE "$tex.blend"
#define _AI_MATKEY_MAPPINGMODE_U_BASE "$tex.mapmodeu" #define _AI_MATKEY_MAPPINGMODE_U_BASE "$tex.mapmodeu"
#define _AI_MATKEY_MAPPINGMODE_V_BASE "$tex.mapmodev" #define _AI_MATKEY_MAPPINGMODE_V_BASE "$tex.mapmodev"
#define _AI_MATKEY_TEXMAP_AXIS_BASE "$tex.mapaxis" #define _AI_MATKEY_TEXMAP_AXIS_BASE "$tex.mapaxis"
#define _AI_MATKEY_UVTRANSFORM_BASE "$tex.uvtrafo" #define _AI_MATKEY_UVTRANSFORM_BASE "$tex.uvtrafo"
#define _AI_MATKEY_TEXFLAGS_BASE "$tex.flags" #define _AI_MATKEY_TEXFLAGS_BASE "$tex.flags"
//! @endcond //! @endcond
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -60,3 +60,12 @@ TEST_F( AssimpAPITest, aiGetLastErrorTest ) {
const char *error = aiGetErrorString(); const char *error = aiGetErrorString();
EXPECT_NE(nullptr, error); EXPECT_NE(nullptr, error);
} }
TEST_F(AssimpAPITest, aiImportFileFromMemoryTest) {
const aiScene *scene_null_buffer = aiImportFileFromMemory(nullptr, 0u, 0u, nullptr);
EXPECT_EQ(nullptr, scene_null_buffer);
char buffer[1024] = {'\0'};
const aiScene *scene_null_size = aiImportFileFromMemory(buffer, 0u, 0u, nullptr);
EXPECT_EQ(nullptr, scene_null_size);
}

View File

@ -85,15 +85,15 @@ TEST_F(utD3MFImporterExporter, import3MFFromFileTest) {
#ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_EXPORT
TEST_F(utD3MFImporterExporter, export3MFtoMemTest) { TEST_F(utD3MFImporterExporter, export3MFtoMemTest) {
EXPECT_TRUE(exporterTest()); //EXPECT_TRUE(exporterTest());
} }
TEST_F(utD3MFImporterExporter, roundtrip3MFtoMemTest) { TEST_F(utD3MFImporterExporter, roundtrip3MFtoMemTest) {
EXPECT_TRUE(exporterTest()); /*EXPECT_TRUE(exporterTest());
Assimp::Importer importer; Assimp::Importer importer;
const aiScene *scene = importer.ReadFile("test.3mf", 0); const aiScene *scene = importer.ReadFile("test.3mf", 0);
EXPECT_NE(nullptr, scene); EXPECT_NE(nullptr, scene));*/
} }
#endif // ASSIMP_BUILD_NO_EXPORT #endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -61,7 +61,7 @@ TEST_F( utVersion, aiGetVersionMinorTest ) {
} }
TEST_F( utVersion, aiGetVersionPatchTest ) { TEST_F( utVersion, aiGetVersionPatchTest ) {
EXPECT_EQ(aiGetVersionPatch(), 0U ); EXPECT_EQ(aiGetVersionPatch(), 1U );
} }
TEST_F( utVersion, aiGetCompileFlagsTest ) { TEST_F( utVersion, aiGetCompileFlagsTest ) {
@ -69,7 +69,7 @@ TEST_F( utVersion, aiGetCompileFlagsTest ) {
} }
TEST_F( utVersion, aiGetVersionRevisionTest ) { TEST_F( utVersion, aiGetVersionRevisionTest ) {
EXPECT_NE( aiGetVersionRevision(), 0U ); EXPECT_NO_THROW(aiGetVersionRevision());
} }
TEST_F( utVersion, aiGetBranchNameTest ) { TEST_F( utVersion, aiGetBranchNameTest ) {

View File

@ -106,6 +106,11 @@ int CDisplay::EnableAnimTools(BOOL hm) {
EnableWindow(GetDlgItem(g_hDlg,IDC_PLAY),hm); EnableWindow(GetDlgItem(g_hDlg,IDC_PLAY),hm);
EnableWindow(GetDlgItem(g_hDlg,IDC_SLIDERANIM),hm); EnableWindow(GetDlgItem(g_hDlg,IDC_SLIDERANIM),hm);
if (hm == FALSE) {
g_dCurrent = 0.0;
SendDlgItemMessage(g_hDlg, IDC_SLIDERANIM, TBM_SETPOS, TRUE, LPARAM(0));
}
return 1; return 1;
} }
@ -115,9 +120,16 @@ int CDisplay::FillAnimList(void) {
if (0 != g_pcAsset->pcScene->mNumAnimations) if (0 != g_pcAsset->pcScene->mNumAnimations)
{ {
// now fill in all animation names // now fill in all animation names
for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumAnimations;++i) { for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumAnimations; ++i)
{
std::string animationLabel(g_pcAsset->pcScene->mAnimations[i]->mName.data);
if (animationLabel.empty())
{
animationLabel = std::string("Animation ") + std::to_string(i) + " (UNNAMED)";
}
SendDlgItemMessage(g_hDlg,IDC_COMBO1,CB_ADDSTRING,0, SendDlgItemMessage(g_hDlg,IDC_COMBO1,CB_ADDSTRING,0,
( LPARAM ) g_pcAsset->pcScene->mAnimations[i]->mName.data); (LPARAM)animationLabel.c_str());
} }
// also add a dummy - 'none' // also add a dummy - 'none'
@ -139,6 +151,7 @@ int CDisplay::ClearAnimList(void)
{ {
// clear the combo box // clear the combo box
SendDlgItemMessage(g_hDlg,IDC_COMBO1,CB_RESETCONTENT,0,0); SendDlgItemMessage(g_hDlg,IDC_COMBO1,CB_RESETCONTENT,0,0);
EnableAnimTools(FALSE);
return 1; return 1;
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
@ -725,23 +738,25 @@ int CDisplay::OnRender()
// update possible animation // update possible animation
if( g_pcAsset) if( g_pcAsset)
{ {
static double lastPlaying = 0.; static double lastRenderTime = 0.;
ai_assert( g_pcAsset->mAnimator); ai_assert( g_pcAsset->mAnimator);
double currentTime = clock() / double(CLOCKS_PER_SEC);
if (g_bPlay) { if (g_bPlay) {
g_dCurrent += clock()/ double( CLOCKS_PER_SEC) -lastPlaying; g_dCurrent += currentTime - lastRenderTime;
double time = g_dCurrent; double time = g_dCurrent;
aiAnimation* mAnim = g_pcAsset->mAnimator->CurrentAnim(); aiAnimation* mAnim = g_pcAsset->mAnimator->CurrentAnim();
if( mAnim && mAnim->mDuration > 0.0) { if (mAnim && mAnim->mDuration > 0.0) {
double tps = mAnim->mTicksPerSecond ? mAnim->mTicksPerSecond : 25.f; double tps = mAnim->mTicksPerSecond ? mAnim->mTicksPerSecond : ANIM_DEFAULT_TICKS_PER_SECOND;
time = fmod( time, mAnim->mDuration/tps); time = fmod(time, mAnim->mDuration/tps);
SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_SETPOS,TRUE,LPARAM(10000 * (time/(mAnim->mDuration/tps)))); SendDlgItemMessage(g_hDlg, IDC_SLIDERANIM, TBM_SETPOS, TRUE, LPARAM(ANIM_SLIDER_MAX * (time / (mAnim->mDuration / tps))));
} }
g_pcAsset->mAnimator->Calculate( time ); g_pcAsset->mAnimator->Calculate( time );
lastPlaying = g_dCurrent;
} }
lastRenderTime = currentTime;
} }
// begin the frame // begin the frame
g_piDevice->BeginScene(); g_piDevice->BeginScene();
@ -793,8 +808,10 @@ int CDisplay::FillDefaultStatistics(void)
SetDlgItemText(g_hDlg,IDC_EVERT,"0"); SetDlgItemText(g_hDlg,IDC_EVERT,"0");
SetDlgItemText(g_hDlg,IDC_EFACE,"0"); SetDlgItemText(g_hDlg,IDC_EFACE,"0");
SetDlgItemText(g_hDlg,IDC_EMAT,"0"); SetDlgItemText(g_hDlg,IDC_EMAT,"0");
SetDlgItemText(g_hDlg,IDC_ENODE,"0"); SetDlgItemText(g_hDlg,IDC_EMESH,"0");
SetDlgItemText(g_hDlg,IDC_ENODEWND,"0");
SetDlgItemText(g_hDlg,IDC_ESHADER,"0"); SetDlgItemText(g_hDlg,IDC_ESHADER,"0");
SetDlgItemText(g_hDlg,IDC_ELOAD,"");
SetDlgItemText(g_hDlg,IDC_ETEX,"0"); SetDlgItemText(g_hDlg,IDC_ETEX,"0");
return 1; return 1;
} }
@ -877,7 +894,7 @@ int CDisplay::OnSetupNormalView()
SetWindowText(GetDlgItem(g_hDlg,IDC_NUMSHADERS),"Shaders:"); SetWindowText(GetDlgItem(g_hDlg,IDC_NUMSHADERS),"Shaders:");
SetWindowText(GetDlgItem(g_hDlg,IDC_NUMMATS),"Materials:"); SetWindowText(GetDlgItem(g_hDlg,IDC_NUMMATS),"Materials:");
SetWindowText(GetDlgItem(g_hDlg,IDC_NUMMESHES),"Meshes:"); SetWindowText(GetDlgItem(g_hDlg,IDC_NUMMESHES),"Meshes:");
SetWindowText(GetDlgItem(g_hDlg,IDC_LOADTIME),"Time:"); SetWindowText(GetDlgItem(g_hDlg,IDC_LOADTIME),"Loading Time:");
FillDefaultStatistics(); FillDefaultStatistics();
SetViewMode(VIEWMODE_FULL); SetViewMode(VIEWMODE_FULL);

View File

@ -874,9 +874,10 @@ void OpenAsset() {
RegSetValueExA(g_hRegistry,"CurrentApp",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH); RegSetValueExA(g_hRegistry,"CurrentApp",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH);
if (0 != strcmp(g_szFileName,szFileName)) { if (0 != strcmp(g_szFileName,szFileName)) {
strcpy(g_szFileName, szFileName);
DeleteAssetData(); DeleteAssetData();
DeleteAsset(); DeleteAsset();
strcpy(g_szFileName, szFileName);
LoadAsset(); LoadAsset();
// update the history // update the history
@ -1197,7 +1198,7 @@ void InitUI() {
LoadCheckerPatternColors(); LoadCheckerPatternColors();
SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_SETRANGEMIN,TRUE,0); SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_SETRANGEMIN,TRUE,0);
SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_SETRANGEMAX,TRUE,10000); SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_SETRANGEMAX,TRUE,ANIM_SLIDER_MAX);
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
@ -1274,11 +1275,14 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam
// XXX quick and dirty fix for #3029892 // XXX quick and dirty fix for #3029892
if (GetDlgItem(g_hDlg, IDC_SLIDERANIM) == (HWND)lParam && g_pcAsset && g_pcAsset->pcScene->mAnimations) if (GetDlgItem(g_hDlg, IDC_SLIDERANIM) == (HWND)lParam && g_pcAsset && g_pcAsset->pcScene->mAnimations)
{ {
double num = (double)SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_GETPOS,0,0);
const aiAnimation* anim = g_pcAsset->pcScene->mAnimations[ g_pcAsset->mAnimator->CurrentAnimIndex() ]; const aiAnimation* anim = g_pcAsset->pcScene->mAnimations[ g_pcAsset->mAnimator->CurrentAnimIndex() ];
if (anim && anim->mDuration > 0.0)
g_dCurrent = (anim->mDuration/anim->mTicksPerSecond) * num/10000; {
g_pcAsset->mAnimator->Calculate(g_dCurrent); double tps = anim->mTicksPerSecond ? anim->mTicksPerSecond : ANIM_DEFAULT_TICKS_PER_SECOND;
double sliderValue = (double)SendDlgItemMessage(g_hDlg, IDC_SLIDERANIM, TBM_GETPOS, 0, 0);
g_dCurrent = (anim->mDuration / tps) * sliderValue / ANIM_SLIDER_MAX;
g_pcAsset->mAnimator->Calculate(g_dCurrent);
}
} }
break; break;
@ -1666,10 +1670,11 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam
} }
fclose(pFile); fclose(pFile);
} else { } else {
strcpy(g_szFileName,szFile);
DeleteAsset(); DeleteAsset();
strcpy(g_szFileName, szFile);
LoadAsset(); LoadAsset();
UpdateHistory(); UpdateHistory();
SaveHistory(); SaveHistory();
} }
@ -1690,6 +1695,9 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam
g_pcAsset->mAnimator->SetAnimIndex(sel); g_pcAsset->mAnimator->SetAnimIndex(sel);
SendDlgItemMessage(hwndDlg,IDC_SLIDERANIM,TBM_SETPOS,TRUE,0); SendDlgItemMessage(hwndDlg,IDC_SLIDERANIM,TBM_SETPOS,TRUE,0);
} }
const size_t count = static_cast<size_t>(ComboBox_GetCount(GetDlgItem(hwndDlg, IDC_COMBO1)));
CDisplay::Instance().EnableAnimTools(g_pcAsset && count > 0 && sel < count - 1 ? TRUE : FALSE);
} }
} else if (ID_VIEWER_RESETVIEW == LOWORD(wParam)) { } else if (ID_VIEWER_RESETVIEW == LOWORD(wParam)) {
g_sCamera.vPos = aiVector3D(0.0f,0.0f,-10.0f); g_sCamera.vPos = aiVector3D(0.0f,0.0f,-10.0f);
@ -1827,7 +1835,12 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam
} }
else if (ID_VIEWER_RELOAD == LOWORD(wParam)) else if (ID_VIEWER_RELOAD == LOWORD(wParam))
{ {
// Save the filename to reload and clear
char toReloadFileName[MAX_PATH];
strcpy(toReloadFileName, g_szFileName);
DeleteAsset(); DeleteAsset();
strcpy(g_szFileName, toReloadFileName);
LoadAsset(); LoadAsset();
} }
else if (ID_IMPORTSETTINGS_RESETTODEFAULT == LOWORD(wParam)) else if (ID_IMPORTSETTINGS_RESETTODEFAULT == LOWORD(wParam))
@ -2036,9 +2049,10 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam
{ {
if (AI_VIEW_RECENT_FILE_ID(i) == LOWORD(wParam)) if (AI_VIEW_RECENT_FILE_ID(i) == LOWORD(wParam))
{ {
strcpy(g_szFileName,g_aPreviousFiles[i].c_str());
DeleteAssetData(); DeleteAssetData();
DeleteAsset(); DeleteAsset();
strcpy(g_szFileName, g_aPreviousFiles[i].c_str());
LoadAsset(); LoadAsset();
// update and safe the history // update and safe the history
@ -2209,6 +2223,8 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
CLogDisplay::Instance().AddEntry("[OK] Here we go!"); CLogDisplay::Instance().AddEntry("[OK] Here we go!");
CDisplay::Instance().EnableAnimTools(FALSE);
// create the log window // create the log window
CLogWindow::Instance().Init(); CLogWindow::Instance().Init();
// set the focus to the main window // set the focus to the main window
@ -2397,7 +2413,6 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
} }
} }
// render the scene // render the scene
CDisplay::Instance().OnRender(); CDisplay::Instance().OnRender();

View File

@ -81,7 +81,7 @@ float g_fWheelPos = -10.0f;
bool g_bLoadingCanceled = false; bool g_bLoadingCanceled = false;
IDirect3DTexture9 *g_pcTexture = nullptr; IDirect3DTexture9 *g_pcTexture = nullptr;
bool g_bPlay = false; bool g_bPlay = false;
double g_dCurrent = 0.; double g_dCurrent = 0.; // Animation time
// default pp steps // default pp steps
unsigned int ppsteps = aiProcess_CalcTangentSpace | // calculate tangents and bitangents if possible unsigned int ppsteps = aiProcess_CalcTangentSpace | // calculate tangents and bitangents if possible
@ -191,8 +191,8 @@ DWORD WINAPI LoadThreadProc(LPVOID) {
} }
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
// load the current asset // Load the current asset
// THe path to the asset is specified in the global path variable // The path to the asset is specified in the global variable g_szFileName
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
int LoadAsset() { int LoadAsset() {
// set the world and world rotation matrices to the identity // set the world and world rotation matrices to the identity
@ -267,14 +267,6 @@ int LoadAsset() {
if (1 != CreateAssetData()) if (1 != CreateAssetData())
return 0; return 0;
if (!g_pcAsset->pcScene->HasAnimations()) {
EnableWindow(GetDlgItem(g_hDlg, IDC_PLAY), FALSE);
EnableWindow(GetDlgItem(g_hDlg, IDC_SLIDERANIM), FALSE);
} else {
EnableWindow(GetDlgItem(g_hDlg, IDC_PLAY), TRUE);
EnableWindow(GetDlgItem(g_hDlg, IDC_SLIDERANIM), TRUE);
}
CLogDisplay::Instance().AddEntry("[OK] The asset has been loaded successfully"); CLogDisplay::Instance().AddEntry("[OK] The asset has been loaded successfully");
CDisplay::Instance().FillDisplayList(); CDisplay::Instance().FillDisplayList();
CDisplay::Instance().FillAnimList(); CDisplay::Instance().FillAnimList();
@ -312,6 +304,8 @@ int DeleteAsset(void) {
delete g_pcAsset; delete g_pcAsset;
g_pcAsset = nullptr; g_pcAsset = nullptr;
g_szFileName[0] = '\0';
// reset the caption of the viewer window // reset the caption of the viewer window
SetWindowText(g_hDlg, AI_VIEW_CAPTION_BASE); SetWindowText(g_hDlg, AI_VIEW_CAPTION_BASE);

View File

@ -78,6 +78,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// default movement speed // default movement speed
#define MOVE_SPEED 3.f #define MOVE_SPEED 3.f
// Anim constants
#define ANIM_DEFAULT_TICKS_PER_SECOND 25.f
#define ANIM_SLIDER_MAX 10000
#include "AssetHelper.h" #include "AssetHelper.h"
#include "Background.h" #include "Background.h"
#include "Camera.h" #include "Camera.h"

View File

@ -80,32 +80,32 @@ BEGIN
CONTROL "Two lights [L]",IDC_3LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,393,80,10 CONTROL "Two lights [L]",IDC_3LIGHTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,393,80,10
CONTROL "Backface culling [C]",IDC_BFCULL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,405,80,10 CONTROL "Backface culling [C]",IDC_BFCULL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,405,80,10
CONTROL "No transparency [T]",IDC_NOAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,417,80,10 CONTROL "No transparency [T]",IDC_NOAB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,417,80,10
GROUPBOX "Statistics",IDC_STATIC,186,345,164,63 GROUPBOX "Statistics",IDC_STATIC,186,345,200,63
LTEXT "Vertices:",IDC_NUMVERTS,192,357,35,8 LTEXT "Vertices:",IDC_NUMVERTS,192,357,35,8
LTEXT "Nodes:",IDC_NUMNODES,192,369,35,8 LTEXT "Nodes:",IDC_NUMNODES,192,369,35,8
LTEXT "Shaders:",IDC_NUMSHADERS,192,381,35,8 LTEXT "Shaders:",IDC_NUMSHADERS,192,381,35,8
LTEXT "Time:",IDC_LOADTIME,192,393,35,8 LTEXT "Loading Time:",IDC_LOADTIME,192,393,46,8
EDITTEXT IDC_EVERT,227,357,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_EVERT,241,357,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
EDITTEXT IDC_ENODEWND,227,369,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_ENODEWND,241,369,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
EDITTEXT IDC_ESHADER,227,381,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_ESHADER,241,381,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
EDITTEXT IDC_ELOAD,227,393,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_ELOAD,241,393,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
LTEXT "Faces:",IDC_NUMFACES,272,357,35,8 LTEXT "Faces:",IDC_NUMFACES,306,357,35,8
LTEXT "Materials:",IDC_NUMMATS,272,369,35,8 LTEXT "Materials:",IDC_NUMMATS,306,369,35,8
LTEXT "Meshes:",IDC_NUMMESHES,272,381,35,8 LTEXT "Meshes:",IDC_NUMMESHES,306,381,35,8
LTEXT "FPS:",IDC_FPS,272,393,35,8 LTEXT "FPS:",IDC_FPS,306,393,35,8
EDITTEXT IDC_EFACE,307,357,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_EFACE,341,357,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
EDITTEXT IDC_EMAT,307,369,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_EMAT,341,369,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
EDITTEXT IDC_EMESH,307,381,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_EMESH,341,381,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
EDITTEXT IDC_EFPS,307,393,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER EDITTEXT IDC_EFPS,341,393,35,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
EDITTEXT IDC_VIEWMATRIX,192,412,72,44,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_VISIBLE | NOT WS_BORDER EDITTEXT IDC_VIEWMATRIX,192,412,72,44,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_VISIBLE | NOT WS_BORDER
GROUPBOX "Colors",IDC_STATIC,357,345,109,87 GROUPBOX "Colors",IDC_STATIC,397,345,109,87
LTEXT "Primary:",IDC_STATIC,363,360,48,8 LTEXT "Primary:",IDC_STATIC,403,360,48,8
LTEXT "Secondary:",IDC_STATIC,363,378,54,8 LTEXT "Secondary:",IDC_STATIC,403,377,54,8
LTEXT "Ambient:",IDC_STATIC,363,396,54,8 LTEXT "Ambient:",IDC_STATIC,403,396,54,8
CONTROL "Button1",IDC_LCOLOR1,"Button",BS_OWNERDRAW | WS_TABSTOP,423,357,35,14 CONTROL "Button1",IDC_LCOLOR1,"Button",BS_OWNERDRAW | WS_TABSTOP,463,357,35,14
CONTROL "Button1",IDC_LCOLOR2,"Button",BS_OWNERDRAW | WS_TABSTOP,423,375,35,14 CONTROL "Button1",IDC_LCOLOR2,"Button",BS_OWNERDRAW | WS_TABSTOP,463,374,35,14
CONTROL "Button1",IDC_LCOLOR3,"Button",BS_OWNERDRAW | WS_TABSTOP,423,393,35,14 CONTROL "Button1",IDC_LCOLOR3,"Button",BS_OWNERDRAW | WS_TABSTOP,463,393,35,14
PUSHBUTTON "Reset",IDC_LRESET,423,411,35,14 PUSHBUTTON "Reset",IDC_LRESET,463,411,35,14
END END
IDD_LOADDIALOG DIALOGEX 0, 0, 143, 60 IDD_LOADDIALOG DIALOGEX 0, 0, 143, 60