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
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
index 5abfc8e..5d243da 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])
-   {
-   }
-
-   ~FileReader() {
-       delete[] mReadBuf;
-   }
-
-   long read(unsigned char** nextBuffer, long readSize) const {
-       *nextBuffer = mReadBuf;
-       return fread(mReadBuf, 1, readSize, mFp);
-   }
-
-   FILE* mFp;
-   unsigned char* mReadBuf;
+  private:
+    FILE* mFp;
+    mutable uint32_t mCurrentOffset;
 };
 
-class FdReader {
-public:
-   explicit FdReader(int fd) :
-       mFd(fd), mReadBuf(new unsigned char[kReadBufSize])
-   {
-   }
+class FdReader : public zip_archive::Reader {
+  public:
+    explicit FdReader(int fd) : mFd(fd) {
+    }
 
-   ~FdReader() {
-       delete[] mReadBuf;
-   }
+    bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+      return android::base::ReadFullyAtOffset(mFd, buf, len, static_cast<off_t>(offset));
+    }
 
-   long read(unsigned char** nextBuffer, long readSize) const {
-       *nextBuffer = mReadBuf;
-       return TEMP_FAILURE_RETRY(::read(mFd, mReadBuf, readSize));
-   }
-
-   int mFd;
-   unsigned char* mReadBuf;
+  private:
+    const int mFd;
 };
 
-class BufferReader {
-public:
-    BufferReader(void* input, size_t inputSize) :
-        mInput(reinterpret_cast<unsigned char*>(input)),
-        mInputSize(inputSize),
-        mBufferReturned(false)
-    {
+class BufferReader : public zip_archive::Reader {
+  public:
+    BufferReader(const void* input, size_t inputSize) : Reader(),
+        mInput(reinterpret_cast<const uint8_t*>(input)),
+        mInputSize(inputSize) {
     }
 
-    long read(unsigned char** nextBuffer, long /*readSize*/) {
-        if (!mBufferReturned) {
-            mBufferReturned = true;
-            *nextBuffer = mInput;
-            return mInputSize;
+    bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+        if (offset + len > mInputSize) {
+            return false;
         }
 
-        *nextBuffer = NULL;
-        return 0;
+        memcpy(buf, mInput + offset, len);
+        return true;
     }
 
-    unsigned char* mInput;
+  private:
+    const uint8_t* mInput;
     const size_t mInputSize;
-    bool mBufferReturned;
+};
+
+class BufferWriter : public zip_archive::Writer {
+  public:
+    BufferWriter(void* output, size_t outputSize) : Writer(),
+        mOutput(reinterpret_cast<uint8_t*>(output)), mOutputSize(outputSize), mBytesWritten(0) {
+    }
+
+    bool Append(uint8_t* buf, size_t bufSize) override {
+        if (mBytesWritten + bufSize > mOutputSize) {
+            return false;
+        }
+
+        memcpy(mOutput + mBytesWritten, buf, bufSize);
+        mBytesWritten += bufSize;
+        return true;
+    }
+
+  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 @@
     /* 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 */