blob: 0b6ede45c27e1e666d8b02fd06d90b7110cd61b2 [file] [log] [blame]
Adam Lesinskiad4ad8c2015-10-05 18:16:18 -07001/*
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
Elliott Hughes4f713192015-12-04 22:00:26 -080020#include "android-base/macros.h"
Adam Lesinskiad4ad8c2015-10-05 18:16:18 -070021#include <utils/Compat.h>
22
23#include <cstdio>
Adam Lesinskiad4ad8c2015-10-05 18:16:18 -070024#include <ctime>
Adam Lesinski591fd392015-10-06 15:23:46 -070025#include <memory>
26#include <string>
Adam Lesinskiad4ad8c2015-10-05 18:16:18 -070027#include <vector>
Adam Lesinski591fd392015-10-06 15:23:46 -070028#include <zlib.h>
Adam Lesinskiad4ad8c2015-10-05 18:16:18 -070029
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 */
51class ZipWriter {
52public:
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 /**
Christopher Ferris5e9f3d42016-01-19 10:33:03 -080090 * 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 /**
Adam Lesinskiad4ad8c2015-10-05 18:16:18 -0700100 * 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 /**
Christopher Ferris5e9f3d42016-01-19 10:33:03 -0800105 * 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 /**
Adam Lesinskiad4ad8c2015-10-05 18:16:18 -0700111 * 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
130private:
131 DISALLOW_COPY_AND_ASSIGN(ZipWriter);
132
Adam Lesinskiad4ad8c2015-10-05 18:16:18 -0700133 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
Adam Lesinski591fd392015-10-06 15:23:46 -0700144 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
Adam Lesinskiad4ad8c2015-10-05 18:16:18 -0700150 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_;
Adam Lesinski591fd392015-10-06 15:23:46 -0700161
162 std::unique_ptr<z_stream, void(*)(z_stream*)> z_stream_;
163 std::vector<uint8_t> buffer_;
Adam Lesinskiad4ad8c2015-10-05 18:16:18 -0700164};
165
166#endif /* LIBZIPARCHIVE_ZIPWRITER_H_ */