Lua: Fix type confusion between signed and unsigned
[lsnes.git] / include / library / zip.hpp
blobfce5c93878df038a8fa42bb50ec3803a08fe1dc7
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) throw(std::bad_alloc)
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*() throw(std::bad_alloc)
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->() throw(std::bad_alloc)
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) throw(std::bad_alloc)
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) throw(std::bad_alloc)
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) throw(std::bad_alloc, std::runtime_error);
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() throw(std::bad_alloc);
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) throw(std::bad_alloc);
188 * Starting iterator
190 * returns: The iterator pointing to first name.
191 * throws std::bad_alloc: Not enough memory.
193 iterator begin() throw(std::bad_alloc);
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() throw(std::bad_alloc);
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() throw(std::bad_alloc);
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() throw(std::bad_alloc);
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) throw(std::bad_alloc, std::runtime_error);
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)
247 throw(std::bad_alloc, std::runtime_error);
249 * Read a raw file.
251 * Parameter member: Name of the member to read.
252 * Parameter out: Buffer to write the output to.
253 * Throws std::bad_alloc: Not enough memory.
254 * Throws std::runtime_error: Error reading file.
256 void read_raw_file(const std::string& member, std::vector<char>& out) throw(std::bad_alloc,
257 std::runtime_error);
259 * Reads a file consisting of single numeric constant.
261 * Parameter member: Name of the member to read.
262 * Parameter out: The output value.
263 * Parameter conditional: If true and the file does not exist, return false instead of throwing.
264 * Returns: True on success, false on failure.
265 * Throws std::bad_alloc: Not enough memory.
266 * Throws std::runtime_error: Error reading file.
268 template<typename T>
269 bool read_numeric_file(const std::string& member, T& out, bool conditional = false)
270 throw(std::bad_alloc, std::runtime_error)
272 std::string _out;
273 if(!read_linefile(member, _out, conditional))
274 return false;
275 out = parse_value<T>(_out);
276 return true;
278 private:
279 reader(reader&);
280 reader& operator=(reader&);
281 std::map<std::string, uint64_t> offsets;
282 std::ifstream* zipstream;
283 size_t* refcnt;
287 * Opens the file named by name parameter, which is interpretted relative to file designated by referencing_path.
288 * The file can be inside ZIP archive. The resulting stream may or may not be seekable.
290 * If referencing_path is "", then name is traditional relative/absolute path. Otherwise if name is relative,
291 * it is relative to directory containing referencing_path, not current directory.
293 * parameter name: The name of file to open.
294 * parameter referencing_path: The path to file name is interpretted against.
295 * returns: The new stream, allocated by new.
296 * throw std::bad_alloc: Not enough memory.
297 * throw std::runtime_error: The file does not exist or can't be opened.
299 std::istream& openrel(const std::string& name, const std::string& referencing_path) throw(std::bad_alloc,
300 std::runtime_error);
303 * As zip::openrel, but instead of returning handle to file, reads the entiere contents of the file and returns
304 * that.
306 * parameter name: As in zip::openrel
307 * parameter referencing_path: As in zip::openrel.
308 * returns: The file contents.
309 * throws std::bad_alloc: Not enough memory.
310 * throws std::runtime_error: The file does not exist or can't be opened.
312 std::vector<char> readrel(const std::string& name, const std::string& referencing_path)
313 throw(std::bad_alloc, std::runtime_error);
316 * Resolves the final file path that zip::openrel/zip::readrel would open.
318 * parameter name: As in zip::openrel
319 * parameter referencing_path: As in zip::openrel
320 * returns: The file absolute path.
321 * throws std::bad_alloc: Not enough memory.
322 * throws std::runtime_error: Bad path.
324 std::string resolverel(const std::string& name, const std::string& referencing_path) throw(std::bad_alloc,
325 std::runtime_error);
328 * Does the specified file (maybe inside .zip) exist?
330 * parameter name: The name of file.
331 * returns: True if file exists, false if not.
332 * throws std::bad_alloc: Not enough memory.
334 bool file_exists(const std::string& name) throw(std::bad_alloc);
337 * This class handles writing a ZIP archives.
339 class writer
341 public:
343 * Creates new empty ZIP archive. The members will be compressed according to specified compression.
345 * parameter zipfile: The zipfile to create.
346 * parameter stream: The stream to write the ZIP to.
347 * parameter _compression: Compression. 0 is uncompressed, 1-9 are deflate compression levels.
348 * throws std::bad_alloc: Not enough memory.
349 * throws std::runtime_error: Can't open archive or invalid argument.
351 writer(const std::string& zipfile, unsigned _compression) throw(std::bad_alloc, std::runtime_error);
352 writer(std::ostream& stream, unsigned _compression) throw(std::bad_alloc, std::runtime_error);
354 * Destroys ZIP writer, aborting the transaction (unless commit() has been called).
356 ~writer() throw();
359 * Commits the ZIP file. Does atomic replace of existing file if possible.
361 * throws std::bad_alloc: Not enough memory.
362 * throws std::logic_error: Existing file open.
363 * throws std::runtime_error: Can't commit archive (OS error or member open).
365 void commit() throw(std::bad_alloc, std::logic_error, std::runtime_error);
368 * Create a new member inside ZIP file. No existing member may be open.
370 * parameter name: The name for new member.
371 * returns: Writing stream for the file (don't free).
372 * throws std::bad_alloc: Not enough memory.
373 * throws std::logic_error: Existing file open.
374 * throws std::runtime_error: Illegal name.
376 std::ostream& create_file(const std::string& name) throw(std::bad_alloc, std::logic_error,
377 std::runtime_error);
380 * Closes open member and destroys stream corresponding to it.
382 * throws std::bad_alloc: Not enough memory.
383 * throws std::logic_error: No file open.
384 * throws std::runtime_error: Error from operating system.
386 void close_file() throw(std::bad_alloc, std::logic_error, std::runtime_error);
388 * Write a file consisting of single line. No existing member may be open.
390 * Parameter member: The name of the member.
391 * Parameter value: The value to write.
392 * Parameter conditional: If true and the value is empty, skip the write.
393 * throws std::bad_alloc: Not enough memory.
394 * throws std::runtime_error: Error from operating system.
396 void write_linefile(const std::string& member, const std::string& value, bool conditional = false)
397 throw(std::bad_alloc, std::runtime_error);
399 * Write a raw file. No existing member may be open.
401 * Parameter member: The name of the member.
402 * Parameter content: The contents for the file.
403 * throws std::bad_alloc: Not enough memory.
404 * throws std::runtime_error: Error from operating system.
406 void write_raw_file(const std::string& member, const std::vector<char>& content)
407 throw(std::bad_alloc, std::runtime_error);
409 * Write a file consisting of a single number. No existing member may be open.
411 * Parameter member: The name of the member.
412 * Parameter value: The value to write.
413 * throws std::bad_alloc: Not enough memory.
414 * throws std::runtime_error: Error from operating system.
416 template<typename T>
417 void write_numeric_file(const std::string& member, T value) throw(std::bad_alloc, std::runtime_error)
419 write_linefile(member, (stringfmt() << value).str());
421 private:
422 struct file_info
424 uint32_t crc;
425 uint32_t uncompressed_size;
426 uint32_t compressed_size;
427 uint32_t offset;
430 writer(writer&);
431 writer& operator=(writer&);
432 std::ostream* zipstream;
433 bool system_stream;
434 std::string temp_path;
435 std::string zipfile_path;
436 std::string open_file;
437 uint32_t base_offset;
438 std::vector<char> current_compressed_file;
439 std::map<std::string, file_info> files;
440 unsigned compression;
441 boost::iostreams::filtering_ostream* s;
442 uint32_t basepos;
443 bool committed;
446 #endif