Home | History | Annotate | Download | only in ziparchive
      1 /*
      2  * Copyright (C) 2013 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 LIBZIPARCHIVE_ZIPARCHIVE_H_
     21 #define LIBZIPARCHIVE_ZIPARCHIVE_H_
     22 
     23 #include <stdint.h>
     24 #include <string.h>
     25 #include <sys/cdefs.h>
     26 #include <sys/types.h>
     27 #include <utils/Compat.h>
     28 
     29 /* Zip compression methods we support */
     30 enum {
     31   kCompressStored = 0,    // no compression
     32   kCompressDeflated = 8,  // standard deflate
     33 };
     34 
     35 struct ZipString {
     36   const uint8_t* name;
     37   uint16_t name_length;
     38 
     39   ZipString() {}
     40 
     41   /*
     42    * entry_name has to be an c-style string with only ASCII characters.
     43    */
     44   explicit ZipString(const char* entry_name);
     45 
     46   bool operator==(const ZipString& rhs) const {
     47     return name && (name_length == rhs.name_length) && (memcmp(name, rhs.name, name_length) == 0);
     48   }
     49 
     50   bool StartsWith(const ZipString& prefix) const {
     51     return name && (name_length >= prefix.name_length) &&
     52            (memcmp(name, prefix.name, prefix.name_length) == 0);
     53   }
     54 
     55   bool EndsWith(const ZipString& suffix) const {
     56     return name && (name_length >= suffix.name_length) &&
     57            (memcmp(name + name_length - suffix.name_length, suffix.name, suffix.name_length) == 0);
     58   }
     59 };
     60 
     61 /*
     62  * Represents information about a zip entry in a zip file.
     63  */
     64 struct ZipEntry {
     65   // Compression method: One of kCompressStored or
     66   // kCompressDeflated.
     67   uint16_t method;
     68 
     69   // Modification time. The zipfile format specifies
     70   // that the first two little endian bytes contain the time
     71   // and the last two little endian bytes contain the date.
     72   // See `GetModificationTime`.
     73   // TODO: should be overridden by extra time field, if present.
     74   uint32_t mod_time;
     75 
     76   // Returns `mod_time` as a broken-down struct tm.
     77   struct tm GetModificationTime() const;
     78 
     79   // Suggested Unix mode for this entry, from the zip archive if created on
     80   // Unix, or a default otherwise.
     81   mode_t unix_mode;
     82 
     83   // 1 if this entry contains a data descriptor segment, 0
     84   // otherwise.
     85   uint8_t has_data_descriptor;
     86 
     87   // Crc32 value of this ZipEntry. This information might
     88   // either be stored in the local file header or in a special
     89   // Data descriptor footer at the end of the file entry.
     90   uint32_t crc32;
     91 
     92   // Compressed length of this ZipEntry. Might be present
     93   // either in the local file header or in the data descriptor
     94   // footer.
     95   uint32_t compressed_length;
     96 
     97   // Uncompressed length of this ZipEntry. Might be present
     98   // either in the local file header or in the data descriptor
     99   // footer.
    100   uint32_t uncompressed_length;
    101 
    102   // The offset to the start of data for this ZipEntry.
    103   off64_t offset;
    104 };
    105 
    106 typedef void* ZipArchiveHandle;
    107 
    108 /*
    109  * Open a Zip archive, and sets handle to the value of the opaque
    110  * handle for the file. This handle must be released by calling
    111  * CloseArchive with this handle.
    112  *
    113  * Returns 0 on success, and negative values on failure.
    114  */
    115 int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle);
    116 
    117 /*
    118  * Like OpenArchive, but takes a file descriptor open for reading
    119  * at the start of the file.  The descriptor must be mappable (this does
    120  * not allow access to a stream).
    121  *
    122  * Sets handle to the value of the opaque handle for this file descriptor.
    123  * This handle must be released by calling CloseArchive with this handle.
    124  *
    125  * If assume_ownership parameter is 'true' calling CloseArchive will close
    126  * the file.
    127  *
    128  * This function maps and scans the central directory and builds a table
    129  * of entries for future lookups.
    130  *
    131  * "debugFileName" will appear in error messages, but is not otherwise used.
    132  *
    133  * Returns 0 on success, and negative values on failure.
    134  */
    135 int32_t OpenArchiveFd(const int fd, const char* debugFileName, ZipArchiveHandle* handle,
    136                       bool assume_ownership = true);
    137 
    138 int32_t OpenArchiveFromMemory(void* address, size_t length, const char* debugFileName,
    139                               ZipArchiveHandle* handle);
    140 /*
    141  * Close archive, releasing resources associated with it. This will
    142  * unmap the central directory of the zipfile and free all internal
    143  * data structures associated with the file. It is an error to use
    144  * this handle for any further operations without an intervening
    145  * call to one of the OpenArchive variants.
    146  */
    147 void CloseArchive(ZipArchiveHandle handle);
    148 
    149 /*
    150  * Find an entry in the Zip archive, by name. |entryName| must be a null
    151  * terminated string, and |data| must point to a writeable memory location.
    152  *
    153  * Returns 0 if an entry is found, and populates |data| with information
    154  * about this entry. Returns negative values otherwise.
    155  *
    156  * It's important to note that |data->crc32|, |data->compLen| and
    157  * |data->uncompLen| might be set to values from the central directory
    158  * if this file entry contains a data descriptor footer. To verify crc32s
    159  * and length, a call to VerifyCrcAndLengths must be made after entry data
    160  * has been processed.
    161  *
    162  * On non-Windows platforms this method does not modify internal state and
    163  * can be called concurrently.
    164  */
    165 int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName, ZipEntry* data);
    166 
    167 /*
    168  * Start iterating over all entries of a zip file. The order of iteration
    169  * is not guaranteed to be the same as the order of elements
    170  * in the central directory but is stable for a given zip file. |cookie| will
    171  * contain the value of an opaque cookie which can be used to make one or more
    172  * calls to Next. All calls to StartIteration must be matched by a call to
    173  * EndIteration to free any allocated memory.
    174  *
    175  * This method also accepts optional prefix and suffix to restrict iteration to
    176  * entry names that start with |optional_prefix| or end with |optional_suffix|.
    177  *
    178  * Returns 0 on success and negative values on failure.
    179  */
    180 int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, const ZipString* optional_prefix,
    181                        const ZipString* optional_suffix);
    182 
    183 /*
    184  * Advance to the next element in the zipfile in iteration order.
    185  *
    186  * Returns 0 on success, -1 if there are no more elements in this
    187  * archive and lower negative values on failure.
    188  */
    189 int32_t Next(void* cookie, ZipEntry* data, ZipString* name);
    190 
    191 /*
    192  * End iteration over all entries of a zip file and frees the memory allocated
    193  * in StartIteration.
    194  */
    195 void EndIteration(void* cookie);
    196 
    197 /*
    198  * Uncompress and write an entry to an open file identified by |fd|.
    199  * |entry->uncompressed_length| bytes will be written to the file at
    200  * its current offset, and the file will be truncated at the end of
    201  * the uncompressed data (no truncation if |fd| references a block
    202  * device).
    203  *
    204  * Returns 0 on success and negative values on failure.
    205  */
    206 int32_t ExtractEntryToFile(ZipArchiveHandle handle, ZipEntry* entry, int fd);
    207 
    208 /**
    209  * Uncompress a given zip entry to the memory region at |begin| and of
    210  * size |size|. This size is expected to be the same as the *declared*
    211  * uncompressed length of the zip entry. It is an error if the *actual*
    212  * number of uncompressed bytes differs from this number.
    213  *
    214  * Returns 0 on success and negative values on failure.
    215  */
    216 int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, uint8_t* begin, uint32_t size);
    217 
    218 int GetFileDescriptor(const ZipArchiveHandle handle);
    219 
    220 const char* ErrorCodeString(int32_t error_code);
    221 
    222 #if !defined(_WIN32)
    223 typedef bool (*ProcessZipEntryFunction)(const uint8_t* buf, size_t buf_size, void* cookie);
    224 
    225 /*
    226  * Stream the uncompressed data through the supplied function,
    227  * passing cookie to it each time it gets called.
    228  */
    229 int32_t ProcessZipEntryContents(ZipArchiveHandle handle, ZipEntry* entry,
    230                                 ProcessZipEntryFunction func, void* cookie);
    231 #endif
    232 
    233 namespace zip_archive {
    234 
    235 class Writer {
    236  public:
    237   virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
    238   virtual ~Writer();
    239 
    240  protected:
    241   Writer() = default;
    242 
    243  private:
    244   Writer(const Writer&) = delete;
    245   void operator=(const Writer&) = delete;
    246 };
    247 
    248 class Reader {
    249  public:
    250   virtual bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const = 0;
    251   virtual ~Reader();
    252 
    253  protected:
    254   Reader() = default;
    255 
    256  private:
    257   Reader(const Reader&) = delete;
    258   void operator=(const Reader&) = delete;
    259 };
    260 
    261 /*
    262  * Inflates the first |compressed_length| bytes of |reader| to a given |writer|.
    263  * |crc_out| is set to the CRC32 checksum of the uncompressed data.
    264  *
    265  * Returns 0 on success and negative values on failure, for example if |reader|
    266  * cannot supply the right amount of data, or if the number of bytes written to
    267  * data does not match |uncompressed_length|.
    268  *
    269  * If |crc_out| is not nullptr, it is set to the crc32 checksum of the
    270  * uncompressed data.
    271  */
    272 int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
    273                 const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out);
    274 }  // namespace zip_archive
    275 
    276 #endif  // LIBZIPARCHIVE_ZIPARCHIVE_H_
    277