Add zip_entry_(f)read (#7)

This commit is contained in:
Kuba Podgórski 2017-02-19 00:31:45 +01:00 committed by GitHub
parent c02431f3a0
commit 5f6e4a8f66
7 changed files with 473 additions and 144 deletions

7
.gitignore vendored
View File

@ -1,3 +1,6 @@
/build/
/xcodeproj/
# Object files
*.o
*.ko
@ -29,6 +32,6 @@
*.x86_64
*.hex
/build/
# Temporary
*.swp
.DS_Store

View File

@ -7,4 +7,4 @@ compiler:
script:
- mkdir build
- cd build
- cmake .. && make
- cmake .. && make && make test

View File

@ -8,6 +8,14 @@ if (MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
endif (MSVC)
# libzip
set(SRC src/miniz.h src/zip.h src/zip.c)
add_library(${CMAKE_PROJECT_NAME} ${SRC})
# zip_test
add_executable(zip_test test/main.c)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(zip_test ${CMAKE_PROJECT_NAME})
enable_testing()
add_test(NAME zip_test COMMAND zip_test)

149
README.md
View File

@ -1,4 +1,4 @@
### A portable (OSX/Linux/Windows), simple zip library written in C
### A portable (OSX/Linux/Windows), 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.
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/d70fb0b050b74ef7aed70087e377e7d7)](https://www.codacy.com/app/kuba--/zip?utm_source=github.com&utm_medium=referral&utm_content=kuba--/zip&utm_campaign=Badge_Grade)
@ -10,67 +10,128 @@ This is done by hacking awesome [miniz](https://code.google.com/p/miniz) library
[osx-linux-badge]: https://img.shields.io/travis/kuba--/zip/master.svg?label=linux/osx "Travis CI build status"
[osx-linux-link]: https://travis-ci.org/kuba--/zip "Travis CI build status"
# The Idea
<img src="zip.png" name="zip" />
# The Idea
<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.
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.
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.
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.
# Example
### Example (compress)
```c
#include <stdio.h>
#include <string.h>
#include "zip.h"
#include <zip.h>
int main() {
/*
Create a new zip archive with default compression level (6)
*/
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
// we should check if zip is NULL and if any other function returned < 0
{
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);
}
// always remember to close and release resources
zip_close(zip);
/*
Append to existing zip archive
*/
zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
// we should check if zip is NULL
{
zip_entry_open(zip, "foo-3.txt");
{
char *buf = "Append some data here...";
zip_entry_write(zip, buf, strlen(buf));
}
zip_entry_close(zip);
}
// always remember to close and release resources
zip_close(zip);
return 0;
}
```
### Example (decompress)
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zip.h>
// callback function
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);
static int i = 0;
int n = *(int *)arg;
printf("Extracted: %s (%d of %d)\n", filename, ++i, n);
return 0;
return 0;
}
int main() {
/*
Create a new zip archive with default compression level (6)
*/
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 0);
// we should check if zip is NULL
{
zip_entry_open(zip, "foo-1.txt");
{
char *buf = "Some data here...";
zip_entry_write(zip, buf, strlen(buf));
}
zip_entry_close(zip);
/*
Extract the zip archive into /tmp folder
*/
int arg = 2;
zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
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);
}
// always remember to close and release resources
zip_close(zip);
/*
...or open the zip archive with only read access
*/
void *buf = NULL;
size_t bufsize;
/*
Extract a zip archive into /tmp folder
*/
int arg = 2;
zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
// we should check if zip is NULL and if any other function returned < 0
{
zip_entry_open(zip, "foo-1.txt");
{
// extract into memory
zip_entry_read(zip, &buf, &bufsize);
printf("Read(foo-1.txt): %zu bytes: %.*s\n", bufsize, (int)bufsize,
buf);
}
zip_entry_close(zip);
return 0;
zip_entry_open(zip, "foo-2.txt");
{
// extract into a file
zip_entry_fread(zip, "foo-2.txt");
}
zip_entry_close(zip);
}
// always remember to close and release resources
zip_close(zip);
// do something with buffer... and remember to free memory
free(buf);
return 0;
}
```

203
src/zip.c
View File

@ -1,12 +1,12 @@
/*
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 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.
*/
* 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 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.
*/
#include "zip.h"
#include "miniz.h"
@ -40,7 +40,7 @@
#define ISSLASH(C) ((C) == '/')
#endif
#define cleanup(ptr) \
#define CLEANUP(ptr) \
do { \
if (ptr) { \
free((void *)ptr); \
@ -48,6 +48,20 @@
} \
} while (0)
static void __suppress_unused__(void) {
(void)__suppress_unused__;
(void)zip_open;
(void)zip_close;
(void)zip_entry_open;
(void)zip_entry_close;
(void)zip_entry_write;
(void)zip_entry_fwrite;
(void)zip_entry_read;
(void)zip_entry_fread;
(void)zip_create;
(void)zip_extract;
}
static char *basename(const char *name) {
char const *p;
char const *base = name += FILESYSTEM_PREFIX_LEN(name);
@ -83,6 +97,7 @@ static int mkpath(const char *path) {
}
struct zip_entry_t {
int index;
const char *name;
mz_uint64 uncomp_size;
mz_uint64 comp_size;
@ -99,52 +114,64 @@ struct zip_t {
mz_zip_archive archive;
mz_uint level;
struct zip_entry_t entry;
char mode;
};
struct zip_t *zip_open(const char *zipname, int level, int append) {
struct zip_t *zip_open(const char *zipname, int level, char mode) {
struct zip_t *zip = NULL;
struct MZ_FILE_STAT_STRUCT fstat;
if (!zipname || strlen(zipname) < 1) {
// zip_t archive name is empty or NULL
return NULL;
goto cleanup;
}
if (level < 0) level = MZ_DEFAULT_LEVEL;
if ((level & 0xF) > MZ_UBER_COMPRESSION) {
// Wrong compression level
return NULL;
goto cleanup;
}
zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
if (zip) {
zip->level = level;
if (!zip) goto cleanup;
if (append && MZ_FILE_STAT(zipname, &fstat) == 0) {
// Append to an existing archive.
if (!mz_zip_reader_init_file(
&(zip->archive), zipname,
level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) {
cleanup(zip);
return NULL;
}
if (!mz_zip_writer_init_from_reader(&(zip->archive), zipname)) {
mz_zip_reader_end(&(zip->archive));
cleanup(zip);
return NULL;
}
} else {
zip->level = level;
zip->mode = mode;
switch (mode) {
case 'w':
// Create a new archive.
if (!mz_zip_writer_init_file(&(zip->archive), zipname, 0)) {
// Cannot initialize zip_archive writer
cleanup(zip);
return NULL;
goto cleanup;
}
}
break;
case 'r':
case 'a':
if (!mz_zip_reader_init_file(
&(zip->archive), zipname,
level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) {
// An archive file does not exist or cannot initialize
// zip_archive reader
goto cleanup;
}
if (mode == 'a' &&
!mz_zip_writer_init_from_reader(&(zip->archive), zipname)) {
mz_zip_reader_end(&(zip->archive));
goto cleanup;
}
break;
default:
goto cleanup;
}
return zip;
cleanup:
CLEANUP(zip);
return NULL;
}
void zip_close(struct zip_t *zip) {
@ -152,9 +179,11 @@ void zip_close(struct zip_t *zip) {
// Always finalize, even if adding failed for some reason, so we have a
// valid central directory.
mz_zip_writer_finalize_archive(&(zip->archive));
mz_zip_writer_end(&(zip->archive));
cleanup(zip);
mz_zip_writer_end(&(zip->archive));
mz_zip_reader_end(&(zip->archive));
CLEANUP(zip);
}
}
@ -172,6 +201,14 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
return -1;
}
pzip = &(zip->archive);
if (zip->mode == 'r') {
zip->entry.index = mz_zip_reader_locate_file(pzip, entryname, NULL, 0);
return (zip->entry.index < 0) ? -1 : 0;
}
zip->entry.index = zip->archive.m_total_files;
zip->entry.name = STRCLONE(entryname);
if (!zip->entry.name) {
// Cannot parse zip entry name
@ -187,7 +224,6 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
zip->entry.method = 0;
pzip = &(zip->archive);
num_alignment_padding_bytes =
mz_zip_writer_compute_padding_needed_for_file_alignment(pzip);
@ -256,20 +292,24 @@ int zip_entry_close(struct zip_t *zip) {
time_t t;
struct tm *tm;
mz_uint16 dos_time, dos_date;
int status = -1;
if (!zip) {
// zip_t handler is not initialized
return -1;
}
if (zip->mode == 'r') {
return 0;
}
pzip = &(zip->archive);
level = zip->level & 0xF;
if (level) {
done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH);
if (done != TDEFL_STATUS_DONE && done != TDEFL_STATUS_OKAY) {
// Cannot flush compressed buffer
cleanup(zip->entry.name);
return -1;
goto cleanup;
}
zip->entry.comp_size = zip->entry.state.m_comp_size;
zip->entry.offset = zip->entry.state.m_cur_archive_file_ofs;
@ -288,8 +328,7 @@ int zip_entry_close(struct zip_t *zip) {
if ((zip->entry.comp_size > 0xFFFFFFFF) ||
(zip->entry.offset > 0xFFFFFFFF)) {
// No zip64 support, yet
cleanup(zip->entry.name);
return -1;
goto cleanup;
}
if (!mz_zip_writer_create_local_dir_header(
@ -297,16 +336,14 @@ int zip_entry_close(struct zip_t *zip) {
zip->entry.comp_size, zip->entry.uncomp_crc32, zip->entry.method, 0,
dos_time, dos_date)) {
// Cannot create zip entry header
cleanup(zip->entry.name);
return -1;
goto cleanup;
}
if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset,
zip->entry.header, sizeof(zip->entry.header)) !=
sizeof(zip->entry.header)) {
// Cannot write zip entry header
cleanup(zip->entry.name);
return -1;
goto cleanup;
}
if (!mz_zip_writer_add_to_central_dir(
@ -315,15 +352,16 @@ int zip_entry_close(struct zip_t *zip) {
zip->entry.uncomp_crc32, zip->entry.method, 0, dos_time, dos_date,
zip->entry.header_offset, 0)) {
// Cannot write to zip central dir
cleanup(zip->entry.name);
return -1;
goto cleanup;
}
pzip->m_total_files++;
pzip->m_archive_size = zip->entry.offset;
status = 0;
cleanup(zip->entry.name);
return 0;
cleanup:
CLEANUP(zip->entry.name);
return status;
}
int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) {
@ -393,6 +431,55 @@ int zip_entry_fwrite(struct zip_t *zip, const char *filename) {
return status;
}
int zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) {
mz_zip_archive *pzip = NULL;
mz_uint idx;
if (!zip) {
// zip_t handler is not initialized
return -1;
}
if (zip->mode != 'r' || zip->entry.index < 0) {
// the entry is not found or we do not have read access
return -1;
}
pzip = &(zip->archive);
idx = (mz_uint)zip->entry.index;
if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
// the entry is a directory
return -1;
}
*buf = mz_zip_reader_extract_to_heap(pzip, idx, bufsize, 0);
return (*buf) ? 0 : -1;
}
int zip_entry_fread(struct zip_t *zip, const char *filename) {
mz_zip_archive *pzip = NULL;
mz_uint idx;
if (!zip) {
// zip_t handler is not initialized
return -1;
}
if (zip->mode != 'r' || zip->entry.index < 0) {
// the entry is not found or we do not have read access
return -1;
}
pzip = &(zip->archive);
idx = (mz_uint)zip->entry.index;
if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
// the entry is a directory
return -1;
}
return (mz_zip_reader_extract_to_file(pzip, idx, filename, 0)) ? 0 : -1;
}
int zip_create(const char *zipname, const char *filenames[], size_t len) {
int status = 0;
size_t i;
@ -436,7 +523,7 @@ int zip_create(const char *zipname, const char *filenames[], size_t len) {
int zip_extract(const char *zipname, const char *dir,
int (*on_extract)(const char *filename, void *arg), void *arg) {
int status = 0;
int status = -1;
mz_uint i, n;
char path[MAX_PATH + 1] = {0};
mz_zip_archive zip_archive;
@ -461,8 +548,7 @@ int zip_extract(const char *zipname, const char *dir,
// Now try to open the archive.
if (!mz_zip_reader_init_file(&zip_archive, zipname, 0)) {
// Cannot initialize zip_archive reader
status = -1;
goto finally;
return -1;
}
strcpy(path, dir);
@ -480,36 +566,33 @@ int zip_extract(const char *zipname, const char *dir,
for (i = 0; i < n; ++i) {
if (!mz_zip_reader_file_stat(&zip_archive, i, &info)) {
// Cannot get information about zip archive;
status = -1;
break;
goto out;
}
strncpy(&path[dirlen], info.m_filename, MAX_PATH - dirlen);
if (mkpath(path) < 0) {
// Cannot make a path
status = -1;
break;
goto out;
}
if (!mz_zip_reader_extract_to_file(&zip_archive, i, path, 0)) {
// Cannot extract zip archive to file
status = -1;
break;
goto out;
}
if (on_extract) {
if (on_extract(path, arg) < 0) {
status = -1;
break;
goto out;
}
}
}
status = 0;
out:
// Close the archive, freeing any resources it was using
if (!mz_zip_reader_end(&zip_archive)) {
// Cannot end zip reader
status = -1;
}
finally:
return status;
}

150
src/zip.h
View File

@ -1,15 +1,15 @@
/*
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 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.
*/
* 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 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.
*/
#pragma once
#ifndef ZIP_H
#ifndef ZIP_H
#define ZIP_H
#include <string.h>
@ -19,72 +19,150 @@ extern "C" {
#endif
#ifndef MAX_PATH
#define MAX_PATH 32767 /* # chars in a path name including NULL */
#define MAX_PATH 32767 /* # chars in a path name including NULL */
#endif
#define ZIP_DEFAULT_COMPRESSION_LEVEL 6
#define ZIP_DEFAULT_COMPRESSION_LEVEL 6
/* This data structure is used throughout the library to represent zip archive - forward declaration. */
/*
This data structure is used throughout the library to represent zip archive
- forward declaration.
*/
struct zip_t;
/*
Opens zip archive with compression level.
If append is 0 then new archive will be created, otherwise function will try to append to the specified zip archive,
instead of creating a new one.
Compression levels: 0-9 are the standard zlib-style levels.
Returns pointer to zip_t structure or NULL on error.
*/
struct zip_t *zip_open(const char *zipname, int level, int append);
Opens zip archive with compression level using the given mode.
/* Closes zip archive, releases resources - always finalize. */
Args:
zipname: zip archive file name.
level: compression level (0-9 are the standard zlib-style levels).
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.
Returns:
The zip archive handler or NULL on error
*/
struct zip_t *zip_open(const char *zipname, int level, char mode);
/*
Closes zip archive, releases resources - always finalize.
Args:
zip: zip archive handler.
*/
void zip_close(struct zip_t *zip);
/*
Opens a new entry for writing in a zip archive.
Returns negative number (< 0) on error, 0 on success.
Args:
zip: zip archive handler.
entryname: an entry name in local dictionary.
Returns:
The return code - 0 on success, negative number (< 0) on error.
*/
int zip_entry_open(struct zip_t *zip, const char *entryname);
/*
Closes zip entry, flushes buffer and releases resources.
Returns negative number (< 0) on error, 0 on success.
Closes a zip entry, flushes buffer and releases resources.
Args:
zip: zip archive handler.
Returns:
The return code - 0 on success, negative number (< 0) on error.
*/
int zip_entry_close(struct zip_t *zip);
/*
Compresses an input buffer for the current zip entry.
Returns negative number (< 0) on error, 0 on success.
Args:
zip: zip archive handler.
buf: input buffer.
bufsize: input buffer size (in bytes).
Returns:
The return code - 0 on success, negative number (< 0) on error.
*/
int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
/*
Compresses a file for the current zip entry.
Returns negative number (< 0) on error, 0 on success.
Args:
zip: zip archive handler.
filename: input file.
Returns:
The return code - 0 on success, negative number (< 0) on error.
*/
int zip_entry_fwrite(struct zip_t *zip, const char *filename);
/*
Creates a new archive and puts len files into a single zip archive
Returns negative number (< 0) on error, 0 on success.
Extracts the current zip entry into output buffer.
Args:
zip: zip archive handler.
buf: output buffer.
bufsize: output buffer size (in bytes)
Returns:
The return code - 0 on success, negative number (< 0) on error.
*/
int zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
/*
Extracts the current zip entry into output file.
Args:
zip: zip archive handler.
filename: output file.
Returns:
The return code - 0 on success, negative number (< 0) on error.
*/
int zip_entry_fread(struct zip_t *zip, const char *filename);
/*
Creates a new archive and puts files into a single zip archive.
Args:
zipname: zip archive file.
filenames: input files.
len: number of input files.
Returns:
The return code - 0 on success, negative number (< 0) on error.
*/
int zip_create(const char *zipname, const char *filenames[], size_t len);
/*
Extracts a zip archive file into dir.
If on_extract_entry is not NULL, the callback will be called after successfully extracted each zip entry.
Returning a negative value from the callback will cause abort the extract and return an error.
Extracts a zip archive file into directory.
The last argument (void *arg) is optional, which you can use to pass some data to the on_extract_entry callback.
If on_extract_entry is not NULL, the callback will be called after
successfully extracted each zip entry.
Returning a negative value from the callback will cause abort and return an
error. The last argument (void *arg) is optional, which you can use to pass
some data to the on_extract_entry callback.
Returns negative number (< 0) on error, 0 on success.
Args:
zipname: zip archive file.
dir: output directory.
on_extract_entry: on extract callback.
Returns:
The return code - 0 on success, negative number (< 0) on error.
*/
int zip_extract(const char *zipname, const char *dir, int (* on_extract_entry)(const char *filename, void *arg), void *arg);
int zip_extract(const char *zipname, const char *dir,
int (*on_extract_entry)(const char *filename, void *arg),
void *arg);
#ifdef __cplusplus
}
#endif
#endif

96
test/main.c Normal file
View File

@ -0,0 +1,96 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <zip.h>
// callback function
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);
return 0;
}
int main() {
/*
Create a new zip archive with default compression level (6)
*/
struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
// we should check if zip is NULL and if any other function returned < 0
{
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);
}
// always remember to close and release resources
zip_close(zip);
/*
Append to existing zip archive
*/
zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a');
// we should check if zip is NULL
{
zip_entry_open(zip, "foo-3.txt");
{
char *buf = "Append some data here...";
zip_entry_write(zip, buf, strlen(buf));
}
zip_entry_close(zip);
}
// always remember to close and release resources
zip_close(zip);
/*
Extract the zip archive into /tmp folder
*/
int arg = 2;
zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
/*
...or open the zip archive with only read access
*/
void *buf = NULL;
size_t bufsize;
zip = zip_open("foo.zip", 0, 'r');
// we should check if zip is NULL and if any other function returned < 0
{
zip_entry_open(zip, "foo-1.txt");
{
// extract into memory
zip_entry_read(zip, &buf, &bufsize);
printf("Read(foo-1.txt): %zu bytes: %.*s\n", bufsize, (int)bufsize,
buf);
}
zip_entry_close(zip);
zip_entry_open(zip, "foo-2.txt");
{
// extract into a file
zip_entry_fread(zip, "foo-2.txt");
}
zip_entry_close(zip);
}
// always remember to close and release resources
zip_close(zip);
// do something with buffer... and remember to free memory
free(buf);
return 0;
}