diff --git a/src/zip.c b/src/zip.c index 43c938e9..a35f86e3 100644 --- a/src/zip.c +++ b/src/zip.c @@ -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; @@ -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; @@ -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; @@ -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; @@ -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, @@ -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, @@ -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; @@ -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; } @@ -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( @@ -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) { @@ -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; @@ -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, diff --git a/src/zip.h b/src/zip.h index ce2246e8..324904ca 100644 --- a/src/zip.h +++ b/src/zip.h @@ -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. * diff --git a/test/test_entry.c b/test/test_entry.c index 3646edfc..a0c40256 100644 --- a/test/test_entry.c +++ b/test/test_entry.c @@ -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 @@ -160,8 +164,10 @@ 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)); @@ -169,6 +175,7 @@ MU_TEST(test_entry_openbyindex) { 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)); @@ -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); @@ -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