Fix number of compile errors and warnings with GCC 14
[lsnes.git] / include / library / zip.hpp
blob5d8177364fac333c25f8d2528a82925c1cf5ba24
1 #ifndef _library__zip__hpp__included__
2 #define _library__zip__hpp__included__
4 #include <boost/iostreams/filtering_stream.hpp>
5 #include <iostream>
6 #include <iterator>
7 #include <string>
8 #include <map>
9 #include <fstream>
10 #include <sstream>
11 #include <zlib.h>
12 #include "string.hpp"
14 namespace zip
16 /**
17 * This class opens ZIP archive and offers methods to read members off it.
19 class reader
21 public:
22 /**
23 * This iterator iterates members of ZIP archive.
25 template<typename T, typename V>
26 class iterator_class
28 public:
29 /**
30 * C++ iterators stuff.
32 typedef std::bidirectional_iterator_tag iterator_category;
33 typedef V value_type;
34 typedef int difference_type;
35 typedef const V& reference;
36 typedef const V* pointer;
38 /**
39 * This constructs new iteration sequence. Only the first component (keys) are taken into
40 * account, the second component (values) are ignored.
42 * parameter _itr: The underlying map iterator.
43 * throws std::bad_alloc: Not enough memory.
45 iterator_class(T _itr)
46 : itr(_itr)
50 /**
51 * Get name of current member.
53 * returns: Name of member.
54 * throws std::bad_alloc: Not enough memory.
56 reference operator*()
58 return itr->first;
61 /**
62 * Get name of current member.
64 * returns: Name of member.
65 * throws std::bad_alloc: Not enough memory.
67 pointer operator->()
69 return &(itr->first);
72 /**
73 * Are these two iterators the same?
75 * parameter i: The another iterator
76 * returns: True if iterators are the same, false otherwise.
78 bool operator==(const iterator_class<T, V>& i) const throw()
80 return itr == i.itr;
83 /**
84 * Are these two iterators diffrent?
86 * paramer i: The another iterator
87 * returns: True if iterators are diffrent, false otherwise.
89 bool operator!=(const iterator_class<T, V>& i) const throw()
91 return itr != i.itr;
94 /**
95 * Advance iterator one step.
97 * returns: The old value of iterator.
98 * throws std::bad_alloc: Not enough memory.
100 const iterator_class<T, V> operator++(int)
102 iterator_class<T, V> c(*this);
103 ++itr;
104 return c;
108 * Regress iterator one step.
110 * returns: The old value of iterator.
111 * throws std::bad_alloc: Not enough memory.
113 const iterator_class<T, V> operator--(int)
115 iterator_class<T, V> c(*this);
116 --itr;
117 return c;
121 * Advance iterator one step.
123 * returns: Reference to this iterator.
125 iterator_class<T, V>& operator++() throw()
127 ++itr;
128 return *this;
132 * Regress iterator one step.
134 * returns: Reference to this iterator.
136 iterator_class<T, V>& operator--() throw()
138 --itr;
139 return *this;
141 private:
142 T itr;
146 * This iterator iterates members of ZIP archive in forward order.
148 typedef iterator_class<std::map<std::string, uint64_t>::iterator, std::string> iterator;
151 * This iterator iterates members of ZIP archive in reverse order
153 typedef iterator_class<std::map<std::string, uint64_t>::reverse_iterator, std::string>
154 riterator;
157 * Opens specified ZIP archive for reading.
159 * parameter zipfile: The name of ZIP file to open.
160 * throws std::bad_alloc: Not enough memory.
161 * throws std::runtime_error: Can't open the ZIP file.
163 reader(const std::string& zipfile);
166 * Destroy the ZIP reader. Opened input streams continue to be valid.
168 ~reader() throw();
171 * Gives the name of the first member, or "" if empty archive.
173 * returns: The member name
174 * throws std::bad_alloc: Not enough memory.
176 std::string find_first();
179 * Gives the name of the next member after specified, or "" if that member is the last.
181 * parameter name: The name to start the search from.
182 * returns: The member name
183 * throws std::bad_alloc: Not enough memory.
185 std::string find_next(const std::string& name);
188 * Starting iterator
190 * returns: The iterator pointing to first name.
191 * throws std::bad_alloc: Not enough memory.
193 iterator begin();
196 * Ending iterator (one past the end).
198 * returns: The iterator pointing to one past the last name.
199 * throws std::bad_alloc: Not enough memory.
201 iterator end();
204 * Starting reverse iterator
206 * returns: The iterator pointing to last name and acting in reverse.
207 * throws std::bad_alloc: Not enough memory.
209 riterator rbegin();
212 * Ending reverse iterator (one past the start).
213 * returrns: The iterator pointing to one before the first name and acting in reverse.
214 * throws std::bad_alloc: Not enough memory.
216 riterator rend();
219 * Check if member with specified name exists.
221 * parameter name: The name of the member to check
222 * returns: True if specified member exists, false otherwise.
224 bool has_member(const std::string& name) throw();
227 * Opens specified member. The resulting stream is not seekable, allocated using new and continues to be valid
228 * after ZIP reader has been destroyed.
230 * parameter name: The name of member to open.
231 * returns: The stream corresponding to member.
232 * throws std::bad_alloc: Not enough memory.
233 * throws std::runtime_error: The specified member does not exist
235 std::istream& operator[](const std::string& name);
237 * Reads a file consisting of single line.
239 * Parameter member: Name of the member to read.
240 * Parameter out: String to write the output to.
241 * Parameter conditional: If true and the file does not exist, return false instead of throwing.
242 * Returns: True on success, false on failure.
243 * Throws std::bad_alloc: Not enough memory.
244 * Throws std::runtime_error: Error reading file.
246 bool read_linefile(const std::string& member, std::string& out, bool conditional = false);
248 * Read a raw file.
250 * Parameter member: Name of the member to read.
251 * Parameter out: Buffer to write the output to.
252 * Throws std::bad_alloc: Not enough memory.
253 * Throws std::runtime_error: Error reading file.
255 void read_raw_file(const std::string& member, std::vector<char>& out);
257 * Reads a file consisting of single numeric constant.
259 * Parameter member: Name of the member to read.
260 * Parameter out: The output value.
261 * Parameter conditional: If true and the file does not exist, return false instead of throwing.
262 * Returns: True on success, false on failure.
263 * Throws std::bad_alloc: Not enough memory.
264 * Throws std::runtime_error: Error reading file.
266 template<typename T>
267 bool read_numeric_file(const std::string& member, T& out, bool conditional = false)
269 std::string _out;
270 if(!read_linefile(member, _out, conditional))
271 return false;
272 out = parse_value<T>(_out);
273 return true;
275 private:
276 reader(reader&);
277 reader& operator=(reader&);
278 std::map<std::string, uint64_t> offsets;
279 std::ifstream* zipstream;
280 size_t* refcnt;
284 * Opens the file named by name parameter, which is interpretted relative to file designated by referencing_path.
285 * The file can be inside ZIP archive. The resulting stream may or may not be seekable.
287 * If referencing_path is "", then name is traditional relative/absolute path. Otherwise if name is relative,
288 * it is relative to directory containing referencing_path, not current directory.
290 * parameter name: The name of file to open.
291 * parameter referencing_path: The path to file name is interpretted against.
292 * returns: The new stream, allocated by new.
293 * throw std::bad_alloc: Not enough memory.
294 * throw std::runtime_error: The file does not exist or can't be opened.
296 std::istream& openrel(const std::string& name, const std::string& referencing_path);
299 * As zip::openrel, but instead of returning handle to file, reads the entiere contents of the file and returns
300 * that.
302 * parameter name: As in zip::openrel
303 * parameter referencing_path: As in zip::openrel.
304 * returns: The file contents.
305 * throws std::bad_alloc: Not enough memory.
306 * throws std::runtime_error: The file does not exist or can't be opened.
308 std::vector<char> readrel(const std::string& name, const std::string& referencing_path);
311 * Resolves the final file path that zip::openrel/zip::readrel would open.
313 * parameter name: As in zip::openrel
314 * parameter referencing_path: As in zip::openrel
315 * returns: The file absolute path.
316 * throws std::bad_alloc: Not enough memory.
317 * throws std::runtime_error: Bad path.
319 std::string resolverel(const std::string& name, const std::string& referencing_path);
322 * Does the specified file (maybe inside .zip) exist?
324 * parameter name: The name of file.
325 * returns: True if file exists, false if not.
326 * throws std::bad_alloc: Not enough memory.
328 bool file_exists(const std::string& name);
331 * This class handles writing a ZIP archives.
333 class writer
335 public:
337 * Creates new empty ZIP archive. The members will be compressed according to specified compression.
339 * parameter zipfile: The zipfile to create.
340 * parameter stream: The stream to write the ZIP to.
341 * parameter _compression: Compression. 0 is uncompressed, 1-9 are deflate compression levels.
342 * throws std::bad_alloc: Not enough memory.
343 * throws std::runtime_error: Can't open archive or invalid argument.
345 writer(const std::string& zipfile, unsigned _compression);
346 writer(std::ostream& stream, unsigned _compression);
348 * Destroys ZIP writer, aborting the transaction (unless commit() has been called).
350 ~writer() throw();
353 * Commits the ZIP file. Does atomic replace of existing file if possible.
355 * throws std::bad_alloc: Not enough memory.
356 * throws std::logic_error: Existing file open.
357 * throws std::runtime_error: Can't commit archive (OS error or member open).
359 void commit();
362 * Create a new member inside ZIP file. No existing member may be open.
364 * parameter name: The name for new member.
365 * returns: Writing stream for the file (don't free).
366 * throws std::bad_alloc: Not enough memory.
367 * throws std::logic_error: Existing file open.
368 * throws std::runtime_error: Illegal name.
370 std::ostream& create_file(const std::string& name);
373 * Closes open member and destroys stream corresponding to it.
375 * throws std::bad_alloc: Not enough memory.
376 * throws std::logic_error: No file open.
377 * throws std::runtime_error: Error from operating system.
379 void close_file();
381 * Write a file consisting of single line. No existing member may be open.
383 * Parameter member: The name of the member.
384 * Parameter value: The value to write.
385 * Parameter conditional: If true and the value is empty, skip the write.
386 * throws std::bad_alloc: Not enough memory.
387 * throws std::runtime_error: Error from operating system.
389 void write_linefile(const std::string& member, const std::string& value, bool conditional = false);
391 * Write a raw file. No existing member may be open.
393 * Parameter member: The name of the member.
394 * Parameter content: The contents for the file.
395 * throws std::bad_alloc: Not enough memory.
396 * throws std::runtime_error: Error from operating system.
398 void write_raw_file(const std::string& member, const std::vector<char>& content);
400 * Write a file consisting of a single number. No existing member may be open.
402 * Parameter member: The name of the member.
403 * Parameter value: The value to write.
404 * throws std::bad_alloc: Not enough memory.
405 * throws std::runtime_error: Error from operating system.
407 template<typename T>
408 void write_numeric_file(const std::string& member, T value)
410 write_linefile(member, (stringfmt() << value).str());
412 private:
413 struct file_info
415 uint32_t crc;
416 uint32_t uncompressed_size;
417 uint32_t compressed_size;
418 uint32_t offset;
421 writer(writer&);
422 writer& operator=(writer&);
423 std::ostream* zipstream;
424 bool system_stream;
425 std::string temp_path;
426 std::string zipfile_path;
427 std::string open_file;
428 uint32_t base_offset;
429 std::vector<char> current_compressed_file;
430 std::map<std::string, file_info> files;
431 unsigned compression;
432 boost::iostreams::filtering_ostream* s;
433 uint32_t basepos;
434 bool committed;
437 #endif