libzip
| Language | C (usable from C++) |
|---|---|
| License | BSD 3-clause |
| Repository | github.com/nih-at/libzip |
| Documentation | libzip.org/documentation |
| Depends on | zlib; optional bzip2, liblzma, zstd, OpenSSL / GnuTLS / mbed TLS / Windows CNG (for AES) |
| Read / write | yes / yes, ZIP64, AES-128/192/256 and ZipCrypto, stored, DEFLATE, bzip2, LZMA, XZ, Zstandard |
libzip reads, creates and modifies ZIP archives. Changes (add, replace, rename, delete) are collected and written when you call zip_close, which writes a new archive to a temporary file and replaces the original. That makes it the best C library for editing existing archives. PHP’s ZipArchive is built on libzip.
The API uses zip_t for an archive, zip_file_t for an entry opened for reading, and zip_source_t for data to add (a buffer, a file or a custom callback). Entries are addressed by index (zip_uint64_t) or name.
Installation#
# Debian / Ubuntu
sudo apt install libzip-dev
# Fedora
sudo dnf install libzip-devel
# macOS
brew install libzip
# Windows (vcpkg)
vcpkg install libzip
With CMake:
find_package(libzip REQUIRED)
target_link_libraries(myapp PRIVATE libzip::zip)
Basic usage: list and read files#
#include <zip.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int err = 0;
zip_t *za = zip_open("in.zip", ZIP_RDONLY, &err);
if (!za) {
zip_error_t error;
zip_error_init_with_code(&error, err);
fprintf(stderr, "cannot open: %s\n", zip_error_strerror(&error));
zip_error_fini(&error);
return 1;
}
zip_int64_t n = zip_get_num_entries(za, 0);
for (zip_int64_t i = 0; i < n; i++) {
zip_stat_t st;
if (zip_stat_index(za, i, 0, &st) == 0) {
printf("%-40s %10llu -> %10llu bytes\n", st.name,
(unsigned long long)st.size, (unsigned long long)st.comp_size);
}
}
// read one file into memory
zip_stat_t st;
if (zip_stat(za, "readme.txt", 0, &st) == 0) {
char *buf = malloc(st.size + 1);
zip_file_t *zf = zip_fopen(za, "readme.txt", 0);
if (buf && zf && zip_fread(zf, buf, st.size) == (zip_int64_t)st.size) {
buf[st.size] = 0;
printf("%s\n", buf);
}
if (zf) zip_fclose(zf);
free(buf);
}
zip_close(za);
return 0;
}
How to create a ZIP file#
Sources passed to zip_file_add are read when zip_close writes the archive, so buffers must stay valid until then:
#include <zip.h>
#include <stdio.h>
#include <string.h>
int main(void) {
int err = 0;
zip_t *za = zip_open("out.zip", ZIP_CREATE | ZIP_TRUNCATE, &err);
if (!za) return 1;
const char *text = "hello from libzip\n";
zip_source_t *src = zip_source_buffer(za, text, strlen(text), 0);
if (!src || zip_file_add(za, "hello.txt", src, ZIP_FL_ENC_UTF_8) < 0) {
zip_source_free(src); // only free on failure; on success the archive owns it
fprintf(stderr, "add failed: %s\n", zip_strerror(za));
}
zip_dir_add(za, "docs", ZIP_FL_ENC_UTF_8);
src = zip_source_file(za, "report.pdf", 0, ZIP_LENGTH_TO_END);
if (!src || zip_file_add(za, "docs/report.pdf", src, ZIP_FL_ENC_UTF_8) < 0) {
zip_source_free(src);
}
if (zip_close(za) < 0) { // the archive is written here
fprintf(stderr, "write failed: %s\n", zip_strerror(za));
zip_discard(za);
return 1;
}
return 0;
}
How to set the compression method and level#
zip_int64_t idx = zip_file_add(za, "data.bin", src, ZIP_FL_OVERWRITE);
if (idx >= 0) {
// ZIP_CM_STORE, ZIP_CM_DEFLATE, ZIP_CM_BZIP2, ZIP_CM_LZMA, ZIP_CM_XZ, ZIP_CM_ZSTD
if (zip_compression_method_supported(ZIP_CM_ZSTD, 1))
zip_set_file_compression(za, idx, ZIP_CM_ZSTD, 19);
else
zip_set_file_compression(za, idx, ZIP_CM_DEFLATE, 9);
}
Level 0 means the default for the method. Stick with DEFLATE when the archive must open in Windows Explorer or macOS.
How to create and read a password-protected ZIP (AES)#
// writing: encrypt one entry with AES-256
zip_int64_t idx = zip_file_add(za, "secret.txt", src, 0);
zip_file_set_encryption(za, idx, ZIP_EM_AES_256, "my password");
// reading: set a default password for all entries, then read normally
zip_set_default_password(za, "my password");
zip_file_t *zf = zip_fopen(za, "secret.txt", 0);
Other methods: ZIP_EM_AES_128, ZIP_EM_AES_192, ZIP_EM_TRAD_PKWARE (ZipCrypto, weak). AES needs libzip built with a crypto backend; check with zip_encryption_method_supported(ZIP_EM_AES_256, 1).
How to delete or rename a file inside a ZIP#
zip_t *za = zip_open("in.zip", 0, &err); // open for modification
zip_int64_t idx = zip_name_locate(za, "old.txt", 0);
if (idx >= 0) zip_file_rename(za, idx, "new.txt", ZIP_FL_ENC_UTF_8);
idx = zip_name_locate(za, "unwanted.log", 0);
if (idx >= 0) zip_delete(za, idx);
zip_close(za); // writes the changes
Tips#
- Open with
ZIP_CHECKCONSto run extra consistency checks on untrusted archives. zip_closereturns -1 on failure and leaves the archive open; callzip_discardto free it without writing.- Entry names from
zip_get_name/zip_statcan contain../: check them before writing files to disk. - libzip ships command-line tools:
zipcmp(compare archives),zipmergeandziptool.