2017-02-19 00:31:45 +01:00
### A portable (OSX/Linux/Windows), simple zip library written in C
2015-03-24 02:38:14 -07:00
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.
2015-03-23 15:08:14 -07:00
2017-02-11 14:15:51 -08:00
[![Windows][win-badge]][win-link] [![OS X][osx-linux-badge]][osx-linux-link]
2017-02-11 13:52:07 -08:00
2017-02-11 14:15:51 -08:00
[win-badge]: https://img.shields.io/appveyor/ci/kuba--/zip/master.svg?label=windows "AppVeyor build status"
2017-02-11 13:52:07 -08:00
[win-link]: https://ci.appveyor.com/project/kuba--/zip "AppVeyor build status"
2017-02-11 14:15:51 -08:00
[osx-linux-badge]: https://img.shields.io/travis/kuba--/zip/master.svg?label=linux/osx "Travis CI build status"
2017-02-11 13:52:07 -08:00
[osx-linux-link]: https://travis-ci.org/kuba--/zip "Travis CI build status"
2017-02-19 00:31:45 +01:00
# The Idea
< img src = "zip.png" name = "zip" / >
2015-04-04 00:10:50 +02:00
... Some day, I was looking for zip library written in C for my project, but I could not find anything simple enough and lightweight.
2017-02-19 00:31:45 +01:00
Everything what I tried required 'crazy mental gymnastics' to integrate or had some limitations or was too heavy.
I hate frameworks, factories and adding new dependencies. If I must to install all those dependencies and link new library, I'm getting almost sick.
I wanted something powerfull and small enough, so I could add just a few files and compile them into my project.
And finally I found miniz.
2015-04-04 00:10:50 +02:00
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.
2015-04-04 00:17:33 +02:00
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.
2015-04-04 00:10:50 +02:00
2017-02-19 15:04:07 +01:00
# Examples
2015-04-04 00:10:50 +02:00
2017-02-19 15:04:07 +01:00
* Create a new zip archive with default compression level.
2015-04-04 00:10:50 +02:00
```c
2017-02-19 00:31:45 +01:00
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
{
zip_entry_open(zip, "foo-1.txt");
{
char *buf = "Some data here...";
zip_entry_write(zip, buf, strlen(buf));
}
zip_entry_close(zip);
zip_entry_open(zip, "foo-2.txt");
{
// merge 3 files into one entry and compress them on-the-fly.
zip_entry_fwrite(zip, "foo-2.1.txt");
zip_entry_fwrite(zip, "foo-2.2.txt");
zip_entry_fwrite(zip, "foo-2.3.txt");
}
zip_entry_close(zip);
}
zip_close(zip);
2017-02-19 15:04:07 +01:00
```
2017-02-19 00:31:45 +01:00
2017-02-19 15:04:07 +01:00
* Append to the existing zip archive.
```c
2017-02-19 15:05:21 +01:00
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
2017-02-19 00:31:45 +01:00
{
zip_entry_open(zip, "foo-3.txt");
{
char *buf = "Append some data here...";
zip_entry_write(zip, buf, strlen(buf));
}
zip_entry_close(zip);
}
zip_close(zip);
```
2017-02-19 15:04:07 +01:00
* Extract a zip archive into a folder.
2017-02-19 00:31:45 +01:00
```c
2017-02-19 15:04:07 +01:00
int on_extract_entry(const char *filename, void *arg) {
static int i = 0;
int n = *(int * )arg;
printf("Extracted: %s (%d of %d)\n", filename, ++i, n);
2017-02-19 00:31:45 +01:00
2017-02-19 15:04:07 +01:00
return 0;
}
2015-04-04 00:10:50 +02:00
2017-02-19 00:31:45 +01:00
int arg = 2;
zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
2017-02-19 15:04:07 +01:00
```
2017-02-19 00:31:45 +01:00
2017-02-19 15:04:07 +01:00
* Extract a zip entry into memory.
```c
2017-02-19 00:31:45 +01:00
void *buf = NULL;
size_t bufsize;
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
zip_entry_open(zip, "foo-1.txt");
{
zip_entry_read(zip, & buf, &bufsize);
}
zip_entry_close(zip);
2017-02-19 15:04:07 +01:00
}
zip_close(zip);
2017-03-16 22:06:56 +01:00
2017-02-19 15:04:07 +01:00
free(buf);
```
2017-02-19 00:31:45 +01:00
2017-03-16 22:06:56 +01:00
* Extract a zip entry into memory using callback.
```c
struct buffer_t {
char *data;
size_t size;
};
static size_t on_extract(void *arg, unsigned long long offset, const void *data, size_t size) {
struct buffer_t *buf = (struct buffer_t * )arg;
buf->data = realloc(buf->data, buf->size + size + 1);
assert(NULL != buf->data);
memcpy(& (buf->data[buf->size]), data, size);
buf->size += size;
buf->data[buf->size] = 0;
return size;
}
struct buffer_t buf = {0};
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
zip_entry_open(zip, "foo-1.txt");
{
zip_entry_extract(zip, on_extract, &buf);
}
zip_entry_close(zip);
}
zip_close(zip);
free(buf.data);
```
2017-02-19 15:04:07 +01:00
* Extract a zip entry into a file.
```c
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
{
2017-02-19 00:31:45 +01:00
zip_entry_open(zip, "foo-2.txt");
{
zip_entry_fread(zip, "foo-2.txt");
}
zip_entry_close(zip);
}
zip_close(zip);
2015-04-04 00:10:50 +02:00
```
2017-03-16 22:06:56 +01:00
2018-01-06 02:39:55 +01:00
# Bindings
* Compile zip library as a dynamic library.
```shell
$ mkdir build
$ cd build
$ cmake -DBUILD_SHARED_LIBS=true ..
$ make
```
2018-01-07 22:38:23 +01:00
### Go (cgo)
```go
package main
/*
#cgo CFLAGS: -I../src
#cgo LDFLAGS: -L. -lzip
#include <zip.h>
*/
import "C"
import "unsafe"
func main() {
path := C.CString("/tmp/go.zip")
zip := C.zip_open(path, 6, 'w')
entryname := C.CString("test")
C.zip_entry_open(zip, entryname)
content := "test content"
buf := unsafe.Pointer(C.CString(content))
bufsize := C.size_t(len(content))
C.zip_entry_write(zip, buf, bufsize)
C.zip_entry_close(zip)
C.zip_close(zip)
}
```
2018-01-06 02:39:55 +01:00
### Ruby (ffi)
* Install _ffi_ gem.
```shell
$ gem install ffi
```
* Bind in your module.
```ruby
require 'ffi'
module Zip
extend FFI::Library
ffi_lib "./libzip.#{::FFI::Platform::LIBSUFFIX}"
attach_function :zip_open, [:string, :int, :char], :pointer
attach_function :zip_close, [:pointer], :void
attach_function :zip_entry_open, [:pointer, :string], :int
attach_function :zip_entry_close, [:pointer], :void
attach_function :zip_entry_write, [:pointer, :string, :int], :int
end
ptr = Zip.zip_open("/tmp/ruby.zip", 6, "w".bytes()[0])
status = Zip.zip_entry_open(ptr, "test")
content = "test content"
status = Zip.zip_entry_write(ptr, content, content.size())
Zip.zip_entry_close(ptr)
Zip.zip_close(ptr)
```
### Python (cffi)
* Install _cffi_ package
```shell
$ pip install cffi
```
* Bind in your package.
```python
import ctypes.util
from cffi import FFI
ffi = FFI()
ffi.cdef("""
struct zip_t *zip_open(const char *zipname, int level, char mode);
void zip_close(struct zip_t *zip);
int zip_entry_open(struct zip_t *zip, const char *entryname);
int zip_entry_close(struct zip_t *zip);
int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
""")
Zip = ffi.dlopen(ctypes.util.find_library("zip"))
ptr = Zip.zip_open("/tmp/python.zip", 6, 'w')
status = Zip.zip_entry_open(ptr, "test")
content = "test content"
status = Zip.zip_entry_write(ptr, content, len(content))
Zip.zip_entry_close(ptr)
Zip.zip_close(ptr)
```