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// Read-only access to Zip archives, with minimal heap allocation. 19// 20#define LOG_TAG "zipro" 21//#define LOG_NDEBUG 0 22#include <androidfw/ZipFileRO.h> 23#include <utils/Log.h> 24#include <utils/Compat.h> 25#include <utils/misc.h> 26#include <utils/threads.h> 27#include <ziparchive/zip_archive.h> 28 29#include <zlib.h> 30 31#include <string.h> 32#include <fcntl.h> 33#include <errno.h> 34#include <assert.h> 35#include <unistd.h> 36 37/* 38 * We must open binary files using open(path, ... | O_BINARY) under Windows. 39 * Otherwise strange read errors will happen. 40 */ 41#ifndef O_BINARY 42# define O_BINARY 0 43#endif 44 45using namespace android; 46 47class _ZipEntryRO { 48public: 49 ZipEntry entry; 50 ZipEntryName name; 51 void *cookie; 52 53 _ZipEntryRO() : cookie(NULL) { 54 } 55 56private: 57 _ZipEntryRO(const _ZipEntryRO& other); 58 _ZipEntryRO& operator=(const _ZipEntryRO& other); 59}; 60 61ZipFileRO::~ZipFileRO() { 62 CloseArchive(mHandle); 63 free(mFileName); 64} 65 66/* 67 * Open the specified file read-only. We memory-map the entire thing and 68 * close the file before returning. 69 */ 70/* static */ ZipFileRO* ZipFileRO::open(const char* zipFileName) 71{ 72 ZipArchiveHandle handle; 73 const int32_t error = OpenArchive(zipFileName, &handle); 74 if (error) { 75 ALOGW("Error opening archive %s: %s", zipFileName, ErrorCodeString(error)); 76 return NULL; 77 } 78 79 return new ZipFileRO(handle, strdup(zipFileName)); 80} 81 82 83ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const 84{ 85 _ZipEntryRO* data = new _ZipEntryRO; 86 const int32_t error = FindEntry(mHandle, entryName, &(data->entry)); 87 if (error) { 88 delete data; 89 return NULL; 90 } 91 92 data->name.name = entryName; 93 data->name.name_length = strlen(entryName); 94 95 return (ZipEntryRO) data; 96} 97 98/* 99 * Get the useful fields from the zip entry. 100 * 101 * Returns "false" if the offsets to the fields or the contents of the fields 102 * appear to be bogus. 103 */ 104bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, 105 size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const 106{ 107 const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); 108 const ZipEntry& ze = zipEntry->entry; 109 110 if (pMethod != NULL) { 111 *pMethod = ze.method; 112 } 113 if (pUncompLen != NULL) { 114 *pUncompLen = ze.uncompressed_length; 115 } 116 if (pCompLen != NULL) { 117 *pCompLen = ze.compressed_length; 118 } 119 if (pOffset != NULL) { 120 *pOffset = ze.offset; 121 } 122 if (pModWhen != NULL) { 123 *pModWhen = ze.mod_time; 124 } 125 if (pCrc32 != NULL) { 126 *pCrc32 = ze.crc32; 127 } 128 129 return true; 130} 131 132bool ZipFileRO::startIteration(void** cookie) 133{ 134 _ZipEntryRO* ze = new _ZipEntryRO; 135 int32_t error = StartIteration(mHandle, &(ze->cookie), NULL /* prefix */); 136 if (error) { 137 ALOGW("Could not start iteration over %s: %s", mFileName, ErrorCodeString(error)); 138 delete ze; 139 return false; 140 } 141 142 *cookie = ze; 143 return true; 144} 145 146ZipEntryRO ZipFileRO::nextEntry(void* cookie) 147{ 148 _ZipEntryRO* ze = reinterpret_cast<_ZipEntryRO*>(cookie); 149 int32_t error = Next(ze->cookie, &(ze->entry), &(ze->name)); 150 if (error) { 151 if (error != -1) { 152 ALOGW("Error iteration over %s: %s", mFileName, ErrorCodeString(error)); 153 } 154 return NULL; 155 } 156 157 return &(ze->entry); 158} 159 160void ZipFileRO::endIteration(void* cookie) 161{ 162 delete reinterpret_cast<_ZipEntryRO*>(cookie); 163} 164 165void ZipFileRO::releaseEntry(ZipEntryRO entry) const 166{ 167 delete reinterpret_cast<_ZipEntryRO*>(entry); 168} 169 170/* 171 * Copy the entry's filename to the buffer. 172 */ 173int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) 174 const 175{ 176 const _ZipEntryRO* zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); 177 const uint16_t requiredSize = zipEntry->name.name_length + 1; 178 179 if (bufLen < requiredSize) { 180 ALOGW("Buffer too short, requires %d bytes for entry name", requiredSize); 181 return requiredSize; 182 } 183 184 memcpy(buffer, zipEntry->name.name, requiredSize - 1); 185 buffer[requiredSize - 1] = '\0'; 186 187 return 0; 188} 189 190/* 191 * Create a new FileMap object that spans the data in "entry". 192 */ 193FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const 194{ 195 const _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); 196 const ZipEntry& ze = zipEntry->entry; 197 int fd = GetFileDescriptor(mHandle); 198 size_t actualLen = 0; 199 200 if (ze.method == kCompressStored) { 201 actualLen = ze.uncompressed_length; 202 } else { 203 actualLen = ze.compressed_length; 204 } 205 206 FileMap* newMap = new FileMap(); 207 if (!newMap->create(mFileName, fd, ze.offset, actualLen, true)) { 208 newMap->release(); 209 return NULL; 210 } 211 212 return newMap; 213} 214 215/* 216 * Uncompress an entry, in its entirety, into the provided output buffer. 217 * 218 * This doesn't verify the data's CRC, which might be useful for 219 * uncompressed data. The caller should be able to manage it. 220 */ 221bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer, size_t size) const 222{ 223 _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); 224 const int32_t error = ExtractToMemory(mHandle, &(zipEntry->entry), 225 (uint8_t*) buffer, size); 226 if (error) { 227 ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error)); 228 return false; 229 } 230 231 return true; 232} 233 234/* 235 * Uncompress an entry, in its entirety, to an open file descriptor. 236 * 237 * This doesn't verify the data's CRC, but probably should. 238 */ 239bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const 240{ 241 _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry); 242 const int32_t error = ExtractEntryToFile(mHandle, &(zipEntry->entry), fd); 243 if (error) { 244 ALOGW("ExtractToMemory failed with %s", ErrorCodeString(error)); 245 return false; 246 } 247 248 return true; 249} 250