xref: /aosp_15_r20/system/libziparchive/include/ziparchive/zip_writer.h (revision adcb0a6279ea715828f9bc5e351569419e478774)
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