Skip to content

Commit

Permalink
offset api (#326)
Browse files Browse the repository at this point in the history
  • Loading branch information
kuba-- authored Dec 17, 2023
1 parent 2dc55b0 commit a93ea8f
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 18 deletions.
47 changes: 29 additions & 18 deletions src/zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ struct zip_entry_t {
mz_uint64 uncomp_size;
mz_uint64 comp_size;
mz_uint32 uncomp_crc32;
mz_uint64 offset;
mz_uint64 dir_offset;
mz_uint8 header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
mz_uint64 header_offset;
mz_uint16 method;
Expand Down Expand Up @@ -1072,7 +1072,7 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname,
zip->entry.comp_size = stats.m_comp_size;
zip->entry.uncomp_size = stats.m_uncomp_size;
zip->entry.uncomp_crc32 = stats.m_crc32;
zip->entry.offset = stats.m_central_dir_ofs;
zip->entry.dir_offset = stats.m_central_dir_ofs;
zip->entry.header_offset = stats.m_local_header_ofs;
zip->entry.method = stats.m_method;
zip->entry.external_attr = stats.m_external_attr;
Expand All @@ -1089,7 +1089,7 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname,
zip->entry.comp_size = 0;
zip->entry.uncomp_size = 0;
zip->entry.uncomp_crc32 = MZ_CRC32_INIT;
zip->entry.offset = zip->archive.m_archive_size;
zip->entry.dir_offset = zip->archive.m_archive_size;
zip->entry.header_offset = zip->archive.m_archive_size;
memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
zip->entry.method = level ? MZ_DEFLATED : 0;
Expand All @@ -1116,7 +1116,7 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname,
goto cleanup;
}

if (!mz_zip_writer_write_zeros(pzip, zip->entry.offset,
if (!mz_zip_writer_write_zeros(pzip, zip->entry.dir_offset,
num_alignment_padding_bytes)) {
// Cannot memset zip entry header
err = ZIP_EMEMSET;
Expand Down Expand Up @@ -1146,7 +1146,8 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname,
goto cleanup;
}

zip->entry.header_offset = zip->entry.offset + num_alignment_padding_bytes;
zip->entry.header_offset =
zip->entry.dir_offset + num_alignment_padding_bytes;

if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset,
zip->entry.header,
Expand All @@ -1160,28 +1161,29 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname,
MZ_ASSERT(
(zip->entry.header_offset & (pzip->m_file_offset_alignment - 1)) == 0);
}
zip->entry.offset += num_alignment_padding_bytes + sizeof(zip->entry.header);
zip->entry.dir_offset +=
num_alignment_padding_bytes + sizeof(zip->entry.header);

if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, zip->entry.name,
if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, zip->entry.name,
entrylen) != entrylen) {
// Cannot write data to zip entry
err = ZIP_EWRTENT;
goto cleanup;
}

zip->entry.offset += entrylen;
zip->entry.dir_offset += entrylen;

if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, extra_data,
if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, extra_data,
extra_size) != extra_size) {
// Cannot write ZIP64 data to zip entry
err = ZIP_EWRTENT;
goto cleanup;
}
zip->entry.offset += extra_size;
zip->entry.dir_offset += extra_size;

