psemek/libs/io/source/file_stream.cpp

114 lines
2.2 KiB
C++

#include <psemek/io/file_stream.hpp>
#include <psemek/util/system_error.hpp>
#include <psemek/util/enum.hpp>
#include <cstring>
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_);
}
}