diff --git a/lib/core/SConscript b/lib/core/SConscript index e69de29..024769d 100644 --- a/lib/core/SConscript +++ b/lib/core/SConscript @@ -0,0 +1,4 @@ +# SConscript +# Eryn Wells + +Library('erw', ['src/File.cc']) diff --git a/lib/core/include/core/File.hh b/lib/core/include/core/File.hh new file mode 100644 index 0000000..5f84641 --- /dev/null +++ b/lib/core/include/core/File.hh @@ -0,0 +1,105 @@ +/* File.hh + * vim: set tw=80: + * Eryn Wells + */ +/** + * File interface. + */ + +#include +#include +#include + +#include "String.hh" + + +namespace erw { +namespace core { + +struct File +{ + enum class SeekFrom { + /** Seek from the beginning of the file. */ + Begin, + /** Seek from the current file offset. */ + Here, + /** Seek from the end of the file. */ + End, + }; + + typedef std::bitset<3> Mode; + + static constexpr Mode In = Mode(1); + static constexpr Mode Out = Mode(2); + static constexpr Mode Binary = Mode(4); + + /** Destructor. */ + virtual ~File(); + + /** Seek to an absolute position in the file. */ + virtual File& seek(size_t pos) = 0; + + /** + * Seek to an `offset` from the given anchor point in the file. + * @see SeekFrom + */ + virtual File& seek(ssize_t offset, SeekFrom from) = 0; + +protected: + /** Convert a File::Mode to an iostream openmode bitset. */ + virtual std::ios_base::openmode modeToIOSMode(Mode mode); +}; + + +/** File handle for reading. */ +struct InFile + : public File +{ + /** Open a file at `path` for reading. */ + InFile(const String& path, File::Mode mode); + + /** Deleted copy constructor. File handles cannot be copied. */ + InFile(const InFile& other) = delete; + + /** Move `other` to this InFile. */ + InFile(InFile&& other); + + virtual ~InFile(); + + /** Move `other` to this InFile. File handles cannot be copied. */ + InFile& operator=(InFile& other); + + /** Read up to `count` characters into the provided `buffer`. */ + InFile& read(char* buffer, ssize_t count); + + /** @see File::seek */ + InFile& seek(size_t pos) override; + + /** @See File::seek */ + InFile& seek(ssize_t pos, File::SeekFrom from) override; + +private: + std::ifstream mStream; + + std::ios_base::openmode modeToIOSMode(File::Mode mode) override; +}; + + +struct OutFile + : public File +{ + /** Write `count` characters from the provided `buffer` into this file. */ + InFile& write(char* buffer, ssize_t count); + + /** @see File::seek */ + InFile& seek(size_t pos) override; + + /** @See File::seek */ + InFile& seek(ssize_t pos, File::SeekFrom from) override; + +private: + std::ofstream stream; +}; + +} /* namespace core */ +} /* namespace erw */ diff --git a/lib/core/src/File.cc b/lib/core/src/File.cc new file mode 100644 index 0000000..68ec789 --- /dev/null +++ b/lib/core/src/File.cc @@ -0,0 +1,140 @@ +/* File.cc + * vim: set tw=80: + * Eryn Wells + */ +/** + * Implementation of file handling. + */ + +#include "core/File.hh" + + +namespace erw { +namespace core { + +#pragma mark - File + +File::~File() +{ } + + +/* + * InFile::modeToIOSMode -- + */ +std::ios_base::openmode +File::modeToIOSMode(Mode mode) +{ + std::ios_base::openmode openmode = 0; + if ((mode & In).any()) { + openmode |= std::ios_base::in; + } + if ((mode & Out).any()) { + openmode |= std::ios_base::out; + } + if ((mode & Binary).any()) { + openmode |= std::ios_base::binary; + } + return openmode; +} + +#pragma mark - InFile + +/* + * InFile::InFile -- + */ +InFile::InFile(const String& path, + InFile::Mode mode) + : mStream(path, modeToIOSMode(mode)) +{ } + + +/* + * InFile::InFile -- + */ +InFile::InFile(InFile&& other) + : mStream(std::move(other.mStream)) +{ } + + +/* + * InFile::~InFile -- + */ +InFile::~InFile() +{ } + + +/* + * InFile::operator= -- + */ +InFile& +InFile::operator=(InFile& other) +{ + mStream = std::move(other.mStream); + return *this; +} + + +/* + * InFile::read -- + */ +InFile& +InFile::read(char* buffer, + ssize_t count) +{ + mStream.read(buffer, count); + return *this; +} + + +/* + * InFile::seek -- + */ +InFile& +InFile::seek(size_t pos) +{ + mStream.seekg(pos); + return *this; +} + + +/* + * InFile::seek -- + */ +InFile& +InFile::seek(ssize_t off, + File::SeekFrom from) +{ + std::ios_base::seekdir dir; + switch (from) { + case File::SeekFrom::Begin: + dir = std::ios_base::beg; + break; + case File::SeekFrom::Here: + dir = std::ios_base::cur; + break; + case File::SeekFrom::End: + dir = std::ios_base::end; + break; + } + mStream.seekg(off, dir); + return *this; +} + + +/* + * InFile::modeToIOSMode -- + */ +std::ios_base::openmode +InFile::modeToIOSMode(File::Mode mode) +{ + // Ensure In flag is always set. + if (!(mode & File::In).any()) { + mode |= File::In; + } + return File::modeToIOSMode(mode); +} + +#pragma mark - OutFile + +} /* namespace core */ +} /* namespace erw */