diff options
-rw-r--r-- | contrib/paq.cpp | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/contrib/paq.cpp b/contrib/paq.cpp new file mode 100644 index 0000000..cd4fb0d --- /dev/null +++ b/contrib/paq.cpp @@ -0,0 +1,116 @@ +#include <iostream> +#include <fstream> +#include <string> +#include <vector> +#include <list> +#include <exception> +#include <boost/filesystem/operations.hpp> +#include <boost/filesystem/fstream.hpp> +#include <boost/iostreams/filtering_streambuf.hpp> +#include <boost/iostreams/filter/gzip.hpp> +#include <boost/iostreams/copy.hpp> + +using namespace std; + +class my_exception : public exception +{ +private: + string cause; + +public: + my_exception(const string& cause) : cause(cause) { } + virtual const char* what() const { return cause.c_str(); } +}; + +class paq_builder +{ +private: + struct index_entry + { + index_entry(const string& file_name, bool is_dir) : file_name(file_name), is_dir(is_dir) { } + + string file_name; + bool is_dir; + }; + + list<index_entry> index; + list<vector<char> > files; + + void process(string path) + { + boost::filesystem::directory_iterator end; + for (boost::filesystem::directory_iterator itr(path.c_str()); itr != end ; ++itr) + { + index.push_back(index_entry(itr->filename(), boost::filesystem::is_directory(itr->status()))); + if (index.back().is_dir) + process(path + "/" + itr->filename()); + else + { + ifstream in(itr->string().c_str(), ios::binary); + if (!in) throw my_exception(string("Can't open ") + itr->string()); + vector<char> v(4); + *reinterpret_cast<unsigned int*>(&v[0]) = boost::filesystem::file_size(itr->path()); + boost::iostreams::filtering_streambuf<boost::iostreams::output> out; + out.push(boost::iostreams::gzip_compressor()); + out.push(boost::iostreams::back_inserter(v)); + boost::iostreams::copy(in, out); + files.push_back(v); + } + } + index.push_back(index_entry(string(""), 0)); + } + +public: + paq_builder(const char* path) + { + if (!boost::filesystem::exists(path) || !boost::filesystem::is_directory(path)) + throw my_exception(string(path) + " doesn't exist or isn't a directory!"); + + process(string(path)); + } + + void write_to_file(const char* path) + { + ofstream paq(path, ios::binary); + if (!paq) throw my_exception(string("Can't open ") + path); + + paq.write("NPAQ", 4); + + list<vector<char> >::iterator f_it = files.begin(); + for (list<index_entry>::iterator i_it = index.begin(); i_it != index.end(); i_it++) + { + paq << static_cast<char>(i_it->file_name.size()); + if (i_it->file_name.size()) + { + paq.write(i_it->file_name.c_str(), i_it->file_name.size()); + unsigned int file_size = i_it->is_dir ? 0 : f_it++->size(); + paq.write(reinterpret_cast<char*>(&file_size), 4); + paq << static_cast<char>(file_size ? 0 : 1); + } + } + + for(f_it = files.begin(); f_it != files.end(); f_it++) + paq.write(&(*f_it)[0], f_it->size()); + } +}; + +int main(int argc, char** argv) +{ + if (argc < 3) + { + cout << "Usage: " << argv[0] << " <in-directory> <out-paq>" << endl; + return 0; + } + + try + { + paq_builder(argv[1]).write_to_file(argv[2]); + } + catch (const exception& e) + { + cerr << e.what() << endl; + return -1; + } + + return 0; +}
\ No newline at end of file |