#include #include #include #include namespace psemek::io { namespace { void throw_fopen [[noreturn]] (std::filesystem::path const & path) { throw util::system_error(std::error_code{errno, std::system_category()}, "Failed to open " + path.string()); } #ifdef __WIN32__ wchar_t const * fopen_read_mode() { return L"rb"; } wchar_t const * fopen_write_mode(unsigned flags) { switch (flags) { case 0: return L"wb"; case file_ostream::append: return L"ab"; } throw util::exception("Unknown file_ostream open flags"); } FILE * safe_fopen(std::filesystem::path const & path, wchar_t const * mode) { auto f = _wfopen(path.c_str(), mode); if (!f) throw_fopen(path); return f; } #else char const * fopen_read_mode() { return "rb"; } char const * fopen_write_mode(unsigned flags) { switch (flags) { case 0: return "wb"; case file_ostream::append: return "ab"; } throw util::exception("Unknown file_ostream open flags"); } FILE * safe_fopen(std::filesystem::path const & path, char const * mode) { auto f = std::fopen(path.c_str(), mode); if (!f) throw_fopen(path); return f; } #endif } file_istream::file_istream(std::filesystem::path const & path) : file_{safe_fopen(path, fopen_read_mode())} {} void file_istream::reset() { if (file_) std::fclose(file_); file_ = nullptr; } std::size_t file_istream::read(char * p, std::size_t size) { if (!file_) throw null_istream{}; return std::fread(p, 1, size, file_); } bool file_istream::finished() const { if (!file_) throw null_istream{}; return std::feof(file_) != 0; } file_ostream::file_ostream(std::filesystem::path const & path, unsigned flags) : file_{safe_fopen(path, fopen_write_mode(flags))} {} void file_ostream::reset() { if (file_) std::fclose(file_); file_ = nullptr; } std::size_t file_ostream::write(char const * p, std::size_t size) { if (!file_) throw null_ostream{}; return std::fwrite(p, 1, size, file_); } void file_ostream::flush() { if (!file_) throw null_ostream{}; std::fflush(file_); } }