11f5762e646bed2290934280464832782766ee68eMathias Agopian/*
21f5762e646bed2290934280464832782766ee68eMathias Agopian * Copyright (C) 2007 The Android Open Source Project
31f5762e646bed2290934280464832782766ee68eMathias Agopian *
41f5762e646bed2290934280464832782766ee68eMathias Agopian * Licensed under the Apache License, Version 2.0 (the "License");
51f5762e646bed2290934280464832782766ee68eMathias Agopian * you may not use this file except in compliance with the License.
61f5762e646bed2290934280464832782766ee68eMathias Agopian * You may obtain a copy of the License at
71f5762e646bed2290934280464832782766ee68eMathias Agopian *
81f5762e646bed2290934280464832782766ee68eMathias Agopian *      http://www.apache.org/licenses/LICENSE-2.0
91f5762e646bed2290934280464832782766ee68eMathias Agopian *
101f5762e646bed2290934280464832782766ee68eMathias Agopian * Unless required by applicable law or agreed to in writing, software
111f5762e646bed2290934280464832782766ee68eMathias Agopian * distributed under the License is distributed on an "AS IS" BASIS,
121f5762e646bed2290934280464832782766ee68eMathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131f5762e646bed2290934280464832782766ee68eMathias Agopian * See the License for the specific language governing permissions and
141f5762e646bed2290934280464832782766ee68eMathias Agopian * limitations under the License.
151f5762e646bed2290934280464832782766ee68eMathias Agopian */
161f5762e646bed2290934280464832782766ee68eMathias Agopian
171f5762e646bed2290934280464832782766ee68eMathias Agopian//
181f5762e646bed2290934280464832782766ee68eMathias Agopian// Misc zip/gzip utility functions.
191f5762e646bed2290934280464832782766ee68eMathias Agopian//
201f5762e646bed2290934280464832782766ee68eMathias Agopian
211f5762e646bed2290934280464832782766ee68eMathias Agopian#define LOG_TAG "ziputil"
221f5762e646bed2290934280464832782766ee68eMathias Agopian
231f5762e646bed2290934280464832782766ee68eMathias Agopian#include <androidfw/ZipUtils.h>
241f5762e646bed2290934280464832782766ee68eMathias Agopian#include <androidfw/ZipFileRO.h>
251f5762e646bed2290934280464832782766ee68eMathias Agopian#include <utils/Log.h>
261f5762e646bed2290934280464832782766ee68eMathias Agopian#include <utils/Compat.h>
271f5762e646bed2290934280464832782766ee68eMathias Agopian
281f5762e646bed2290934280464832782766ee68eMathias Agopian#include <stdlib.h>
291f5762e646bed2290934280464832782766ee68eMathias Agopian#include <string.h>
301f5762e646bed2290934280464832782766ee68eMathias Agopian#include <assert.h>
311f5762e646bed2290934280464832782766ee68eMathias Agopian
321f5762e646bed2290934280464832782766ee68eMathias Agopian#include <zlib.h>
331f5762e646bed2290934280464832782766ee68eMathias Agopian
341f5762e646bed2290934280464832782766ee68eMathias Agopianusing namespace android;
351f5762e646bed2290934280464832782766ee68eMathias Agopian
36afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathstatic inline unsigned long get4LE(const unsigned char* buf) {
37afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
38afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath}
39afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
40afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
41afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathstatic const unsigned long kReadBufSize = 32768;
42afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
431f5762e646bed2290934280464832782766ee68eMathias Agopian/*
441f5762e646bed2290934280464832782766ee68eMathias Agopian * Utility function that expands zip/gzip "deflate" compressed data
451f5762e646bed2290934280464832782766ee68eMathias Agopian * into a buffer.
461f5762e646bed2290934280464832782766ee68eMathias Agopian *
47afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath * (This is a clone of the previous function, but it takes a FILE* instead
48afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath * of an fd.  We could pass fileno(fd) to the above, but we can run into
49afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath * trouble when "fp" has a different notion of what fd's file position is.)
50afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath *
51afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath * "fp" is an open file positioned at the start of the "deflate" data
521f5762e646bed2290934280464832782766ee68eMathias Agopian * "buf" must hold at least "uncompressedLen" bytes.
531f5762e646bed2290934280464832782766ee68eMathias Agopian */
54afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath/*static*/ template<typename T> bool inflateToBuffer(T& reader, void* buf,
551f5762e646bed2290934280464832782766ee68eMathias Agopian    long uncompressedLen, long compressedLen)
561f5762e646bed2290934280464832782766ee68eMathias Agopian{
571f5762e646bed2290934280464832782766ee68eMathias Agopian    bool result = false;
58afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
591f5762e646bed2290934280464832782766ee68eMathias Agopian    z_stream zstream;
601f5762e646bed2290934280464832782766ee68eMathias Agopian    int zerr;
611f5762e646bed2290934280464832782766ee68eMathias Agopian    unsigned long compRemaining;
621f5762e646bed2290934280464832782766ee68eMathias Agopian
631f5762e646bed2290934280464832782766ee68eMathias Agopian    assert(uncompressedLen >= 0);
641f5762e646bed2290934280464832782766ee68eMathias Agopian    assert(compressedLen >= 0);
651f5762e646bed2290934280464832782766ee68eMathias Agopian
661f5762e646bed2290934280464832782766ee68eMathias Agopian    compRemaining = compressedLen;
671f5762e646bed2290934280464832782766ee68eMathias Agopian
681f5762e646bed2290934280464832782766ee68eMathias Agopian    /*
691f5762e646bed2290934280464832782766ee68eMathias Agopian     * Initialize the zlib stream.
701f5762e646bed2290934280464832782766ee68eMathias Agopian     */
71afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    memset(&zstream, 0, sizeof(zstream));
721f5762e646bed2290934280464832782766ee68eMathias Agopian    zstream.zalloc = Z_NULL;
731f5762e646bed2290934280464832782766ee68eMathias Agopian    zstream.zfree = Z_NULL;
741f5762e646bed2290934280464832782766ee68eMathias Agopian    zstream.opaque = Z_NULL;
751f5762e646bed2290934280464832782766ee68eMathias Agopian    zstream.next_in = NULL;
761f5762e646bed2290934280464832782766ee68eMathias Agopian    zstream.avail_in = 0;
771f5762e646bed2290934280464832782766ee68eMathias Agopian    zstream.next_out = (Bytef*) buf;
781f5762e646bed2290934280464832782766ee68eMathias Agopian    zstream.avail_out = uncompressedLen;
791f5762e646bed2290934280464832782766ee68eMathias Agopian    zstream.data_type = Z_UNKNOWN;
801f5762e646bed2290934280464832782766ee68eMathias Agopian
81afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    /*
82afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath     * Use the undocumented "negative window bits" feature to tell zlib
83afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath     * that there's no zlib header waiting for it.
84afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath     */
851f5762e646bed2290934280464832782766ee68eMathias Agopian    zerr = inflateInit2(&zstream, -MAX_WBITS);
861f5762e646bed2290934280464832782766ee68eMathias Agopian    if (zerr != Z_OK) {
871f5762e646bed2290934280464832782766ee68eMathias Agopian        if (zerr == Z_VERSION_ERROR) {
881f5762e646bed2290934280464832782766ee68eMathias Agopian            ALOGE("Installed zlib is not compatible with linked version (%s)\n",
891f5762e646bed2290934280464832782766ee68eMathias Agopian                ZLIB_VERSION);
901f5762e646bed2290934280464832782766ee68eMathias Agopian        } else {
911f5762e646bed2290934280464832782766ee68eMathias Agopian            ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
921f5762e646bed2290934280464832782766ee68eMathias Agopian        }
931f5762e646bed2290934280464832782766ee68eMathias Agopian        goto bail;
941f5762e646bed2290934280464832782766ee68eMathias Agopian    }
951f5762e646bed2290934280464832782766ee68eMathias Agopian
961f5762e646bed2290934280464832782766ee68eMathias Agopian    /*
971f5762e646bed2290934280464832782766ee68eMathias Agopian     * Loop while we have data.
981f5762e646bed2290934280464832782766ee68eMathias Agopian     */
991f5762e646bed2290934280464832782766ee68eMathias Agopian    do {
1001f5762e646bed2290934280464832782766ee68eMathias Agopian        unsigned long getSize;
1011f5762e646bed2290934280464832782766ee68eMathias Agopian
1021f5762e646bed2290934280464832782766ee68eMathias Agopian        /* read as much as we can */
1031f5762e646bed2290934280464832782766ee68eMathias Agopian        if (zstream.avail_in == 0) {
1041f5762e646bed2290934280464832782766ee68eMathias Agopian            getSize = (compRemaining > kReadBufSize) ?
1051f5762e646bed2290934280464832782766ee68eMathias Agopian                        kReadBufSize : compRemaining;
1061f5762e646bed2290934280464832782766ee68eMathias Agopian            ALOGV("+++ reading %ld bytes (%ld left)\n",
1071f5762e646bed2290934280464832782766ee68eMathias Agopian                getSize, compRemaining);
1081f5762e646bed2290934280464832782766ee68eMathias Agopian
109afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            unsigned char* nextBuffer = NULL;
110afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            const unsigned long nextSize = reader.read(&nextBuffer, getSize);
111afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
112afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            if (nextSize < getSize || nextBuffer == NULL) {
113afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath                ALOGD("inflate read failed (%ld vs %ld)\n", nextSize, getSize);
1141f5762e646bed2290934280464832782766ee68eMathias Agopian                goto z_bail;
1151f5762e646bed2290934280464832782766ee68eMathias Agopian            }
1161f5762e646bed2290934280464832782766ee68eMathias Agopian
117afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            compRemaining -= nextSize;
1181f5762e646bed2290934280464832782766ee68eMathias Agopian
119afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            zstream.next_in = nextBuffer;
120afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            zstream.avail_in = nextSize;
1211f5762e646bed2290934280464832782766ee68eMathias Agopian        }
1221f5762e646bed2290934280464832782766ee68eMathias Agopian
1231f5762e646bed2290934280464832782766ee68eMathias Agopian        /* uncompress the data */
1241f5762e646bed2290934280464832782766ee68eMathias Agopian        zerr = inflate(&zstream, Z_NO_FLUSH);
1251f5762e646bed2290934280464832782766ee68eMathias Agopian        if (zerr != Z_OK && zerr != Z_STREAM_END) {
1261f5762e646bed2290934280464832782766ee68eMathias Agopian            ALOGD("zlib inflate call failed (zerr=%d)\n", zerr);
1271f5762e646bed2290934280464832782766ee68eMathias Agopian            goto z_bail;
1281f5762e646bed2290934280464832782766ee68eMathias Agopian        }
1291f5762e646bed2290934280464832782766ee68eMathias Agopian
13000adb8685ee996f9d2650d617c8c0e98f13ef406Mark Salyzyn        /* output buffer holds all, so no need to write the output */
1311f5762e646bed2290934280464832782766ee68eMathias Agopian    } while (zerr == Z_OK);
1321f5762e646bed2290934280464832782766ee68eMathias Agopian
1331f5762e646bed2290934280464832782766ee68eMathias Agopian    assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
1341f5762e646bed2290934280464832782766ee68eMathias Agopian
1351f5762e646bed2290934280464832782766ee68eMathias Agopian    if ((long) zstream.total_out != uncompressedLen) {
1361f5762e646bed2290934280464832782766ee68eMathias Agopian        ALOGW("Size mismatch on inflated file (%ld vs %ld)\n",
1371f5762e646bed2290934280464832782766ee68eMathias Agopian            zstream.total_out, uncompressedLen);
1381f5762e646bed2290934280464832782766ee68eMathias Agopian        goto z_bail;
1391f5762e646bed2290934280464832782766ee68eMathias Agopian    }
1401f5762e646bed2290934280464832782766ee68eMathias Agopian
1411f5762e646bed2290934280464832782766ee68eMathias Agopian    // success!
1421f5762e646bed2290934280464832782766ee68eMathias Agopian    result = true;
1431f5762e646bed2290934280464832782766ee68eMathias Agopian
1441f5762e646bed2290934280464832782766ee68eMathias Agopianz_bail:
1451f5762e646bed2290934280464832782766ee68eMathias Agopian    inflateEnd(&zstream);        /* free up any allocated structures */
1461f5762e646bed2290934280464832782766ee68eMathias Agopian
1471f5762e646bed2290934280464832782766ee68eMathias Agopianbail:
1481f5762e646bed2290934280464832782766ee68eMathias Agopian    return result;
1491f5762e646bed2290934280464832782766ee68eMathias Agopian}
1501f5762e646bed2290934280464832782766ee68eMathias Agopian
151afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathclass FileReader {
152afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathpublic:
153c6baf563ba6aa207a48317c177b29f1d2b70cf3dChih-Hung Hsieh   explicit FileReader(FILE* fp) :
154afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath       mFp(fp), mReadBuf(new unsigned char[kReadBufSize])
155afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   {
156afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   }
157afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
158afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   ~FileReader() {
159afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath       delete[] mReadBuf;
160afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   }
161afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
162afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   long read(unsigned char** nextBuffer, long readSize) const {
163afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath       *nextBuffer = mReadBuf;
164afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath       return fread(mReadBuf, 1, readSize, mFp);
165afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   }
166afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
167afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   FILE* mFp;
168afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   unsigned char* mReadBuf;
169afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath};
170afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
171afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathclass FdReader {
172afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathpublic:
173c6baf563ba6aa207a48317c177b29f1d2b70cf3dChih-Hung Hsieh   explicit FdReader(int fd) :
174afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath       mFd(fd), mReadBuf(new unsigned char[kReadBufSize])
175afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   {
176afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   }
177afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
178afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   ~FdReader() {
179afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath       delete[] mReadBuf;
180afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   }
181afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
182afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   long read(unsigned char** nextBuffer, long readSize) const {
183afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath       *nextBuffer = mReadBuf;
184afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath       return TEMP_FAILURE_RETRY(::read(mFd, mReadBuf, readSize));
185afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   }
186afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
187afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   int mFd;
188afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath   unsigned char* mReadBuf;
189afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath};
190afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath
191afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathclass BufferReader {
192afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamathpublic:
193afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    BufferReader(void* input, size_t inputSize) :
194afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        mInput(reinterpret_cast<unsigned char*>(input)),
195afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        mInputSize(inputSize),
196afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        mBufferReturned(false)
197afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    {
1981f5762e646bed2290934280464832782766ee68eMathias Agopian    }
1991f5762e646bed2290934280464832782766ee68eMathias Agopian
20000adb8685ee996f9d2650d617c8c0e98f13ef406Mark Salyzyn    long read(unsigned char** nextBuffer, long /*readSize*/) {
201afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        if (!mBufferReturned) {
202afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            mBufferReturned = true;
203afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            *nextBuffer = mInput;
204afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath            return mInputSize;
2051f5762e646bed2290934280464832782766ee68eMathias Agopian        }
2061f5762e646bed2290934280464832782766ee68eMathias Agopian
207afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        *nextBuffer = NULL;
208afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        return 0;
209afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    }
2101f5762e646bed2290934280464832782766ee68eMathias Agopian
211afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    unsigned char* mInput;
212afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    const size_t mInputSize;
213afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    bool mBufferReturned;
214afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath};
2151f5762e646bed2290934280464832782766ee68eMathias Agopian
216afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
217afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    long uncompressedLen, long compressedLen)
218afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath{
219afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    FileReader reader(fp);
220afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    return ::inflateToBuffer<FileReader>(reader, buf,
221afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        uncompressedLen, compressedLen);
222afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath}
2231f5762e646bed2290934280464832782766ee68eMathias Agopian
224afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
225afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    long uncompressedLen, long compressedLen)
226afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath{
227afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    FdReader reader(fd);
228afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    return ::inflateToBuffer<FdReader>(reader, buf,
229afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        uncompressedLen, compressedLen);
230afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath}
2311f5762e646bed2290934280464832782766ee68eMathias Agopian
232afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath/*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf,
233afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    long uncompressedLen, long compressedLen)
234afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath{
235afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    BufferReader reader(in, compressedLen);
236afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    return ::inflateToBuffer<BufferReader>(reader, buf,
237afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath        uncompressedLen, compressedLen);
238afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath}
2391f5762e646bed2290934280464832782766ee68eMathias Agopian
2401f5762e646bed2290934280464832782766ee68eMathias Agopian
2411f5762e646bed2290934280464832782766ee68eMathias Agopian
2421f5762e646bed2290934280464832782766ee68eMathias Agopian/*
2431f5762e646bed2290934280464832782766ee68eMathias Agopian * Look at the contents of a gzip archive.  We want to know where the
2441f5762e646bed2290934280464832782766ee68eMathias Agopian * data starts, and how long it will be after it is uncompressed.
2451f5762e646bed2290934280464832782766ee68eMathias Agopian *
2461f5762e646bed2290934280464832782766ee68eMathias Agopian * We expect to find the CRC and length as the last 8 bytes on the file.
2471f5762e646bed2290934280464832782766ee68eMathias Agopian * This is a pretty reasonable thing to expect for locally-compressed
2481f5762e646bed2290934280464832782766ee68eMathias Agopian * files, but there's a small chance that some extra padding got thrown
2491f5762e646bed2290934280464832782766ee68eMathias Agopian * on (the man page talks about compressed data written to tape).  We
2501f5762e646bed2290934280464832782766ee68eMathias Agopian * don't currently deal with that here.  If "gzip -l" whines, we're going
2511f5762e646bed2290934280464832782766ee68eMathias Agopian * to fail too.
2521f5762e646bed2290934280464832782766ee68eMathias Agopian *
2531f5762e646bed2290934280464832782766ee68eMathias Agopian * On exit, "fp" is pointing at the start of the compressed data.
2541f5762e646bed2290934280464832782766ee68eMathias Agopian */
2551f5762e646bed2290934280464832782766ee68eMathias Agopian/*static*/ bool ZipUtils::examineGzip(FILE* fp, int* pCompressionMethod,
2561f5762e646bed2290934280464832782766ee68eMathias Agopian    long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32)
2571f5762e646bed2290934280464832782766ee68eMathias Agopian{
2581f5762e646bed2290934280464832782766ee68eMathias Agopian    enum {  // flags
2591f5762e646bed2290934280464832782766ee68eMathias Agopian        FTEXT       = 0x01,
2601f5762e646bed2290934280464832782766ee68eMathias Agopian        FHCRC       = 0x02,
2611f5762e646bed2290934280464832782766ee68eMathias Agopian        FEXTRA      = 0x04,
2621f5762e646bed2290934280464832782766ee68eMathias Agopian        FNAME       = 0x08,
2631f5762e646bed2290934280464832782766ee68eMathias Agopian        FCOMMENT    = 0x10,
2641f5762e646bed2290934280464832782766ee68eMathias Agopian    };
2651f5762e646bed2290934280464832782766ee68eMathias Agopian    int ic;
2661f5762e646bed2290934280464832782766ee68eMathias Agopian    int method, flags;
2671f5762e646bed2290934280464832782766ee68eMathias Agopian    int i;
2681f5762e646bed2290934280464832782766ee68eMathias Agopian
2691f5762e646bed2290934280464832782766ee68eMathias Agopian    ic = getc(fp);
2701f5762e646bed2290934280464832782766ee68eMathias Agopian    if (ic != 0x1f || getc(fp) != 0x8b)
2711f5762e646bed2290934280464832782766ee68eMathias Agopian        return false;       // not gzip
2721f5762e646bed2290934280464832782766ee68eMathias Agopian    method = getc(fp);
2731f5762e646bed2290934280464832782766ee68eMathias Agopian    flags = getc(fp);
2741f5762e646bed2290934280464832782766ee68eMathias Agopian
2751f5762e646bed2290934280464832782766ee68eMathias Agopian    /* quick sanity checks */
2761f5762e646bed2290934280464832782766ee68eMathias Agopian    if (method == EOF || flags == EOF)
2771f5762e646bed2290934280464832782766ee68eMathias Agopian        return false;
2781f5762e646bed2290934280464832782766ee68eMathias Agopian    if (method != ZipFileRO::kCompressDeflated)
2791f5762e646bed2290934280464832782766ee68eMathias Agopian        return false;
2801f5762e646bed2290934280464832782766ee68eMathias Agopian
2811f5762e646bed2290934280464832782766ee68eMathias Agopian    /* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */
2821f5762e646bed2290934280464832782766ee68eMathias Agopian    for (i = 0; i < 6; i++)
2831f5762e646bed2290934280464832782766ee68eMathias Agopian        (void) getc(fp);
2841f5762e646bed2290934280464832782766ee68eMathias Agopian    /* consume "extra" field, if present */
2851f5762e646bed2290934280464832782766ee68eMathias Agopian    if ((flags & FEXTRA) != 0) {
2861f5762e646bed2290934280464832782766ee68eMathias Agopian        int len;
2871f5762e646bed2290934280464832782766ee68eMathias Agopian
2881f5762e646bed2290934280464832782766ee68eMathias Agopian        len = getc(fp);
2891f5762e646bed2290934280464832782766ee68eMathias Agopian        len |= getc(fp) << 8;
2901f5762e646bed2290934280464832782766ee68eMathias Agopian        while (len-- && getc(fp) != EOF)
2911f5762e646bed2290934280464832782766ee68eMathias Agopian            ;
2921f5762e646bed2290934280464832782766ee68eMathias Agopian    }
2931f5762e646bed2290934280464832782766ee68eMathias Agopian    /* consume filename, if present */
2941f5762e646bed2290934280464832782766ee68eMathias Agopian    if ((flags & FNAME) != 0) {
2951f5762e646bed2290934280464832782766ee68eMathias Agopian        do {
2961f5762e646bed2290934280464832782766ee68eMathias Agopian            ic = getc(fp);
2971f5762e646bed2290934280464832782766ee68eMathias Agopian        } while (ic != 0 && ic != EOF);
2981f5762e646bed2290934280464832782766ee68eMathias Agopian    }
2991f5762e646bed2290934280464832782766ee68eMathias Agopian    /* consume comment, if present */
3001f5762e646bed2290934280464832782766ee68eMathias Agopian    if ((flags & FCOMMENT) != 0) {
3011f5762e646bed2290934280464832782766ee68eMathias Agopian        do {
3021f5762e646bed2290934280464832782766ee68eMathias Agopian            ic = getc(fp);
3031f5762e646bed2290934280464832782766ee68eMathias Agopian        } while (ic != 0 && ic != EOF);
3041f5762e646bed2290934280464832782766ee68eMathias Agopian    }
3051f5762e646bed2290934280464832782766ee68eMathias Agopian    /* consume 16-bit header CRC, if present */
3061f5762e646bed2290934280464832782766ee68eMathias Agopian    if ((flags & FHCRC) != 0) {
3071f5762e646bed2290934280464832782766ee68eMathias Agopian        (void) getc(fp);
3081f5762e646bed2290934280464832782766ee68eMathias Agopian        (void) getc(fp);
3091f5762e646bed2290934280464832782766ee68eMathias Agopian    }
3101f5762e646bed2290934280464832782766ee68eMathias Agopian
3111f5762e646bed2290934280464832782766ee68eMathias Agopian    if (feof(fp) || ferror(fp))
3121f5762e646bed2290934280464832782766ee68eMathias Agopian        return false;
3131f5762e646bed2290934280464832782766ee68eMathias Agopian
3141f5762e646bed2290934280464832782766ee68eMathias Agopian    /* seek to the end; CRC and length are in the last 8 bytes */
3151f5762e646bed2290934280464832782766ee68eMathias Agopian    long curPosn = ftell(fp);
3161f5762e646bed2290934280464832782766ee68eMathias Agopian    unsigned char buf[8];
3171f5762e646bed2290934280464832782766ee68eMathias Agopian    fseek(fp, -8, SEEK_END);
3181f5762e646bed2290934280464832782766ee68eMathias Agopian    *pCompressedLen = ftell(fp) - curPosn;
3191f5762e646bed2290934280464832782766ee68eMathias Agopian
3201f5762e646bed2290934280464832782766ee68eMathias Agopian    if (fread(buf, 1, 8, fp) != 8)
3211f5762e646bed2290934280464832782766ee68eMathias Agopian        return false;
3221f5762e646bed2290934280464832782766ee68eMathias Agopian    /* seek back to start of compressed data */
3231f5762e646bed2290934280464832782766ee68eMathias Agopian    fseek(fp, curPosn, SEEK_SET);
3241f5762e646bed2290934280464832782766ee68eMathias Agopian
3251f5762e646bed2290934280464832782766ee68eMathias Agopian    *pCompressionMethod = method;
326afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    *pCRC32 = get4LE(&buf[0]);
327afd31e08299008fdc5c2813f21b2573f29dc53dfNarayan Kamath    *pUncompressedLen = get4LE(&buf[4]);
3281f5762e646bed2290934280464832782766ee68eMathias Agopian
3291f5762e646bed2290934280464832782766ee68eMathias Agopian    return true;
3301f5762e646bed2290934280464832782766ee68eMathias Agopian}
331