Add on_snoop Lua callback
[lsnes.git] / zip.hpp
blob1153a664b1f2091b827c516d47d15a6494c11ccd
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 * \brief Read files from ZIP archive
15 * This class opens ZIP archive and offers methods to read members off it.
17 class zip_reader
19 public:
20 /**
21 * \brief ZIP file iterator
23 * This iterator iterates members of ZIP archive.
25 template<typename T, typename V>
26 class iterator_class
28 public:
29 /**
30 * \brief C++ iterators stuff.
32 typedef std::bidirectional_iterator_tag iterator_category;
33 /**
34 * \brief C++ iterators stuff.
36 typedef V value_type;
37 /**
38 * \brief C++ iterators stuff.
40 typedef int difference_type;
41 /**
42 * \brief C++ iterators stuff.
44 typedef const V& reference;
45 /**
46 * \brief C++ iterators stuff.
48 typedef const V* pointer;
50 /**
51 * \brief Construct new iterator with specified names
53 * This constructs new iteration sequence. Only the first component (keys) are taken into
54 * account, the second component (values) are ignored.
56 * \param _itr The underlying map iterator.
57 * \throws std::bad_alloc Not enough memory.
59 iterator_class(T _itr) throw(std::bad_alloc)
60 : itr(_itr)
64 /**
65 * \brief Get name of current member.
66 * \return Name of member.
67 * \throws std::bad_alloc Not enough memory.
69 reference operator*() throw(std::bad_alloc)
71 return itr->first;
74 /**
75 * \brief Get name of current member.
76 * \return Name of member.
77 * \throws std::bad_alloc Not enough memory.
79 pointer operator->() throw(std::bad_alloc)
81 return &(itr->first);
84 /**
85 * \brief Are these two iterators the same?
86 * \param i The another iterator
87 * \return True if iterators are the same, false otherwise.
89 bool operator==(const iterator_class<T, V>& i) const throw()
91 return itr == i.itr;
94 /**
95 * \brief Are these two iterators diffrent?
96 * \param i The another iterator
97 * \return True if iterators are diffrent, false otherwise.
99 bool operator!=(const iterator_class<T, V>& i) const throw()
101 return itr != i.itr;
105 * \brief Advance iterator one step.
106 * \return 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 * \brief Regress iterator one step.
118 * \return The old value of iterator.
119 * \throws std::bad_alloc Not enough memory.
121 const iterator_class<T, V> operator--(int) throw(std::bad_alloc)
123 iterator_class<T, V> c(*this);
124 --itr;
125 return c;
129 * \brief Advance iterator one step.
130 * \return Reference to this iterator.
132 iterator_class<T, V>& operator++() throw()
134 ++itr;
135 return *this;
139 * \brief Regress iterator one step.
140 * \return Reference to this iterator.
142 iterator_class<T, V>& operator--() throw()
144 --itr;
145 return *this;
147 private:
148 T itr;
152 * \brief ZIP file forward iterator
154 * This iterator iterates members of ZIP archive in forward order.
156 typedef iterator_class<std::map<std::string, unsigned long long>::iterator, std::string> iterator;
159 * \brief ZIP file reverse iterator
161 * This iterator iterates members of ZIP archive in reverse order
163 typedef iterator_class<std::map<std::string, unsigned long long>::reverse_iterator, std::string>
164 riterator;
167 * \brief Open a ZIP archive.
169 * Opens specified ZIP archive.
170 * \param zipfile The ZIP file to open.
171 * \throws std::bad_alloc Not enough memory.
172 * \throws std::runtime_error Can't open the ZIP file.
174 zip_reader(const std::string& zipfile) throw(std::bad_alloc, std::runtime_error);
177 * \brief Destructor
179 * Destroy the ZIP reader. Opened input streams continue to be valid.
181 ~zip_reader() throw();
184 * \brief Find the name of first member.
186 * Gives the name of the first member, or "" if empty archive.
188 * \return The member name
189 * \throws std::bad_alloc Not enough memory.
191 std::string find_first() throw(std::bad_alloc);
194 * \brief Find the next member.
196 * Gives the name of the next member after specified, or "" if that member is the last.
198 * \param name The name to start the search from.
199 * \return The member name
200 * \throws std::bad_alloc Not enough memory.
202 std::string find_next(const std::string& name) throw(std::bad_alloc);
205 * \brief Starting iterator
206 * \return The iterator pointing to first name.
207 * \throws std::bad_alloc Not enough memory.
209 iterator begin() throw(std::bad_alloc);
212 * \brief Ending iterator
213 * \return The iterator pointing to one past the last name.
214 * \throws std::bad_alloc Not enough memory.
216 iterator end() throw(std::bad_alloc);
219 * \brief Starting reverse iterator
220 * \return The iterator pointing to last name and acting in reverse.
221 * \throws std::bad_alloc Not enough memory.
223 riterator rbegin() throw(std::bad_alloc);
226 * \brief Ending reverse iterator
227 * \return The iterator pointing to one before the first name and acting in reverse.
228 * \throws std::bad_alloc Not enough memory.
230 riterator rend() throw(std::bad_alloc);
233 * \brief Does the member exist?
234 * \param name The name of the member.
235 * \return True if specified member exists, false otherwise.
237 bool has_member(const std::string& name) throw();
240 * \brief Open member
242 * Opens specified member. The stream is not seekable, allocated using new and continues to be valid after
243 * ZIP reader has been destroyed.
245 * \param name The name of member to open.
246 * \return The stream corresponding to member.
247 * \throws std::bad_alloc Not enough memory.
248 * \throws std::runtime_error The specified member does not exist
250 std::istream& operator[](const std::string& name) throw(std::bad_alloc, std::runtime_error);
251 private:
252 zip_reader(zip_reader&);
253 zip_reader& operator=(zip_reader&);
254 std::map<std::string, unsigned long long> offsets;
255 std::ifstream* zipstream;
256 size_t* refcnt;
260 * \brief Open file relative to another
262 * Opens the file named by name parameter, which is interpretted relative to file designated by referencing_path.
263 * The file can be inside ZIP archive. The resulting stream may or may not be seekable.
265 * If referencing_path is "", then name is traditional relative/absolute path. Otherwise if name is relative,
266 * it is relative to directory containing referencing_path, not current directory.
268 * \param name The name of file to open.
269 * \param referencing_path The path to file name is interpretted against.
270 * \return The new stream, allocated by new.
271 * \throw std::bad_alloc Not enough memory.
272 * \throw std::runtime_error The file does not exist or can't be opened.
274 std::istream& open_file_relative(const std::string& name, const std::string& referencing_path) throw(std::bad_alloc,
275 std::runtime_error);
278 * \brief Read file relative to another.
280 * Reads the entiere content of file named by name parameter, which is interpretted relative to file designated by
281 * referencing_path. The file can be inside ZIP archive.
283 * If referencing_path is "", then name is traditional relative/absolute path. Otherwise if name is relative,
284 * it is relative to directory containing referencing_path, not current directory.
286 * \param name The name of file to read.
287 * \param referencing_path The path to file name is interpretted against.
288 * \return The file contents.
289 * \throw std::bad_alloc Not enough memory.
290 * \throw std::runtime_error The file does not exist or can't be opened.
292 std::vector<char> read_file_relative(const std::string& name, const std::string& referencing_path)
293 throw(std::bad_alloc, std::runtime_error);
296 * \brief Resolve full path of file relative to another.
298 * Resolves the final file path that open_file_relative/read_file_relative would open.
300 * \param name The name of file to read.
301 * \param referencing_path The path to file name is interpretted against.
302 * \return The file absolute path.
303 * \throw std::bad_alloc Not enough memory.
304 * \throw std::runtime_error Bad path.
306 std::string resolve_file_relative(const std::string& name, const std::string& referencing_path) throw(std::bad_alloc,
307 std::runtime_error);
310 * \brief Write a ZIP archive
312 * This class handles writing a ZIP archive.
314 class zip_writer
316 public:
318 * \brief Create new empty ZIP archive.
320 * Creates new empty ZIP archive. The members will be compressed according to specified compression.
322 * \param zipfile The zipfile to create.
323 * \param _compression Compression. 0 is uncompressed, 1-9 are deflate compression levels.
324 * \throws std::bad_alloc Not enough memory.
325 * \throws std::runtime_error Can't open archive or invalid argument.
327 zip_writer(const std::string& zipfile, unsigned _compression) throw(std::bad_alloc, std::runtime_error);
330 * \brief Destroy ZIP writer.
332 * Destroys ZIP writer, aborting the transaction (unless commit() has been called).
334 ~zip_writer() throw();
337 * \brief Commit the transaction
339 * Commits the ZIP file. Does atomic replace of existing file if possible.
341 * \throws std::bad_alloc Not enough memory.
342 * \throws std::logic_error Existing file open.
343 * \throws std::runtime_error Can't commit archive (OS error or member open).
345 void commit() throw(std::bad_alloc, std::logic_error, std::runtime_error);
348 * \brief Create a new member
350 * Create a new member inside ZIP file. No existing member may be open.
352 * \param name The name for new member.
353 * \return Writing stream for the file (don't free).
355 * \throws std::bad_alloc Not enough memory.
356 * \throws std::logic_error Existing file open.
357 * \throws std::runtime_error Illegal name.
359 std::ostream& create_file(const std::string& name) throw(std::bad_alloc, std::logic_error, std::runtime_error);
362 * \brief Close open member
364 * Closes open member and destroys stream corresponding to it.
366 * \throws std::bad_alloc Not enough memory.
367 * \throws std::logic_error No file open.
368 * \throws std::runtime_error Error from operating system.
370 void close_file() throw(std::bad_alloc, std::logic_error, std::runtime_error);
371 private:
372 struct zip_file_info
374 unsigned long crc;
375 unsigned long uncompressed_size;
376 unsigned long compressed_size;
377 unsigned long offset;
380 zip_writer(zip_writer&);
381 zip_writer& operator=(zip_writer&);
382 std::ofstream zipstream;
383 std::string temp_path;
384 std::string zipfile_path;
385 std::string open_file;
386 uint32_t base_offset;
387 std::vector<char> current_compressed_file;
388 std::map<std::string, zip_file_info> files;
389 unsigned compression;
390 boost::iostreams::filtering_ostream* s;
391 uint32_t basepos;
392 bool committed;
395 #endif