diff options
author | Narayan Kamath <narayan@google.com> | 2017-10-30 12:57:24 +0000 |
---|---|---|
committer | Narayan Kamath <narayan@google.com> | 2017-11-02 12:01:17 +0000 |
commit | a07e12251d5b246d2d7188df998a6f0487b09ed1 (patch) | |
tree | a8893da58c8725d48067e59b10705d0cd1aee40e /libs/androidfw/ZipUtils.cpp | |
parent | 80c3c7093040a6c66a2fa7c634451694d2bb5ee8 (diff) |
ZipUtils: Rewrite in terms of zip_archive::Inflate.
Removes duplicated zlib related code.
Bug: 35246701
Test: make
Test: run cts-dev -m CtsContentTestCases -t android.content.res.cts
Change-Id: Ie93cab4eb442b02ee171203a043ef02edbc35f2b
Diffstat (limited to 'libs/androidfw/ZipUtils.cpp')
-rw-r--r-- | libs/androidfw/ZipUtils.cpp | 235 |
1 files changed, 73 insertions, 162 deletions
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp index 5abfc8ee917e..5d243da2097c 100644 --- a/libs/androidfw/ZipUtils.cpp +++ b/libs/androidfw/ZipUtils.cpp @@ -20,10 +20,11 @@ #define LOG_TAG "ziputil" +#include "android-base/file.h" #include <androidfw/ZipUtils.h> -#include <androidfw/ZipFileRO.h> #include <utils/Log.h> #include <utils/Compat.h> +#include <ziparchive/zip_archive.h> #include <stdlib.h> #include <string.h> @@ -33,211 +34,121 @@ using namespace android; -static inline unsigned long get4LE(const unsigned char* buf) { - return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); -} - - -static const unsigned long kReadBufSize = 32768; - -/* - * Utility function that expands zip/gzip "deflate" compressed data - * into a buffer. - * - * (This is a clone of the previous function, but it takes a FILE* instead - * of an fd. We could pass fileno(fd) to the above, but we can run into - * trouble when "fp" has a different notion of what fd's file position is.) - * - * "fp" is an open file positioned at the start of the "deflate" data - * "buf" must hold at least "uncompressedLen" bytes. - */ -/*static*/ template<typename T> bool inflateToBuffer(T& reader, void* buf, - long uncompressedLen, long compressedLen) -{ - bool result = false; - - z_stream zstream; - int zerr; - unsigned long compRemaining; - - assert(uncompressedLen >= 0); - assert(compressedLen >= 0); - - compRemaining = compressedLen; - - /* - * Initialize the zlib stream. - */ - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = NULL; - zstream.avail_in = 0; - zstream.next_out = (Bytef*) buf; - zstream.avail_out = uncompressedLen; - zstream.data_type = Z_UNKNOWN; - - /* - * Use the undocumented "negative window bits" feature to tell zlib - * that there's no zlib header waiting for it. - */ - zerr = inflateInit2(&zstream, -MAX_WBITS); - if (zerr != Z_OK) { - if (zerr == Z_VERSION_ERROR) { - ALOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr); - } - goto bail; +// TODO: This can go away once the only remaining usage in aapt goes away. +class FileReader : public zip_archive::Reader { + public: + FileReader(FILE* fp) : Reader(), mFp(fp), mCurrentOffset(0) { } - /* - * Loop while we have data. - */ - do { - unsigned long getSize; - - /* read as much as we can */ - if (zstream.avail_in == 0) { - getSize = (compRemaining > kReadBufSize) ? - kReadBufSize : compRemaining; - ALOGV("+++ reading %ld bytes (%ld left)\n", - getSize, compRemaining); - - unsigned char* nextBuffer = NULL; - const unsigned long nextSize = reader.read(&nextBuffer, getSize); - - if (nextSize < getSize || nextBuffer == NULL) { - ALOGD("inflate read failed (%ld vs %ld)\n", nextSize, getSize); - goto z_bail; + bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const { + // Data is usually requested sequentially, so this helps avoid pointless + // fseeks every time we perform a read. There's an impedence mismatch + // here because the original API was designed around pread and pwrite. + if (offset != mCurrentOffset) { + if (fseek(mFp, offset, SEEK_SET) != 0) { + return false; } - compRemaining -= nextSize; - - zstream.next_in = nextBuffer; - zstream.avail_in = nextSize; + mCurrentOffset = offset; } - /* uncompress the data */ - zerr = inflate(&zstream, Z_NO_FLUSH); - if (zerr != Z_OK && zerr != Z_STREAM_END) { - ALOGD("zlib inflate call failed (zerr=%d)\n", zerr); - goto z_bail; + size_t read = fread(buf, 1, len, mFp); + if (read != len) { + return false; } - /* output buffer holds all, so no need to write the output */ - } while (zerr == Z_OK); - - assert(zerr == Z_STREAM_END); /* other errors should've been caught */ - - if ((long) zstream.total_out != uncompressedLen) { - ALOGW("Size mismatch on inflated file (%ld vs %ld)\n", - zstream.total_out, uncompressedLen); - goto z_bail; + mCurrentOffset += read; + return true; } - // success! - result = true; - -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ - -bail: - return result; -} - -class FileReader { -public: - explicit FileReader(FILE* fp) : - mFp(fp), mReadBuf(new unsigned char[kReadBufSize]) - { - } + private: + FILE* mFp; + mutable uint32_t mCurrentOffset; +}; - ~FileReader() { - delete[] mReadBuf; - } +class FdReader : public zip_archive::Reader { + public: + explicit FdReader(int fd) : mFd(fd) { + } - long read(unsigned char** nextBuffer, long readSize) const { - *nextBuffer = mReadBuf; - return fread(mReadBuf, 1, readSize, mFp); - } + bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const { + return android::base::ReadFullyAtOffset(mFd, buf, len, static_cast<off_t>(offset)); + } - FILE* mFp; - unsigned char* mReadBuf; + private: + const int mFd; }; -class FdReader { -public: - explicit FdReader(int fd) : - mFd(fd), mReadBuf(new unsigned char[kReadBufSize]) - { - } +class BufferReader : public zip_archive::Reader { + public: + BufferReader(const void* input, size_t inputSize) : Reader(), + mInput(reinterpret_cast<const uint8_t*>(input)), + mInputSize(inputSize) { + } - ~FdReader() { - delete[] mReadBuf; - } + bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const { + if (offset + len > mInputSize) { + return false; + } - long read(unsigned char** nextBuffer, long readSize) const { - *nextBuffer = mReadBuf; - return TEMP_FAILURE_RETRY(::read(mFd, mReadBuf, readSize)); - } + memcpy(buf, mInput + offset, len); + return true; + } - int mFd; - unsigned char* mReadBuf; + private: + const uint8_t* mInput; + const size_t mInputSize; }; -class BufferReader { -public: - BufferReader(void* input, size_t inputSize) : - mInput(reinterpret_cast<unsigned char*>(input)), - mInputSize(inputSize), - mBufferReturned(false) - { +class BufferWriter : public zip_archive::Writer { + public: + BufferWriter(void* output, size_t outputSize) : Writer(), + mOutput(reinterpret_cast<uint8_t*>(output)), mOutputSize(outputSize), mBytesWritten(0) { } - long read(unsigned char** nextBuffer, long /*readSize*/) { - if (!mBufferReturned) { - mBufferReturned = true; - *nextBuffer = mInput; - return mInputSize; + bool Append(uint8_t* buf, size_t bufSize) override { + if (mBytesWritten + bufSize > mOutputSize) { + return false; } - *nextBuffer = NULL; - return 0; + memcpy(mOutput + mBytesWritten, buf, bufSize); + mBytesWritten += bufSize; + return true; } - unsigned char* mInput; - const size_t mInputSize; - bool mBufferReturned; + private: + uint8_t* const mOutput; + const size_t mOutputSize; + size_t mBytesWritten; }; /*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf, long uncompressedLen, long compressedLen) { FileReader reader(fp); - return ::inflateToBuffer<FileReader>(reader, buf, - uncompressedLen, compressedLen); + BufferWriter writer(buf, uncompressedLen); + return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0); } /*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf, long uncompressedLen, long compressedLen) { FdReader reader(fd); - return ::inflateToBuffer<FdReader>(reader, buf, - uncompressedLen, compressedLen); + BufferWriter writer(buf, uncompressedLen); + return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0); } -/*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf, +/*static*/ bool ZipUtils::inflateToBuffer(const void* in, void* buf, long uncompressedLen, long compressedLen) { BufferReader reader(in, compressedLen); - return ::inflateToBuffer<BufferReader>(reader, buf, - uncompressedLen, compressedLen); + BufferWriter writer(buf, uncompressedLen); + return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0); } - +static inline unsigned long get4LE(const unsigned char* buf) { + return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); +} /* * Look at the contents of a gzip archive. We want to know where the @@ -275,7 +186,7 @@ public: /* quick sanity checks */ if (method == EOF || flags == EOF) return false; - if (method != ZipFileRO::kCompressDeflated) + if (method != kCompressDeflated) return false; /* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */ |