summaryrefslogtreecommitdiffstats
path: root/libs/androidfw/ZipUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/androidfw/ZipUtils.cpp')
-rw-r--r--libs/androidfw/ZipUtils.cpp233
1 files changed, 109 insertions, 124 deletions
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
index 997eb7d..e9ac2fe 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;
}