1*adcb0a62SAndroid Build Coastguard Worker /* 2*adcb0a62SAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project 3*adcb0a62SAndroid Build Coastguard Worker * 4*adcb0a62SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*adcb0a62SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*adcb0a62SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*adcb0a62SAndroid Build Coastguard Worker * 8*adcb0a62SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*adcb0a62SAndroid Build Coastguard Worker * 10*adcb0a62SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*adcb0a62SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*adcb0a62SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*adcb0a62SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*adcb0a62SAndroid Build Coastguard Worker * limitations under the License. 15*adcb0a62SAndroid Build Coastguard Worker */ 16*adcb0a62SAndroid Build Coastguard Worker 17*adcb0a62SAndroid Build Coastguard Worker #pragma once 18*adcb0a62SAndroid Build Coastguard Worker 19*adcb0a62SAndroid Build Coastguard Worker #include <cstdio> 20*adcb0a62SAndroid Build Coastguard Worker #include <ctime> 21*adcb0a62SAndroid Build Coastguard Worker 22*adcb0a62SAndroid Build Coastguard Worker #include <gtest/gtest_prod.h> 23*adcb0a62SAndroid Build Coastguard Worker #include <memory> 24*adcb0a62SAndroid Build Coastguard Worker #include <string> 25*adcb0a62SAndroid Build Coastguard Worker #include <string_view> 26*adcb0a62SAndroid Build Coastguard Worker #include <vector> 27*adcb0a62SAndroid Build Coastguard Worker 28*adcb0a62SAndroid Build Coastguard Worker #include "android-base/macros.h" 29*adcb0a62SAndroid Build Coastguard Worker #include "android-base/off64_t.h" 30*adcb0a62SAndroid Build Coastguard Worker 31*adcb0a62SAndroid Build Coastguard Worker struct z_stream_s; 32*adcb0a62SAndroid Build Coastguard Worker typedef struct z_stream_s z_stream; 33*adcb0a62SAndroid Build Coastguard Worker 34*adcb0a62SAndroid Build Coastguard Worker /** 35*adcb0a62SAndroid Build Coastguard Worker * Writes a Zip file via a stateful interface. 36*adcb0a62SAndroid Build Coastguard Worker * 37*adcb0a62SAndroid Build Coastguard Worker * Example: 38*adcb0a62SAndroid Build Coastguard Worker * 39*adcb0a62SAndroid Build Coastguard Worker * FILE* file = fopen("path/to/zip.zip", "wb"); 40*adcb0a62SAndroid Build Coastguard Worker * 41*adcb0a62SAndroid Build Coastguard Worker * ZipWriter writer(file); 42*adcb0a62SAndroid Build Coastguard Worker * 43*adcb0a62SAndroid Build Coastguard Worker * writer.StartEntry("test.txt", ZipWriter::kCompress | ZipWriter::kAlign); 44*adcb0a62SAndroid Build Coastguard Worker * writer.WriteBytes(buffer, bufferLen); 45*adcb0a62SAndroid Build Coastguard Worker * writer.WriteBytes(buffer2, bufferLen2); 46*adcb0a62SAndroid Build Coastguard Worker * writer.FinishEntry(); 47*adcb0a62SAndroid Build Coastguard Worker * 48*adcb0a62SAndroid Build Coastguard Worker * writer.StartEntry("empty.txt", 0); 49*adcb0a62SAndroid Build Coastguard Worker * writer.FinishEntry(); 50*adcb0a62SAndroid Build Coastguard Worker * 51*adcb0a62SAndroid Build Coastguard Worker * writer.Finish(); 52*adcb0a62SAndroid Build Coastguard Worker * 53*adcb0a62SAndroid Build Coastguard Worker * fclose(file); 54*adcb0a62SAndroid Build Coastguard Worker */ 55*adcb0a62SAndroid Build Coastguard Worker class ZipWriter { 56*adcb0a62SAndroid Build Coastguard Worker public: 57*adcb0a62SAndroid Build Coastguard Worker enum { 58*adcb0a62SAndroid Build Coastguard Worker /** 59*adcb0a62SAndroid Build Coastguard Worker * Flag to compress the zip entry using deflate. 60*adcb0a62SAndroid Build Coastguard Worker */ 61*adcb0a62SAndroid Build Coastguard Worker kCompress = 0x01, 62*adcb0a62SAndroid Build Coastguard Worker 63*adcb0a62SAndroid Build Coastguard Worker /** 64*adcb0a62SAndroid Build Coastguard Worker * Flag to align the zip entry data on a 32bit boundary. Useful for 65*adcb0a62SAndroid Build Coastguard Worker * mmapping the data at runtime. 66*adcb0a62SAndroid Build Coastguard Worker */ 67*adcb0a62SAndroid Build Coastguard Worker kAlign32 = 0x02, 68*adcb0a62SAndroid Build Coastguard Worker 69*adcb0a62SAndroid Build Coastguard Worker /** 70*adcb0a62SAndroid Build Coastguard Worker * Flag to use gzip's default level of compression (6). If not set, 9 will 71*adcb0a62SAndroid Build Coastguard Worker * be used. 72*adcb0a62SAndroid Build Coastguard Worker */ 73*adcb0a62SAndroid Build Coastguard Worker kDefaultCompression = 0x04, 74*adcb0a62SAndroid Build Coastguard Worker }; 75*adcb0a62SAndroid Build Coastguard Worker 76*adcb0a62SAndroid Build Coastguard Worker /** 77*adcb0a62SAndroid Build Coastguard Worker * A struct representing a zip file entry. 78*adcb0a62SAndroid Build Coastguard Worker */ 79*adcb0a62SAndroid Build Coastguard Worker struct FileEntry { 80*adcb0a62SAndroid Build Coastguard Worker std::string path; 81*adcb0a62SAndroid Build Coastguard Worker uint16_t compression_method; 82*adcb0a62SAndroid Build Coastguard Worker uint32_t crc32; 83*adcb0a62SAndroid Build Coastguard Worker uint32_t compressed_size; 84*adcb0a62SAndroid Build Coastguard Worker uint32_t uncompressed_size; 85*adcb0a62SAndroid Build Coastguard Worker uint16_t last_mod_time; 86*adcb0a62SAndroid Build Coastguard Worker uint16_t last_mod_date; 87*adcb0a62SAndroid Build Coastguard Worker uint16_t padding_length; 88*adcb0a62SAndroid Build Coastguard Worker off64_t local_file_header_offset; 89*adcb0a62SAndroid Build Coastguard Worker }; 90*adcb0a62SAndroid Build Coastguard Worker 91*adcb0a62SAndroid Build Coastguard Worker static const char* ErrorCodeString(int32_t error_code); 92*adcb0a62SAndroid Build Coastguard Worker 93*adcb0a62SAndroid Build Coastguard Worker /** 94*adcb0a62SAndroid Build Coastguard Worker * Create a ZipWriter that will write into a FILE stream. The file should be opened with 95*adcb0a62SAndroid Build Coastguard Worker * open mode of "wb" or "w+b". ZipWriter does not take ownership of the file stream. The 96*adcb0a62SAndroid Build Coastguard Worker * caller is responsible for closing the file. 97*adcb0a62SAndroid Build Coastguard Worker */ 98*adcb0a62SAndroid Build Coastguard Worker explicit ZipWriter(FILE* f); 99*adcb0a62SAndroid Build Coastguard Worker 100*adcb0a62SAndroid Build Coastguard Worker // Move constructor. 101*adcb0a62SAndroid Build Coastguard Worker ZipWriter(ZipWriter&& zipWriter) noexcept; 102*adcb0a62SAndroid Build Coastguard Worker 103*adcb0a62SAndroid Build Coastguard Worker // Move assignment. 104*adcb0a62SAndroid Build Coastguard Worker ZipWriter& operator=(ZipWriter&& zipWriter) noexcept; 105*adcb0a62SAndroid Build Coastguard Worker 106*adcb0a62SAndroid Build Coastguard Worker /** 107*adcb0a62SAndroid Build Coastguard Worker * Starts a new zip entry with the given path and flags. 108*adcb0a62SAndroid Build Coastguard Worker * Flags can be a bitwise OR of ZipWriter::kCompress and ZipWriter::kAlign. 109*adcb0a62SAndroid Build Coastguard Worker * Subsequent calls to WriteBytes(const void*, size_t) will add data to this entry. 110*adcb0a62SAndroid Build Coastguard Worker * Returns 0 on success, and an error value < 0 on failure. 111*adcb0a62SAndroid Build Coastguard Worker */ 112*adcb0a62SAndroid Build Coastguard Worker int32_t StartEntry(std::string_view path, size_t flags); 113*adcb0a62SAndroid Build Coastguard Worker 114*adcb0a62SAndroid Build Coastguard Worker /** 115*adcb0a62SAndroid Build Coastguard Worker * Starts a new zip entry with the given path and flags, where the 116*adcb0a62SAndroid Build Coastguard Worker * entry will be aligned to the given alignment. 117*adcb0a62SAndroid Build Coastguard Worker * Flags can only be ZipWriter::kCompress. Using the flag ZipWriter::kAlign32 118*adcb0a62SAndroid Build Coastguard Worker * will result in an error. 119*adcb0a62SAndroid Build Coastguard Worker * Subsequent calls to WriteBytes(const void*, size_t) will add data to this entry. 120*adcb0a62SAndroid Build Coastguard Worker * Returns 0 on success, and an error value < 0 on failure. 121*adcb0a62SAndroid Build Coastguard Worker */ 122*adcb0a62SAndroid Build Coastguard Worker int32_t StartAlignedEntry(std::string_view path, size_t flags, uint32_t alignment); 123*adcb0a62SAndroid Build Coastguard Worker 124*adcb0a62SAndroid Build Coastguard Worker /** 125*adcb0a62SAndroid Build Coastguard Worker * Same as StartEntry(const char*, size_t), but sets a last modified time for the entry. 126*adcb0a62SAndroid Build Coastguard Worker */ 127*adcb0a62SAndroid Build Coastguard Worker int32_t StartEntryWithTime(std::string_view path, size_t flags, time_t time); 128*adcb0a62SAndroid Build Coastguard Worker 129*adcb0a62SAndroid Build Coastguard Worker /** 130*adcb0a62SAndroid Build Coastguard Worker * Same as StartAlignedEntry(const char*, size_t), but sets a last modified time for the entry. 131*adcb0a62SAndroid Build Coastguard Worker */ 132*adcb0a62SAndroid Build Coastguard Worker int32_t StartAlignedEntryWithTime(std::string_view path, size_t flags, time_t time, uint32_t alignment); 133*adcb0a62SAndroid Build Coastguard Worker 134*adcb0a62SAndroid Build Coastguard Worker /** 135*adcb0a62SAndroid Build Coastguard Worker * Writes bytes to the zip file for the previously started zip entry. 136*adcb0a62SAndroid Build Coastguard Worker * Returns 0 on success, and an error value < 0 on failure. 137*adcb0a62SAndroid Build Coastguard Worker */ 138*adcb0a62SAndroid Build Coastguard Worker int32_t WriteBytes(const void* data, size_t len); 139*adcb0a62SAndroid Build Coastguard Worker 140*adcb0a62SAndroid Build Coastguard Worker /** 141*adcb0a62SAndroid Build Coastguard Worker * Finish a zip entry started with StartEntry(const char*, size_t) or 142*adcb0a62SAndroid Build Coastguard Worker * StartEntryWithTime(const char*, size_t, time_t). This must be called before 143*adcb0a62SAndroid Build Coastguard Worker * any new zip entries are started, or before Finish() is called. 144*adcb0a62SAndroid Build Coastguard Worker * Returns 0 on success, and an error value < 0 on failure. 145*adcb0a62SAndroid Build Coastguard Worker */ 146*adcb0a62SAndroid Build Coastguard Worker int32_t FinishEntry(); 147*adcb0a62SAndroid Build Coastguard Worker 148*adcb0a62SAndroid Build Coastguard Worker /** 149*adcb0a62SAndroid Build Coastguard Worker * Discards the last-written entry. Can only be called after an entry has been written using 150*adcb0a62SAndroid Build Coastguard Worker * FinishEntry(). 151*adcb0a62SAndroid Build Coastguard Worker * Returns 0 on success, and an error value < 0 on failure. 152*adcb0a62SAndroid Build Coastguard Worker */ 153*adcb0a62SAndroid Build Coastguard Worker int32_t DiscardLastEntry(); 154*adcb0a62SAndroid Build Coastguard Worker 155*adcb0a62SAndroid Build Coastguard Worker /** 156*adcb0a62SAndroid Build Coastguard Worker * Sets `out_entry` to the last entry written after a call to FinishEntry(). 157*adcb0a62SAndroid Build Coastguard Worker * Returns 0 on success, and an error value < 0 if no entries have been written. 158*adcb0a62SAndroid Build Coastguard Worker */ 159*adcb0a62SAndroid Build Coastguard Worker int32_t GetLastEntry(FileEntry* out_entry); 160*adcb0a62SAndroid Build Coastguard Worker 161*adcb0a62SAndroid Build Coastguard Worker /** 162*adcb0a62SAndroid Build Coastguard Worker * Writes the Central Directory Headers and flushes the zip file stream. 163*adcb0a62SAndroid Build Coastguard Worker * Returns 0 on success, and an error value < 0 on failure. 164*adcb0a62SAndroid Build Coastguard Worker */ 165*adcb0a62SAndroid Build Coastguard Worker int32_t Finish(); 166*adcb0a62SAndroid Build Coastguard Worker 167*adcb0a62SAndroid Build Coastguard Worker private: 168*adcb0a62SAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(ZipWriter); 169*adcb0a62SAndroid Build Coastguard Worker 170*adcb0a62SAndroid Build Coastguard Worker int32_t HandleError(int32_t error_code); 171*adcb0a62SAndroid Build Coastguard Worker int32_t PrepareDeflate(int compression_level); 172*adcb0a62SAndroid Build Coastguard Worker int32_t StoreBytes(FileEntry* file, const void* data, uint32_t len); 173*adcb0a62SAndroid Build Coastguard Worker int32_t CompressBytes(FileEntry* file, const void* data, uint32_t len); 174*adcb0a62SAndroid Build Coastguard Worker int32_t FlushCompressedBytes(FileEntry* file); 175*adcb0a62SAndroid Build Coastguard Worker bool ShouldUseDataDescriptor() const; 176*adcb0a62SAndroid Build Coastguard Worker 177*adcb0a62SAndroid Build Coastguard Worker enum class State { 178*adcb0a62SAndroid Build Coastguard Worker kWritingZip, 179*adcb0a62SAndroid Build Coastguard Worker kWritingEntry, 180*adcb0a62SAndroid Build Coastguard Worker kDone, 181*adcb0a62SAndroid Build Coastguard Worker kError, 182*adcb0a62SAndroid Build Coastguard Worker }; 183*adcb0a62SAndroid Build Coastguard Worker 184*adcb0a62SAndroid Build Coastguard Worker FILE* file_; 185*adcb0a62SAndroid Build Coastguard Worker bool seekable_; 186*adcb0a62SAndroid Build Coastguard Worker off64_t current_offset_; 187*adcb0a62SAndroid Build Coastguard Worker State state_; 188*adcb0a62SAndroid Build Coastguard Worker std::vector<FileEntry> files_; 189*adcb0a62SAndroid Build Coastguard Worker FileEntry current_file_entry_; 190*adcb0a62SAndroid Build Coastguard Worker 191*adcb0a62SAndroid Build Coastguard Worker std::unique_ptr<z_stream, void (*)(z_stream*)> z_stream_; 192*adcb0a62SAndroid Build Coastguard Worker std::vector<uint8_t> buffer_; 193*adcb0a62SAndroid Build Coastguard Worker 194*adcb0a62SAndroid Build Coastguard Worker FRIEND_TEST(zipwriter, WriteToUnseekableFile); 195*adcb0a62SAndroid Build Coastguard Worker }; 196