mirror of
https://github.com/QuasarApp/zip.git
synced 2025-04-29 13:54:35 +00:00
add zip_entry_openbyindex (#24)
This commit is contained in:
parent
f246c22e9b
commit
f5b6a916f0
15
README.md
15
README.md
@ -137,6 +137,21 @@ It was the reason, why I decided to write zip module on top of the miniz. It req
|
||||
zip_close(zip);
|
||||
```
|
||||
|
||||
* List of all zip entries
|
||||
```c
|
||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
||||
int i, n = zip_total_entries(zip);
|
||||
for (i = 0; i < n; ++i) {
|
||||
zip_entry_openbyindex(zip, i);
|
||||
{
|
||||
const char *name = zip_entry_name(zip);
|
||||
int isdir = zip_entry_isdir(zip);
|
||||
}
|
||||
zip_entry_close(zip);
|
||||
}
|
||||
zip_close(zip);
|
||||
```
|
||||
|
||||
# Bindings
|
||||
* Compile zip library as a dynamic library.
|
||||
```shell
|
||||
|
99
src/zip.c
99
src/zip.c
@ -83,16 +83,16 @@ static int mkpath(const char *path) {
|
||||
}
|
||||
|
||||
static char *strrpl(const char *str, size_t n, char oldchar, char newchar) {
|
||||
char *rpl = (char *)malloc(sizeof(char) * (1 + n));
|
||||
char *rpl = (char *)calloc((1 + n), sizeof(char));
|
||||
char *begin = rpl;
|
||||
char c;
|
||||
while((c = *str++)) {
|
||||
size_t i;
|
||||
for(i = 0; (i < n) && (c = *str++); ++i) {
|
||||
if (c == oldchar) {
|
||||
c = newchar;
|
||||
}
|
||||
*rpl++ = c;
|
||||
}
|
||||
*rpl = '\0';
|
||||
|
||||
return begin;
|
||||
}
|
||||
@ -115,7 +115,6 @@ 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, char mode) {
|
||||
@ -136,7 +135,6 @@ struct zip_t *zip_open(const char *zipname, int level, char mode) {
|
||||
if (!zip) goto cleanup;
|
||||
|
||||
zip->level = level;
|
||||
zip->mode = mode;
|
||||
switch (mode) {
|
||||
case 'w':
|
||||
// Create a new archive.
|
||||
@ -155,13 +153,11 @@ struct zip_t *zip_open(const char *zipname, int level, char mode) {
|
||||
// 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:
|
||||
@ -220,7 +216,7 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
|
||||
}
|
||||
|
||||
pzip = &(zip->archive);
|
||||
if (zip->mode == 'r') {
|
||||
if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) {
|
||||
zip->entry.index = mz_zip_reader_locate_file(pzip, zip->entry.name, NULL, 0);
|
||||
if (zip->entry.index < 0) {
|
||||
goto cleanup;
|
||||
@ -302,6 +298,58 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int zip_entry_openbyindex(struct zip_t *zip, int index) {
|
||||
mz_zip_archive *pZip = NULL;
|
||||
if (!zip) {
|
||||
// zip_t handler is not initialized
|
||||
return -1;
|
||||
}
|
||||
|
||||
pZip = &(zip->archive);
|
||||
if (pZip->m_zip_mode != MZ_ZIP_MODE_READING) {
|
||||
// open by index requires readonly mode
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (index < 0 || index >= pZip->m_total_files) {
|
||||
// index out of range
|
||||
return -1;
|
||||
}
|
||||
|
||||
const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, index));
|
||||
if (!pHeader) {
|
||||
// cannot find header in central directory
|
||||
return -1;
|
||||
}
|
||||
|
||||
mz_uint namelen = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
|
||||
const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
|
||||
if (!pFilename) {
|
||||
// entry name is NULL
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
.ZIP File Format Specification Version: 6.3.3
|
||||
|
||||
4.4.17.1 The name of the file, with optional relative path.
|
||||
The path stored MUST not contain a drive or
|
||||
device letter, or a leading slash. All slashes
|
||||
MUST be forward slashes '/' as opposed to
|
||||
backwards slashes '\' for compatibility with Amiga
|
||||
and UNIX file systems etc. If input came from standard
|
||||
input, there is no file name field.
|
||||
*/
|
||||
zip->entry.name = strrpl(pFilename, namelen, '\\', '/');
|
||||
if (!zip->entry.name) {
|
||||
// local entry name is NULL
|
||||
return -1;
|
||||
}
|
||||
zip->entry.index = index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zip_entry_close(struct zip_t *zip) {
|
||||
mz_zip_archive *pzip = NULL;
|
||||
mz_uint level;
|
||||
@ -317,12 +365,12 @@ int zip_entry_close(struct zip_t *zip) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (zip->mode == 'r') {
|
||||
pzip = &(zip->archive);
|
||||
if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) {
|
||||
status = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pzip = &(zip->archive);
|
||||
level = zip->level & 0xF;
|
||||
if (level) {
|
||||
done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH);
|
||||
@ -401,6 +449,20 @@ int zip_entry_index(struct zip_t *zip) {
|
||||
return zip->entry.index;
|
||||
}
|
||||
|
||||
int zip_entry_isdir(struct zip_t *zip) {
|
||||
if (!zip) {
|
||||
// zip_t handler is not initialized
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (zip->entry.index < 0) {
|
||||
// zip entry is not opened
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)mz_zip_reader_is_file_a_directory(&zip->archive, (mz_uint)zip->entry.index);
|
||||
}
|
||||
|
||||
int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) {
|
||||
mz_uint level;
|
||||
mz_zip_archive *pzip = NULL;
|
||||
@ -477,12 +539,12 @@ int zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (zip->mode != 'r' || zip->entry.index < 0) {
|
||||
pzip = &(zip->archive);
|
||||
if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || 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
|
||||
@ -502,12 +564,12 @@ int zip_entry_fread(struct zip_t *zip, const char *filename) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (zip->mode != 'r' || zip->entry.index < 0) {
|
||||
pzip = &(zip->archive);
|
||||
if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || 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
|
||||
@ -529,17 +591,14 @@ int zip_entry_extract(struct zip_t *zip,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (zip->mode != 'r' || zip->entry.index < 0) {
|
||||
pzip = &(zip->archive);
|
||||
if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || 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;
|
||||
|
||||
return (mz_zip_reader_extract_to_callback(pzip, idx, on_extract, arg, 0))
|
||||
? 0
|
||||
: -1;
|
||||
return (mz_zip_reader_extract_to_callback(pzip, idx, on_extract, arg, 0)) ? 0 : -1;
|
||||
}
|
||||
|
||||
int zip_total_entries(struct zip_t *zip) {
|
||||
|
29
src/zip.h
29
src/zip.h
@ -55,7 +55,10 @@ extern struct zip_t *zip_open(const char *zipname, int level, char mode);
|
||||
extern void zip_close(struct zip_t *zip);
|
||||
|
||||
/*
|
||||
Opens a new entry for writing in the zip archive.
|
||||
Opens an entry by name in the zip archive.
|
||||
For zip archive opened in 'w' or 'a' mode the function will append
|
||||
a new entry. In readonly mode the function tries to locate the entry
|
||||
in global dictionary.
|
||||
|
||||
Args:
|
||||
zip: zip archive handler.
|
||||
@ -66,6 +69,19 @@ extern void zip_close(struct zip_t *zip);
|
||||
*/
|
||||
extern int zip_entry_open(struct zip_t *zip, const char *entryname);
|
||||
|
||||
/*
|
||||
Opens a new entry by index in the zip archive.
|
||||
This function is only valid if zip archive was opened in 'r' (readonly) mode.
|
||||
|
||||
Args:
|
||||
zip: zip archive handler.
|
||||
index: index in local dictionary.
|
||||
|
||||
Returns:
|
||||
The return code - 0 on success, negative number (< 0) on error.
|
||||
*/
|
||||
extern int zip_entry_openbyindex(struct zip_t *zip, int index);
|
||||
|
||||
/*
|
||||
Closes a zip entry, flushes buffer and releases resources.
|
||||
|
||||
@ -105,6 +121,17 @@ extern const char *zip_entry_name(struct zip_t *zip);
|
||||
*/
|
||||
extern int zip_entry_index(struct zip_t *zip);
|
||||
|
||||
/*
|
||||
Determines if the current zip entry is a directory entry.
|
||||
|
||||
Args:
|
||||
zip: zip archive handler.
|
||||
|
||||
Returns:
|
||||
The return code - 1 (true), 0 (false), negative number (< 0) on error.
|
||||
*/
|
||||
extern int zip_entry_isdir(struct zip_t *zip);
|
||||
|
||||
/*
|
||||
Compresses an input buffer for the current zip entry.
|
||||
|
||||
|
40
test/test.c
40
test/test.c
@ -159,6 +159,44 @@ static void test_entry_index(void) {
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
static void test_entry_openbyindex(void) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
assert(zip != NULL);
|
||||
|
||||
assert(0 == zip_entry_openbyindex(zip, 1));
|
||||
assert(1 == zip_entry_index(zip));
|
||||
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt"));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
assert(0 == zip_entry_openbyindex(zip, 0));
|
||||
assert(0 == zip_entry_index(zip));
|
||||
assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt"));
|
||||
assert(0 == zip_entry_close(zip));
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
static void test_list_entries(void) {
|
||||
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
|
||||
assert(zip != NULL);
|
||||
|
||||
int i = 0, n = zip_total_entries(zip);
|
||||
for (; i < n; ++i) {
|
||||
assert(0 == zip_entry_openbyindex(zip, i));
|
||||
fprintf(stdout, "[%d]: %s", i, zip_entry_name(zip));
|
||||
if (zip_entry_isdir(zip)) {
|
||||
fprintf(stdout, " (DIR)");
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
assert(0 == zip_entry_close(zip));
|
||||
}
|
||||
|
||||
zip_close(zip);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_write();
|
||||
test_append();
|
||||
@ -167,6 +205,8 @@ int main(int argc, char *argv[]) {
|
||||
test_total_entries();
|
||||
test_entry_name();
|
||||
test_entry_index();
|
||||
test_entry_openbyindex();
|
||||
test_list_entries();
|
||||
|
||||
return remove(ZIPNAME);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user