Improve support for 3MF files. Some of these set lots of data in the EOCD to 0xff, relying on the EOCD64 data. Add two test cases, one for this, and one for multidisk support (which doesn't exist in libzip).
diff --git a/lib/zip_open.c b/lib/zip_open.c index 3f866a9..d6209ee 100644 --- a/lib/zip_open.c +++ b/lib/zip_open.c
@@ -293,11 +293,6 @@ return NULL; } - if (_zip_buffer_get_32(buffer) != 0) { - zip_error_set(error, ZIP_ER_MULTIDISK, 0); - return NULL; - } - if (eocd_offset >= EOCD64LOCLEN && memcmp(_zip_buffer_data(buffer) + eocd_offset - EOCD64LOCLEN, EOCD64LOC_MAGIC, 4) == 0) { _zip_buffer_set_offset(buffer, eocd_offset - EOCD64LOCLEN); cd = _zip_read_eocd64(za->src, buffer, buf_offset, za->flags, error); @@ -668,7 +663,8 @@ } -static zip_cdir_t *_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error) +static zip_cdir_t * +_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error) { zip_cdir_t *cd; zip_uint64_t i, nentry, size, offset, eocd_offset; @@ -680,7 +676,12 @@ eocd_offset = _zip_buffer_offset(buffer); - _zip_buffer_get(buffer, 8); /* magic and number of disks already verified */ + _zip_buffer_get(buffer, 4); /* magic already verified */ + + if (_zip_buffer_get_32(buffer) != 0) { + zip_error_set(error, ZIP_ER_MULTIDISK, 0); + return NULL; + } /* number of cdir-entries on this disk */ i = _zip_buffer_get_16(buffer); @@ -730,10 +731,14 @@ zip_uint64_t eocd_offset; zip_uint64_t size, nentry, i, eocdloc_offset; bool free_buffer; + zip_uint32_t num_disks, num_disks64, eocd_disk, eocd_disk64; eocdloc_offset = _zip_buffer_offset(buffer); - _zip_buffer_get(buffer, 8); /* magic and single disk already verified */ + _zip_buffer_get(buffer, 4); /* magic already verified */ + + num_disks = _zip_buffer_get_16(buffer); + eocd_disk = _zip_buffer_get_16(buffer); eocd_offset = _zip_buffer_get_64(buffer); if (eocd_offset > ZIP_INT64_MAX || eocd_offset + EOCD64LEN < eocd_offset) { @@ -779,8 +784,29 @@ return NULL; } - _zip_buffer_get(buffer, 12); /* skip version made by/needed and num disks */ - + _zip_buffer_get(buffer, 4); /* skip version made by/needed */ + + num_disks64 = _zip_buffer_get_32(buffer); + eocd_disk64 = _zip_buffer_get_32(buffer); + + /* if eocd values are 0xffff, we have to use eocd64 values. + otherwise, if the values are not the same, it's inconsistent; + in any case, if the value is not 0, we don't support it */ + if (num_disks == 0xffff) { + num_disks = num_disks64; + } + if (eocd_disk == 0xffff) { + eocd_disk = eocd_disk64; + } + if ((flags & ZIP_CHECKCONS) && (eocd_disk != eocd_disk64 || num_disks != num_disks64)) { + zip_error_set(error, ZIP_ER_INCONS, 0); + return NULL; + } + if (num_disks != 0 || eocd_disk != 0) { + zip_error_set(error, ZIP_ER_MULTIDISK, 0); + return NULL; + } + nentry = _zip_buffer_get_64(buffer); i = _zip_buffer_get_64(buffer);
diff --git a/regress/CMakeLists.txt b/regress/CMakeLists.txt index 8d7816e..332530f 100644 --- a/regress/CMakeLists.txt +++ b/regress/CMakeLists.txt
@@ -72,6 +72,7 @@ open_filename_empty.test open_incons.test open_many_ok.test + open_multidisk.test open_new_but_exists.test open_new_ok.test open_nonarchive.test @@ -79,6 +80,7 @@ open_ok.test open_too_short.test open_truncate.test + open_zip64_3mf.test open_zip64_ok.test rename_ascii.test rename_cp437.test
diff --git a/regress/Makefile.am b/regress/Makefile.am index 065e15e..0fb4c06 100644 --- a/regress/Makefile.am +++ b/regress/Makefile.am
@@ -86,6 +86,7 @@ incons-local-size-larger.zip \ large-uncompressable \ manyfiles-zip.zip \ + multidisk.zip \ rename_ok.zip \ streamed.zip \ streamed-zip64.zip \ @@ -119,7 +120,8 @@ utf-8-standardization-input.zip \ utf-8-standardization-output.zip \ zip-in-archive-comment.zip \ - zip64.zip + zip64.zip \ + zip64-3mf.zip TESTS_ENVIRONMENT= ZIPCMP=${top_builddir}/src/zipcmp # ${srcdir}/runtest @@ -186,6 +188,7 @@ open_filename_empty.test \ open_incons.test \ open_many_ok.test \ + open_multidisk.test \ open_new_but_exists.test \ open_new_ok.test \ open_nonarchive.test \ @@ -193,6 +196,7 @@ open_ok.test \ open_too_short.test \ open_truncate.test \ + open_zip64_3mf.test \ open_zip64_ok.test \ rename_ascii.test \ rename_cp437.test \
diff --git a/regress/multidisk.zip b/regress/multidisk.zip new file mode 100644 index 0000000..28dafb9 --- /dev/null +++ b/regress/multidisk.zip Binary files differ
diff --git a/regress/open_multidisk.test b/regress/open_multidisk.test new file mode 100644 index 0000000..1da4a5c --- /dev/null +++ b/regress/open_multidisk.test
@@ -0,0 +1,7 @@ +# zip_open: file is part of a multi-disk zip archive +program tryopen +args test.piz +return 1 +file test.piz multidisk.zip multidisk.zip +stdout opening 'test.piz' returned error 1 +stderr 1 errors
diff --git a/regress/open_zip64_3mf.test b/regress/open_zip64_3mf.test new file mode 100644 index 0000000..4a57154 --- /dev/null +++ b/regress/open_zip64_3mf.test
@@ -0,0 +1,6 @@ +# zip_open: ZIP64 file opens fine even when most eocd entries are 0xff (3MF format) +program tryopen +args test.zip +return 0 +file test.zip zip64-3mf.zip zip64-3mf.zip +stdout opening 'test.zip' succeeded, 1 entries
diff --git a/regress/zip64-3mf.zip b/regress/zip64-3mf.zip new file mode 100644 index 0000000..a2ccf24 --- /dev/null +++ b/regress/zip64-3mf.zip Binary files differ