Home | History | Annotate | Download | only in ziparchive
      1 /*
      2  * Copyright (C) 2015 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 #ifndef LIBZIPARCHIVE_ZIPWRITER_H_
     18 #define LIBZIPARCHIVE_ZIPWRITER_H_
     19 
     20 #include "android-base/macros.h"
     21 #include <utils/Compat.h>
     22 
     23 #include <cstdio>
     24 #include <ctime>
     25 #include <memory>
     26 #include <string>
     27 #include <vector>
     28 #include <zlib.h>
     29 
     30 /**
     31  * Writes a Zip file via a stateful interface.
     32  *
     33  * Example:
     34  *
     35  *   FILE* file = fopen("path/to/zip.zip", "wb");
     36  *
     37  *   ZipWriter writer(file);
     38  *
     39  *   writer.StartEntry("test.txt", ZipWriter::kCompress | ZipWriter::kAlign);
     40  *   writer.WriteBytes(buffer, bufferLen);
     41  *   writer.WriteBytes(buffer2, bufferLen2);
     42  *   writer.FinishEntry();
     43  *
     44  *   writer.StartEntry("empty.txt", 0);
     45  *   writer.FinishEntry();
     46  *
     47  *   writer.Finish();
     48  *
     49  *   fclose(file);
     50  */
     51 class ZipWriter {
     52 public:
     53   enum {
     54     /**
     55      * Flag to compress the zip entry using deflate.
     56      */
     57     kCompress = 0x01,
     58 
     59     /**
     60      * Flag to align the zip entry data on a 32bit boundary. Useful for
     61      * mmapping the data at runtime.
     62      */
     63     kAlign32 = 0x02,
     64   };
     65 
     66   static const char* ErrorCodeString(int32_t error_code);
     67 
     68   /**
     69    * Create a ZipWriter that will write into a FILE stream. The file should be opened with
     70    * open mode of "wb" or "w+b". ZipWriter does not take ownership of the file stream. The
     71    * caller is responsible for closing the file.
     72    */
     73   explicit ZipWriter(FILE* f);
     74 
     75   // Move constructor.
     76   ZipWriter(ZipWriter&& zipWriter);
     77 
     78   // Move assignment.
     79   ZipWriter& operator=(ZipWriter&& zipWriter);
     80 
     81   /**
     82    * Starts a new zip entry with the given path and flags.
     83    * Flags can be a bitwise OR of ZipWriter::kCompress and ZipWriter::kAlign.
     84    * Subsequent calls to WriteBytes(const void*, size_t) will add data to this entry.
     85    * Returns 0 on success, and an error value < 0 on failure.
     86    */
     87   int32_t StartEntry(const char* path, size_t flags);
     88 
     89   /**
     90    * Starts a new zip entry with the given path and flags, where the
     91    * entry will be aligned to the given alignment.
     92    * Flags can only be ZipWriter::kCompress. Using the flag ZipWriter::kAlign32
     93    * will result in an error.
     94    * Subsequent calls to WriteBytes(const void*, size_t) will add data to this entry.
     95    * Returns 0 on success, and an error value < 0 on failure.
     96    */
     97   int32_t StartAlignedEntry(const char* path, size_t flags, uint32_t alignment);
     98 
     99   /**
    100    * Same as StartEntry(const char*, size_t), but sets a last modified time for the entry.
    101    */
    102   int32_t StartEntryWithTime(const char* path, size_t flags, time_t time);
    103 
    104   /**
    105    * Same as StartAlignedEntry(const char*, size_t), but sets a last modified time for the entry.
    106    */
    107   int32_t StartAlignedEntryWithTime(const char* path, size_t flags, time_t time,
    108                                     uint32_t alignment);
    109 
    110   /**
    111    * Writes bytes to the zip file for the previously started zip entry.
    112    * Returns 0 on success, and an error value < 0 on failure.
    113    */
    114   int32_t WriteBytes(const void* data, size_t len);
    115 
    116   /**
    117    * Finish a zip entry started with StartEntry(const char*, size_t) or
    118    * StartEntryWithTime(const char*, size_t, time_t). This must be called before
    119    * any new zip entries are started, or before Finish() is called.
    120    * Returns 0 on success, and an error value < 0 on failure.
    121    */
    122   int32_t FinishEntry();
    123 
    124   /**
    125    * Writes the Central Directory Headers and flushes the zip file stream.
    126    * Returns 0 on success, and an error value < 0 on failure.
    127    */
    128   int32_t Finish();
    129 
    130 private:
    131   DISALLOW_COPY_AND_ASSIGN(ZipWriter);
    132 
    133   struct FileInfo {
    134     std::string path;
    135     uint16_t compression_method;
    136     uint32_t crc32;
    137     uint32_t compressed_size;
    138     uint32_t uncompressed_size;
    139     uint16_t last_mod_time;
    140     uint16_t last_mod_date;
    141     uint32_t local_file_header_offset;
    142   };
    143 
    144   int32_t HandleError(int32_t error_code);
    145   int32_t PrepareDeflate();
    146   int32_t StoreBytes(FileInfo* file, const void* data, size_t len);
    147   int32_t CompressBytes(FileInfo* file, const void* data, size_t len);
    148   int32_t FlushCompressedBytes(FileInfo* file);
    149 
    150   enum class State {
    151     kWritingZip,
    152     kWritingEntry,
    153     kDone,
    154     kError,
    155   };
    156 
    157   FILE* file_;
    158   off64_t current_offset_;
    159   State state_;
    160   std::vector<FileInfo> files_;
    161 
    162   std::unique_ptr<z_stream, void(*)(z_stream*)> z_stream_;
    163   std::vector<uint8_t> buffer_;
    164 };
    165 
    166 #endif /* LIBZIPARCHIVE_ZIPWRITER_H_ */
    167