{"id":16214807,"url":"https://github.com/lecrapouille/zipper","last_synced_at":"2025-04-09T14:13:26.369Z","repository":{"id":115857497,"uuid":"536754890","full_name":"Lecrapouille/zipper","owner":"Lecrapouille","description":"[Lib][Version 2.2.0][Functional] C++ wrapper around minizip compression library","archived":false,"fork":false,"pushed_at":"2025-02-28T01:24:23.000Z","size":113,"stargazers_count":72,"open_issues_count":6,"forks_count":16,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-02T12:12:24.026Z","etag":null,"topics":["compression","compression-library","cpp","minizip","minizip-compression-library","zlib","zlib-ng"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Lecrapouille.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-14T20:49:01.000Z","updated_at":"2025-03-06T11:58:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"9b3f5f3f-0039-46ca-a6be-31e849bd9aee","html_url":"https://github.com/Lecrapouille/zipper","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lecrapouille%2Fzipper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lecrapouille%2Fzipper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lecrapouille%2Fzipper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lecrapouille%2Fzipper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Lecrapouille","download_url":"https://codeload.github.com/Lecrapouille/zipper/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248054193,"owners_count":21039952,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compression","compression-library","cpp","minizip","minizip-compression-library","zlib","zlib-ng"],"created_at":"2024-10-10T11:13:03.928Z","updated_at":"2025-04-09T14:13:26.336Z","avatar_url":"https://github.com/Lecrapouille.png","language":"C++","readme":"[![CI testing](https://github.com/Lecrapouille/zipper/actions/workflows/ci.yaml/badge.svg)](https://github.com/Lecrapouille/zipper/actions/workflows/ci.yaml)\n\n![Zipper](doc/logo.png)\n\n[Zipper](https://github.com/lecrapouille/zipper) is a C++11 wrapper around minizip compression library. Its goal is to bring the power and simplicity of minizip to a more object-oriented/c++ user-friendly library. Note: We are currently using C++14 because the unit tests library needs it.\n\nThis project is the continuation of the original [project](https://github.com/sebastiandev/zipper/tree/v2.x.y). The original project was born out of the necessity of a compression library that would be reliable, simple, and flexible. By flexibility I mean supporting all kinds of inputs and outputs, but specifically being able to compress into memory instead of being restricted to file compression only, and using data from memory instead of just files as well.\n\nThis current fork repo has been made because the original project was no longer maintained by the original authors and I, Lecrapouille, have some issues due to missing administration rights (needed for CI, branch management ...).\n\n## Zipper Features\n\n- [x] Create zip in memory.\n- [x] Allow files, vectors, and generic streams as input to zip.\n- [x] File mappings for replacing strategies (overwrite if exists or use alternative names from mapping).\n- [x] Password-protected zip (EAS).\n- [x] Multi-platform.\n- [x] Project compiled as static and dynamic libraries.\n- [x] Protection against the [Zip Slip attack](https://security.snyk.io/research/zip-slip-vulnerability).\n- [x] Non-regression tests.\n\n**:warning: Security Notice**\n\n- Zipper currently follows an outdated (and probably vulnerable) version of the https://github.com/Lecrapouille/minizip library:\nSHA1 0bb5afeb0d3f23149b086ccda7e4fee7d48f4fdf of https://github.com/zlib-ng/minizip-ng which dated of 2017).\n- While some fixes have been added this lib may be still vulnerable to ZipSlip attacks and mitigations should be put in place by Zipper's users.\n\n## Getting Started\n\n### Compiling / Installing\n\nTo download the project and compile it:\n\n```shell\ngit clone https://github.com/lecrapouille/zipper.git --recursive\ncd zipper\n# Optionally: make download-external-libs\nmake compile-external-libs\nmake -j`nproc --all`\n# make -j`sysctl -n hw.logicalcpu` for MacOS X\n```\n\nNotes:\n- Git cloning needs the recursivity option to install the Makefile helper and third-part libs (`zlib` and `minizip`). They are based on fixed SHA1.\n- Optionaly `make download-external-libs` will git clone HEADs of zlib and minizip to the `external` folder. This replaces git submodules.\n- `make compile-external-libs` will compile zlib and minizip but not install them on your operating system. They are\ncompiled as static libraries and merged into this library.\n\nInstalling C++ header files and compiled libraries, type:\n\n```shell\nsudo make install\n```\n\nFor Linux, you will see a message like:\n\n```shell\n*** Installing: doc =\u003e /usr/share/Zipper/2.0.0/doc\n*** Installing: libs =\u003e /usr/lib\n*** Installing: pkg-config =\u003e /usr/lib/pkgconfig\n*** Installing: headers =\u003e /usr/include/Zipper-2.0.0\n*** Installing: Zipper =\u003e /usr/include/Zipper-2.0.0\n```\n\nOptionally, you can compile demos present in the folder doc/demos:\n\n```shell\nmake demos -j8\n```\n\nSee their README files for their usage.\n\n### Linking Zipper to your project\n\n- In your project add the needed headers in your c++ files:\n\n```c++\n#include \u003cZipper/Unzipper.hpp\u003e\n#include \u003cZipper/Zipper.hpp\u003e\n```\n\n- To compile your project against Zipper use pkg-config:\n\n```shell\ng++ -W -Wall --std=c++11 main.cpp -o prog `pkg-config zipper --cflags --libs`\n```\n\n- For Makefile:\n  - set `LDFLAGS` to `pkg-config zipper --libs`\n  - set `CPPFLAGS` to `pkg-config zipper --cflags`\n\n- For CMake:\n```\ninclude(FindPkgConfig)\nfind_package(zipper)\n```\n\n## API\n\nThere are two classes available `Zipper` and `Unzipper`. They behave in the same manner regarding constructors and storage parameters.\n\n### Zipping API\n\n#### Header\n\n```c++\n#include \u003cZipper/Zipper.hpp\u003e\nusing namespace zipper;\n```\n\n#### Constructor\n\n- Constructor without password and replace `ziptest.zip` if already present. The new zip archive is dummy.\n\n```c++\nZipper zipper(\"ziptest.zip\", Zipper::openFlags::Overwrite);\n// Or simply: zipper(\"ziptest.zip\");\n```\n\n- Constructor without password and preserve `ziptest.zip` if already present.\n\n```c++\nZipper zipper(\"ziptest.zip\", Zipper::openFlags::Append);\n```\n\n- Constructor with password (using AES algorithm) and replace `ziptest.zip` if already present. The new zip archive is dummy.\n\n```c++\nZipper zipper(\"ziptest.zip\", \"mypassword\", Zipper::openFlags::Overwrite);\n// Or simply: zipper(\"ziptest.zip\");\n```\n\n- Constructor with a password and preserve `ziptest.zip` if already present.\n\n```c++\nZipper zipper(\"ziptest.zip\", \"mypassword\", Zipper::openFlags::Append);\n```\n\n- Note: all constructors will throw `std::run_time` exception in case of failure.\n\n```c++\ntry\n{\n    Zipper zipper(\"ziptest.zip\", ...);\n    ...\n}\ncatch (std::run_time const\u0026 e)\n{\n    std::cerr \u003c\u003c e.what() \u003c\u003c std::endl;\n}\n```\n\n#### Destructor / closing / reopening\n\nDo not forget to call explicitly `close()` (called implicitly from its destructor) else\nthe zip will not be well formed and `Unzipper` will fail to open it for example.\n\n```c++\nZipper zipper(\"ziptest.zip\", ...);\n...\nzipper.close(); // Now Unzipper unzipper(\"ziptest.zip\") can work\n```\n\nAfter `close()` you can reopen the zip archive with `open()`. The implicit option\n`Zipper::openFlags::Append` is to preserve the zip content. To replace the zip\nfile is to use `Zipper::openFlags::Overwrite`.\n\n```c++\nZipper zipper(\"ziptest.zip\", ...);\n...\nzipper.close();\n...\n\nzipper.open(); // equivalent to zipper.open(Zipper::openFlags::Append);\n// or zipper.open(Zipper::openFlags::Overwrite);\n...\nzipper.close();\n```\n\nIn case of success the `open()` will return `true` else will return `false` and the\n`error()` should be used for getting the [std::error_code](https://akrzemi1.wordpress.com/2017/07/12/your-own-error-code/).\n\n```c++\nif (!zipper.open())\n{\n    std::cerr \u003c\u003c zipper.error().message() \u003c\u003c std::endl;\n}\n```\n\n#### Appending files or folders inside the archive.\n\nThe `add()` method allows appending files or folders. The `Zipper::zipFlags::Better` is set implicitly. Other options are (in the last option in the arguments):\n- Store only: `Zipper::zipFlags::Store`.\n- Compress faster, less compressed: `Zipper::zipFlags::Faster`.\n- Compress intermediate time/compression: `Zipper::zipFlags::Medium`.\n- Compress faster better: `Zipper::zipFlags::Better`.\n\nIn case of success the `open()` will return `true` else will return `false` and the `error()` should be used for getting the std::error_code.\n\n- Adding an entire folder to a zip:\n\n```c++\nZipper zipper(\"ziptest.zip\");\nzipper.add(\"myFolder/\");\nzipper.close();\n```\n\n- Adding a file by name:\n\n```c++\nZipper zipper(\"ziptest.zip\");\nzipper.add(\"somefile.txt\");\nzipper.close();\n```\n\n- You can change their name in the archive:\n\n```c++\nZipper zipper(\"ziptest.zip\");\nzipper.add(\"somefile.txt\", \"new_name_in_archive\");\nzipper.close();\n```\n\n- Create a zip file with 2 files referred by their `std::ifstream` and change their name in the archive:\n\n```c++\nstd::ifstream input1(\"first_file\");\nstd::ifstream input2(\"second_file\");\n\nZipper zipper(\"ziptest.zip\");\nzipper.add(input1, \"Test1\");\nzipper.add(input2, \"Test2\");\nzipper.close();\n```\n\n- Zipper has security against [Zip Slip vulnerability](https://security.snyk.io/research/zip-slip-vulnerability).\n\n```c++\nzipper.add(input1, \"../Test1\");\n```\n\nWill always return `false` because `Test1` will be extracted outside the destination folder. This prevents malicious attack from replacing your password files:\n\n```c++\nzipper.add(malicious_passwd, \"../../../../../../../../../../../../../../../etc/passwd\");\n```\n\nBecase in Unix try to go outside the root folder `/` will stay in the root folder. Example\n```bash\ncd /\npwd\ncd ../../../../../../../../../../../../../../..\npwd\n```\n\n- The Zipper lib force canonical paths in the archive. The following code works (will return `true`):\n```c++\nzipper.add(input1, \"foo/../Test1\");\n```\n\nbecause `foo/../Test1` is replaced by `Test1` (even if the folder `foo` is not present in the\nzip archive.\n\n#### Vector and stream\n\n- Creating a zip file using the awesome streams from the [boost](https://www.boost.org/) library that lets us use a vector as a stream:\n\n```c++\n#include \u003cboost/interprocess/streams/vectorstream.hpp\u003e\n...\n\nboost::interprocess::basic_vectorstream\u003cstd::vector\u003cchar\u003e\u003e input_data(some_vector);\n\nZipper zipper(\"ziptest.zip\");\nzipper.add(input_data, \"Test1\");\nzipper.close();\n```\n\n- Creating a zip in a vector with files:\n\n```c++\n#include \u003cboost/interprocess/streams/vectorstream.hpp\u003e\n...\n\nboost::interprocess::basic_vectorstream\u003cstd::vector\u003cchar\u003e\u003e zip_in_memory;\nstd::ifstream input1(\"some file\");\n\nZipper zipper(zip_in_memory); // You can pass password\nzipper.add(input1, \"Test1\");\nzipper.close();\n\nzipper::Unzipper unzipper(zip_in_memory);\nunzipper.extractEntry(...\n```\n\nOr:\n\n```c++\n#include \u003cvector\u003e\n\nstd::vector\u003cunsigned char\u003e zip_vect;\nstd::ifstream input1(\"some file\");\n\nZipper zipper(zip_vect); // You can pass password\nzipper.add(input1, \"Test1\");\nzipper.close();\n```\n\n- Creating a zip in-memory stream with files:\n\n```c++\nstd::stringstream ss;\nstd::ifstream input1(\"some file\");\n\nZipper zipper(ss); // You can pass password\nzipper.add(input1, \"Test1\");\nzipper.close();\n\nzipper::Unzipper unzipper(ss);\nunzipper.extractEntry(...\n```\n\n### Unzipping API\n\n#### Header\n\n```c++\n#include \u003cZipper/Unzipper.hpp\u003e\nusing namespace zipper;\n```\n\n#### Constructor\n\n- Constructor without password and opening `ziptest.zip` (shall be already present).\n\n```c++\nZipper unzipper(\"ziptest.zip\");\n...\nzipper.close();\n```\n\n- Constructor with a password and opening `ziptest.zip` (shall be already present).\n\n```c++\nZipper unzipper(\"ziptest.zip\", \"mypassword\");\n...\nzipper.close();\n```\n\n- Note: all constructors will throw `std::run_time` exception in case of failure.\n\n```c++\ntry\n{\n    Zipper zipper(\"ziptest.zip\", ...);\n    ...\n}\ncatch (std::run_time const\u0026 e)\n{\n    std::cerr \u003c\u003c e.what() \u003c\u003c std::endl;\n}\n```\n\n#### Getting the list of zip entries\n\n```c++\nUnzipper unzipper(\"zipfile.zip\");\nstd::vector\u003cZipEntry\u003e entries = unzipper.entries();\nfor (auto\u0026 it: unzipper.entries())\n{\n    std::cout \u003c\u003c it.name \u003c\u003c \": \"\n              \u003c\u003c it.timestamp\n              \u003c\u003c std::endl;\n}\nunzipper.close();\n```\n\n#### Extracting all entries from the zip file\n\nTwo methods `extract()` for the whole archive and `extractEntry()` for\na single element in the archive. They return `true` in case of success\nor `false` in case of failure. In case of failure, use `unzipper.error();`\nto get the `std::error_code`.\n\n- If you do not care about replacing existing files or folders:\n\n```c++\nUnzipper unzipper(\"zipfile.zip\");\nunzipper.extractAll(true);\nunzipper.close();\n```\n\n- If you care about replacing existing files or folders. The method will fail (return `false`)\nif a file is replaced.\n\n```c++\nUnzipper unzipper(\"zipfile.zip\");\nunzipper.extractAll(); // equivalent to unzipper.extractAll(false);\nunzipper.close();\n```\n\n- Extracting all entries from the zip file to the desired destination:\n\n```c++\nUnzipper unzipper(\"zipfile.zip\");\nunzipper.extractAll(\"/the/destination/path\");        // Fail if a file exists (false argument is implicit)\nunzipper.extractAll(\"/the/destination/path\", true);  // Replace existing files\nunzipper.close();\n```\n\n- Extracting all entries from the zip file using alternative names for existing files on disk:\n\n```c++\nstd::map\u003cstd::string, std::string\u003e alternativeNames = { {\"Test1\", \"alternative_name_test1\"} };\nUnzipper unzipper(\"zipfile.zip\");\nunzipper.extractAll(\".\", alternativeNames);\nunzipper.close();\n```\n\n- Extracting a single entry from the zip file:\n\n```c++\nUnzipper unzipper(\"zipfile.zip\");\nunzipper.extractEntry(\"entry name\");\nunzipper.close();\n```\n\nReturn `true` in case of success or `false` in case of failure.\nIn case of failure, use `unzipper.error();` to get the `std::error_code`.\n\n- Extracting a single entry from the zip file to destination:\n\n```c++\nUnzipper unzipper(\"zipfile.zip\");\nunzipper.extractEntry(\"entry name\", \"/the/destination/path\"); // Fail if a file exists (false argument is implicit)\nunzipper.extractEntry(\"entry name\", \"/the/destination/path\", true); // Replace existing file\nunzipper.close();\n```\n\nReturn `true` in case of success or `false` in case of failure.\nIn case of failure, use `unzipper.error();` to get the `std::error_code`.\n\n- Extracting a single entry from the zip file to memory:\n\n```c++\nstd::vector\u003cunsigned char\u003e unzipped_entry;\nUnzipper unzipper(\"zipfile.zip\");\nunzipper.extractEntryToMemory(\"entry name\", unzipped_entry);\nunzipper.close();\n```\n\nReturn `true` in case of success or `false` in case of failure.\nIn case of failure, use `unzipper.error();` to get the `std::error_code`.\n\n- Extracting from a vector:\n\n```c++\n\nstd::vector\u003cunsigned char\u003e zip_vect; // Populated with Zipper zipper(zip_vect);\n\nUnzipper unzipper(zip_vect);\nunzipper.extractEntry(\"Test1\");\n```\n\n- Zipper has security against [Zip Slip vulnerability](https://security.snyk.io/research/zip-slip-vulnerability): if an entry has a path outside the extraction folder (like `../foo.txt`) it\nwill returns `false` even if the replace option is set.\n\n## Hello zip\n\nBasic unzipper standalone application given as demo in [doc/demos](doc/demos).\n\n## For developers\n\n### Non regression tests\n\nDepends on:\n- [googletest](https://github.com/google/googletest) framework\n- lcov for code coverage:\n\nTwo ways of running them:\n- From the root folder:\n```shell\nmake tests -j`nproc --all`\n```\n\n- From the tests/ folder:\n```shell\ncd tests\nmake coverage -j`nproc --all`\n```\n\nA coverage report has created an opening. If you do not desire to generate the report.\n```shell\ncd tests\nmake -j`nproc --all`\n./build/Zipper-UnitTest\n```\n\n## FAQ\n\n- Q: I used a password when zipping with the Zipper lib, but now when I want to extract data with my operating system zip tool, I got an error.\n  A: By default, Zipper encrypts with the EAS algorithm which is not the default encryption algorithm for zip files. Your operating system zip tools seem\n  not to understand EAS. You can extract it with the 7-Zip tool: `7za e your.zip`. If you want the default zip encryption (at your own risk since the\n  password can be cracked) you can remove EAS option in the following files: [Make](Make) and [external/compile-external-libs.sh](external/compile-external-libs.sh)\n  and recompile the Zipper project.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flecrapouille%2Fzipper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flecrapouille%2Fzipper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flecrapouille%2Fzipper/lists"}