aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2023-10-05 21:41:32 +0800
committercrupest <crupest@outlook.com>2023-10-05 21:41:32 +0800
commita5d07d55ef4395a5836fd0d2cd86b94290cb2d07 (patch)
tree93559c7402df97171b84e43a67aef82d36552da1
parentc1f491712ab071030ed8ca9587c896ca2856ab97 (diff)
downloadcru-a5d07d55ef4395a5836fd0d2cd86b94290cb2d07.tar.gz
cru-a5d07d55ef4395a5836fd0d2cd86b94290cb2d07.tar.bz2
cru-a5d07d55ef4395a5836fd0d2cd86b94290cb2d07.zip
...
-rw-r--r--demos/graphics/DrawCircle.cpp8
-rw-r--r--include/cru/common/io/Stream.h23
-rw-r--r--include/cru/common/platform/unix/UnixFileStream.h15
-rw-r--r--src/common/io/Stream.cpp25
-rw-r--r--src/common/platform/unix/UnixFileStream.cpp83
-rw-r--r--test/common/platform/unix/UnixFileStreamTest.cpp8
6 files changed, 98 insertions, 64 deletions
diff --git a/demos/graphics/DrawCircle.cpp b/demos/graphics/DrawCircle.cpp
index 61b4bd81..1ec06744 100644
--- a/demos/graphics/DrawCircle.cpp
+++ b/demos/graphics/DrawCircle.cpp
@@ -1,5 +1,4 @@
-#include "cru/common/io/FileStream.h"
-#include "cru/common/io/OpenFileFlag.h"
+#include "cru/common/io/CFileStream.h"
#include "cru/platform/Color.h"
#include "cru/platform/bootstrap/Bootstrap.h"
#include "cru/platform/graphics/Factory.h"
@@ -22,10 +21,7 @@ int main() {
painter->EndDraw();
}
- cru::io::FileStream file_stream(u"./test_image.png",
- cru::io::OpenFileFlags::Write |
- cru::io::OpenFileFlags::Create |
- cru::io::OpenFileFlags::Truncate);
+ cru::io::CFileStream file_stream("./test_image.png", "w");
graphics_factory->GetImageFactory()->EncodeToStream(
image.get(), &file_stream, cru::platform::graphics::ImageFormat::Png,
diff --git a/include/cru/common/io/Stream.h b/include/cru/common/io/Stream.h
index f833b0b9..2388874e 100644
--- a/include/cru/common/io/Stream.h
+++ b/include/cru/common/io/Stream.h
@@ -9,6 +9,27 @@
#include <vector>
namespace cru::io {
+class CRU_BASE_API StreamOperationNotSupportedException : public Exception {
+ public:
+ explicit StreamOperationNotSupportedException(String operation);
+
+ CRU_DEFAULT_COPY(StreamOperationNotSupportedException)
+ CRU_DEFAULT_MOVE(StreamOperationNotSupportedException)
+
+ CRU_DEFAULT_DESTRUCTOR(StreamOperationNotSupportedException)
+
+ public:
+ String GetOperation() const { return operation_; }
+
+ public:
+ static void CheckSeek(bool seekable);
+ static void CheckRead(bool readable);
+ static void CheckWrite(bool writable);
+
+ private:
+ String operation_;
+};
+
class CRU_BASE_API StreamAlreadyClosedException : public Exception {
public:
using Exception::Exception;
@@ -17,6 +38,8 @@ class CRU_BASE_API StreamAlreadyClosedException : public Exception {
CRU_DEFAULT_MOVE(StreamAlreadyClosedException)
CRU_DEFAULT_DESTRUCTOR(StreamAlreadyClosedException)
+
+ static void Check(bool closed);
};
class CRU_BASE_API Stream : public Object {
diff --git a/include/cru/common/platform/unix/UnixFileStream.h b/include/cru/common/platform/unix/UnixFileStream.h
index 0c8ef340..bf13358b 100644
--- a/include/cru/common/platform/unix/UnixFileStream.h
+++ b/include/cru/common/platform/unix/UnixFileStream.h
@@ -4,14 +4,14 @@
#ifdef CRU_PLATFORM_UNIX
-#include "../../String.h"
-#include "../../io/OpenFileFlag.h"
#include "../../io/Stream.h"
namespace cru::platform::unix {
class UnixFileStream : public io::Stream {
public:
- UnixFileStream(String path, io::OpenFileFlag flags);
+ UnixFileStream(const char* path, int oflag);
+ UnixFileStream(int fd, bool can_seek, bool can_read, bool can_write,
+ bool auto_close);
CRU_DELETE_COPY(UnixFileStream)
CRU_DELETE_MOVE(UnixFileStream)
@@ -36,10 +36,11 @@ class UnixFileStream : public io::Stream {
void CheckClosed();
private:
- String path_;
- io::OpenFileFlag flags_;
- int file_descriptor_;
- bool closed_ = false;
+ int file_descriptor_; // -1 for no file descriptor
+ bool can_seek_;
+ bool can_read_;
+ bool can_write_;
+ bool auto_close_;
};
} // namespace cru::platform::unix
diff --git a/src/common/io/Stream.cpp b/src/common/io/Stream.cpp
index bc045f03..07677fa8 100644
--- a/src/common/io/Stream.cpp
+++ b/src/common/io/Stream.cpp
@@ -1,6 +1,31 @@
#include "cru/common/io/Stream.h"
+#include "cru/common/Format.h"
+
+#include <utility>
namespace cru::io {
+StreamOperationNotSupportedException::StreamOperationNotSupportedException(
+ String operation)
+ : operation_(std::move(operation)) {
+ SetMessage(Format(u"Stream operation {} not supported.", operation_));
+}
+
+void StreamOperationNotSupportedException::CheckSeek(bool seekable) {
+ if (!seekable) throw StreamOperationNotSupportedException(u"seek");
+}
+
+void StreamOperationNotSupportedException::CheckRead(bool readable) {
+ if (!readable) throw StreamOperationNotSupportedException(u"read");
+}
+
+void StreamOperationNotSupportedException::CheckWrite(bool writable) {
+ if (!writable) throw StreamOperationNotSupportedException(u"write");
+}
+
+void StreamAlreadyClosedException::Check(bool closed) {
+ if (closed) throw StreamAlreadyClosedException();
+}
+
Index Stream::Tell() { return Seek(0, SeekOrigin::Current); }
void Stream::Rewind() { Seek(0, SeekOrigin::Begin); }
diff --git a/src/common/platform/unix/UnixFileStream.cpp b/src/common/platform/unix/UnixFileStream.cpp
index 7c1b0280..c0373c5a 100644
--- a/src/common/platform/unix/UnixFileStream.cpp
+++ b/src/common/platform/unix/UnixFileStream.cpp
@@ -1,45 +1,24 @@
#include "cru/common/platform/unix/UnixFileStream.h"
#include "cru/common/Format.h"
-#include "cru/common/io/OpenFileFlag.h"
+#include "cru/common/io/Stream.h"
#include "cru/common/platform/unix/ErrnoException.h"
#include <fcntl.h>
+#include <sys/fcntl.h>
#include <unistd.h>
namespace cru::platform::unix {
using namespace cru::io;
namespace {
-int MapOpenFileFlag(OpenFileFlag flags) {
- int result = 0;
- if (flags & OpenFileFlags::Read) {
- if (flags & OpenFileFlags::Write) {
- result |= O_RDWR;
- } else {
- result |= O_RDONLY;
- }
- } else {
- if (flags & OpenFileFlags::Write) {
- result |= O_WRONLY;
- } else {
- throw Exception(u"Invalid open file flag.");
- }
- }
-
- if (flags & OpenFileFlags::Append) {
- result |= O_APPEND;
- }
-
- if (flags & OpenFileFlags::Create) {
- result |= O_CREAT;
- }
+bool OflagCanSeek([[maybe_unused]] int oflag) {
+ // Treat every file seekable.
+ return true;
+}
- if (flags & OpenFileFlags::Truncate) {
- result |= O_TRUNC;
- }
+bool OflagCanRead(int oflag) { return oflag & O_RDONLY || oflag & O_RDWR; }
- return result;
-}
+bool OflagCanWrite(int oflag) { return oflag & O_WRONLY || oflag & O_RDWR; }
int MapSeekOrigin(Stream::SeekOrigin origin) {
switch (origin) {
@@ -55,26 +34,38 @@ int MapSeekOrigin(Stream::SeekOrigin origin) {
}
} // namespace
-UnixFileStream::~UnixFileStream() { Close(); }
-
-UnixFileStream::UnixFileStream(String path, OpenFileFlag flags)
- : path_(std::move(path)), flags_(flags) {
- auto p = path_.ToUtf8();
- file_descriptor_ =
- ::open(p.c_str(), MapOpenFileFlag(flags_), S_IRUSR | S_IWUSR);
+UnixFileStream::UnixFileStream(const char *path, int oflag) {
+ file_descriptor_ = ::open(path, oflag);
if (file_descriptor_ == -1) {
- throw ErrnoException(
- Format(u"Failed to open file {} with flags {}.", path_, flags_.value));
+ throw ErrnoException(Format(u"Failed to open file {} with oflag {}.",
+ String::FromUtf8(path), oflag));
}
+
+ can_seek_ = OflagCanSeek(oflag);
+ can_read_ = OflagCanRead(oflag);
+ can_write_ = OflagCanWrite(oflag);
+ auto_close_ = true;
+}
+
+UnixFileStream::UnixFileStream(int fd, bool can_seek, bool can_read,
+ bool can_write, bool auto_close) {
+ file_descriptor_ = fd;
+ can_seek_ = can_seek;
+ can_read_ = can_read;
+ can_write_ = can_write;
+ auto_close_ = auto_close;
}
+UnixFileStream::~UnixFileStream() { Close(); }
+
bool UnixFileStream::CanSeek() {
CheckClosed();
- return true;
+ return can_seek_;
}
Index UnixFileStream::Seek(Index offset, SeekOrigin origin) {
CheckClosed();
+ StreamOperationNotSupportedException::CheckSeek(can_seek_);
off_t result = ::lseek(file_descriptor_, offset, MapSeekOrigin(origin));
if (result == -1) {
throw ErrnoException(u"Failed to seek file.");
@@ -84,11 +75,12 @@ Index UnixFileStream::Seek(Index offset, SeekOrigin origin) {
bool UnixFileStream::CanRead() {
CheckClosed();
- return flags_ & OpenFileFlags::Read;
+ return can_read_;
}
Index UnixFileStream::Read(std::byte *buffer, Index offset, Index size) {
CheckClosed();
+ StreamOperationNotSupportedException::CheckRead(can_read_);
auto result = ::read(file_descriptor_, buffer + offset, size);
if (result == -1) {
throw ErrnoException(u"Failed to read file.");
@@ -98,11 +90,12 @@ Index UnixFileStream::Read(std::byte *buffer, Index offset, Index size) {
bool UnixFileStream::CanWrite() {
CheckClosed();
- return flags_ & OpenFileFlags::Write;
+ return can_write_;
}
Index UnixFileStream::Write(const std::byte *buffer, Index offset, Index size) {
CheckClosed();
+ StreamOperationNotSupportedException::CheckWrite(can_write_);
auto result = ::write(file_descriptor_, buffer + offset, size);
if (result == -1) {
throw ErrnoException(u"Failed to write file.");
@@ -111,16 +104,14 @@ Index UnixFileStream::Write(const std::byte *buffer, Index offset, Index size) {
}
void UnixFileStream::Close() {
- if (closed_) return;
+ if (file_descriptor_ < 0) return;
if (::close(file_descriptor_) == -1) {
throw ErrnoException(u"Failed to close file.");
}
- closed_ = true;
+ file_descriptor_ = -1;
}
void UnixFileStream::CheckClosed() {
- if (closed_) {
- throw Exception(u"File is closed.");
- }
+ StreamAlreadyClosedException::Check(file_descriptor_ < 0);
}
} // namespace cru::platform::unix
diff --git a/test/common/platform/unix/UnixFileStreamTest.cpp b/test/common/platform/unix/UnixFileStreamTest.cpp
index b9ff40da..c27e485b 100644
--- a/test/common/platform/unix/UnixFileStreamTest.cpp
+++ b/test/common/platform/unix/UnixFileStreamTest.cpp
@@ -3,7 +3,7 @@
#include <catch2/catch_test_macros.hpp>
-#include <cstdio>
+#include <fcntl.h>
#include <filesystem>
TEST_CASE("UnixFileStream Work", "[stream]") {
@@ -16,13 +16,11 @@ TEST_CASE("UnixFileStream Work", "[stream]") {
.generic_string();
mktemp(temp_file_path.data());
- String path = String::FromUtf8(temp_file_path);
-
- UnixFileStream file(path, OpenFileFlags::Write | OpenFileFlags::Create);
+ UnixFileStream file(temp_file_path.c_str(), O_WRONLY | O_CREAT);
file.Write("abc", 3);
file.Close();
- UnixFileStream file2(path, OpenFileFlags::Read);
+ UnixFileStream file2(temp_file_path.c_str(), OpenFileFlags::Read);
auto buffer = std::make_unique<std::byte[]>(3);
file2.Read(buffer.get(), 3);
REQUIRE(std::string_view(reinterpret_cast<const char*>(buffer.get()), 3) ==