Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 148f7af1 authored by Tianjie Xu's avatar Tianjie Xu Committed by Gerrit Code Review
Browse files

Merge "Allow parsing zip entries larger than 4GiB"

parents 3fc16fed 85c5d231
Loading
Loading
Loading
Loading
+74 −23
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <sys/cdefs.h>
#include <sys/types.h>

#include <functional>
#include <string>
#include <string_view>

@@ -36,10 +37,10 @@ enum {
  kCompressDeflated = 8,  // standard deflate
};

/*
 * Represents information about a zip entry in a zip file.
 */
struct ZipEntry {
// This struct holds the common information of a zip entry other than the
// the entry size. The compressed and uncompressed length will be handled
// separately in the derived class.
struct ZipEntryCommon {
  // Compression method. One of kCompressStored or kCompressDeflated.
  // See also `gpbf` for deflate subtypes.
  uint16_t method;
@@ -67,16 +68,6 @@ struct ZipEntry {
  // Data descriptor footer at the end of the file entry.
  uint32_t crc32;

  // Compressed length of this ZipEntry. Might be present
  // either in the local file header or in the data descriptor
  // footer.
  uint32_t compressed_length;

  // Uncompressed length of this ZipEntry. Might be present
  // either in the local file header or in the data descriptor
  // footer.
  uint32_t uncompressed_length;

  // If the value of uncompressed length and compressed length are stored in
  // the zip64 extended info of the extra field.
  bool zip64_format_size{false};
@@ -97,6 +88,52 @@ struct ZipEntry {
  bool is_text;
};

struct ZipEntry64;
// Many users of the library assume the entry size is capped at UNIT32_MAX. So we keep
// the interface for the old ZipEntry here; and we could switch them over to the new
// ZipEntry64 later.
struct ZipEntry : public ZipEntryCommon {
  // Compressed length of this ZipEntry. The maximum value is UNIT32_MAX.
  // Might be present either in the local file header or in the data
  // descriptor footer.
  uint32_t compressed_length{0};

  // Uncompressed length of this ZipEntry. The maximum value is UNIT32_MAX.
  // Might be present either in the local file header or in the data
  // descriptor footer.
  uint32_t uncompressed_length{0};

  // Copies the contents of a ZipEntry64 object to a 32 bits ZipEntry. Returns 0 if the
  // size of the entry fits into uint32_t, returns a negative error code
  // (kUnsupportedEntrySize) otherwise.
  static int32_t CopyFromZipEntry64(ZipEntry* dst, const ZipEntry64* src);

 private:
  ZipEntry& operator=(const ZipEntryCommon& other) {
    ZipEntryCommon::operator=(other);
    return *this;
  }
};

// Represents information about a zip entry in a zip file.
struct ZipEntry64 : public ZipEntryCommon {
  // Compressed length of this ZipEntry. The maximum value is UNIT64_MAX.
  // Might be present either in the local file header, the zip64 extended field,
  // or in the data descriptor footer.
  uint64_t compressed_length{0};

  // Uncompressed length of this ZipEntry. The maximum value is UNIT64_MAX.
  // Might be present either in the local file header, the zip64 extended field,
  // or in the data descriptor footer.
  uint64_t uncompressed_length{0};

  explicit ZipEntry64() = default;
  explicit ZipEntry64(const ZipEntry& zip_entry) : ZipEntryCommon(zip_entry) {
    compressed_length = zip_entry.compressed_length;
    uncompressed_length = zip_entry.uncompressed_length;
  }
};

struct ZipArchive;
typedef ZipArchive* ZipArchiveHandle;

@@ -172,7 +209,8 @@ ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive);
 * On non-Windows platforms this method does not modify internal state and
 * can be called concurrently.
 */
int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName, ZipEntry* data);
int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName,
                  ZipEntry64* data);

/*
 * Start iterating over all entries of a zip file. The order of iteration
@@ -206,8 +244,8 @@ int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
 * Returns 0 on success, -1 if there are no more elements in this
 * archive and lower negative values on failure.
 */
int32_t Next(void* cookie, ZipEntry* data, std::string* name);
int32_t Next(void* cookie, ZipEntry* data, std::string_view* name);
int32_t Next(void* cookie, ZipEntry64* data, std::string_view* name);
int32_t Next(void* cookie, ZipEntry64* data, std::string* name);

