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 using namespace android; 38 39 class _ZipEntryRO { 40 public: 41 ZipEntry entry; 42 ZipString name; 43 void *cookie; 44 45 _ZipEntryRO() : cookie(NULL) {} 46 47 ~_ZipEntryRO() { 48 EndIteration(cookie); 49 } 50 51 private: 52 _ZipEntryRO(const _ZipEntryRO& other); 53 _ZipEntryRO& operator=(const _ZipEntryRO& other); 54 }; 55 56 ZipFileRO::~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 79 ZipEntryRO 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 */ 100 bool 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 129 bool ZipFileRO::startIteration(void** cookie) { 130 return startIteration(cookie, NULL, NULL); 131 } 132 133 bool 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 151 ZipEntryRO 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 165 void ZipFileRO::endIteration(void* cookie) 166 { 167 delete reinterpret_cast<_ZipEntryRO*>(cookie); 168 } 169 170 void 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 */ 178 int 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 */ 198 FileMap* 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 */ 226 bool 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 */ 244 bool 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