if (level) {
zip->entry.state.m_pZip = pzip;
zip->entry.state.m_cur_archive_file_ofs = zip->entry.offset;
zip->entry.state.m_cur_archive_file_ofs = zip->entry.dir_offset;
zip->entry.state.m_comp_size = 0;

if (tdefl_init(&(zip->entry.comp), mz_zip_writer_add_put_buf_callback,
Expand Down Expand Up @@ -1277,7 +1279,7 @@ int zip_entry_openbyindex(struct zip_t *zip, size_t index) {
zip->entry.comp_size = stats.m_comp_size;
zip->entry.uncomp_size = stats.m_uncomp_size;
zip->entry.uncomp_crc32 = stats.m_crc32;
zip->entry.offset = stats.m_central_dir_ofs;
zip->entry.dir_offset = stats.m_central_dir_ofs;
zip->entry.header_offset = stats.m_local_header_ofs;
zip->entry.method = stats.m_method;
zip->entry.external_attr = stats.m_external_attr;
Expand Down Expand Up @@ -1321,7 +1323,7 @@ int zip_entry_close(struct zip_t *zip) {
goto cleanup;
}
zip->entry.comp_size = zip->entry.state.m_comp_size;
zip->entry.offset = zip->entry.state.m_cur_archive_file_ofs;
zip->entry.dir_offset = zip->entry.state.m_cur_archive_file_ofs;
zip->entry.method = MZ_DEFLATED;
}

Expand All @@ -1335,13 +1337,14 @@ int zip_entry_close(struct zip_t *zip) {
MZ_WRITE_LE64(local_dir_footer + 8, zip->entry.comp_size);
MZ_WRITE_LE64(local_dir_footer + 16, zip->entry.uncomp_size);

if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, local_dir_footer,
if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset,
local_dir_footer,
local_dir_footer_size) != local_dir_footer_size) {
// Cannot write zip entry header
err = ZIP_EWRTHDR;
goto cleanup;
}
zip->entry.offset += local_dir_footer_size;
zip->entry.dir_offset += local_dir_footer_size;

pExtra_data = extra_data;
extra_size = mz_zip_writer_create_zip64_extra_data(
Expand Down Expand Up @@ -1372,7 +1375,7 @@ int zip_entry_close(struct zip_t *zip) {
}

pzip->m_total_files++;
pzip->m_archive_size = zip->entry.offset;
pzip->m_archive_size = zip->entry.dir_offset;

cleanup:
if (zip) {
Expand Down Expand Up @@ -1431,6 +1434,14 @@ unsigned int zip_entry_crc32(struct zip_t *zip) {
return zip ? zip->entry.uncomp_crc32 : 0;
}

unsigned long long zip_entry_dir_offset(struct zip_t *zip) {
return zip ? zip->entry.dir_offset : 0;
}

unsigned long long zip_entry_header_offset(struct zip_t *zip) {
return zip ? zip->entry.header_offset : 0;
}

int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) {
mz_uint level;
mz_zip_archive *pzip = NULL;
Expand All @@ -1449,12 +1460,12 @@ int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) {

level = zip->level & 0xF;
if (!level) {
if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, buf,
if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, buf,
bufsize) != bufsize)) {
// Cannot write buffer
return ZIP_EWRTENT;
}
zip->entry.offset += bufsize;
zip->entry.dir_offset += bufsize;
zip->entry.comp_size += bufsize;
} else {
status = tdefl_compress_buffer(&(zip->entry.comp), buf, bufsize,
Expand Down
19 changes: 19 additions & 0 deletions src/zip.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,25 @@ extern ZIP_EXPORT unsigned long long zip_entry_comp_size(struct zip_t *zip);
*/
extern ZIP_EXPORT unsigned int zip_entry_crc32(struct zip_t *zip);

/**
* Returns byte offset of the current zip entry
* in the archive's central directory.
*
* @param zip zip archive handler.
*
* @return the offset in bytes.
*/
extern ZIP_EXPORT unsigned long long zip_entry_dir_offset(struct zip_t *zip);

/**
* Returns the current zip entry's local header file offset in bytes.
*
* @param zip zip archive handler.
*
* @return the entry's local header file offset in bytes.
*/
extern ZIP_EXPORT unsigned long long zip_entry_header_offset(struct zip_t *zip);

/**
* Compresses an input buffer for the current zip entry.
*
Expand Down
33 changes: 33 additions & 0 deletions test/test_entry.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
#define UNLINK unlink
#endif

#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE \
(sizeof(unsigned short) * 2 + sizeof(unsigned long long) * 3)
#define MZ_ZIP_LOCAL_DIR_HEADER_SIZE 30

static char ZIPNAME[L_tmpnam + 1] = {0};

#define CRC32DATA1 2220805626
Expand Down Expand Up @@ -160,15 +164,18 @@ MU_TEST(test_entry_openbyindex) {

mu_assert_int_eq(0, zip_entry_openbyindex(zip, 1));
mu_assert_int_eq(1, zip_entry_index(zip));

mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip));
mu_check(CRC32DATA2 == zip_entry_crc32(zip));

mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt"));
mu_assert_int_eq(0, zip_entry_close(zip));

mu_assert_int_eq(0, zip_entry_openbyindex(zip, 0));
mu_assert_int_eq(0, zip_entry_index(zip));
mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip));
mu_check(CRC32DATA1 == zip_entry_crc32(zip));

mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt"));
mu_assert_int_eq(0, zip_entry_close(zip));

Expand Down Expand Up @@ -380,6 +387,31 @@ MU_TEST(test_entries_delete) {
zip_close(zip);
}

MU_TEST(test_entry_offset) {
struct zip_t *zip = zip_open(ZIPNAME, 0, 'r');
mu_check(zip != NULL);

unsigned long long off = 0ULL;
int i = 0, n = zip_entries_total(zip);
for (; i < n; i++) {
mu_assert_int_eq(0, zip_entry_openbyindex(zip, i));
mu_assert_int_eq(i, zip_entry_index(zip));

mu_assert_int_eq(off, zip_entry_header_offset(zip));

off = zip_entry_header_offset(zip) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
strlen(zip_entry_name(zip)) + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE +
zip_entry_comp_size(zip);
fprintf(stdout, "\n[%d: %s]: header: %llu, dir: %llu, size: %llu (%llu)\n",
i, zip_entry_name(zip), zip_entry_header_offset(zip),
zip_entry_dir_offset(zip), zip_entry_comp_size(zip), off);

mu_assert_int_eq(0, zip_entry_close(zip));
}

zip_close(zip);
}

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

Expand All @@ -391,6 +423,7 @@ MU_TEST_SUITE(test_entry_suite) {
MU_RUN_TEST(test_list_entries);
MU_RUN_TEST(test_entries_deletebyindex);
MU_RUN_TEST(test_entries_delete);
MU_RUN_TEST(test_entry_offset);
}

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

0 comments on commit a93ea8f

Please sign in to comment.