/*
 * End iteration over all entries of a zip file and frees the memory allocated
@@ -224,7 +262,7 @@ void EndIteration(void* cookie);
 *
 * Returns 0 on success and negative values on failure.
 */
int32_t ExtractEntryToFile(ZipArchiveHandle archive, ZipEntry* entry, int fd);
int32_t ExtractEntryToFile(ZipArchiveHandle archive, const ZipEntry64* entry, int fd);

/**
 * Uncompress a given zip entry to the memory region at |begin| and of
@@ -234,7 +272,8 @@ int32_t ExtractEntryToFile(ZipArchiveHandle archive, ZipEntry* entry, int fd);
 *
 * Returns 0 on success and negative values on failure.
 */
int32_t ExtractToMemory(ZipArchiveHandle archive, ZipEntry* entry, uint8_t* begin, uint32_t size);
int32_t ExtractToMemory(ZipArchiveHandle archive, const ZipEntry64* entry, uint8_t* begin,
                        size_t size);

int GetFileDescriptor(const ZipArchiveHandle archive);

@@ -246,6 +285,16 @@ off64_t GetFileDescriptorOffset(const ZipArchiveHandle archive);

const char* ErrorCodeString(int32_t error_code);

// Many users of libziparchive assume the entry size to be 32 bits long. So we keep these
// interfaces that use 32 bit ZipEntry to make old code work. TODO(xunchang) Remove the 32 bit
// wrapper functions once we switch all users to recognize ZipEntry64.
int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName, ZipEntry* data);
int32_t Next(void* cookie, ZipEntry* data, std::string* name);
int32_t Next(void* cookie, ZipEntry* data, std::string_view* name);
int32_t ExtractEntryToFile(ZipArchiveHandle archive, const ZipEntry* entry, int fd);
int32_t ExtractToMemory(ZipArchiveHandle archive, const ZipEntry* entry, uint8_t* begin,
                        size_t size);

#if !defined(_WIN32)
typedef bool (*ProcessZipEntryFunction)(const uint8_t* buf, size_t buf_size, void* cookie);

@@ -253,7 +302,9 @@ typedef bool (*ProcessZipEntryFunction)(const uint8_t* buf, size_t buf_size, voi
 * Stream the uncompressed data through the supplied function,
 * passing cookie to it each time it gets called.
 */
int32_t ProcessZipEntryContents(ZipArchiveHandle archive, ZipEntry* entry,
int32_t ProcessZipEntryContents(ZipArchiveHandle archive, const ZipEntry* entry,
                                ProcessZipEntryFunction func, void* cookie);
int32_t ProcessZipEntryContents(ZipArchiveHandle archive, const ZipEntry64* entry,
                                ProcessZipEntryFunction func, void* cookie);
#endif

@@ -274,7 +325,7 @@ class Writer {

class Reader {
 public:
  virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const = 0;
  virtual bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const = 0;
  virtual ~Reader();

 protected:
@@ -296,6 +347,6 @@ class Reader {
 * If |crc_out| is not nullptr, it is set to the crc32 checksum of the
 * uncompressed data.
 */
int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
                const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out);
int32_t Inflate(const Reader& reader, const uint64_t compressed_length,
                const uint64_t uncompressed_length, Writer* writer, uint64_t* crc_out);
}  // namespace zip_archive
+31 −3
Original line number Diff line number Diff line
@@ -83,7 +83,7 @@ class Zip64Test(unittest.TestCase):
    self._ExtractEntries(zip_path.name)


  def test_largeCompressedEntries(self):
  def test_largeCompressedEntriesSmallerThan4G(self):
    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
    with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED,
                         allowZip64=True) as output_zip:
@@ -99,8 +99,7 @@ class Zip64Test(unittest.TestCase):

  def test_forceDataDescriptor(self):
    file_path = tempfile.NamedTemporaryFile(suffix='.txt')
    # TODO create the entry > 4GiB.
    self._WriteFile(file_path.name, 1024)
    self._WriteFile(file_path.name, 5000 * 1024)

    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
    with zipfile.ZipFile(zip_path, 'w', allowZip64=True) as output_zip:
@@ -113,6 +112,35 @@ class Zip64Test(unittest.TestCase):
    self.assertEquals([file_path.name[1:]], read_names)
    self._ExtractEntries(zip_path.name)


  def test_largeUncompressedEntriesLargerThan4G(self):
    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
    with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_STORED,
                         allowZip64=True) as output_zip:
      # Add entries close to 4GiB in size. Somehow the python library will put the (un)compressed
      # sizes in the extra field. Test if our ziptool should be able to parse it.
      entry_dict = {'g.txt': 5000 * 1024, 'h.txt': 6000 * 1024}
      self._AddEntriesToZip(output_zip, entry_dict)

    read_names = self._getEntryNames(zip_path.name)
    self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
    self._ExtractEntries(zip_path.name)


  def test_largeCompressedEntriesLargerThan4G(self):
    zip_path = tempfile.NamedTemporaryFile(suffix='.zip')
    with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED,
                         allowZip64=True) as output_zip:
      # Add entries close to 4GiB in size. Somehow the python library will put the (un)compressed
      # sizes in the extra field. Test if our ziptool should be able to parse it.
      entry_dict = {'i.txt': 4096 * 1024, 'j.txt': 7000 * 1024}
      self._AddEntriesToZip(output_zip, entry_dict)

    read_names = self._getEntryNames(zip_path.name)
    self.assertEquals(sorted(entry_dict.keys()), sorted(read_names))
    self._ExtractEntries(zip_path.name)


