diff options
-rw-r--r-- | src/tools/singlejar/combiners.cc | 7 | ||||
-rw-r--r-- | src/tools/singlejar/input_jar.cc | 18 | ||||
-rw-r--r-- | src/tools/singlejar/input_jar.h | 2 | ||||
-rw-r--r-- | src/tools/singlejar/output_huge_jar_test.cc | 77 | ||||
-rw-r--r-- | src/tools/singlejar/output_jar.cc | 185 | ||||
-rw-r--r-- | src/tools/singlejar/output_jar.h | 6 | ||||
-rw-r--r-- | src/tools/singlejar/zip_headers.h | 100 |
7 files changed, 299 insertions, 96 deletions
diff --git a/src/tools/singlejar/combiners.cc b/src/tools/singlejar/combiners.cc index b0a712a2a7..ca2e224c7e 100644 --- a/src/tools/singlejar/combiners.cc +++ b/src/tools/singlejar/combiners.cc @@ -53,7 +53,7 @@ void *Concatenator::OutputEntry(bool compress) { // and compressed size values. uint8_t zip64_extension_buffer[sizeof(Zip64ExtraField) + 2 * sizeof(uint64_t)]; - bool huge_buffer = (buffer_->data_size() >= 0xFFFFFFFF); + bool huge_buffer = ziph::zfield_needs_ext64(buffer_->data_size()); if (huge_buffer) { deflated_buffer_size += sizeof(zip64_extension_buffer); } @@ -97,8 +97,9 @@ void *Concatenator::OutputEntry(bool compress) { lh->crc32(checksum); lh->compression_method(method); if (huge_buffer) { - lh->compressed_file_size32(compressed_size < 0xFFFFFFFF ? compressed_size - : 0xFFFFFFFF); + lh->compressed_file_size32(ziph::zfield_needs_ext64(compressed_size) + ? 0xFFFFFFFF + : compressed_size); // Not sure if this has to be written in the small case, but it shouldn't // hurt. const_cast<Zip64ExtraField *>(lh->zip64_extra_field()) diff --git a/src/tools/singlejar/input_jar.cc b/src/tools/singlejar/input_jar.cc index 348733689d..4a4a92c3b3 100644 --- a/src/tools/singlejar/input_jar.cc +++ b/src/tools/singlejar/input_jar.cc @@ -75,7 +75,7 @@ bool InputJar::Open(const std::string &path) { // First, sanity checks. uint64_t cen_position = ecd->cen_offset32(); - if (cen_position != 0xFFFFFFFF) { + if (!ziph::zfield_has_ext64(cen_position)) { if (!mapped_file_.mapped(mapped_file_.address(cen_position))) { diag_warnx("%s:%d: %s is corrupt: Central Directory location 0x%" PRIx64 " is invalid", @@ -93,7 +93,7 @@ bool InputJar::Open(const std::string &path) { } } uint64_t cen_size = ecd->cen_size32(); - if (cen_size != 0xFFFFFFFF) { + if (!ziph::zfield_has_ext64(cen_size)) { if (cen_size > mapped_file_.offset(ecd)) { diag_warnx("%s:%d: %s is corrupt: Central Directory size 0x%" PRIx64 " is too large", @@ -108,10 +108,10 @@ bool InputJar::Open(const std::string &path) { preamble_size_ = mapped_file_.offset(cdh_) - cen_position; } else { auto ecd64loc = reinterpret_cast<const ECD64Locator *>( - byte_ptr(ecd) - sizeof(ECD64Locator)); + ziph::byte_ptr(ecd) - sizeof(ECD64Locator)); if (ecd64loc->is()) { - auto ecd64 = - reinterpret_cast<const ECD64 *>(byte_ptr(ecd64loc) - sizeof(ECD64)); + auto ecd64 = reinterpret_cast<const ECD64 *>(ziph::byte_ptr(ecd64loc) - + sizeof(ECD64)); if (!ecd64->is()) { diag_warnx( "%s:%d: %s is corrupt, expected ECD64 record at offset 0x%" PRIx64 @@ -120,18 +120,20 @@ bool InputJar::Open(const std::string &path) { mapped_file_.Close(); return false; } - cdh_ = reinterpret_cast<const CDH *>(byte_ptr(ecd64) - ecd64->cen_size()); + cdh_ = reinterpret_cast<const CDH *>(ziph::byte_ptr(ecd64) - + ecd64->cen_size()); preamble_size_ = mapped_file_.offset(cdh_) - ecd64->cen_offset(); // Find CEN and preamble size. } else { - if (cen_size == 0xFFFFFFFF || cen_position == 0xFFFFFFFF) { + if (ziph::zfield_has_ext64(cen_size) || + ziph::zfield_has_ext64(cen_position)) { diag_warnx( "%s:%d: %s is corrupt, expected ECD64 locator record at " "offset 0x%" PRIx64 " is missing", __FILE__, __LINE__, path.c_str(), mapped_file_.offset(ecd64loc)); return false; } - cdh_ = reinterpret_cast<const CDH *>(byte_ptr(ecd) - cen_size); + cdh_ = reinterpret_cast<const CDH *>(ziph::byte_ptr(ecd) - cen_size); preamble_size_ = mapped_file_.offset(cdh_) - cen_position; } if (!cdh_->is()) { diff --git a/src/tools/singlejar/input_jar.h b/src/tools/singlejar/input_jar.h index 9c30df2856..35545f65e7 100644 --- a/src/tools/singlejar/input_jar.h +++ b/src/tools/singlejar/input_jar.h @@ -55,7 +55,7 @@ class InputJar { return nullptr; } const CDH *current_cdh = cdh_; - const uint8_t *new_cdr = byte_ptr(cdh_) + cdh_->size(); + const uint8_t *new_cdr = ziph::byte_ptr(cdh_) + cdh_->size(); if (!mapped_file_.mapped(new_cdr)) { diag_errx( 1, diff --git a/src/tools/singlejar/output_huge_jar_test.cc b/src/tools/singlejar/output_huge_jar_test.cc new file mode 100644 index 0000000000..6eefc7f24d --- /dev/null +++ b/src/tools/singlejar/output_huge_jar_test.cc @@ -0,0 +1,77 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <stdlib.h> + +#include "src/main/cpp/util/file.h" +#include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/port.h" +#include "src/main/cpp/util/strings.h" +#include "src/tools/singlejar/input_jar.h" +#include "src/tools/singlejar/options.h" +#include "src/tools/singlejar/output_jar.h" +#include "src/tools/singlejar/test_util.h" +#include "gtest/gtest.h" + +namespace { + +using singlejar_test_util::AllocateFile; +using singlejar_test_util::OutputFilePath; +using singlejar_test_util::VerifyZip; + +using std::string; + +#if !defined(DATA_DIR_TOP) +#define DATA_DIR_TOP +#endif + +class OutputHugeJarTest : public ::testing::Test { + protected: + void CreateOutput(const string &out_path, const std::vector<string> &args) { + const char *option_list[100] = {"--output", out_path.c_str()}; + int nargs = 2; + for (auto &arg : args) { + if (arg.empty()) { + continue; + } + option_list[nargs++] = arg.c_str(); + if (arg.find(' ') == string::npos) { + fprintf(stderr, " '%s'", arg.c_str()); + } else { + fprintf(stderr, " %s", arg.c_str()); + } + } + fprintf(stderr, "\n"); + options_.ParseCommandLine(nargs, option_list); + ASSERT_EQ(0, output_jar_.Doit(&options_)); + EXPECT_EQ(0, VerifyZip(out_path)); + } + + OutputJar output_jar_; + Options options_; +}; + +TEST_F(OutputHugeJarTest, EntryAbove4G) { + // Verifies that an entry above 4G is handled correctly. + + // Have huge launcher, then the first jar entry will be above 4G. + string launcher_path = OutputFilePath("launcher"); + ASSERT_TRUE(AllocateFile(launcher_path, 0x100000010)); + + string out_path = OutputFilePath("out.jar"); + CreateOutput(out_path, {"--java_launcher", launcher_path, "--sources", + DATA_DIR_TOP "src/tools/singlejar/libtest1.jar"}); +} + +} // namespace diff --git a/src/tools/singlejar/output_jar.cc b/src/tools/singlejar/output_jar.cc index 47ab373e2d..26f445fb5e 100644 --- a/src/tools/singlejar/output_jar.cc +++ b/src/tools/singlejar/output_jar.cc @@ -399,12 +399,13 @@ bool OutputJar::AddJar(int jar_path_index) { lh->data() + jar_entry->compressed_file_size()); num_bytes += jar_entry->compressed_file_size() + - ddr->size(0xFFFFFFFF == jar_entry->compressed_file_size32(), - 0xFFFFFFFF == jar_entry->uncompressed_file_size32()); + ddr->size( + ziph::zfield_has_ext64(jar_entry->compressed_file_size32()), + ziph::zfield_has_ext64(jar_entry->uncompressed_file_size32())); } else { num_bytes += lh->compressed_file_size(); } - off_t output_position = Position(); + off_t local_header_offset = Position(); // When normalize_timestamps is set, entry's timestamp is to be set to // 01/01/1980 00:00:00 (or to 01/01/1980 00:00:02, if an entry is a .class @@ -431,9 +432,10 @@ bool OutputJar::AddJar(int jar_path_index) { : reinterpret_cast<LH *>(lh_buffer); // Remove Unix timestamp field. if (lh_field_to_remove != nullptr) { - auto from_end = byte_ptr(lh) + lh->size(); + auto from_end = ziph::byte_ptr(lh) + lh->size(); size_t removed_size = lh_field_to_remove->size(); - size_t chunk1_size = byte_ptr(lh_field_to_remove) - byte_ptr(lh); + size_t chunk1_size = + ziph::byte_ptr(lh_field_to_remove) - ziph::byte_ptr(lh); size_t chunk2_size = lh->size() - (chunk1_size + removed_size); memcpy(lh_new, lh, chunk1_size); if (chunk2_size) { @@ -466,37 +468,8 @@ bool OutputJar::AddJar(int jar_path_index) { input_jar_path.c_str()); } - // Append central directory header for this file to the output central - // directory we are building. - TODO(output_position < 0xFFFFFFFF, "Handle Zip64"); - - CDH *out_cdh; - auto field_to_remove = - fix_timestamp ? jar_entry->unix_time_extra_field() : nullptr; - if (field_to_remove != nullptr) { - // Remove extra fields. - auto from_start = byte_ptr(jar_entry); - auto from_end = from_start + jar_entry->size(); - size_t removed_size = field_to_remove->size(); - size_t chunk1_size = byte_ptr(field_to_remove) - from_start; - size_t chunk2_size = jar_entry->size() - (chunk1_size + removed_size); - out_cdh = - reinterpret_cast<CDH *>(ReserveCdr(jar_entry->size() - removed_size)); - memcpy(out_cdh, jar_entry, chunk1_size); - if (chunk2_size) { - memcpy(reinterpret_cast<uint8_t *>(out_cdh) + chunk1_size, - from_end - chunk2_size, chunk2_size); - } - out_cdh->extra_fields(out_cdh->extra_fields(), - jar_entry->extra_fields_length() - removed_size); - } else { - out_cdh = AppendToDirectoryBuffer(jar_entry); - } - out_cdh->local_header_offset32(output_position); - if (fix_timestamp) { - out_cdh->last_mod_file_time(normalized_time); - out_cdh->last_mod_file_date(33); - } + AppendToDirectoryBuffer(jar_entry, local_header_offset, normalized_time, + fix_timestamp); ++entries_; } return input_jar.Close(); @@ -509,7 +482,6 @@ off_t OutputJar::Position() { // You'd think this could be "return ftell(file_);", but that // generates a needless call to lseek. So instead we cache our // current position in the output. - TODO(outpos_ < 0xFFFFFFFF, "Handle Zip64"); return outpos_; } @@ -560,8 +532,15 @@ void OutputJar::WriteEntry(void *buffer) { diag_err(1, "%s:%d: write", __FILE__, __LINE__); } // Data written, allocate CDH space and populate CDH. - CDH *cdh = reinterpret_cast<CDH *>(ReserveCdh( - sizeof(CDH) + entry->file_name_length() + entry->extra_fields_length())); + // Space needed for the CDH varies depending on whether output position field + // fits into 32 bits (we do not handle compressed/uncompressed entry sizes + // exceeding 32 bits at the moment). + uint16_t zip64_size = ziph::zfield_needs_ext64(output_position) + ? Zip64ExtraField::space_needed(1) + : 0; + CDH *cdh = reinterpret_cast<CDH *>( + ReserveCdh(sizeof(CDH) + entry->file_name_length() + + entry->extra_fields_length() + zip64_size)); cdh->signature(); // Note: do not set the version to Unix 3.0 spec, otherwise // unzip will think that 'external_attributes' field contains access mode @@ -578,11 +557,24 @@ void OutputJar::WriteEntry(void *buffer) { cdh->uncompressed_file_size32(entry->uncompressed_file_size32()); cdh->file_name(entry->file_name(), entry->file_name_length()); cdh->extra_fields(entry->extra_fields(), entry->extra_fields_length()); + if (zip64_size > 0) { + Zip64ExtraField *zip64_ef = reinterpret_cast<Zip64ExtraField *>( + cdh->extra_fields() + cdh->extra_fields_length()); + zip64_ef->signature(); + zip64_ef->attr_count(1); + zip64_ef->attr64(0, output_position); + cdh->local_header_offset32(0xFFFFFFFF); + // Field address argument points to the already existing field, + // so the call just updates the length. + cdh->extra_fields(cdh->extra_fields(), + cdh->extra_fields_length() + zip64_size); + } else { + cdh->local_header_offset32(output_position); + } cdh->comment_length(0); cdh->start_disk_nr(0); cdh->internal_attributes(0); cdh->external_attributes(0); - cdh->local_header_offset32(output_position); ++entries_; free(reinterpret_cast<void *>(entry)); } @@ -613,11 +605,112 @@ void OutputJar::WriteMetaInf() { WriteEntry(lh); } -// Appends a Central Directory Entry to the directory buffer. -CDH *OutputJar::AppendToDirectoryBuffer(const CDH *cdh) { - size_t cdh_size = cdh->size(); - return reinterpret_cast<CDH *>( - memcpy(reinterpret_cast<CDH *>(ReserveCdr(cdh_size)), cdh, cdh_size)); +// Create output Central Directory entry for the input jar entry. +void OutputJar::AppendToDirectoryBuffer(const CDH *cdh, off_t lh_pos, + uint16_t normalized_time, + bool fix_timestamp) { + // While copying from the input CDH pointed to by 'cdh', we may need to drop + // Unix timestamp extra field, and we might need to change the number of + // attributes of the Zip64 extra field, or create it, or destroy it if entry's + // position relative to 4G boundary changes. + // The rest of the input CDH is copied. + + // 1. Decide if we need to drop UnixTime. + size_t removed_unix_time_field_size = 0; + if (fix_timestamp) { + auto unix_time_field = cdh->unix_time_extra_field(); + if (unix_time_field != nullptr) { + removed_unix_time_field_size = unix_time_field->size(); + } + } + + // 2. Figure out how many attributes input entry has and how many + // the output entry is going to have. + const Zip64ExtraField *zip64_ef = cdh->zip64_extra_field(); + const int zip64_attr_count = zip64_ef == nullptr ? 0 : zip64_ef->attr_count(); + const bool lh_pos_needs64 = ziph::zfield_needs_ext64(lh_pos); + size_t out_zip64_attr_count; + if (zip64_attr_count > 0) { + out_zip64_attr_count = zip64_attr_count; + // The number of attributes may remain the same, or it may increase or + // decrease by 1, depending on local_header_offset value. + if (ziph::zfield_has_ext64(cdh->local_header_offset32()) != + lh_pos_needs64) { + if (lh_pos_needs64) { + out_zip64_attr_count += 1; + } else { + out_zip64_attr_count -= 1; + } + } + } else { + out_zip64_attr_count = lh_pos_needs64 ? 1 : 0; + } + const uint16_t zip64_size = Zip64ExtraField::space_needed(zip64_attr_count); + const uint16_t out_zip64_size = + Zip64ExtraField::space_needed(out_zip64_attr_count); + + // Allocate output CDH and copy everything but extra fields. + const uint16_t ef_size = cdh->extra_fields_length(); + const uint16_t out_ef_size = + (ef_size + out_zip64_size) - (removed_unix_time_field_size + zip64_size); + + const size_t out_cdh_size = cdh->size() + out_ef_size - ef_size; + CDH *out_cdh = reinterpret_cast<CDH *>(ReserveCdr(out_cdh_size)); + + // Calculate ExtraFields boundaries in the input and output entries. + auto ef_begin = reinterpret_cast<const ExtraField *>(cdh->extra_fields()); + auto ef_end = + reinterpret_cast<const ExtraField *>(ziph::byte_ptr(ef_begin) + ef_size); + // Copy [cdh..ef_begin) -> [out_cdh..out_ef_begin) + memcpy(out_cdh, cdh, ziph::byte_ptr(ef_begin) - ziph::byte_ptr(cdh)); + + auto out_ef_begin = reinterpret_cast<ExtraField *>( + const_cast<uint8_t *>(out_cdh->extra_fields())); + auto out_ef_end = reinterpret_cast<ExtraField *>( + reinterpret_cast<uint8_t *>(out_ef_begin) + out_ef_size); + + // Copy [ef_end..cdh_end) -> [out_ef_end..out_cdh_end) + memcpy(out_ef_end, ef_end, + ziph::byte_ptr(cdh) + cdh->size() - ziph::byte_ptr(ef_end)); + + // Copy extra fields, dropping Zip64 and possibly UnixTime fields. + ExtraField *out_ef = out_ef_begin; + for (const ExtraField *ef = ef_begin; ef < ef_end; ef = ef->next()) { + if ((fix_timestamp && ef->is_unix_time()) || ef->is_zip64()) { + // Skip this one. + } else { + memcpy(out_ef, ef, ef->size()); + out_ef = reinterpret_cast<ExtraField *>( + reinterpret_cast<uint8_t *>(out_ef) + ef->size()); + } + } + + // Set up Zip64 extra field if necessary. + if (out_zip64_size > 0) { + Zip64ExtraField *out_zip64_ef = reinterpret_cast<Zip64ExtraField *>(out_ef); + out_zip64_ef->signature(); + out_zip64_ef->attr_count(out_zip64_attr_count); + int copy_count = out_zip64_attr_count < zip64_attr_count + ? out_zip64_attr_count + : zip64_attr_count; + if (copy_count > 0) { + out_zip64_ef->attr64(0, zip64_ef->attr64(0)); + if (copy_count > 1) { + out_zip64_ef->attr64(1, zip64_ef->attr64(1)); + } + } + // Set 64-bit local_header_offset if necessary. It's always the last + // attribute. + if (lh_pos_needs64) { + out_zip64_ef->attr64(out_zip64_attr_count - 1, lh_pos); + } + } + out_cdh->extra_fields(ziph::byte_ptr(out_ef_begin), out_ef_size); + out_cdh->local_header_offset32(lh_pos_needs64 ? 0xFFFFFFFF : lh_pos); + if (fix_timestamp) { + out_cdh->last_mod_file_time(normalized_time); + out_cdh->last_mod_file_date(33); + } } uint8_t *OutputJar::ReserveCdr(size_t chunk_size) { @@ -658,8 +751,6 @@ bool OutputJar::Close() { bool write_zip64_ecd = output_position >= 0xFFFFFFFF || entries_ >= 0xFFFF || cen_size_ >= 0xFFFFFFFF; - TODO(output_position < 0xFFFFFFFF, "Handle Zip64"); - size_t cen_size = cen_size_; // Save it before ReserveCdh updates it. if (write_zip64_ecd) { ECD64 *ecd64 = reinterpret_cast<ECD64 *>(ReserveCdh(sizeof(ECD64))); diff --git a/src/tools/singlejar/output_jar.h b/src/tools/singlejar/output_jar.h index be3bef8aad..f5ee2007db 100644 --- a/src/tools/singlejar/output_jar.h +++ b/src/tools/singlejar/output_jar.h @@ -73,8 +73,10 @@ class OutputJar { void WriteEntry(void *local_header_and_payload); // Write META_INF/ entry (the first entry on output). void WriteMetaInf(); - // Append given Central Directory Header to CEN (Central Directory) buffer. - CDH *AppendToDirectoryBuffer(const CDH *cdh); + // Create output Central Directory Header for the given input entry and + // append it to CEN (Central Directory) buffer. + void AppendToDirectoryBuffer(const CDH *cdh, off_t local_header_offset, + uint16_t normalized_time, bool fix_timestamp); // Reserve space in CEN buffer. uint8_t *ReserveCdr(size_t chunk_size); // Reserve space for the Central Directory Header in CEN buffer. diff --git a/src/tools/singlejar/zip_headers.h b/src/tools/singlejar/zip_headers.h index 8947fc6adb..7d8c3018e7 100644 --- a/src/tools/singlejar/zip_headers.h +++ b/src/tools/singlejar/zip_headers.h @@ -41,9 +41,23 @@ #include <string> #include <type_traits> -static const uint8_t *byte_ptr(const void *ptr) { - return reinterpret_cast<const uint8_t *>(ptr); -} +class ziph { + public: + static const uint8_t *byte_ptr(const void *ptr) { + return reinterpret_cast<const uint8_t *>(ptr); + } + + /* Utility functions to handle Zip64 extensions. Size and position fields in + * the Zip headers are 32-bit wide. If field's value does not fit into 32 + * bits (more precisely, it is >= 0xFFFFFFFF), the field contains 0xFFFFFFFF + * and the actual value is saved in the corresponding 64-bit extension field. + * The first function returns true if there is an extension for the given + * field value, and the second returns true if given field value needs + * extension. + */ + static bool zfield_has_ext64(uint32_t v) { return v == 0xFFFFFFFF; } + static bool zfield_needs_ext64(uint64_t v) { return v >= 0xFFFFFFFF; } +}; /* Overall .ZIP file format (section 4.3.6), and the corresponding classes * [local file header 1] class LH @@ -78,11 +92,13 @@ class ExtraField { if (extra_field->is(tag)) { return extra_field; } - start = byte_ptr(start) + extra_field->size(); + start = ziph::byte_ptr(start) + extra_field->size(); } return nullptr; } bool is(uint16_t tag) const { return htole16(tag_) == tag; } + bool is_zip64() const { return is(1); } + bool is_unix_time() const { return is(0x5455); } void signature(uint16_t tag) { tag_ = le16toh(tag); } uint16_t payload_size() const { return le16toh(payload_size_); } @@ -90,6 +106,10 @@ class ExtraField { uint16_t size() const { return sizeof(ExtraField) + payload_size(); } + const ExtraField *next() const { + return reinterpret_cast<const ExtraField *>(ziph::byte_ptr(this) + size()); + } + protected: uint16_t tag_; uint16_t payload_size_; @@ -115,13 +135,23 @@ class Zip64ExtraField : public ExtraField { ExtraField::find(1, start, end)); } - bool is() const { return ExtraField::is(1); } + bool is() const { return is_zip64(); } void signature() { ExtraField::signature(1); } // The value of i-th attribute uint64_t attr64(int index) const { return le64toh(attr_[index]); } void attr64(int index, uint64_t v) { attr_[index] = htole64(v); } + // Attribute count + int attr_count() const { return payload_size() / sizeof(attr_[0]); } + void attr_count(int n) { payload_size(n * sizeof(attr_[0])); } + + // Space needed for this field to accomodate n_attr attributes + static uint16_t space_needed(int n_attrs) { + return n_attrs > 0 ? sizeof(Zip64ExtraField) + n_attrs * sizeof(uint64_t) + : 0; + } + private: uint64_t attr_[]; } __attribute__((packed)); @@ -143,7 +173,7 @@ class UnixTimeExtraField : public ExtraField { return reinterpret_cast<const UnixTimeExtraField *>( ExtraField::find(0x5455, start, end)); } - bool is() const { return ExtraField::is(0x5455); } + bool is() const { return is_unix_time(); } void signature() { ExtraField::signature(0x5455); } void flags(uint8_t v) { flags_ = v; } @@ -191,11 +221,11 @@ class LH { size_t compressed_file_size() const { size_t size32 = compressed_file_size32(); - if (size32 != 0xFFFFFFFF) { - return size32; + if (ziph::zfield_has_ext64(size32)) { + const Zip64ExtraField *z64 = zip64_extra_field(); + return z64 == nullptr ? 0xFFFFFFFF : z64->attr64(1); } - const Zip64ExtraField *z64 = zip64_extra_field(); - return z64 == nullptr ? 0xFFFFFFFF : z64->attr64(1); + return size32; } size_t compressed_file_size32() const { return le32toh(compressed_file_size32_); @@ -206,11 +236,11 @@ class LH { size_t uncompressed_file_size() const { size_t size32 = uncompressed_file_size32(); - if (size32 != 0xFFFFFFFF) { - return size32; + if (ziph::zfield_has_ext64(size32)) { + const Zip64ExtraField *z64 = zip64_extra_field(); + return z64 == nullptr ? 0xFFFFFFFF : z64->attr64(0); } - const Zip64ExtraField *z64 = zip64_extra_field(); - return z64 == nullptr ? 0xFFFFFFFF : z64->attr64(0); + return size32; } size_t uncompressed_file_size32() const { return le32toh(uncompressed_file_size32_); @@ -238,7 +268,7 @@ class LH { uint16_t extra_fields_length() const { return le16toh(extra_fields_length_); } const uint8_t *extra_fields() const { - return byte_ptr(file_name_ + file_name_length()); + return ziph::byte_ptr(file_name_ + file_name_length()); } uint8_t *extra_fields() { return reinterpret_cast<uint8_t *>(file_name_) + file_name_length(); @@ -357,13 +387,13 @@ class CDH { size_t compressed_file_size() const { size_t size32 = compressed_file_size32(); - if (size32 != 0xFFFFFFFF) { - return size32; + if (ziph::zfield_has_ext64(size32)) { + const Zip64ExtraField *z64 = zip64_extra_field(); + return z64 == nullptr ? 0xFFFFFFFF + : z64->attr64(ziph::zfield_has_ext64( + uncompressed_file_size32())); } - const Zip64ExtraField *z64 = zip64_extra_field(); - return z64 == nullptr - ? 0xFFFFFFFF - : z64->attr64(uncompressed_file_size32() == 0xFFFFFFFF ? 1 : 0); + return size32; } size_t compressed_file_size32() const { return le32toh(compressed_file_size32_); @@ -374,11 +404,11 @@ class CDH { size_t uncompressed_file_size() const { uint32_t size32 = uncompressed_file_size32(); - if (size32 != 0xFFFFFFFF) { - return size32; + if (ziph::zfield_has_ext64(size32)) { + const Zip64ExtraField *z64 = zip64_extra_field(); + return z64 == nullptr ? 0xFFFFFFFF : z64->attr64(0); } - const Zip64ExtraField *z64 = zip64_extra_field(); - return z64 == nullptr ? 0xFFFFFFFF : z64->attr64(0); + return size32; } size_t uncompressed_file_size32() const { return le32toh(uncompressed_file_size32_); @@ -407,7 +437,7 @@ class CDH { uint16_t extra_fields_length() const { return le16toh(extra_fields_length_); } const uint8_t *extra_fields() const { - return byte_ptr(file_name_ + file_name_length()); + return ziph::byte_ptr(file_name_ + file_name_length()); } uint8_t *extra_fields() { return reinterpret_cast<uint8_t *>(file_name_) + file_name_length(); @@ -433,15 +463,15 @@ class CDH { uint64_t local_header_offset() const { uint32_t size32 = local_header_offset32(); - if (size32 != 0xFFFFFFFF) { - return size32; - } - const Zip64ExtraField *z64 = zip64_extra_field(); - int attr_no = uncompressed_file_size32() == 0xFFFFFFFF ? 1 : 0; - if (compressed_file_size32() == 0xFFFFFFFF) { - ++attr_no; + if (ziph::zfield_has_ext64(size32)) { + const Zip64ExtraField *z64 = zip64_extra_field(); + int attr_no = ziph::zfield_has_ext64(uncompressed_file_size32()); + if (ziph::zfield_has_ext64(compressed_file_size32())) { + ++attr_no; + } + return z64 == nullptr ? 0xFFFFFFFF : z64->attr64(attr_no); } - return z64 == nullptr ? 0xFFFFFFFF : z64->attr64(attr_no); + return size32; } uint32_t local_header_offset32() const { @@ -548,7 +578,7 @@ class ECD { uint64_t ecd64_offset() const { const ECD64Locator *locator = reinterpret_cast<const ECD64Locator *>( - byte_ptr(this) - sizeof(ECD64Locator)); + ziph::byte_ptr(this) - sizeof(ECD64Locator)); return locator->is() ? locator->ecd64_offset() : 0xFFFFFFFFFFFFFFFF; } |