aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/common/Exception.h17
-rw-r--r--include/cru/common/io/CFileStream.h46
-rw-r--r--include/cru/common/io/Stream.h11
-rw-r--r--include/cru/common/platform/unix/ErrnoException.h18
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/Exception.cpp11
-rw-r--r--src/common/io/CFileStream.cpp132
-rw-r--r--src/common/platform/unix/ErrnoException.cpp11
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