if __name__ == '__main__':
  testsuite = unittest.TestLoader().discover(
      os.path.dirname(os.path.realpath(__file__)))
+140 −62

File changed.

Preview size limit exceeded, changes collapsed.

+2 −1
Original line number Diff line number Diff line
@@ -106,7 +106,8 @@ struct ZipArchive {
  bool InitializeCentralDirectory(off64_t cd_start_offset, size_t cd_size);
};

int32_t ExtractToWriter(ZipArchiveHandle handle, ZipEntry* entry, zip_archive::Writer* writer);
int32_t ExtractToWriter(ZipArchiveHandle handle, const ZipEntry64* entry,
                        zip_archive::Writer* writer);

// Reads the unaligned data of type |T| and auto increment the offset.
template <typename T>
+39 −39
Original line number Diff line number Diff line
@@ -217,7 +217,7 @@ TEST(ziparchive, Iteration_std_string_view) {
  void* iteration_cookie;
  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie));

  ZipEntry data;
  ZipEntry64 data;
  std::vector<std::string_view> names;
  std::string_view name;
  while (Next(iteration_cookie, &data, &name) == 0) names.push_back(name);
@@ -232,12 +232,12 @@ TEST(ziparchive, Iteration_std_string_view) {

static void AssertIterationNames(void* iteration_cookie,
                                 const std::vector<std::string>& expected_names_sorted) {
  ZipEntry data;
  ZipEntry64 data;
  std::vector<std::string> names;
  std::string name;
  std::string_view name;
  for (size_t i = 0; i < expected_names_sorted.size(); ++i) {
    ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    names.push_back(name);
    names.push_back(std::string(name));
  }
  // End of iteration.
  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
@@ -325,8 +325,8 @@ TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
  void* iteration_cookie;
  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, "x", "y"));

  ZipEntry data;
  std::string name;
  ZipEntry64 data;
  std::string_view name;

  // End of iteration.
  ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
@@ -338,7 +338,7 @@ TEST(ziparchive, FindEntry) {
  ZipArchiveHandle handle;
  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));

  ZipEntry data;
  ZipEntry64 data;
  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));

  // Known facts about a.txt, from zipinfo -v.
@@ -359,7 +359,7 @@ TEST(ziparchive, FindEntry_empty) {
  ZipArchiveHandle handle;
  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));

  ZipEntry data;
  ZipEntry64 data;
  ASSERT_EQ(kInvalidEntryName, FindEntry(handle, "", &data));

  CloseArchive(handle);
@@ -370,7 +370,7 @@ TEST(ziparchive, FindEntry_too_long) {
  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));

  std::string very_long_name(65536, 'x');
  ZipEntry data;
  ZipEntry64 data;
  ASSERT_EQ(kInvalidEntryName, FindEntry(handle, very_long_name, &data));

  CloseArchive(handle);
@@ -383,8 +383,8 @@ TEST(ziparchive, TestInvalidDeclaredLength) {
  void* iteration_cookie;
  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie));

  std::string name;
  ZipEntry data;
  std::string_view name;
  ZipEntry64 data;

  ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
  ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
