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