Skip to content

Commit

Permalink
Update zip.c and zip.h with new functions for reading in-memory zip a…
Browse files Browse the repository at this point in the history
…rchives
  • Loading branch information
bytesiz3d committed Feb 14, 2024
1 parent 4696e96 commit 3028843
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 2 deletions.
48 changes: 46 additions & 2 deletions src/zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ struct zip_entry_mark_t {
size_t lf_length;
};

static const char *const zip_errlist[33] = {
static const char *const zip_errlist[34] = {
NULL,
"not initialized\0",
"invalid entry name\0",
Expand Down Expand Up @@ -150,11 +150,12 @@ static const char *const zip_errlist[33] = {
"cannot initialize reader\0",
"cannot initialize writer\0",
"cannot initialize writer from reader\0",
"invalid in-memory zip archive\0",
};

const char *zip_strerror(int errnum) {
errnum = -errnum;
if (errnum <= 0 || errnum >= 33) {
if (errnum <= 0 || errnum >= 34) {
return NULL;
}

Expand Down Expand Up @@ -1011,6 +1012,49 @@ struct zip_t *zip_openwitherror(const char *zipname, int level, char mode,
return NULL;
}

struct zip_t *zip_openwitherror_mem(const void *data, size_t size, int level,
int *errnum) {
struct zip_t *zip = NULL;
*errnum = 0;

if (!data || size == 0) {
// zip_t archive memory is empty
*errnum = ZIP_EINVZIPMEM;
goto cleanup;
}

if (level < 0)
level = MZ_DEFAULT_LEVEL;
if ((level & 0xF) > MZ_UBER_COMPRESSION) {
// Wrong compression level
*errnum = ZIP_EINVLVL;
goto cleanup;
}

zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
if (!zip) {
// out of memory
*errnum = ZIP_EOOMEM;
goto cleanup;
}

zip->level = (mz_uint)level;
if (!mz_zip_reader_init_mem(
&(zip->archive), data, size,
zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) {
// Memory does not point to valid zip archive
// or cannot initialize zip_archive reader
*errnum = ZIP_ERINIT;
goto cleanup;
}

return zip;

cleanup:
CLEANUP(zip);
return NULL;
}

void zip_close(struct zip_t *zip) {
if (zip) {
mz_zip_archive *pZip = &(zip->archive);
Expand Down
15 changes: 15 additions & 0 deletions src/zip.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ typedef long ssize_t; /* byte count or error */
#define ZIP_ERINIT -30 // cannot initialize reader
#define ZIP_EWINIT -31 // cannot initialize writer
#define ZIP_EWRINIT -32 // cannot initialize writer from reader
#define ZIP_EINVZIPMEM -33 // invalid in-memory zip archive

/**
* Looks up the error message string corresponding to an error number.
Expand Down Expand Up @@ -144,6 +145,20 @@ extern ZIP_EXPORT struct zip_t *zip_open(const char *zipname, int level,
extern ZIP_EXPORT struct zip_t *
zip_openwitherror(const char *zipname, int level, char mode, int *errnum);

/**
* Opens in-memory zip archive with compression level in read-only mode.
* The function additionally returns @param errnum -
*
* @param data pointer to zip archive raw data
* @param size size of zip archive
* @param level compression level (0-9 are the standard zlib-style levels).
* @param errnum 0 on success, negative number (< 0) on error.
*
* @return the zip archive handler or NULL on error
*/
extern ZIP_EXPORT struct zip_t *
zip_openwitherror_mem(const void *data, size_t size, int level, int *errnum);

/**
* Closes the zip archive, releases resources - always finalize.
*
Expand Down
59 changes: 59 additions & 0 deletions test/test_read.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,70 @@ MU_TEST(test_noallocread) {
zip_close(zip);
}

MU_TEST(test_read_mem) {
char *buf = NULL;
ssize_t bufsize;
size_t buftmp;

void *zip_mem = NULL;
size_t zip_mem_size = 0;
{
FILE *f = fopen(ZIPNAME, "rb");
mu_check(f != NULL);

fseek(f, 0, SEEK_END);
zip_mem_size = ftell(f);
rewind(f);

zip_mem = malloc(zip_mem_size);
mu_check(zip_mem != NULL);

size_t read_size = fread(zip_mem, 1, zip_mem_size, f);
mu_assert_int_eq(zip_mem_size, read_size);
fclose(f);
}

int errnum = 0;
struct zip_t *zip = zip_openwitherror_mem(zip_mem, zip_mem_size, 0, &errnum);
mu_check(zip != NULL);
mu_assert_int_eq(1, zip_is64(zip));

mu_assert_int_eq(0, zip_entry_open(zip, "test\\test-1.txt"));
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
mu_check(CRC32DATA1 == zip_entry_crc32(zip));
bufsize = zip_entry_read(zip, (void **)&buf, &buftmp);
mu_assert_int_eq(strlen(TESTDATA1), bufsize);
mu_assert_int_eq((size_t)bufsize, buftmp);
mu_assert_int_eq(0, strncmp(buf, TESTDATA1, bufsize));
mu_assert_int_eq(0, zip_entry_close(zip));
free(buf);
buf = NULL;

mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt"));
mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
mu_check(CRC32DATA2 == zip_entry_crc32(zip));
bufsize = zip_entry_read(zip, (void **)&buf, NULL);
mu_assert_int_eq(strlen(TESTDATA2), (size_t)bufsize);
mu_assert_int_eq(0, strncmp(buf, TESTDATA2, (size_t)bufsize));
mu_assert_int_eq(0, zip_entry_close(zip));
free(buf);
buf = NULL;

mu_assert_int_eq(0, zip_entry_open(zip, "test\\empty/"));
mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/empty/"));
mu_assert_int_eq(0, zip_entry_size(zip));
mu_assert_int_eq(0, zip_entry_crc32(zip));
mu_assert_int_eq(0, zip_entry_close(zip));

zip_close(zip);
}

MU_TEST_SUITE(test_read_suite) {
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);

MU_RUN_TEST(test_read);
MU_RUN_TEST(test_noallocread);
MU_RUN_TEST(test_read_mem);
}

#define UNUSED(x) (void)x
Expand Down

0 comments on commit 3028843

Please sign in to comment.