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