diff options
author | Narayan Kamath <narayan@google.com> | 2013-12-03 13:16:03 +0000 |
---|---|---|
committer | Narayan Kamath <narayan@google.com> | 2013-12-09 16:23:16 +0000 |
commit | afd31e08299008fdc5c2813f21b2573f29dc53df (patch) | |
tree | 7f83dd8f1e7ed71d4fe8ce280841e43ce275ac6d /libs/androidfw/ZipUtils.cpp | |
parent | 6e2d0c1d91f644ab50e0c0b7cae4306262a4ca41 (diff) |
Reimplement ZipFileRO in terms of libziparchive.
This lets us share zip archive processing code with both
the runtime (Art, dalvik) and critical java code
(StrictJarFile).
This change also moves several utility methods to ZipUtils
and dedups code across several zip inflation methods.
One of the side effects of this change is that several
processing loops are now O(n) instead of O(n^2).
bug: 10193060
Change-Id: I3c7188496837a47246c4f342e45485a70fef3169
Diffstat (limited to 'libs/androidfw/ZipUtils.cpp')
-rw-r--r-- | libs/androidfw/ZipUtils.cpp | 233 |
1 files changed, 109 insertions, 124 deletions
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp index 997eb7d85edd..e9ac2fe25f58 100644 --- a/libs/androidfw/ZipUtils.cpp +++ b/libs/androidfw/ZipUtils.cpp @@ -33,19 +33,29 @@ 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. * - * "fd" is an open file positioned at the start of the "deflate" data + * (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*/ bool ZipUtils::inflateToBuffer(int fd, void* buf, +/*static*/ template<typename T> bool inflateToBuffer(T& reader, void* buf, long uncompressedLen, long compressedLen) { bool result = false; - const unsigned long kReadBufSize = 32768; - unsigned char* readBuf = NULL; + z_stream zstream; int zerr; unsigned long compRemaining; @@ -53,15 +63,12 @@ using namespace android; assert(uncompressedLen >= 0); assert(compressedLen >= 0); - readBuf = new unsigned char[kReadBufSize]; - if (readBuf == NULL) - goto bail; compRemaining = compressedLen; /* * Initialize the zlib stream. */ - memset(&zstream, 0, sizeof(zstream)); + memset(&zstream, 0, sizeof(zstream)); zstream.zalloc = Z_NULL; zstream.zfree = Z_NULL; zstream.opaque = Z_NULL; @@ -71,10 +78,10 @@ using namespace android; 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. - */ + /* + * 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) { @@ -99,18 +106,18 @@ using namespace android; ALOGV("+++ reading %ld bytes (%ld left)\n", getSize, compRemaining); - int cc = TEMP_FAILURE_RETRY(read(fd, readBuf, getSize)); - if (cc < 0) { - ALOGW("inflate read failed: %s", strerror(errno)); - } else if (cc != (int) getSize) { - ALOGW("inflate read failed (%d vs %ld)", cc, getSize); + 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; } - compRemaining -= getSize; + compRemaining -= nextSize; - zstream.next_in = readBuf; - zstream.avail_in = getSize; + zstream.next_in = nextBuffer; + zstream.avail_in = nextSize; } /* uncompress the data */ @@ -138,121 +145,99 @@ z_bail: inflateEnd(&zstream); /* free up any allocated structures */ bail: - delete[] readBuf; return result; } -/* - * 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*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf, - long uncompressedLen, long compressedLen) -{ - bool result = false; - const unsigned long kReadBufSize = 32768; - unsigned char* readBuf = NULL; - z_stream zstream; - int zerr; - unsigned long compRemaining; - - assert(uncompressedLen >= 0); - assert(compressedLen >= 0); - - readBuf = new unsigned char[kReadBufSize]; - if (readBuf == NULL) - goto bail; - 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; +class FileReader { +public: + FileReader(FILE* fp) : + mFp(fp), mReadBuf(new unsigned char[kReadBufSize]) + { + } + + ~FileReader() { + delete[] mReadBuf; + } + + long read(unsigned char** nextBuffer, long readSize) const { + *nextBuffer = mReadBuf; + return fread(mReadBuf, 1, readSize, mFp); + } + + FILE* mFp; + unsigned char* mReadBuf; +}; + +class FdReader { +public: + FdReader(int fd) : + mFd(fd), mReadBuf(new unsigned char[kReadBufSize]) + { + } + + ~FdReader() { + delete[] mReadBuf; + } + + long read(unsigned char** nextBuffer, long readSize) const { + *nextBuffer = mReadBuf; + return TEMP_FAILURE_RETRY(::read(mFd, mReadBuf, readSize)); + } + + int mFd; + unsigned char* mReadBuf; +}; + +class BufferReader { +public: + BufferReader(void* input, size_t inputSize) : + mInput(reinterpret_cast<unsigned char*>(input)), + mInputSize(inputSize), + mBufferReturned(false) + { } - /* - * 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); - - int cc = fread(readBuf, 1, getSize, fp); - if (cc != (int) getSize) { - ALOGD("inflate read failed (%d vs %ld)\n", - cc, getSize); - goto z_bail; - } - - compRemaining -= getSize; - - zstream.next_in = readBuf; - zstream.avail_in = getSize; + long read(unsigned char** nextBuffer, long readSize) { + if (!mBufferReturned) { + mBufferReturned = true; + *nextBuffer = mInput; + return mInputSize; } - /* 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; - } + *nextBuffer = NULL; + return 0; + } - /* output buffer holds all, so no need to write the output */ - } while (zerr == Z_OK); + unsigned char* mInput; + const size_t mInputSize; + bool mBufferReturned; +}; - assert(zerr == Z_STREAM_END); /* other errors should've been caught */ +/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf, + long uncompressedLen, long compressedLen) +{ + FileReader reader(fp); + return ::inflateToBuffer<FileReader>(reader, buf, + uncompressedLen, compressedLen); +} - if ((long) zstream.total_out != uncompressedLen) { - ALOGW("Size mismatch on inflated file (%ld vs %ld)\n", - zstream.total_out, uncompressedLen); - goto z_bail; - } +/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf, + long uncompressedLen, long compressedLen) +{ + FdReader reader(fd); + return ::inflateToBuffer<FdReader>(reader, buf, + uncompressedLen, compressedLen); +} - // success! - result = true; +/*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf, + long uncompressedLen, long compressedLen) +{ + BufferReader reader(in, compressedLen); + return ::inflateToBuffer<BufferReader>(reader, buf, + uncompressedLen, compressedLen); +} -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ -bail: - delete[] readBuf; - return result; -} /* * Look at the contents of a gzip archive. We want to know where the @@ -338,8 +323,8 @@ bail: fseek(fp, curPosn, SEEK_SET); *pCompressionMethod = method; - *pCRC32 = ZipFileRO::get4LE(&buf[0]); - *pUncompressedLen = ZipFileRO::get4LE(&buf[4]); + *pCRC32 = get4LE(&buf[0]); + *pUncompressedLen = get4LE(&buf[4]); return true; } |