lsnes rr0-β2
[lsnes.git] / zip.hpp
blob3ec5ad9fa31d98c16cb4e87772e228e8c61af36c
1 #ifndef _zip__hpp__included__
2 #define _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 <zlib.h>
12 /**
13 * This class opens ZIP archive and offers methods to read members off it.
15 class zip_reader
17 public:
18 /**
19 * This iterator iterates members of ZIP archive.
21 template<typename T, typename V>
22 class iterator_class
24 public:
25 /**
26 * C++ iterators stuff.
28 typedef std::bidirectional_iterator_tag iterator_category;
29 typedef V value_type;
30 typedef int difference_type;
31 typedef const V& reference;
32 typedef const V* pointer;
34 /**
35 * This constructs new iteration sequence. Only the first component (keys) are taken into
36 * account, the second component (values) are ignored.
38 * parameter _itr: The underlying map iterator.
39 * throws std::bad_alloc: Not enough memory.
41 iterator_class(T _itr) throw(std::bad_alloc)
42 : itr(_itr)
46 /**
47 * Get name of current member.
49 * returns: Name of member.
50 * throws std::bad_alloc: Not enough memory.
52 reference operator*() throw(std::bad_alloc)
54 return itr->first;
57 /**
58 * Get name of current member.
60 * returns: Name of member.
61 * throws std::bad_alloc: Not enough memory.
63 pointer operator->() throw(std::bad_alloc)
65 return &(itr->first);
68 /**
69 * Are these two iterators the same?
71 * parameter i: The another iterator
72 * returns: True if iterators are the same, false otherwise.
74 bool operator==(const iterator_class<T, V>& i) const throw()
76 return itr == i.itr;
79 /**
80 * Are these two iterators diffrent?
82 * paramer i: The another iterator
83 * returns: True if iterators are diffrent, false otherwise.
85 bool operator!=(const iterator_class<T, V>& i) const throw()
87 return itr != i.itr;
90 /**
91 * Advance iterator one step.
93 * returns: The old value of iterator.
94 * throws std::bad_alloc: Not enough memory.
96 const iterator_class<T, V> operator++(int) throw(std::bad_alloc)
98 iterator_class<T, V> c(*this);
99 ++itr;
100 return c;
104 * Regress iterator one step.
106 * returns: The old value of iterator.
107 * throws std::bad_alloc: Not enough memory.
109 const iterator_class<T, V> operator--(int) throw(std::bad_alloc)
111 iterator_class<T, V> c(*this);
112 --itr;
113 return c;
117 * Advance iterator one step.
119 * returns: Reference to this iterator.
121 iterator_class<T, V>& operator++() throw()
123 ++itr;
124 return *this;
128 * Regress iterator one step.
130 * returns: Reference to this iterator.
132 iterator_class<T, V>& operator--() throw()
134 --itr;
135 return *this;
137 private:
138 T itr;
142 * This iterator iterates members of ZIP archive in forward order.
144 typedef iterator_class<std::map<std::string, unsigned long long>::iterator, std::string> iterator;
147 * This iterator iterates members of ZIP archive in reverse order
149 typedef iterator_class<std::map<std::string, unsigned long long>::reverse_iterator, std::string>
150 riterator;
153 * Opens specified ZIP archive for reading.
155 * parameter zipfile: The name of ZIP file to open.
156 * throws std::bad_alloc: Not enough memory.
157 * throws std::runtime_error: Can't open the ZIP file.
159 zip_reader(const std::string& zipfile) throw(std::bad_alloc, std::runtime_error);
162 * Destroy the ZIP reader. Opened input streams continue to be valid.
164 ~zip_reader() throw();
167 * Gives the name of the first member, or "" if empty archive.
169 * returns: The member name
170 * throws std::bad_alloc: Not enough memory.
172 std::string find_first() throw(std::bad_alloc);
175 * Gives the name of the next member after specified, or "" if that member is the last.
177 * parameter name: The name to start the search from.
178 * returns: The member name
179 * throws std::bad_alloc: Not enough memory.
181 std::string find_next(const std::string& name) throw(std::bad_alloc);
184 * Starting iterator
186 * returns: The iterator pointing to first name.
187 * throws std::bad_alloc: Not enough memory.
189 iterator begin() throw(std::bad_alloc);
192 * Ending iterator (one past the end).
194 * returns: The iterator pointing to one past the last name.
195 * throws std::bad_alloc: Not enough memory.
197 iterator end() throw(std::bad_alloc);
200 * Starting reverse iterator
202 * returns: The iterator pointing to last name and acting in reverse.
203 * throws std::bad_alloc: Not enough memory.
205 riterator rbegin() throw(std::bad_alloc);
208 * Ending reverse iterator (one past the start).
209 * returrns: The iterator pointing to one before the first name and acting in reverse.
210 * throws std::bad_alloc: Not enough memory.
212 riterator rend() throw(std::bad_alloc);
215 * Check if member with specified name exists.
217 * parameter name: The name of the member to check
218 * returns: True if specified member exists, false otherwise.
220 bool has_member(const std::string& name) throw();
223 * Opens specified member. The resulting stream is not seekable, allocated using new and continues to be valid
224 * after ZIP reader has been destroyed.
226 * parameter name: The name of member to open.
227 * returns: The stream corresponding to member.
228 * throws std::bad_alloc: Not enough memory.
229 * throws std::runtime_error: The specified member does not exist
231 std::istream& operator[](const std::string& name) throw(std::bad_alloc, std::runtime_error);
232 private:
233 zip_reader(zip_reader&);
234 zip_reader& operator=(zip_reader&);
235 std::map<std::string, unsigned long long> offsets;
236 std::ifstream* zipstream;
237 size_t* refcnt;
241 * Opens the file named by name parameter, which is interpretted relative to file designated by referencing_path.
242 * The file can be inside ZIP archive. The resulting stream may or may not be seekable.
244 * If referencing_path is "", then name is traditional relative/absolute path. Otherwise if name is relative,
245 * it is relative to directory containing referencing_path, not current directory.
247 * parameter name: The name of file to open.
248 * parameter referencing_path: The path to file name is interpretted against.
249 * returns: The new stream, allocated by new.
250 * throw std::bad_alloc: Not enough memory.
251 * throw std::runtime_error: The file does not exist or can't be opened.
253 std::istream& open_file_relative(const std::string& name, const std::string& referencing_path) throw(std::bad_alloc,
254 std::runtime_error);
257 * As open_file_relative, but instead of returning handle to file, reads the entiere contents of the file and returns
258 * that.
260 * parameter name: As in open_file_relative
261 * parameter referencing_path: As in open_file_relative.
262 * returns: The file contents.
263 * throws std::bad_alloc: Not enough memory.
264 * throws std::runtime_error: The file does not exist or can't be opened.
266 std::vector<char> read_file_relative(const std::string& name, const std::string& referencing_path)
267 throw(std::bad_alloc, std::runtime_error);
270 * Resolves the final file path that open_file_relative/read_file_relative would open.
272 * parameter name: As in open_file_relative
273 * parameter referencing_path: As in open_file_relative
274 * returns: The file absolute path.
275 * throws std::bad_alloc: Not enough memory.
276 * throws std::runtime_error: Bad path.
278 std::string resolve_file_relative(const std::string& name, const std::string& referencing_path) throw(std::bad_alloc,
279 std::runtime_error);
282 * This class handles writing a ZIP archives.
284 class zip_writer
286 public:
288 * Creates new empty ZIP archive. The members will be compressed according to specified compression.
290 * parameter zipfile: The zipfile to create.
291 * parameter _compression: Compression. 0 is uncompressed, 1-9 are deflate compression levels.
292 * throws std::bad_alloc: Not enough memory.
293 * throws std::runtime_error: Can't open archive or invalid argument.
295 zip_writer(const std::string& zipfile, unsigned _compression) throw(std::bad_alloc, std::runtime_error);
298 * Destroys ZIP writer, aborting the transaction (unless commit() has been called).
300 ~zip_writer() throw();
303 * Commits the ZIP file. Does atomic replace of existing file if possible.
305 * throws std::bad_alloc: Not enough memory.
306 * throws std::logic_error: Existing file open.
307 * throws std::runtime_error: Can't commit archive (OS error or member open).
309 void commit() throw(std::bad_alloc, std::logic_error, std::runtime_error);
312 * Create a new member inside ZIP file. No existing member may be open.
314 * parameter name: The name for new member.
315 * returns: Writing stream for the file (don't free).
316 * throws std::bad_alloc: Not enough memory.
317 * throws std::logic_error: Existing file open.
318 * throws std::runtime_error: Illegal name.
320 std::ostream& create_file(const std::string& name) throw(std::bad_alloc, std::logic_error, std::runtime_error);
323 * Closes open member and destroys stream corresponding to it.
325 * throws std::bad_alloc: Not enough memory.
326 * throws std::logic_error: No file open.
327 * throws std::runtime_error: Error from operating system.
329 void close_file() throw(std::bad_alloc, std::logic_error, std::runtime_error);
330 private:
331 struct zip_file_info
333 unsigned long crc;
334 unsigned long uncompressed_size;
335 unsigned long compressed_size;
336 unsigned long offset;
339 zip_writer(zip_writer&);
340 zip_writer& operator=(zip_writer&);
341 std::ofstream zipstream;
342 std::string temp_path;
343 std::string zipfile_path;
344 std::string open_file;
345 uint32_t base_offset;
346 std::vector<char> current_compressed_file;
347 std::map<std::string, zip_file_info> files;
348 unsigned compression;
349 boost::iostreams::filtering_ostream* s;
350 uint32_t basepos;
351 bool committed;
354 #endif