Home | History | Annotate | Download | only in androidfw
      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 
     45 using namespace android;
     46 
     47 class _ZipEntryRO {
     48 public:
     49     ZipEntry entry;
     50     ZipEntryName name;
     51     void *cookie;
     52 
     53     _ZipEntryRO() : cookie(NULL) {
     54     }
     55 
     56 private:
     57     _ZipEntryRO(const _ZipEntryRO& other);
     58     _ZipEntryRO& operator=(const _ZipEntryRO& other);
     59 };
     60 
     61 ZipFileRO::~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 
     83 ZipEntryRO 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  */
    104 bool 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 
    132 bool 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 
    146 ZipEntryRO 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 
    160 void ZipFileRO::endIteration(void* cookie)
    161 {
    162     delete reinterpret_cast<_ZipEntryRO*>(cookie);
    163 }
    164 
    165 void 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  */
    173 int 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  */
    193 FileMap* 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  */
    221 bool 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  */
    239 bool 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