Home | History | Annotate | Download | only in libdex
      1 /*
      2  * Copyright (C) 2008 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 #ifndef LIBDEX_ZIPARCHIVE_H_
     21 #define LIBDEX_ZIPARCHIVE_H_
     22 
     23 #include "SysUtil.h"
     24 #include "DexFile.h"            // need DEX_INLINE
     25 
     26 /*
     27  * Trivial typedef to ensure that ZipEntry is not treated as a simple
     28  * integer.  We use NULL to indicate an invalid value.
     29  */
     30 typedef void* ZipEntry;
     31 
     32 /*
     33  * One entry in the hash table.
     34  */
     35 struct ZipHashEntry {
     36     const char*     name;
     37     unsigned short  nameLen;
     38 };
     39 
     40 /*
     41  * Read-only Zip archive.
     42  *
     43  * We want "open" and "find entry by name" to be fast operations, and
     44  * we want to use as little memory as possible.  We memory-map the zip
     45  * central directory, and load a hash table with pointers to the filenames
     46  * (which aren't null-terminated).  The other fields are at a fixed offset
     47  * from the filename, so we don't need to extract those (but we do need
     48  * to byte-read and endian-swap them every time we want them).
     49  *
     50  * It's possible that somebody has handed us a massive (~1GB) zip archive,
     51  * so we can't expect to mmap the entire file.
     52  *
     53  * To speed comparisons when doing a lookup by name, we could make the mapping
     54  * "private" (copy-on-write) and null-terminate the filenames after verifying
     55  * the record structure.  However, this requires a private mapping of
     56  * every page that the Central Directory touches.  Easier to tuck a copy
     57  * of the string length into the hash table entry.
     58  */
     59 struct ZipArchive {
     60     /* open Zip archive */
     61     int         mFd;
     62 
     63     /* mapped central directory area */
     64     off_t       mDirectoryOffset;
     65     MemMapping  mDirectoryMap;
     66 
     67     /* number of entries in the Zip archive */
     68     int         mNumEntries;
     69 
     70     /*
     71      * We know how many entries are in the Zip archive, so we can have a
     72      * fixed-size hash table.  We probe on collisions.
     73      */
     74     int         mHashTableSize;
     75     ZipHashEntry* mHashTable;
     76 };
     77 
     78 /* Zip compression methods we support */
     79 enum {
     80     kCompressStored     = 0,        // no compression
     81     kCompressDeflated   = 8,        // standard deflate
     82 };
     83 
     84 
     85 /*
     86  * Open a Zip archive.
     87  *
     88  * On success, returns 0 and populates "pArchive".  Returns nonzero errno
     89  * value on failure.
     90  */
     91 int dexZipOpenArchive(const char* fileName, ZipArchive* pArchive);
     92 
     93 /*
     94  * Like dexZipOpenArchive, but takes a file descriptor open for reading
     95  * at the start of the file.  The descriptor must be mappable (this does
     96  * not allow access to a stream).
     97  *
     98  * "debugFileName" will appear in error messages, but is not otherwise used.
     99  */
    100 int dexZipPrepArchive(int fd, const char* debugFileName, ZipArchive* pArchive);
    101 
    102 /*
    103  * Close archive, releasing resources associated with it.
    104  *
    105  * Depending on the implementation this could unmap pages used by classes
    106  * stored in a Jar.  This should only be done after unloading classes.
    107  */
    108 void dexZipCloseArchive(ZipArchive* pArchive);
    109 
    110 /*
    111  * Return the archive's file descriptor.
    112  */
    113 DEX_INLINE int dexZipGetArchiveFd(const ZipArchive* pArchive) {
    114     return pArchive->mFd;
    115 }
    116 
    117 /*
    118  * Find an entry in the Zip archive, by name.  Returns NULL if the entry
    119  * was not found.
    120  */
    121 ZipEntry dexZipFindEntry(const ZipArchive* pArchive,
    122     const char* entryName);
    123 
    124 /*
    125  * Retrieve one or more of the "interesting" fields.  Non-NULL pointers
    126  * are filled in.
    127  *
    128  * Returns 0 on success.
    129  */
    130 int dexZipGetEntryInfo(const ZipArchive* pArchive, ZipEntry entry,
    131     int* pMethod, size_t* pUncompLen, size_t* pCompLen, off_t* pOffset,
    132     long* pModWhen, long* pCrc32);
    133 
    134 /*
    135  * Simple accessors.
    136  */
    137 DEX_INLINE long dexGetZipEntryOffset(const ZipArchive* pArchive,
    138     const ZipEntry entry)
    139 {
    140     off_t val = 0;
    141     dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, &val, NULL, NULL);
    142     return (long) val;
    143 }
    144 DEX_INLINE size_t dexGetZipEntryUncompLen(const ZipArchive* pArchive,
    145     const ZipEntry entry)
    146 {
    147     size_t val = 0;
    148     dexZipGetEntryInfo(pArchive, entry, NULL, &val, NULL, NULL, NULL, NULL);
    149     return val;
    150 }
    151 DEX_INLINE long dexGetZipEntryModTime(const ZipArchive* pArchive,
    152     const ZipEntry entry)
    153 {
    154     long val = 0;
    155     dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, NULL, &val, NULL);
    156     return val;
    157 }
    158 DEX_INLINE long dexGetZipEntryCrc32(const ZipArchive* pArchive,
    159     const ZipEntry entry)
    160 {
    161     long val = 0;
    162     dexZipGetEntryInfo(pArchive, entry, NULL, NULL, NULL, NULL, NULL, &val);
    163     return val;
    164 }
    165 
    166 /*
    167  * Uncompress and write an entry to a file descriptor.
    168  *
    169  * Returns 0 on success.
    170  */
    171 int dexZipExtractEntryToFile(const ZipArchive* pArchive,
    172     const ZipEntry entry, int fd);
    173 
    174 /*
    175  * Utility function to compute a CRC-32.
    176  */
    177 u4 dexInitCrc32(void);
    178 u4 dexComputeCrc32(u4 crc, const void* buf, size_t len);
    179 
    180 #endif  // LIBDEX_ZIPARCHIVE_H_
    181