@@ -415,9 +415,9 @@ TEST(ziparchive, OpenArchiveFdRange) {
                                  static_cast<off64_t>(leading_garbage.size())));

  // An entry that's deflated.
  ZipEntry data;
  ZipEntry64 data;
  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
  const uint32_t a_size = data.uncompressed_length;
  const auto a_size = static_cast<size_t>(data.uncompressed_length);
  ASSERT_EQ(a_size, kATxtContents.size());
  auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[a_size]);
  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer.get(), a_size));
@@ -425,7 +425,7 @@ TEST(ziparchive, OpenArchiveFdRange) {

  // An entry that's stored.
  ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
  const uint32_t b_size = data.uncompressed_length;
  const auto b_size = static_cast<size_t>(data.uncompressed_length);
  ASSERT_EQ(b_size, kBTxtContents.size());
  buffer = std::unique_ptr<uint8_t[]>(new uint8_t[b_size]);
  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer.get(), b_size));
@@ -439,9 +439,9 @@ TEST(ziparchive, ExtractToMemory) {
  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));

  // An entry that's deflated.
  ZipEntry data;
  ZipEntry64 data;
  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
  const uint32_t a_size = data.uncompressed_length;
  const auto a_size = static_cast<size_t>(data.uncompressed_length);
  ASSERT_EQ(a_size, kATxtContents.size());
  uint8_t* buffer = new uint8_t[a_size];
  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
@@ -450,7 +450,7 @@ TEST(ziparchive, ExtractToMemory) {

  // An entry that's stored.
  ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
  const uint32_t b_size = data.uncompressed_length;
  const auto b_size = static_cast<size_t>(data.uncompressed_length);
  ASSERT_EQ(b_size, kBTxtContents.size());
  buffer = new uint8_t[b_size];
  ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
@@ -503,7 +503,7 @@ TEST(ziparchive, EmptyEntries) {
  ZipArchiveHandle handle;
  ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle, false));

  ZipEntry entry;
  ZipEntry64 entry;
  ASSERT_EQ(0, FindEntry(handle, "empty.txt", &entry));
  ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
  uint8_t buffer[1];
@@ -526,7 +526,7 @@ TEST(ziparchive, EntryLargerThan32K) {
  ZipArchiveHandle handle;
  ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle, false));

  ZipEntry entry;
  ZipEntry64 entry;
  ASSERT_EQ(0, FindEntry(handle, kAbTxtName, &entry));
  ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);

@@ -583,7 +583,7 @@ TEST(ziparchive, ExtractToFile) {
  ZipArchiveHandle handle;
  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));

  ZipEntry entry;
  ZipEntry64 entry;
  ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
  ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));

@@ -594,9 +594,9 @@ TEST(ziparchive, ExtractToFile) {
  ASSERT_EQ(0, memcmp(read_buffer, data, data_size));

  // Assert that the remainder of the file contains the incompressed data.
  std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
  ASSERT_TRUE(
      android::base::ReadFully(tmp_file.fd, uncompressed_data.data(), entry.uncompressed_length));
  std::vector<uint8_t> uncompressed_data(static_cast<size_t>(entry.uncompressed_length));
  ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, uncompressed_data.data(),
                                       static_cast<size_t>(entry.uncompressed_length)));
  ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(), kATxtContents.size()));

  // Assert that the total length of the file is sane
@@ -620,7 +620,7 @@ TEST(ziparchive, OpenFromMemory) {
            OpenArchiveFromMemory(file_map->data(), file_map->size(), zip_path.c_str(), &handle));

  // Assert one entry can be found and extracted correctly.
  ZipEntry binary_entry;
  ZipEntry64 binary_entry;
  ASSERT_EQ(0, FindEntry(handle, "META-INF/com/google/android/update-binary", &binary_entry));
  TemporaryFile tmp_binary;
  ASSERT_NE(-1, tmp_binary.fd);
