Zipper
[Lib][Version 3.0.1][Functional] C++14 wrapper around minizip compression library
Install / Use
/learn @Lecrapouille/ZipperREADME

Zipper is a C++14 wrapper around the minizip compression library. Its goal is to bring the power and simplicity of minizip to a more object-oriented and C++ user-friendly library.
This project is a continuation of the original project. The original project was created out of the need for a compression library that would be reliable, simple, and flexible. By flexibility, we mean supporting various types of inputs and outputs, specifically the ability to compress into memory instead of being restricted to file compression only, and using data from memory instead of just files.
This current fork repository was created because the original project was no longer maintained by its authors, and I, Lecrapouille, encountered issues due to missing administrative rights (needed for CI, branch management, API breaking changes, etc.).
Zipper Features
- [x] Create zip files in memory.
- [x] Support for files, vectors, and generic streams as input for zipping.
- [x] File mappings for replacement strategies (overwrite if exists or use alternative names from mapping).
- [x] Password-protected zip (AES).
- [x] Multi-platform support.
- [x] Project compiles as both static and dynamic libraries.
- [x] Protection flags against overwriting existing files during extraction.
- [x] Protection against the Zip Slip attack.
- [x] API to detect Zip Bomb attacks. Extraction is not recursive.
- [x] Non-regression tests.
:warning: Security Notice
- Zipper currently uses an outdated (and potentially vulnerable) version of minizip from 2017 (SHA1 0bb5afeb0d3f23149b086ccda7e4fee7d48f4fdf) with some custom modifications.
Getting Started
There are two ways to compile the project:
- Makefile: This is the official compilation method but only supports Linux and macOS
- CMake: Recently added, it supports all operating systems and was primarily added for Windows support
Compiling / Installing with Makefile (Linux, MacOs, not working for Windows)
This is the official way to download the project and compile it:
git clone https://github.com/lecrapouille/zipper.git --recursive
cd zipper
make download-external-libs
make compile-external-libs
make -j8
Explanations of compilation commands:
- Git cloning requires the recursive option to install the Makefile helper and third-party libs (
zlibandminizip) in theexternalfolder. They are based on fixed SHA1. They are installed in the folderexternal. - Optionally
make download-external-libswill git clone HEADs of third-party libs (zlibandminizip) in theexternalfolder. It is optional since it was initially used instead of git submodule. make compile-external-libswill compile third-party libs (zlibandminizip) but not install them on your operating system. They are compiled as static libraries and merged into this library inside thebuildfolder.makewill compile this library against the third-party libs (zlibandminizip). Abuildfolder is created with two demos inside. Note:-j8should be adapted to your number of CPU cores.
See the README file for using the demos. To run demos, you can run them:
cd build
./unzipper-demo -h
./zipper-demo -h
To install C++ header files, shared and static libraries on your operating system, type:
sudo make install
You will see a message like:
*** Installing: doc => /usr/share/Zipper/2.0.0/doc
*** Installing: libs => /usr/lib
*** Installing: pkg-config => /usr/lib/pkgconfig
*** Installing: headers => /usr/include/Zipper-2.0.0
*** Installing: Zipper => /usr/include/Zipper-2.0.0
For developers, you can run non regression tests. They depend on:
- googletest framework
- lcov for code coverage
make tests -j8
Compiling / Installing with CMake (Linux, MacOs, Windows)
As an alternative, you can also build the project using CMake:
git clone https://github.com/lecrapouille/zipper.git --recursive
cd zipper
mkdir build
cd build
cmake .. -DZIPPER_SHARED_LIB=ON -DZIPPER_BUILD_DEMOS=ON -DZIPPER_BUILD_TESTS=ON
# Either:
cmake --build . --config Release
# Or: make -j8
Optional options:
-DZIPPER_SHARED_LIB=ONallows creating a shared lib instead of static lib.-DZIPPER_BUILD_DEMOS=ONallows compiling zipper and unzipper "hello world" demos.-DZIPPER_BUILD_TESTS=ONallows compiling unit tests (if you are a developer).
Linking Zipper to your project
- In your project, add the needed headers in your C++ files:
#include <Zipper/Unzipper.hpp>
#include <Zipper/Zipper.hpp>
- To compile your project "as it" against Zipper, the simplest way is to use the
pkg-configcommand:
g++ -W -Wall --std=c++14 main.cpp -o prog `pkg-config zipper --cflags --libs`
-
For Makefile:
- set
LDFLAGStopkg-config zipper --libs - set
CPPFLAGStopkg-config zipper --cflags
- set
-
For CMake:
find_package(zipper REQUIRED)
target_link_libraries(your_application zipper::zipper)
You have an example doc/demos/CMakeHelloWorld.
API
There are two classes available: Zipper and Unzipper. They behave in the same manner regarding constructors and storage parameters.
Zipping API
Header
#include <Zipper/Zipper.hpp>
using namespace zipper;
Constructor
- Constructor without password and replace
ziptest.zipif already present. The new zip archive is empty. The flagZipper::OpenFlags::Overwriteis optional.
Zipper zipper("ziptest.zip", Zipper::OpenFlags::Overwrite);
- Constructor without password and preserve
ziptest.zipif already present. The flagZipper::OpenFlags::Appendis mandatory!
Zipper zipper("ziptest.zip", Zipper::OpenFlags::Append);
- Constructor with password (using AES algorithm) and replace
ziptest.zipif already present. The new zip archive is empty. The flagZipper::OpenFlags::Overwriteis optional.
Zipper zipper("ziptest.zip", "my_password", Zipper::OpenFlags::Overwrite);
- Constructor with a password and preserve
ziptest.zipif already present. The flagZipper::OpenFlags::Appendis mandatory!
Zipper zipper("ziptest.zip", "my_password", Zipper::OpenFlags::Append);
- Constructor for in-memory zip compression (storage inside std::iostream):
std::stringstream zipStream;
Zipper zipper(zipStream);
Zipper zipper(zipStream, Zipper::OpenFlags::Overwrite);
Zipper zipper(zipStream, Zipper::OpenFlags::Append);
Zipper zipper(zipStream, "my_password");
Zipper zipper(zipStream, "my_password", Zipper::OpenFlags::Overwrite);
Zipper zipper(zipStream, "my_password", Zipper::OpenFlags::Append);
- Constructor for in-memory zip compression (storage inside std::vector):
std::vector<unsigned char> zipVector;
Zipper zipper(zipVector);
Zipper zipper(zipVector, Zipper::OpenFlags::Overwrite);
Zipper zipper(zipVector, Zipper::OpenFlags::Append);
Zipper zipper(zipVector, "my_password");
Zipper zipper(zipVector, "my_password", Zipper::OpenFlags::Overwrite);
Zipper zipper(zipVector, "my_password", Zipper::OpenFlags::Append);
- Note: all constructors will throw a
std::runtime_errorexception in case of failure.
try
{
Zipper zipper("ziptest.zip", ...);
...
}
catch (std::runtime_error const& e)
{
std::cerr << e.what() << std::endl;
}
- If this is not a desired behavior, you can choose the alternative dummy constructor followed by the
openmethod which takes the same arguments as constructors. This method does not throw but will returnfalsein case of error, you can get the reason by callingerror().
// Dummy constructor
Zipper zipper;
// Same arguments than seen previously with constructors.
if (!zipper.open(...))
{
std::cerr << zipper.error() << std::endl;
}
Closing / Reopening
Do not forget to call close() explicitly (it's called implicitly from the destructor) otherwise
the zip will not be well-formed and Unzipper (or any unzipper application) will fail to open it, for example.
Zipper zipper("ziptest.zip", ...);
...
zipper.close(); // Now Unzipper unzipper("ziptest.zip") can work
After close() you can reopen the zip archive with open() without arguments. You can pass the same arguments than seen previously with constructors to open with new password or flags. Note: that any open method will call implicitly the close() method.
Zipper zipper("ziptest.zip", ...);
...
zipper.close();
...
zipper.open();
...
zipper.close();
Appending files or folders inside the archive
The add() method allows appending files or folders. The Zipper::ZipFlags::Better is set implicitly. Other options are (as the last argument):
- Store only:
Zipper::ZipFlags::Store. - Compress faster, less compressed:
Zipper::ZipFlags::Faster. - Compress intermediate time/compression:
Zipper::ZipFlags::Medium. - Compress better:
Zipper::ZipFlags::Better. - To preserve directory hierarchy add
| Zipper::ZipFlags::SaveHierarchyelse files are only stored.
In case of success, the add() will return true; otherwise it will return false and error() should be used for getting the std::error_code.
- Adding an entire folder to a zip:
Zipper zipper("ziptest.zip");
zipper.add("myFolder/");
zipper.close();
- Adding a file by name:
Zipper zipper("ziptest.zip");
zipper.add("myFolder/somefile.txt");
zipper.close();
- You can change their name in the archive:
Zipper zipper("ziptest.zip");
zipper.add("somefile.txt", "new_name_in_archive");
zipper.close();
- Create a zip file with 2 files referred by their
std::ifstreamand change their name in the archive:
std:
