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