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