diff options
-rw-r--r-- | include/cru/common/Exception.h | 17 | ||||
-rw-r--r-- | include/cru/common/io/CFileStream.h | 46 | ||||
-rw-r--r-- | include/cru/common/io/Stream.h | 11 | ||||
-rw-r--r-- | include/cru/common/platform/unix/ErrnoException.h | 18 | ||||
-rw-r--r-- | src/common/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/common/Exception.cpp | 11 | ||||
-rw-r--r-- | src/common/io/CFileStream.cpp | 132 | ||||
-rw-r--r-- | src/common/platform/unix/ErrnoException.cpp | 11 |
8 files changed, 221 insertions, 26 deletions
diff --git a/include/cru/common/Exception.h b/include/cru/common/Exception.h index 365d2064..6f458d35 100644 --- a/include/cru/common/Exception.h +++ b/include/cru/common/Exception.h @@ -29,4 +29,21 @@ class CRU_BASE_API TextEncodeException : public Exception { public: using Exception::Exception; }; + +class ErrnoException : public Exception { + public: + ErrnoException() : ErrnoException(String{}) {} + explicit ErrnoException(const String& message); + ErrnoException(const String& message, int errno_code); + + CRU_DELETE_COPY(ErrnoException) + CRU_DELETE_MOVE(ErrnoException) + + ~ErrnoException() override = default; + + int GetErrnoCode() const { return errno_code_; } + + private: + int errno_code_; +}; } // namespace cru diff --git a/include/cru/common/io/CFileStream.h b/include/cru/common/io/CFileStream.h new file mode 100644 index 00000000..65de2ac7 --- /dev/null +++ b/include/cru/common/io/CFileStream.h @@ -0,0 +1,46 @@ +#pragma once + +#include "Stream.h" + +#include <cstdio> + +namespace cru::io { +class CRU_BASE_API CFileStream : public Stream { + public: + CFileStream(const char* path, const char* mode); + explicit CFileStream(std::FILE* file, bool readable = true, + bool writable = true, bool auto_close = true); + + CRU_DELETE_COPY(CFileStream) + CRU_DELETE_MOVE(CFileStream) + + ~CFileStream() override; + + public: + bool CanSeek() override; + Index Seek(Index offset, SeekOrigin origin = SeekOrigin::Current) override; + Index Tell() override; + void Rewind() override; + + bool CanRead() override; + Index Read(std::byte* buffer, Index offset, Index size) override; + + bool CanWrite() override; + Index Write(const std::byte* buffer, Index offset, Index size) override; + + void Flush() override; + + void Close() override; + + std::FILE* GetHandle() const; + + private: + void CheckClosed(); + + private: + std::FILE* file_; + bool readable_; + bool writable_; + bool auto_close_; +}; +} // namespace cru::io diff --git a/include/cru/common/io/Stream.h b/include/cru/common/io/Stream.h index 66be4468..f833b0b9 100644 --- a/include/cru/common/io/Stream.h +++ b/include/cru/common/io/Stream.h @@ -2,12 +2,23 @@ #include "../Base.h" +#include "../Exception.h" #include "../String.h" #include <cstddef> #include <vector> namespace cru::io { +class CRU_BASE_API StreamAlreadyClosedException : public Exception { + public: + using Exception::Exception; + + CRU_DEFAULT_COPY(StreamAlreadyClosedException) + CRU_DEFAULT_MOVE(StreamAlreadyClosedException) + + CRU_DEFAULT_DESTRUCTOR(StreamAlreadyClosedException) +}; + class CRU_BASE_API Stream : public Object { public: enum class SeekOrigin { Current, Begin, End }; diff --git a/include/cru/common/platform/unix/ErrnoException.h b/include/cru/common/platform/unix/ErrnoException.h index 00e1864b..97edcc78 100644 --- a/include/cru/common/platform/unix/ErrnoException.h +++ b/include/cru/common/platform/unix/ErrnoException.h @@ -7,22 +7,8 @@ #include "../Exception.h" namespace cru::platform::unix { -class ErrnoException : public PlatformException { - public: - ErrnoException() : ErrnoException(String{}) {} - explicit ErrnoException(const String& message); - ErrnoException(const String& message, int errno_code); - - CRU_DELETE_COPY(ErrnoException) - CRU_DELETE_MOVE(ErrnoException) - - ~ErrnoException() override = default; - - int GetErrnoCode() const { return errno_code_; } - - private: - int errno_code_; -}; +// Moved to Exception.h +using ErrnoException = cru::ErrnoException; } // namespace cru::platform::unix #endif diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index fb2dd471..2c7f28e0 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -6,6 +6,7 @@ add_library(CruBase String.cpp StringToNumberConverter.cpp StringUtil.cpp + io/CFileStream.cpp io/Stream.cpp io/Resource.cpp io/MemoryStream.cpp diff --git a/src/common/Exception.cpp b/src/common/Exception.cpp index 86816720..b0053bac 100644 --- a/src/common/Exception.cpp +++ b/src/common/Exception.cpp @@ -1,5 +1,9 @@ #include "cru/common/Exception.h" +#include "cru/common/Format.h" + +#include <cerrno> + namespace cru { Exception::Exception() {} @@ -14,4 +18,11 @@ const char* Exception::what() const noexcept { return utf8_message_.c_str(); } + +ErrnoException::ErrnoException(const String& message) + : ErrnoException(message, errno) {} + +ErrnoException::ErrnoException(const String& message, int errno_code) + : Exception(Format(u"{}. Errno is {}.", message, errno_code)), + errno_code_(errno_code) {} } // namespace cru diff --git a/src/common/io/CFileStream.cpp b/src/common/io/CFileStream.cpp new file mode 100644 index 00000000..de195538 --- /dev/null +++ b/src/common/io/CFileStream.cpp @@ -0,0 +1,132 @@ +#include "cru/common/io/CFileStream.h" +#include "cru/common/Exception.h" +#include "cru/common/io/Stream.h" + +#include <cstdio> + +namespace cru::io { +static bool ModeCanRead(const char* mode) { + for (const char* p = mode; *p != '\0'; p++) { + if (*p == 'r' || *p == '+') { + return true; + } + } + return false; +} + +static bool ModeCanWrite(const char* mode) { + for (const char* p = mode; *p != '\0'; p++) { + if (*p == 'w' || *p == 'a' || *p == '+') { + return true; + } + } + return false; +} + +CFileStream::CFileStream(const char* path, const char* mode) + : file_(std::fopen(path, mode)), + readable_(ModeCanRead(mode)), + writable_(ModeCanWrite(mode)), + auto_close_(true) { + if (file_ == nullptr) { + throw ErrnoException(u"Cannot open file."); + } +} + +CFileStream::CFileStream(std::FILE* file, bool readable, bool writable, + bool auto_close) + : file_(file), + readable_(readable), + writable_(writable), + auto_close_(auto_close) { + if (file_ == nullptr) { + throw Exception(u"File is NULL."); + } +} + +CFileStream::~CFileStream() { + if (auto_close_ && file_ != nullptr) { + std::fclose(file_); + } +} + +bool CFileStream::CanSeek() { + CheckClosed(); + return true; +} + +static int ConvertOriginFlag(Stream::SeekOrigin origin) { + switch (origin) { + case Stream::SeekOrigin::Begin: + return SEEK_SET; + case Stream::SeekOrigin::Current: + return SEEK_CUR; + case Stream::SeekOrigin::End: + return SEEK_END; + default: + throw Exception(u"Unknown seek origin."); + } +} + +Index CFileStream::Seek(Index offset, SeekOrigin origin) { + CheckClosed(); + if (std::fseek(file_, offset, ConvertOriginFlag(origin))) { + throw ErrnoException(u"Seek failed."); + } + return Tell(); +} + +Index CFileStream::Tell() { + CheckClosed(); + long position = std::ftell(file_); + if (position == -1) { + throw ErrnoException(u"Tell failed."); + } + return position; +} + +void CFileStream::Rewind() { + CheckClosed(); + std::rewind(file_); +} + +bool CFileStream::CanRead() { + CheckClosed(); + return readable_; +} + +Index CFileStream::Read(std::byte* buffer, Index offset, Index size) { + CheckClosed(); + auto count = std::fread(buffer + offset, 1, size, file_); + return count; +} + +bool CFileStream::CanWrite() { + CheckClosed(); + return writable_; +} + +Index CFileStream::Write(const std::byte* buffer, Index offset, Index size) { + CheckClosed(); + auto count = std::fwrite(buffer + offset, 1, size, file_); + return count; +} + +void CFileStream::Flush() { + CheckClosed(); + std::fflush(file_); +} + +void CFileStream::Close() { + if (file_ != nullptr) { + std::fclose(file_); + file_ = nullptr; + } +} + +void CFileStream::CheckClosed() { + if (file_ == nullptr) { + throw StreamAlreadyClosedException(u"File is closed."); + } +} +} // namespace cru::io diff --git a/src/common/platform/unix/ErrnoException.cpp b/src/common/platform/unix/ErrnoException.cpp index f2171943..06c42ff6 100644 --- a/src/common/platform/unix/ErrnoException.cpp +++ b/src/common/platform/unix/ErrnoException.cpp @@ -1,14 +1,5 @@ #include "cru/common/platform/unix/ErrnoException.h" -#include "cru/common/Format.h" - -#include <errno.h> - namespace cru::platform::unix { -ErrnoException::ErrnoException(const String& message) - : ErrnoException(message, errno) {} - -ErrnoException::ErrnoException(const String& message, int errno_code) - : PlatformException(Format(u"{}. Errno is {}.", message, errno_code)), - errno_code_(errno_code) {} +// Moved to Exception.cpp } // namespace cru::platform::unix |