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
This commit is contained in:
Narayan Kamath 2017-10-26 14:08:38 +01:00
parent 41a9b3c81d
commit 8b8faed17d
2 changed files with 49 additions and 14 deletions

View File

@ -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<uint8_t> read_buf(kBufSize);
std::vector<uint8_t> write_buf(kBufSize);
@ -898,25 +927,23 @@ static int32_t InflateEntryToWriter(MappedZipFile& mapped_zip, const ZipEntry* e
std::unique_ptr<z_stream, decltype(zstream_deleter)> 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);

View File

@ -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