aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/common/io/FileStream.hpp5
-rw-r--r--include/cru/common/io/Win32FileStream.hpp53
-rw-r--r--src/common/CMakeLists.txt6
-rw-r--r--src/common/io/Win32FileStream.cpp127
-rw-r--r--test/common/CMakeLists.txt4
-rw-r--r--test/common/io/Win32FileStreamTest.cpp32
6 files changed, 227 insertions, 0 deletions
diff --git a/include/cru/common/io/FileStream.hpp b/include/cru/common/io/FileStream.hpp
index da7849cd..fdde13fa 100644
--- a/include/cru/common/io/FileStream.hpp
+++ b/include/cru/common/io/FileStream.hpp
@@ -5,4 +5,9 @@
namespace cru::io {
using FileStream = UnixFileStream;
}
+#elif CRU_PLATFORM_WINDOWS
+#include "Win32FileStream.hpp"
+namespace cru::io {
+using FileStream = Win32FileStream;
+}
#endif
diff --git a/include/cru/common/io/Win32FileStream.hpp b/include/cru/common/io/Win32FileStream.hpp
new file mode 100644
index 00000000..08600a8e
--- /dev/null
+++ b/include/cru/common/io/Win32FileStream.hpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include "../PreConfig.hpp"
+
+#ifdef CRU_PLATFORM_WINDOWS
+
+#include "../String.hpp"
+#include "OpenFileFlag.hpp"
+#include "Stream.hpp"
+#include "cru/common/Base.hpp"
+
+namespace cru::io {
+namespace details {
+class Win32FileStreamPrivate;
+}
+
+class CRU_BASE_API Win32FileStream : public Stream {
+ public:
+ Win32FileStream(String path, OpenFileFlag flags);
+
+ CRU_DELETE_COPY(Win32FileStream)
+ CRU_DELETE_MOVE(Win32FileStream)
+
+ ~Win32FileStream() override;
+
+ public:
+ bool CanSeek() override;
+ Index Tell() override;
+ void Seek(Index offset, SeekOrigin origin = SeekOrigin::Current) override;
+
+ bool CanRead() override;
+ Index Read(std::byte* buffer, Index offset, Index size) override;
+ using Stream::Read;
+
+ bool CanWrite() override;
+ Index Write(const std::byte* buffer, Index offset, Index size) override;
+ using Stream::Write;
+
+ void Close() override;
+
+ private:
+ void CheckClosed();
+
+ private:
+ String path_;
+ OpenFileFlag flags_;
+ bool closed_ = false;
+
+ details::Win32FileStreamPrivate* p_;
+};
+} // namespace cru::io
+
+#endif
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 40c85ef0..d8462abf 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -21,6 +21,12 @@ if (UNIX)
endif()
if (WIN32)
+ target_sources(cru_base PRIVATE
+ io/Win32FileStream.cpp
+ )
+endif()
+
+if (WIN32)
target_compile_definitions(cru_base PUBLIC CRU_PLATFORM_WINDOWS)
elseif(APPLE)
target_compile_definitions(cru_base PUBLIC CRU_PLATFORM_OSX)
diff --git a/src/common/io/Win32FileStream.cpp b/src/common/io/Win32FileStream.cpp
new file mode 100644
index 00000000..e7ee0e6a
--- /dev/null
+++ b/src/common/io/Win32FileStream.cpp
@@ -0,0 +1,127 @@
+#include "cru/common/io/Win32FileStream.hpp"
+
+#include "cru/common/Exception.hpp"
+#include "cru/common/io/OpenFileFlag.hpp"
+
+#include <Windows.h>
+
+namespace cru::io {
+namespace details {
+struct Win32FileStreamPrivate {
+ HANDLE handle;
+};
+} // namespace details
+
+Win32FileStream::Win32FileStream(String path, OpenFileFlag flags)
+ : path_(std::move(path)), flags_(flags) {
+ p_ = new details::Win32FileStreamPrivate();
+
+ DWORD dwDesiredAccess = 0;
+ if (flags & OpenFileFlags::Read) {
+ dwDesiredAccess |= GENERIC_READ;
+ }
+ if (flags & OpenFileFlags::Write) {
+ dwDesiredAccess |= GENERIC_WRITE;
+ }
+
+ DWORD dwCreationDisposition = 0;
+ if (flags & OpenFileFlags::Create) {
+ if (flags & OpenFileFlags::ThrowOnExist) {
+ dwCreationDisposition = CREATE_NEW;
+ } else {
+ dwCreationDisposition = OPEN_ALWAYS;
+ }
+ } else {
+ dwCreationDisposition = OPEN_EXISTING;
+ }
+
+ p_->handle =
+ ::CreateFileW(path_.WinCStr(), dwDesiredAccess, 0, nullptr,
+ dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
+
+ if (p_->handle == INVALID_HANDLE_VALUE) {
+ throw Exception(u"Failed to call CreateFileW.");
+ }
+}
+
+Win32FileStream::~Win32FileStream() {
+ Close();
+ delete p_;
+}
+
+bool Win32FileStream::CanSeek() { return true; }
+
+Index Win32FileStream::Tell() {
+ CheckClosed();
+
+ LARGE_INTEGER offset;
+ offset.QuadPart = 0;
+ LARGE_INTEGER file_pointer;
+ if (::SetFilePointerEx(p_->handle, offset, &file_pointer, FILE_CURRENT) ==
+ 0) {
+ throw Exception(u"Failed to call SetFilePointerEx.");
+ }
+
+ return file_pointer.QuadPart;
+}
+
+void Win32FileStream::Seek(Index offset, SeekOrigin origin) {
+ CheckClosed();
+
+ DWORD dwMoveMethod = 0;
+
+ if (origin == SeekOrigin::Current) {
+ dwMoveMethod = FILE_CURRENT;
+ } else if (origin == SeekOrigin::End) {
+ dwMoveMethod = FILE_END;
+ } else {
+ dwMoveMethod = FILE_BEGIN;
+ }
+
+ LARGE_INTEGER n_offset;
+ n_offset.QuadPart = offset;
+ if (::SetFilePointerEx(p_->handle, n_offset, nullptr, dwMoveMethod) == 0) {
+ throw Exception(u"Failed to call SetFilePointerEx.");
+ }
+}
+
+bool Win32FileStream::CanRead() { return true; }
+
+Index Win32FileStream::Read(std::byte* buffer, Index offset, Index size) {
+ CheckClosed();
+
+ DWORD dwRead;
+ if (::ReadFile(p_->handle, buffer + offset, size, &dwRead, nullptr) == 0) {
+ throw Exception(u"Failed to call ReadFile.");
+ }
+ return dwRead;
+}
+
+bool Win32FileStream::CanWrite() { return true; }
+
+Index Win32FileStream::Write(const std::byte* buffer, Index offset,
+ Index size) {
+ CheckClosed();
+
+ DWORD dwWritten;
+ if (::WriteFile(p_->handle, buffer + offset, size, &dwWritten, nullptr) ==
+ 0) {
+ throw Exception(u"Failed to call WriteFile.");
+ }
+
+ return dwWritten;
+}
+
+void Win32FileStream::Close() {
+ if (closed_) return;
+
+ ::CloseHandle(p_->handle);
+
+ closed_ = true;
+}
+
+void Win32FileStream::CheckClosed() {
+ if (closed_) throw Exception(u"Stream is closed.");
+}
+
+} // namespace cru::io
diff --git a/test/common/CMakeLists.txt b/test/common/CMakeLists.txt
index 7926437c..38c15000 100644
--- a/test/common/CMakeLists.txt
+++ b/test/common/CMakeLists.txt
@@ -13,6 +13,10 @@ if (UNIX)
endif()
if (WIN32)
+ target_sources(cru_base_test PRIVATE
+ io/Win32FileStreamTest.cpp
+ )
+
add_custom_command(TARGET cru_base_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:cru_base_test> $<TARGET_FILE_DIR:cru_base_test>
COMMAND_EXPAND_LISTS
diff --git a/test/common/io/Win32FileStreamTest.cpp b/test/common/io/Win32FileStreamTest.cpp
new file mode 100644
index 00000000..6c3edb6f
--- /dev/null
+++ b/test/common/io/Win32FileStreamTest.cpp
@@ -0,0 +1,32 @@
+#include "cru/common/io/OpenFileFlag.hpp"
+#include "cru/common/io/Win32FileStream.hpp"
+
+#include <gtest/gtest.h>
+
+#include <cstdio>
+#include <filesystem>
+
+TEST(UnixFileStream, Work) {
+ using namespace cru;
+ using namespace cru::io;
+
+ auto temp_file_path =
+ (std::filesystem::temp_directory_path() / "cru_test_temp.XXXXXX")
+ .native();
+ _wmktemp(temp_file_path.data());
+
+ String path = temp_file_path;
+
+ Win32FileStream file(path, OpenFileFlags::Write | OpenFileFlags::Create);
+ file.Write("abc", 3);
+ file.Close();
+
+ Win32FileStream file2(path, OpenFileFlags::Read);
+ auto buffer = std::make_unique<std::byte[]>(3);
+ file2.Read(buffer.get(), 3);
+ ASSERT_EQ(std::string_view(reinterpret_cast<const char*>(buffer.get()), 3),
+ "abc");
+ file2.Close();
+
+ std::filesystem::remove(temp_file_path);
+}