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);
|
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
|
# Bindings
|
||||||
* Compile zip library as a dynamic library.
|
* Compile zip library as a dynamic library.
|
||||||
```shell
|
```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) {
|
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 *begin = rpl;
|
||||||
char c;
|
char c;
|
||||||
while((c = *str++)) {
|
size_t i;
|
||||||
|
for(i = 0; (i < n) && (c = *str++); ++i) {
|
||||||
if (c == oldchar) {
|
if (c == oldchar) {
|
||||||
c = newchar;
|
c = newchar;
|
||||||
}
|
}
|
||||||
*rpl++ = c;
|
*rpl++ = c;
|
||||||
}
|
}
|
||||||
*rpl = '\0';
|
|
||||||
|
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
@ -115,7 +115,6 @@ struct zip_t {
|
|||||||
mz_zip_archive archive;
|
mz_zip_archive archive;
|
||||||
mz_uint level;
|
mz_uint level;
|
||||||
struct zip_entry_t entry;
|
struct zip_entry_t entry;
|
||||||
char mode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct zip_t *zip_open(const char *zipname, int level, 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;
|
if (!zip) goto cleanup;
|
||||||
|
|
||||||
zip->level = level;
|
zip->level = level;
|
||||||
zip->mode = mode;
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 'w':
|
case 'w':
|
||||||
// Create a new archive.
|
// Create a new archive.
|
||||||
@ -155,13 +153,11 @@ struct zip_t *zip_open(const char *zipname, int level, char mode) {
|
|||||||
// zip_archive reader
|
// zip_archive reader
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 'a' &&
|
if (mode == 'a' &&
|
||||||
!mz_zip_writer_init_from_reader(&(zip->archive), zipname)) {
|
!mz_zip_writer_init_from_reader(&(zip->archive), zipname)) {
|
||||||
mz_zip_reader_end(&(zip->archive));
|
mz_zip_reader_end(&(zip->archive));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -220,7 +216,7 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pzip = &(zip->archive);
|
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);
|
zip->entry.index = mz_zip_reader_locate_file(pzip, zip->entry.name, NULL, 0);
|
||||||
if (zip->entry.index < 0) {
|
if (zip->entry.index < 0) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@ -302,6 +298,58 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
|
|||||||
return -1;
|
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) {
|
int zip_entry_close(struct zip_t *zip) {
|
||||||
mz_zip_archive *pzip = NULL;
|
mz_zip_archive *pzip = NULL;
|
||||||
mz_uint level;
|
mz_uint level;
|
||||||
@ -317,12 +365,12 @@ int zip_entry_close(struct zip_t *zip) {
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (zip->mode == 'r') {
|
pzip = &(zip->archive);
|
||||||
|
if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) {
|
||||||
status = 0;
|
status = 0;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
pzip = &(zip->archive);
|
|
||||||
level = zip->level & 0xF;
|
level = zip->level & 0xF;
|
||||||
if (level) {
|
if (level) {
|
||||||
done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH);
|
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;
|
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) {
|
int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) {
|
||||||
mz_uint level;
|
mz_uint level;
|
||||||
mz_zip_archive *pzip = NULL;
|
mz_zip_archive *pzip = NULL;
|
||||||
@ -477,12 +539,12 @@ int zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) {
|
|||||||
return -1;
|
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
|
// the entry is not found or we do not have read access
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pzip = &(zip->archive);
|
|
||||||
idx = (mz_uint)zip->entry.index;
|
idx = (mz_uint)zip->entry.index;
|
||||||
if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
|
if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
|
||||||
// the entry is a directory
|
// the entry is a directory
|
||||||
@ -502,12 +564,12 @@ int zip_entry_fread(struct zip_t *zip, const char *filename) {
|
|||||||
return -1;
|
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
|
// the entry is not found or we do not have read access
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pzip = &(zip->archive);
|
|
||||||
idx = (mz_uint)zip->entry.index;
|
idx = (mz_uint)zip->entry.index;
|
||||||
if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
|
if (mz_zip_reader_is_file_a_directory(pzip, idx)) {
|
||||||
// the entry is a directory
|
// the entry is a directory
|
||||||
@ -529,17 +591,14 @@ int zip_entry_extract(struct zip_t *zip,
|
|||||||
return -1;
|
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
|
// the entry is not found or we do not have read access
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pzip = &(zip->archive);
|
|
||||||
idx = (mz_uint)zip->entry.index;
|
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) {
|
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);
|
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:
|
Args:
|
||||||
zip: zip archive handler.
|
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);
|
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.
|
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);
|
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.
|
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);
|
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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
test_write();
|
test_write();
|
||||||
test_append();
|
test_append();
|
||||||
@ -167,6 +205,8 @@ int main(int argc, char *argv[]) {
|
|||||||
test_total_entries();
|
test_total_entries();
|
||||||
test_entry_name();
|
test_entry_name();
|
||||||
test_entry_index();
|
test_entry_index();
|
||||||
|
test_entry_openbyindex();
|
||||||
|
test_list_entries();
|
||||||
|
|
||||||
return remove(ZIPNAME);
|
return remove(ZIPNAME);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user