486
|
1 /* |
|
2 * ZipArchive.cpp -- wrapper around libzip |
|
3 * |
|
4 * Copyright (c) 2013-2015 David Demelier <markand@malikania.fr> |
|
5 * |
|
6 * Permission to use, copy, modify, and/or distribute this software for any |
|
7 * purpose with or without fee is hereby granted, provided that the above |
|
8 * copyright notice and this permission notice appear in all copies. |
|
9 * |
|
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
17 */ |
|
18 |
|
19 #include <cerrno> |
|
20 #include <cstdlib> |
|
21 #include <cstring> |
|
22 #include <stdexcept> |
|
23 |
|
24 #include "ZipArchive.h" |
|
25 |
|
26 namespace source { |
|
27 |
|
28 /* -------------------------------------------------------- |
|
29 * Buffer (zip_source_buffer) |
|
30 * -------------------------------------------------------- */ |
|
31 |
|
32 Buffer::Buffer(std::string data) |
|
33 : m_data(std::move(data)) |
|
34 { |
|
35 } |
|
36 |
|
37 struct zip_source *Buffer::source(struct zip *archive) const |
|
38 { |
|
39 auto size = m_data.size(); |
|
40 auto data = static_cast<char *>(std::malloc(size)); |
|
41 |
|
42 if (data == nullptr) |
|
43 throw std::runtime_error(std::strerror(errno)); |
|
44 |
|
45 std::memcpy(data, m_data.data(), size); |
|
46 |
|
47 auto src = zip_source_buffer(archive, data, size, 1); |
|
48 |
|
49 if (src == nullptr) { |
|
50 std::free(data); |
|
51 throw std::runtime_error(zip_strerror(archive)); |
|
52 } |
|
53 |
|
54 return src; |
|
55 } |
|
56 |
|
57 /* -------------------------------------------------------- |
|
58 * File (zip_source_file) |
|
59 * -------------------------------------------------------- */ |
|
60 |
|
61 File::File(std::string path, ZipUint64 start, ZipInt64 length) |
|
62 : m_path(std::move(path)) |
|
63 , m_start(start) |
|
64 , m_length(length) |
|
65 { |
|
66 } |
|
67 |
|
68 struct zip_source *File::source(struct zip *archive) const |
|
69 { |
|
70 auto src = zip_source_file(archive, m_path.c_str(), m_start, m_length); |
|
71 |
|
72 if (src == nullptr) |
|
73 throw std::runtime_error(zip_strerror(archive)); |
|
74 |
|
75 return src; |
|
76 } |
|
77 |
|
78 } // !source |
|
79 |
|
80 /* -------------------------------------------------------- |
|
81 * ZipArchive |
|
82 * ------------------------------------------------------- */ |
|
83 |
|
84 ZipArchive::ZipArchive(const std::string &path, ZipFlags flags) |
|
85 : m_handle(nullptr, nullptr) |
|
86 { |
|
87 int error; |
|
88 struct zip *archive = zip_open(path.c_str(), flags, &error); |
|
89 |
|
90 if (archive == nullptr) |
|
91 { |
|
92 char buf[128]{}; |
|
93 |
|
94 zip_error_to_str(buf, sizeof (buf), error, errno); |
|
95 |
|
96 throw std::runtime_error(buf); |
|
97 } |
|
98 |
|
99 m_handle = { archive, zip_close }; |
|
100 } |
|
101 |
|
102 void ZipArchive::setFileComment(ZipUint64 index, const std::string &text, ZipFlags flags) |
|
103 { |
|
104 auto size = text.size(); |
|
105 auto cstr = (size == 0) ? nullptr : text.c_str(); |
|
106 |
|
107 if (zip_file_set_comment(m_handle.get(), index, cstr, size, flags) < 0) |
|
108 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
109 } |
|
110 |
|
111 std::string ZipArchive::getFileComment(ZipUint64 index, ZipFlags flags) const |
|
112 { |
|
113 zip_uint32_t length = 0; |
|
114 auto text = zip_file_get_comment(m_handle.get(), index, &length, flags); |
|
115 |
|
116 if (text == nullptr) |
|
117 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
118 |
|
119 return { text, length }; |
|
120 } |
|
121 |
|
122 void ZipArchive::setComment(const std::string &comment) |
|
123 { |
|
124 if (zip_set_archive_comment(m_handle.get(), comment.c_str(), comment.size()) < 0) |
|
125 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
126 } |
|
127 |
|
128 std::string ZipArchive::getComment(ZipFlags flags) const |
|
129 { |
|
130 int length = 0; |
|
131 auto text = zip_get_archive_comment(m_handle.get(), &length, flags); |
|
132 |
|
133 if (text == nullptr) |
|
134 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
135 |
|
136 return { text, static_cast<size_t>(length) }; |
|
137 } |
|
138 |
|
139 bool ZipArchive::exists(const std::string &name, ZipFlags flags) const noexcept |
|
140 { |
|
141 return zip_name_locate(m_handle.get(), name.c_str(), flags) >= 0; |
|
142 } |
|
143 |
|
144 ZipInt64 ZipArchive::find(const std::string &name, ZipFlags flags) const |
|
145 { |
|
146 auto index = zip_name_locate(m_handle.get(), name.c_str(), flags); |
|
147 |
|
148 if (index < 0) |
|
149 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
150 |
|
151 return index; |
|
152 } |
|
153 |
|
154 ZipStat ZipArchive::stat(const std::string &name, ZipFlags flags) const |
|
155 { |
|
156 ZipStat st; |
|
157 |
|
158 if (zip_stat(m_handle.get(), name.c_str(), flags, &st) < 0) |
|
159 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
160 |
|
161 return st; |
|
162 } |
|
163 |
|
164 ZipStat ZipArchive::stat(ZipUint64 index, ZipFlags flags) const |
|
165 { |
|
166 ZipStat st; |
|
167 |
|
168 if (zip_stat_index(m_handle.get(), index, flags, &st) < 0) |
|
169 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
170 |
|
171 return st; |
|
172 } |
|
173 |
|
174 ZipInt64 ZipArchive::add(const ZipSource &source, const std::string &name, ZipFlags flags) |
|
175 { |
|
176 auto src = source.source(m_handle.get()); |
|
177 auto ret = zip_file_add(m_handle.get(), name.c_str(), src, flags); |
|
178 |
|
179 if (ret < 0) { |
|
180 zip_source_free(src); |
|
181 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
182 } |
|
183 |
|
184 return ret; |
|
185 } |
|
186 |
|
187 ZipInt64 ZipArchive::addDirectory(const std::string &directory, ZipFlags flags) |
|
188 { |
|
189 auto ret = zip_dir_add(m_handle.get(), directory.c_str(), flags); |
|
190 |
|
191 if (ret < 0) |
|
192 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
193 |
|
194 return ret; |
|
195 } |
|
196 |
|
197 void ZipArchive::replace(const ZipSource &source, ZipUint64 index, ZipFlags flags) |
|
198 { |
|
199 auto src = source.source(m_handle.get()); |
|
200 |
|
201 if (zip_file_replace(m_handle.get(), index, src, flags) < 0) { |
|
202 zip_source_free(src); |
|
203 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
204 } |
|
205 } |
|
206 |
|
207 ZipFile ZipArchive::open(const std::string &name, ZipFlags flags, const std::string &password) |
|
208 { |
|
209 struct zip_file *file; |
|
210 |
|
211 if (password.size() > 0) |
|
212 file = zip_fopen_encrypted(m_handle.get(), name.c_str(), flags, password.c_str()); |
|
213 else |
|
214 file = zip_fopen(m_handle.get(), name.c_str(), flags); |
|
215 |
|
216 if (file == nullptr) |
|
217 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
218 |
|
219 return file; |
|
220 } |
|
221 |
|
222 ZipFile ZipArchive::open(ZipUint64 index, ZipFlags flags, const std::string &password) |
|
223 { |
|
224 struct zip_file *file; |
|
225 |
|
226 if (password.size() > 0) |
|
227 file = zip_fopen_index_encrypted(m_handle.get(), index, flags, password.c_str()); |
|
228 else |
|
229 file = zip_fopen_index(m_handle.get(), index, flags); |
|
230 |
|
231 if (file == nullptr) |
|
232 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
233 |
|
234 return file; |
|
235 } |
|
236 |
|
237 void ZipArchive::rename(ZipUint64 index, const std::string &name, ZipFlags flags) |
|
238 { |
|
239 if (zip_file_rename(m_handle.get(), index, name.c_str(), flags) < 0) |
|
240 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
241 } |
|
242 |
|
243 void ZipArchive::setFileCompression(ZipUint64 index, ZipInt32 comp, ZipUint32 flags) |
|
244 { |
|
245 if (zip_set_file_compression(m_handle.get(), index, comp, flags) < 0) |
|
246 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
247 } |
|
248 |
|
249 void ZipArchive::remove(ZipUint64 index) |
|
250 { |
|
251 if (zip_delete(m_handle.get(), index) < 0) |
|
252 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
253 } |
|
254 |
|
255 ZipInt64 ZipArchive::numEntries(ZipFlags flags) const noexcept |
|
256 { |
|
257 return zip_get_num_entries(m_handle.get(), flags); |
|
258 } |
|
259 |
|
260 void ZipArchive::unchange(ZipUint64 index) |
|
261 { |
|
262 if (zip_unchange(m_handle.get(), index) < 0) |
|
263 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
264 } |
|
265 |
|
266 void ZipArchive::unchangeAll() |
|
267 { |
|
268 if (zip_unchange_all(m_handle.get()) < 0) |
|
269 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
270 } |
|
271 |
|
272 void ZipArchive::unchangeArchive() |
|
273 { |
|
274 if (zip_unchange_archive(m_handle.get()) < 0) |
|
275 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
276 } |
|
277 |
|
278 void ZipArchive::setDefaultPassword(const std::string &password) |
|
279 { |
|
280 auto cstr = (password.size() > 0) ? password.c_str() : nullptr; |
|
281 |
|
282 if (zip_set_default_password(m_handle.get(), cstr) < 0) |
|
283 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
284 } |
|
285 |
|
286 void ZipArchive::setFlag(ZipFlags flags, int value) |
|
287 { |
|
288 if (zip_set_archive_flag(m_handle.get(), flags, value) < 0) |
|
289 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
290 } |
|
291 |
|
292 int ZipArchive::getFlag(ZipFlags which, ZipFlags flags) const |
|
293 { |
|
294 auto ret = zip_get_archive_flag(m_handle.get(), which, flags); |
|
295 |
|
296 if (ret < 0) |
|
297 throw std::runtime_error(zip_strerror(m_handle.get())); |
|
298 |
|
299 return ret; |
|
300 } |