1ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski/* 2ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 3ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * 4ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * you may not use this file except in compliance with the License. 6ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * You may obtain a copy of the License at 7ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * 8ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * 10ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Unless required by applicable law or agreed to in writing, software 11ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * See the License for the specific language governing permissions and 14ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * limitations under the License. 15ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski */ 16ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 17ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski#ifndef LIBZIPARCHIVE_ZIPWRITER_H_ 18ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski#define LIBZIPARCHIVE_ZIPWRITER_H_ 19ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 204f71319df011d796a60a43fc1bc68e16fbf7d321Elliott Hughes#include "android-base/macros.h" 21ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski#include <utils/Compat.h> 22ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 23ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski#include <cstdio> 24ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski#include <ctime> 25591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski#include <memory> 26591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski#include <string> 27ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski#include <vector> 28591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski#include <zlib.h> 29ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 30ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski/** 31ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Writes a Zip file via a stateful interface. 32ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * 33ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Example: 34ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * 35ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * FILE* file = fopen("path/to/zip.zip", "wb"); 36ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * 37ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * ZipWriter writer(file); 38ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * 39ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * writer.StartEntry("test.txt", ZipWriter::kCompress | ZipWriter::kAlign); 40ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * writer.WriteBytes(buffer, bufferLen); 41ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * writer.WriteBytes(buffer2, bufferLen2); 42ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * writer.FinishEntry(); 43ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * 44ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * writer.StartEntry("empty.txt", 0); 45ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * writer.FinishEntry(); 46ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * 47ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * writer.Finish(); 48ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * 49ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * fclose(file); 50ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski */ 51ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinskiclass ZipWriter { 52ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinskipublic: 53ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski enum { 54ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski /** 55ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Flag to compress the zip entry using deflate. 56ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski */ 57ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski kCompress = 0x01, 58ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 59ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski /** 60ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Flag to align the zip entry data on a 32bit boundary. Useful for 61ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * mmapping the data at runtime. 62ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski */ 63ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski kAlign32 = 0x02, 64ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski }; 65ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 66ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski static const char* ErrorCodeString(int32_t error_code); 67ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 68ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski /** 69ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Create a ZipWriter that will write into a FILE stream. The file should be opened with 70ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * open mode of "wb" or "w+b". ZipWriter does not take ownership of the file stream. The 71ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * caller is responsible for closing the file. 72ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski */ 73ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski explicit ZipWriter(FILE* f); 74ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 75ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski // Move constructor. 76ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski ZipWriter(ZipWriter&& zipWriter); 77ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 78ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski // Move assignment. 79ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski ZipWriter& operator=(ZipWriter&& zipWriter); 80ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 81ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski /** 82ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Starts a new zip entry with the given path and flags. 83ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Flags can be a bitwise OR of ZipWriter::kCompress and ZipWriter::kAlign. 84ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Subsequent calls to WriteBytes(const void*, size_t) will add data to this entry. 85ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Returns 0 on success, and an error value < 0 on failure. 86ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski */ 87ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski int32_t StartEntry(const char* path, size_t flags); 88ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 89ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski /** 905e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris * Starts a new zip entry with the given path and flags, where the 915e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris * entry will be aligned to the given alignment. 925e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris * Flags can only be ZipWriter::kCompress. Using the flag ZipWriter::kAlign32 935e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris * will result in an error. 945e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris * Subsequent calls to WriteBytes(const void*, size_t) will add data to this entry. 955e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris * Returns 0 on success, and an error value < 0 on failure. 965e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris */ 975e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris int32_t StartAlignedEntry(const char* path, size_t flags, uint32_t alignment); 985e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris 995e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris /** 100ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Same as StartEntry(const char*, size_t), but sets a last modified time for the entry. 101ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski */ 102ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski int32_t StartEntryWithTime(const char* path, size_t flags, time_t time); 103ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 104ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski /** 1055e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris * Same as StartAlignedEntry(const char*, size_t), but sets a last modified time for the entry. 1065e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris */ 1075e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris int32_t StartAlignedEntryWithTime(const char* path, size_t flags, time_t time, 1085e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris uint32_t alignment); 1095e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris 1105e9f3d44a3472882f3315e692862dd017cac8875Christopher Ferris /** 111ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Writes bytes to the zip file for the previously started zip entry. 112ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Returns 0 on success, and an error value < 0 on failure. 113ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski */ 114ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski int32_t WriteBytes(const void* data, size_t len); 115ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 116ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski /** 117ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Finish a zip entry started with StartEntry(const char*, size_t) or 118ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * StartEntryWithTime(const char*, size_t, time_t). This must be called before 119ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * any new zip entries are started, or before Finish() is called. 120ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Returns 0 on success, and an error value < 0 on failure. 121ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski */ 122ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski int32_t FinishEntry(); 123ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 124ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski /** 125ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Writes the Central Directory Headers and flushes the zip file stream. 126ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski * Returns 0 on success, and an error value < 0 on failure. 127ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski */ 128ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski int32_t Finish(); 129ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 130ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinskiprivate: 131ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski DISALLOW_COPY_AND_ASSIGN(ZipWriter); 132ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 133ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski struct FileInfo { 134ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski std::string path; 135ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski uint16_t compression_method; 136ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski uint32_t crc32; 137ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski uint32_t compressed_size; 138ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski uint32_t uncompressed_size; 139ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski uint16_t last_mod_time; 140ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski uint16_t last_mod_date; 141ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski uint32_t local_file_header_offset; 142ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski }; 143ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 144591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski int32_t HandleError(int32_t error_code); 145591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski int32_t PrepareDeflate(); 146591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski int32_t StoreBytes(FileInfo* file, const void* data, size_t len); 147591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski int32_t CompressBytes(FileInfo* file, const void* data, size_t len); 148591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski int32_t FlushCompressedBytes(FileInfo* file); 149591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski 150ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski enum class State { 151ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski kWritingZip, 152ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski kWritingEntry, 153ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski kDone, 154ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski kError, 155ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski }; 156ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 157ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski FILE* file_; 158ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski off64_t current_offset_; 159ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski State state_; 160ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski std::vector<FileInfo> files_; 161591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski 162591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski std::unique_ptr<z_stream, void(*)(z_stream*)> z_stream_; 163591fd3953df979293928c82555db259ef9f6e52dAdam Lesinski std::vector<uint8_t> buffer_; 164ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski}; 165ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski 166ad4ad8cfc8c1eada8356d554eeb0639ee48ef00dAdam Lesinski#endif /* LIBZIPARCHIVE_ZIPWRITER_H_ */ 167