#ifndef _FILELIB_H_ #define _FILELIB_H_ #include #include #include #include #include #include #include "gzstream.h" #include "null_deleter.h" bool FileExists(const std::string& file_name); bool DirectoryExists(const std::string& dir_name); void MkDirP(const std::string& dir_name); // reads from standard in if filename is - // uncompresses if file ends with .gz // otherwise, reads from a normal file template struct BaseFile { typedef Stream S; typedef boost::shared_ptr PS; void Reset() { ps_.reset(); } bool is_null() const { return !ps_; } operator bool() const { return ps_; } S* stream() { return ps_.get(); } S* operator->() { return ps_.get(); } // compat with old ReadFile * -> new Readfile. remove? S &operator *() const { return get(); } S &get() const { return *ps_; } bool is_std() { return filename_=="-"; } std::string filename_; protected: void error(std::string const& reason,std::string const& filename) { throw std::runtime_error("File "+filename+" - "+reason); } PS ps_; static bool EndsWith(const std::string& f, const std::string& suf) { return (f.size() > suf.size()) && (f.rfind(suf) == f.size() - suf.size()); } }; class ReadFile : public BaseFile { public: ReadFile() { } explicit ReadFile(const std::string& filename) { Init(filename); } void Init(const std::string& filename) { filename_=filename; if (is_std()) { ps_=PS(&std::cin,null_deleter()); } else { if (!FileExists(filename)) { std::cerr << "File does not exist: " << filename << std::endl; error(filename," couldn't read nonexistant file."); abort(); } char const* file=filename_.c_str(); // just in case the gzstream keeps using the filename for longer than the constructor, e.g. inflateReset2. warning in valgrind that I'm hoping will disappear - it makes no sense. ps_=PS(EndsWith(filename, ".gz") ? static_cast(new igzstream(file)) : static_cast(new std::ifstream(file))); if (!*ps_) { std::cerr << "Failed to open " << filename << std::endl; error(filename," open for reading failed."); abort(); } } } }; class WriteFile : public BaseFile { public: WriteFile() {} explicit WriteFile(std::string const& filename) { Init(filename); } void Init(const std::string& filename) { filename_=filename; if (is_std()) { ps_=PS(&std::cout,null_deleter()); } else { char const* file=filename_.c_str(); // just in case the gzstream keeps using the filename for longer than the constructor, e.g. inflateReset2. warning in valgrind that I'm hoping will disappear - it makes no sense. ps_=PS(EndsWith(filename, ".gz") ? static_cast(new ogzstream(file)) : static_cast(new std::ofstream(file))); if (!*ps_) { std::cerr << "Failed to open " << filename << std::endl; error(filename," open for writing failed."); abort(); } } } ~WriteFile() { if (ps_) get() << std::flush; } }; inline void CopyFile(std::istream &in,std::ostream &out) { out << in.rdbuf(); } inline void CopyFile(std::string const& inf,std::ostream &out) { ReadFile r(inf); CopyFile(*r,out); } inline void CopyFile(std::string const& inf,std::string const& outf) { WriteFile w(outf); CopyFile(inf,*w); } #endif