From 8b8faed17d3cac86fd63776312bcd9ed9a053add Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Thu, 26 Oct 2017 14:08:38 +0100 Subject: [PATCH] zip_archive: generalize deflate method. Remove dependencies on zip_archive specific data structures. In follow up changes, this method will be promoted to a public API and used from androidfw/ZipUtils as well as tools/zipalign, thereby allowing us to remove a near-exact copy of this code and to simplify depdencies. Test: zip_archive_test Bug: 35246701 Change-Id: If24a9965fbd6fff308c8758859026684fd2af3b9 --- libziparchive/zip_archive.cc | 61 +++++++++++++++++++++++------ libziparchive/zip_archive_private.h | 2 +- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc index ad40d42ac..b7d04c721 100644 --- a/libziparchive/zip_archive.cc +++ b/libziparchive/zip_archive.cc @@ -848,6 +848,34 @@ class FileWriter : public Writer { size_t total_bytes_written_; }; +class Reader { + public: + virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const = 0; + virtual ~Reader() {} + + protected: + Reader() = default; + + private: + DISALLOW_COPY_AND_ASSIGN(Reader); +}; + +class EntryReader : public Reader { + public: + EntryReader(const MappedZipFile& zip_file, const ZipEntry* entry) + : Reader(), zip_file_(zip_file), entry_(entry) {} + + virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const { + return zip_file_.ReadAtOffset(buf, len, entry_->offset + offset); + } + + virtual ~EntryReader() {} + + private: + const MappedZipFile& zip_file_; + const ZipEntry* entry_; +}; + // This method is using libz macros with old-style-casts #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" @@ -856,8 +884,9 @@ static inline int zlib_inflateInit2(z_stream* stream, int window_bits) { } #pragma GCC diagnostic pop -static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, - Writer* writer, uint64_t* crc_out) { +static int32_t InflateReaderToWriter(const Reader& reader, const uint32_t compressed_length, + const uint32_t uncompressed_length, Writer* writer, + uint64_t* crc_out) { const size_t kBufSize = 32768; std::vector read_buf(kBufSize); std::vector write_buf(kBufSize); @@ -898,25 +927,23 @@ static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* e std::unique_ptr zstream_guard(&zstream, zstream_deleter); - const uint32_t uncompressed_length = entry->uncompressed_length; - uint64_t crc = 0; - uint32_t compressed_length = entry->compressed_length; + uint32_t remaining_bytes = compressed_length; do { /* read as much as we can */ if (zstream.avail_in == 0) { - const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length; - off64_t offset = entry->offset + (entry->compressed_length - compressed_length); + const size_t read_size = (remaining_bytes > kBufSize) ? kBufSize : remaining_bytes; + const uint32_t offset = (compressed_length - remaining_bytes); // Make sure to read at offset to ensure concurrent access to the fd. - if (!mapped_zip.ReadAtOffset(read_buf.data(), getSize, offset)) { - ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno)); + if (!reader.ReadAtOffset(read_buf.data(), read_size, offset)) { + ALOGW("Zip: inflate read failed, getSize = %zu: %s", read_size, strerror(errno)); return kIoError; } - compressed_length -= getSize; + remaining_bytes -= read_size; zstream.next_in = &read_buf[0]; - zstream.avail_in = getSize; + zstream.avail_in = read_size; } /* uncompress the data */ @@ -952,7 +979,7 @@ static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* e // the same manner that we have above. *crc_out = crc; - if (zstream.total_out != uncompressed_length || compressed_length != 0) { + if (zstream.total_out != uncompressed_length || remaining_bytes != 0) { ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")", zstream.total_out, uncompressed_length); return kInconsistentInformation; @@ -961,6 +988,14 @@ static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* e return 0; } +static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, + Writer* writer, uint64_t* crc_out) { + const EntryReader reader(mapped_zip, entry); + + return InflateReaderToWriter(reader, entry->compressed_length, entry->uncompressed_length, writer, + crc_out); +} + static int32_t CopyEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* entry, Writer* writer, uint64_t* crc_out) { static const uint32_t kBufSize = 32768; @@ -1118,7 +1153,7 @@ off64_t MappedZipFile::GetFileLength() const { } // Attempts to read |len| bytes into |buf| at offset |off|. -bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) { +bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const { if (has_fd_) { if (!android::base::ReadFullyAtOffset(fd_, buf, len, off)) { ALOGE("Zip: failed to read at offset %" PRId64 "\n", off); diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h index 174aa3f45..18e02291d 100644 --- a/libziparchive/zip_archive_private.h +++ b/libziparchive/zip_archive_private.h @@ -106,7 +106,7 @@ class MappedZipFile { off64_t GetFileLength() const; - bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off); + bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const; private: // If has_fd_ is true, fd is valid and we'll read contents of a zip archive