2012-11-13 22:01:12 +02:00
|
|
|
#ifndef _library__zip__hpp__included__
|
|
|
|
#define _library__zip__hpp__included__
|
2011-09-13 17:50:18 +03:00
|
|
|
|
|
|
|
#include <boost/iostreams/filtering_stream.hpp>
|
|
|
|
#include <iostream>
|
|
|
|
#include <iterator>
|
|
|
|
#include <string>
|
|
|
|
#include <map>
|
|
|
|
#include <fstream>
|
|
|
|
#include <zlib.h>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This class opens ZIP archive and offers methods to read members off it.
|
|
|
|
*/
|
|
|
|
class zip_reader
|
|
|
|
{
|
|
|
|
public:
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* This iterator iterates members of ZIP archive.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
template<typename T, typename V>
|
|
|
|
class iterator_class
|
|
|
|
{
|
|
|
|
public:
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* C++ iterators stuff.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
typedef std::bidirectional_iterator_tag iterator_category;
|
|
|
|
typedef V value_type;
|
|
|
|
typedef int difference_type;
|
|
|
|
typedef const V& reference;
|
|
|
|
typedef const V* pointer;
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* This constructs new iteration sequence. Only the first component (keys) are taken into
|
|
|
|
* account, the second component (values) are ignored.
|
|
|
|
*
|
|
|
|
* parameter _itr: The underlying map iterator.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
iterator_class(T _itr) throw(std::bad_alloc)
|
|
|
|
: itr(_itr)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Get name of current member.
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* returns: Name of member.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
reference operator*() throw(std::bad_alloc)
|
|
|
|
{
|
|
|
|
return itr->first;
|
|
|
|
}
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Get name of current member.
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* returns: Name of member.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
pointer operator->() throw(std::bad_alloc)
|
|
|
|
{
|
|
|
|
return &(itr->first);
|
|
|
|
}
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Are these two iterators the same?
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* parameter i: The another iterator
|
|
|
|
* returns: True if iterators are the same, false otherwise.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
bool operator==(const iterator_class<T, V>& i) const throw()
|
|
|
|
{
|
|
|
|
return itr == i.itr;
|
|
|
|
}
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Are these two iterators diffrent?
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* paramer i: The another iterator
|
|
|
|
* returns: True if iterators are diffrent, false otherwise.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
bool operator!=(const iterator_class<T, V>& i) const throw()
|
|
|
|
{
|
|
|
|
return itr != i.itr;
|
|
|
|
}
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Advance iterator one step.
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* returns: The old value of iterator.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
const iterator_class<T, V> operator++(int) throw(std::bad_alloc)
|
|
|
|
{
|
|
|
|
iterator_class<T, V> c(*this);
|
|
|
|
++itr;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Regress iterator one step.
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* returns: The old value of iterator.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
const iterator_class<T, V> operator--(int) throw(std::bad_alloc)
|
|
|
|
{
|
|
|
|
iterator_class<T, V> c(*this);
|
|
|
|
--itr;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Advance iterator one step.
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* returns: Reference to this iterator.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
iterator_class<T, V>& operator++() throw()
|
|
|
|
{
|
|
|
|
++itr;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Regress iterator one step.
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* returns: Reference to this iterator.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
iterator_class<T, V>& operator--() throw()
|
|
|
|
{
|
|
|
|
--itr;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
T itr;
|
|
|
|
};
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* This iterator iterates members of ZIP archive in forward order.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
typedef iterator_class<std::map<std::string, unsigned long long>::iterator, std::string> iterator;
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* This iterator iterates members of ZIP archive in reverse order
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
typedef iterator_class<std::map<std::string, unsigned long long>::reverse_iterator, std::string>
|
|
|
|
riterator;
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Opens specified ZIP archive for reading.
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* parameter zipfile: The name of ZIP file to open.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
* throws std::runtime_error: Can't open the ZIP file.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
zip_reader(const std::string& zipfile) throw(std::bad_alloc, std::runtime_error);
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Destroy the ZIP reader. Opened input streams continue to be valid.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
~zip_reader() throw();
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Gives the name of the first member, or "" if empty archive.
|
|
|
|
*
|
|
|
|
* returns: The member name
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
std::string find_first() throw(std::bad_alloc);
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Gives the name of the next member after specified, or "" if that member is the last.
|
|
|
|
*
|
|
|
|
* parameter name: The name to start the search from.
|
|
|
|
* returns: The member name
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
std::string find_next(const std::string& name) throw(std::bad_alloc);
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Starting iterator
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* returns: The iterator pointing to first name.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
iterator begin() throw(std::bad_alloc);
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Ending iterator (one past the end).
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* returns: The iterator pointing to one past the last name.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
iterator end() throw(std::bad_alloc);
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Starting reverse iterator
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* returns: The iterator pointing to last name and acting in reverse.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
riterator rbegin() throw(std::bad_alloc);
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Ending reverse iterator (one past the start).
|
|
|
|
* returrns: The iterator pointing to one before the first name and acting in reverse.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
riterator rend() throw(std::bad_alloc);
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Check if member with specified name exists.
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* parameter name: The name of the member to check
|
|
|
|
* returns: True if specified member exists, false otherwise.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
bool has_member(const std::string& name) throw();
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Opens specified member. The resulting stream is not seekable, allocated using new and continues to be valid
|
|
|
|
* after ZIP reader has been destroyed.
|
|
|
|
*
|
|
|
|
* parameter name: The name of member to open.
|
|
|
|
* returns: The stream corresponding to member.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
* throws std::runtime_error: The specified member does not exist
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
std::istream& operator[](const std::string& name) throw(std::bad_alloc, std::runtime_error);
|
|
|
|
private:
|
|
|
|
zip_reader(zip_reader&);
|
|
|
|
zip_reader& operator=(zip_reader&);
|
|
|
|
std::map<std::string, unsigned long long> offsets;
|
|
|
|
std::ifstream* zipstream;
|
|
|
|
size_t* refcnt;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Opens the file named by name parameter, which is interpretted relative to file designated by referencing_path.
|
|
|
|
* The file can be inside ZIP archive. The resulting stream may or may not be seekable.
|
|
|
|
*
|
|
|
|
* If referencing_path is "", then name is traditional relative/absolute path. Otherwise if name is relative,
|
|
|
|
* it is relative to directory containing referencing_path, not current directory.
|
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* parameter name: The name of file to open.
|
|
|
|
* parameter referencing_path: The path to file name is interpretted against.
|
|
|
|
* returns: The new stream, allocated by new.
|
|
|
|
* throw std::bad_alloc: Not enough memory.
|
|
|
|
* throw std::runtime_error: The file does not exist or can't be opened.
|
2011-09-13 17:50:18 +03:00
|
|
|
*/
|
|
|
|
std::istream& open_file_relative(const std::string& name, const std::string& referencing_path) throw(std::bad_alloc,
|
|
|
|
std::runtime_error);
|
|
|
|
|
|
|
|
/**
|
2011-09-15 15:12:26 +03:00
|
|
|
* As open_file_relative, but instead of returning handle to file, reads the entiere contents of the file and returns
|
|
|
|
* that.
|
2011-09-13 17:50:18 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* parameter name: As in open_file_relative
|
|
|
|
* parameter referencing_path: As in open_file_relative.
|
|
|
|
* returns: The file contents.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
* throws std::runtime_error: The file does not exist or can't be opened.
|
2011-09-13 17:50:18 +03:00
|
|
|
*/
|
|
|
|
std::vector<char> read_file_relative(const std::string& name, const std::string& referencing_path)
|
|
|
|
throw(std::bad_alloc, std::runtime_error);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resolves the final file path that open_file_relative/read_file_relative would open.
|
2011-09-15 22:56:33 +03:00
|
|
|
*
|
2011-09-15 15:12:26 +03:00
|
|
|
* parameter name: As in open_file_relative
|
|
|
|
* parameter referencing_path: As in open_file_relative
|
|
|
|
* returns: The file absolute path.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
* throws std::runtime_error: Bad path.
|
2011-09-13 17:50:18 +03:00
|
|
|
*/
|
|
|
|
std::string resolve_file_relative(const std::string& name, const std::string& referencing_path) throw(std::bad_alloc,
|
|
|
|
std::runtime_error);
|
|
|
|
|
|
|
|
/**
|
2011-09-15 15:12:26 +03:00
|
|
|
* This class handles writing a ZIP archives.
|
2011-09-13 17:50:18 +03:00
|
|
|
*/
|
|
|
|
class zip_writer
|
|
|
|
{
|
|
|
|
public:
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Creates new empty ZIP archive. The members will be compressed according to specified compression.
|
|
|
|
*
|
|
|
|
* parameter zipfile: The zipfile to create.
|
|
|
|
* parameter _compression: Compression. 0 is uncompressed, 1-9 are deflate compression levels.
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
* throws std::runtime_error: Can't open archive or invalid argument.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
zip_writer(const std::string& zipfile, unsigned _compression) throw(std::bad_alloc, std::runtime_error);
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Destroys ZIP writer, aborting the transaction (unless commit() has been called).
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
~zip_writer() throw();
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Commits the ZIP file. Does atomic replace of existing file if possible.
|
|
|
|
*
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
* throws std::logic_error: Existing file open.
|
|
|
|
* throws std::runtime_error: Can't commit archive (OS error or member open).
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
void commit() throw(std::bad_alloc, std::logic_error, std::runtime_error);
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Create a new member inside ZIP file. No existing member may be open.
|
|
|
|
*
|
|
|
|
* parameter name: The name for new member.
|
|
|
|
* returns: Writing stream for the file (don't free).
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
* throws std::logic_error: Existing file open.
|
|
|
|
* throws std::runtime_error: Illegal name.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
std::ostream& create_file(const std::string& name) throw(std::bad_alloc, std::logic_error, std::runtime_error);
|
|
|
|
|
2011-09-15 15:12:26 +03:00
|
|
|
/**
|
|
|
|
* Closes open member and destroys stream corresponding to it.
|
|
|
|
*
|
|
|
|
* throws std::bad_alloc: Not enough memory.
|
|
|
|
* throws std::logic_error: No file open.
|
|
|
|
* throws std::runtime_error: Error from operating system.
|
|
|
|
*/
|
2011-09-13 17:50:18 +03:00
|
|
|
void close_file() throw(std::bad_alloc, std::logic_error, std::runtime_error);
|
|
|
|
private:
|
|
|
|
struct zip_file_info
|
|
|
|
{
|
|
|
|
unsigned long crc;
|
|
|
|
unsigned long uncompressed_size;
|
|
|
|
unsigned long compressed_size;
|
|
|
|
unsigned long offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
zip_writer(zip_writer&);
|
|
|
|
zip_writer& operator=(zip_writer&);
|
|
|
|
std::ofstream zipstream;
|
|
|
|
std::string temp_path;
|
|
|
|
std::string zipfile_path;
|
|
|
|
std::string open_file;
|
|
|
|
uint32_t base_offset;
|
|
|
|
std::vector<char> current_compressed_file;
|
|
|
|
std::map<std::string, zip_file_info> files;
|
|
|
|
unsigned compression;
|
|
|
|
boost::iostreams::filtering_ostream* s;
|
|
|
|
uint32_t basepos;
|
|
|
|
bool committed;
|
|
|
|
};
|
|
|
|
|
2013-07-31 15:38:35 +03:00
|
|
|
int rename_file_overwrite(const char* oldname, const char* newname);
|
|
|
|
|
2011-09-13 17:50:18 +03:00
|
|
|
#endif
|