@@ -635,13 +635,13 @@ static void ZipArchiveStreamTest(ZipArchiveHandle& handle, const std::string& en
  if (raw) {
    stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
    if (entry->method == kCompressStored) {
      read_data->resize(entry->uncompressed_length);
      read_data->resize(static_cast<size_t>(entry->uncompressed_length));
    } else {
      read_data->resize(entry->compressed_length);
      read_data->resize(static_cast<size_t>(entry->compressed_length));
    }
  } else {
    stream.reset(ZipArchiveStreamEntry::Create(handle, *entry));
    read_data->resize(entry->uncompressed_length);
    read_data->resize(static_cast<size_t>(entry->uncompressed_length));
  }
  uint8_t* read_data_ptr = read_data->data();
  ASSERT_TRUE(stream.get() != nullptr);
@@ -681,7 +681,7 @@ static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file,
  std::vector<uint8_t> read_data;
  ZipArchiveStreamTest(handle, entry_name, false, true, &entry, &read_data);

  std::vector<uint8_t> cmp_data(entry.uncompressed_length);
  std::vector<uint8_t> cmp_data(static_cast<size_t>(entry.uncompressed_length));
  ASSERT_EQ(entry.uncompressed_length, read_data.size());
  ASSERT_EQ(
      0, ExtractToMemory(handle, &entry, cmp_data.data(), static_cast<uint32_t>(cmp_data.size())));
@@ -741,8 +741,8 @@ TEST(ziparchive, StreamUncompressedBadCrc) {
//       FileOutputStream fos = new
//       FileOutputStream("/tmp/data_descriptor.zip");
//       ZipOutputStream zos = new ZipOutputStream(fos);
//       ZipEntry ze = new ZipEntry("name");
//       ze.setMethod(ZipEntry.DEFLATED);
//       ZipEntry64 ze = new ZipEntry64("name");
//       ze.setMethod(ZipEntry64.DEFLATED);
//       zos.putNextEntry(ze);
//       zos.write("abdcdefghijk".getBytes());
//       zos.closeEntry();
@@ -780,7 +780,7 @@ static void ExtractEntryToMemory(const std::vector<uint8_t>& zip_data,
  // This function expects a variant of kDataDescriptorZipFile, for look for
  // an entry whose name is "name" and whose size is 12 (contents =
  // "abdcdefghijk").
  ZipEntry entry;
  ZipEntry64 entry;
  ASSERT_EQ(0, FindEntry(handle, "name", &entry));
  ASSERT_EQ(static_cast<uint32_t>(12), entry.uncompressed_length);

@@ -887,12 +887,12 @@ class VectorReader : public zip_archive::Reader {
 public:
  VectorReader(const std::vector<uint8_t>& input) : Reader(), input_(input) {}

  bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
  bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const {
    if ((offset + len) < input_.size()) {
      return false;
    }

    memcpy(buf, &input_[offset], len);
    memcpy(buf, &input_[static_cast<size_t>(offset)], len);
    return true;
  }

@@ -919,7 +919,7 @@ class BadReader : public zip_archive::Reader {
 public:
  BadReader() : Reader() {}

  bool ReadAtOffset(uint8_t*, size_t, uint32_t) const { return false; }
  bool ReadAtOffset(uint8_t*, size_t, off64_t) const { return false; }
};

class BadWriter : public zip_archive::Writer {
@@ -1222,7 +1222,7 @@ TEST_F(Zip64ParseTest, findEntry) {
  ZipArchiveHandle handle;
  ASSERT_EQ(
      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
  ZipEntry entry;
  ZipEntry64 entry;
  ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
  ASSERT_EQ(200, entry.uncompressed_length);
  ASSERT_EQ(200, entry.compressed_length);
@@ -1245,7 +1245,7 @@ TEST_F(Zip64ParseTest, openFileIncorrectDataSizeInLocalExtendedField) {
  ZipArchiveHandle handle;
  ASSERT_EQ(
      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
  ZipEntry entry;
  ZipEntry64 entry;
  ASSERT_NE(0, FindEntry(handle, "a.txt", &entry));

  CloseArchive(handle);
@@ -1267,7 +1267,7 @@ TEST_F(Zip64ParseTest, iterates) {
  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie));
  std::set<std::string_view> result;
  std::string_view name;
  ZipEntry entry;
  ZipEntry64 entry;
  while (Next(iteration_cookie, &entry, &name) == 0) result.emplace(name);
  ASSERT_EQ(names, result);

@@ -1297,7 +1297,7 @@ TEST_F(Zip64ParseTest, extract) {
  ZipArchiveHandle handle;
  ASSERT_EQ(
      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
  ZipEntry entry;
  ZipEntry64 entry;
  ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));

  VectorWriter writer;
@@ -1315,7 +1315,7 @@ TEST_F(Zip64ParseTest, extractWithDataDescriptor) {
  ZipArchiveHandle handle;
  ASSERT_EQ(
      0, OpenArchiveFromMemory(zip_content_.data(), zip_content_.size(), "debug_zip64", &handle));
  ZipEntry entry;
  ZipEntry64 entry;
  ASSERT_EQ(0, FindEntry(handle, "b.txt", &entry));

  VectorWriter writer;
Loading