1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // 18 // Misc zip/gzip utility functions. 19 // 20 21 #define LOG_TAG "ziputil" 22 23 #include <androidfw/ZipUtils.h> 24 #include <androidfw/ZipFileRO.h> 25 #include <utils/Log.h> 26 #include <utils/Compat.h> 27 28 #include <stdlib.h> 29 #include <string.h> 30 #include <assert.h> 31 32 #include <zlib.h> 33 34 using namespace android; 35 36 static inline unsigned long get4LE(const unsigned char* buf) { 37 return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); 38 } 39 40 41 static const unsigned long kReadBufSize = 32768; 42 43 /* 44 * Utility function that expands zip/gzip "deflate" compressed data 45 * into a buffer. 46 * 47 * (This is a clone of the previous function, but it takes a FILE* instead 48 * of an fd. We could pass fileno(fd) to the above, but we can run into 49 * trouble when "fp" has a different notion of what fd's file position is.) 50 * 51 * "fp" is an open file positioned at the start of the "deflate" data 52 * "buf" must hold at least "uncompressedLen" bytes. 53 */ 54 /*static*/ template<typename T> bool inflateToBuffer(T& reader, void* buf, 55 long uncompressedLen, long compressedLen) 56 { 57 bool result = false; 58 59 z_stream zstream; 60 int zerr; 61 unsigned long compRemaining; 62 63 assert(uncompressedLen >= 0); 64 assert(compressedLen >= 0); 65 66 compRemaining = compressedLen; 67 68 /* 69 * Initialize the zlib stream. 70 */ 71 memset(&zstream, 0, sizeof(zstream)); 72 zstream.zalloc = Z_NULL; 73 zstream.zfree = Z_NULL; 74 zstream.opaque = Z_NULL; 75 zstream.next_in = NULL; 76 zstream.avail_in = 0; 77 zstream.next_out = (Bytef*) buf; 78 zstream.avail_out = uncompressedLen; 79 zstream.data_type = Z_UNKNOWN; 80 81 /* 82 * Use the undocumented "negative window bits" feature to tell zlib 83 * that there's no zlib header waiting for it. 84 */ 85 zerr = inflateInit2(&zstream, -MAX_WBITS); 86 if (zerr != Z_OK) { 87 if (zerr == Z_VERSION_ERROR) { 88 ALOGE("Installed zlib is not compatible with linked version (%s)\n", 89 ZLIB_VERSION); 90 } else { 91 ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr); 92 } 93 goto bail; 94 } 95 96 /* 97 * Loop while we have data. 98 */ 99 do { 100 unsigned long getSize; 101 102 /* read as much as we can */ 103 if (zstream.avail_in == 0) { 104 getSize = (compRemaining > kReadBufSize) ? 105 kReadBufSize : compRemaining; 106 ALOGV("+++ reading %ld bytes (%ld left)\n", 107 getSize, compRemaining); 108 109 unsigned char* nextBuffer = NULL; 110 const unsigned long nextSize = reader.read(&nextBuffer, getSize); 111 112 if (nextSize < getSize || nextBuffer == NULL) { 113 ALOGD("inflate read failed (%ld vs %ld)\n", nextSize, getSize); 114 goto z_bail; 115 } 116 117 compRemaining -= nextSize; 118 119 zstream.next_in = nextBuffer; 120 zstream.avail_in = nextSize; 121 } 122 123 /* uncompress the data */ 124 zerr = inflate(&zstream, Z_NO_FLUSH); 125 if (zerr != Z_OK && zerr != Z_STREAM_END) { 126 ALOGD("zlib inflate call failed (zerr=%d)\n", zerr); 127 goto z_bail; 128 } 129 130 /* output buffer holds all, so no need to write the output */ 131 } while (zerr == Z_OK); 132 133 assert(zerr == Z_STREAM_END); /* other errors should've been caught */ 134 135 if ((long) zstream.total_out != uncompressedLen) { 136 ALOGW("Size mismatch on inflated file (%ld vs %ld)\n", 137 zstream.total_out, uncompressedLen); 138 goto z_bail; 139 } 140 141 // success! 142 result = true; 143 144 z_bail: 145 inflateEnd(&zstream); /* free up any allocated structures */ 146 147 bail: 148 return result; 149 } 150 151 class FileReader { 152 public: 153 FileReader(FILE* fp) : 154 mFp(fp), mReadBuf(new unsigned char[kReadBufSize]) 155 { 156 } 157 158 ~FileReader() { 159 delete[] mReadBuf; 160 } 161 162 long read(unsigned char** nextBuffer, long readSize) const { 163 *nextBuffer = mReadBuf; 164 return fread(mReadBuf, 1, readSize, mFp); 165 } 166 167 FILE* mFp; 168 unsigned char* mReadBuf; 169 }; 170 171 class FdReader { 172 public: 173 FdReader(int fd) : 174 mFd(fd), mReadBuf(new unsigned char[kReadBufSize]) 175 { 176 } 177 178 ~FdReader() { 179 delete[] mReadBuf; 180 } 181 182 long read(unsigned char** nextBuffer, long readSize) const { 183 *nextBuffer = mReadBuf; 184 return TEMP_FAILURE_RETRY(::read(mFd, mReadBuf, readSize)); 185 } 186 187 int mFd; 188 unsigned char* mReadBuf; 189 }; 190 191 class BufferReader { 192 public: 193 BufferReader(void* input, size_t inputSize) : 194 mInput(reinterpret_cast<unsigned char*>(input)), 195 mInputSize(inputSize), 196 mBufferReturned(false) 197 { 198 } 199 200 long read(unsigned char** nextBuffer, long /*readSize*/) { 201 if (!mBufferReturned) { 202 mBufferReturned = true; 203 *nextBuffer = mInput; 204 return mInputSize; 205 } 206 207 *nextBuffer = NULL; 208 return 0; 209 } 210 211 unsigned char* mInput; 212 const size_t mInputSize; 213 bool mBufferReturned; 214 }; 215 216 /*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf, 217 long uncompressedLen, long compressedLen) 218 { 219 FileReader reader(fp); 220 return ::inflateToBuffer<FileReader>(reader, buf, 221 uncompressedLen, compressedLen); 222 } 223 224 /*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf, 225 long uncompressedLen, long compressedLen) 226 { 227 FdReader reader(fd); 228 return ::inflateToBuffer<FdReader>(reader, buf, 229 uncompressedLen, compressedLen); 230 } 231 232 /*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf, 233 long uncompressedLen, long compressedLen) 234 { 235 BufferReader reader(in, compressedLen); 236 return ::inflateToBuffer<BufferReader>(reader, buf, 237 uncompressedLen, compressedLen); 238 } 239 240 241 242 /* 243 * Look at the contents of a gzip archive. We want to know where the 244 * data starts, and how long it will be after it is uncompressed. 245 * 246 * We expect to find the CRC and length as the last 8 bytes on the file. 247 * This is a pretty reasonable thing to expect for locally-compressed 248 * files, but there's a small chance that some extra padding got thrown 249 * on (the man page talks about compressed data written to tape). We 250 * don't currently deal with that here. If "gzip -l" whines, we're going 251 * to fail too. 252 * 253 * On exit, "fp" is pointing at the start of the compressed data. 254 */ 255 /*static*/ bool ZipUtils::examineGzip(FILE* fp, int* pCompressionMethod, 256 long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32) 257 { 258 enum { // flags 259 FTEXT = 0x01, 260 FHCRC = 0x02, 261 FEXTRA = 0x04, 262 FNAME = 0x08, 263 FCOMMENT = 0x10, 264 }; 265 int ic; 266 int method, flags; 267 int i; 268 269 ic = getc(fp); 270 if (ic != 0x1f || getc(fp) != 0x8b) 271 return false; // not gzip 272 method = getc(fp); 273 flags = getc(fp); 274 275 /* quick sanity checks */ 276 if (method == EOF || flags == EOF) 277 return false; 278 if (method != ZipFileRO::kCompressDeflated) 279 return false; 280 281 /* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */ 282 for (i = 0; i < 6; i++) 283 (void) getc(fp); 284 /* consume "extra" field, if present */ 285 if ((flags & FEXTRA) != 0) { 286 int len; 287 288 len = getc(fp); 289 len |= getc(fp) << 8; 290 while (len-- && getc(fp) != EOF) 291 ; 292 } 293 /* consume filename, if present */ 294 if ((flags & FNAME) != 0) { 295 do { 296 ic = getc(fp); 297 } while (ic != 0 && ic != EOF); 298 } 299 /* consume comment, if present */ 300 if ((flags & FCOMMENT) != 0) { 301 do { 302 ic = getc(fp); 303 } while (ic != 0 && ic != EOF); 304 } 305 /* consume 16-bit header CRC, if present */ 306 if ((flags & FHCRC) != 0) { 307 (void) getc(fp); 308 (void) getc(fp); 309 } 310 311 if (feof(fp) || ferror(fp)) 312 return false; 313 314 /* seek to the end; CRC and length are in the last 8 bytes */ 315 long curPosn = ftell(fp); 316 unsigned char buf[8]; 317 fseek(fp, -8, SEEK_END); 318 *pCompressedLen = ftell(fp) - curPosn; 319 320 if (fread(buf, 1, 8, fp) != 8) 321 return false; 322 /* seek back to start of compressed data */ 323 fseek(fp, curPosn, SEEK_SET); 324 325 *pCompressionMethod = method; 326 *pCRC32 = get4LE(&buf[0]); 327 *pUncompressedLen = get4LE(&buf[4]); 328 329 return true; 330 } 331