diff options
-rw-r--r-- | include/cru/common/io/OpenFileFlag.h | 2 | ||||
-rw-r--r-- | include/cru/common/platform/win/Win32FileStream.h | 2 | ||||
-rw-r--r-- | src/common/platform/win/StreamConvert.cpp | 29 | ||||
-rw-r--r-- | src/common/platform/win/Win32FileStream.cpp | 101 | ||||
-rw-r--r-- | src/common/platform/win/Win32FileStreamPrivate.h | 13 | ||||
-rw-r--r-- | test/common/platform/win/Win32FileStreamTest.cpp | 8 |
6 files changed, 76 insertions, 79 deletions
diff --git a/include/cru/common/io/OpenFileFlag.h b/include/cru/common/io/OpenFileFlag.h index b0bceddc..bfbdd38a 100644 --- a/include/cru/common/io/OpenFileFlag.h +++ b/include/cru/common/io/OpenFileFlag.h @@ -13,6 +13,6 @@ struct OpenFileFlags { static constexpr OpenFileFlag Write{0x2}; static constexpr OpenFileFlag Append{0x4}; static constexpr OpenFileFlag Create{0x8}; - static constexpr OpenFileFlag ThrowOnExist{0x10}; + static constexpr OpenFileFlag Truncate{0x10}; }; } // namespace cru::io diff --git a/include/cru/common/platform/win/Win32FileStream.h b/include/cru/common/platform/win/Win32FileStream.h index 521fd58d..06656466 100644 --- a/include/cru/common/platform/win/Win32FileStream.h +++ b/include/cru/common/platform/win/Win32FileStream.h @@ -39,6 +39,8 @@ class CRU_BASE_API Win32FileStream : public io::Stream { String GetPath() const { return path_; } io::OpenFileFlag GetOpenFileFlags() const { return flags_; } + details::Win32FileStreamPrivate* GetPrivate_() { return p_; } + private: void CheckClosed(); diff --git a/src/common/platform/win/StreamConvert.cpp b/src/common/platform/win/StreamConvert.cpp index 8e2648c2..d547caa5 100644 --- a/src/common/platform/win/StreamConvert.cpp +++ b/src/common/platform/win/StreamConvert.cpp @@ -1,5 +1,6 @@ #include "cru/common/platform/win/StreamConvert.h" #include "BrigdeComStream.h" +#include "Win32FileStreamPrivate.h" #include "cru/common/Exception.h" #include "cru/common/io/MemoryStream.h" #include "cru/common/io/OpenFileFlag.h" @@ -19,33 +20,7 @@ IStream* ConvertStreamToComStream(io::Stream* stream) { reinterpret_cast<const BYTE*>(memory_stream->GetBuffer()), memory_stream->GetSize()); } else if (auto file_stream = dynamic_cast<Win32FileStream*>(stream)) { - auto path = file_stream->GetPath(); - auto flags = file_stream->GetOpenFileFlags(); - DWORD grfMode = STGM_SHARE_DENY_NONE | STGM_FAILIFTHERE; - if (flags & io::OpenFileFlags::Read) { - if (flags & io::OpenFileFlags::Write) { - grfMode |= STGM_READWRITE; - } else { - grfMode |= STGM_READ; - } - } else { - if (flags & io::OpenFileFlags::Write) { - grfMode |= STGM_WRITE; - } else { - throw Exception(u"Stream must be readable or writable."); - } - } - - IStream* result; - - ThrowIfFailed(SHCreateStreamOnFileEx( - path.WinCStr(), grfMode, FILE_ATTRIBUTE_NORMAL, FALSE, NULL, &result)); - - LARGE_INTEGER position; - position.QuadPart = stream->Tell(); - result->Seek(position, STREAM_SEEK_SET, NULL); - - return result; + return file_stream->GetPrivate_()->stream_; } else { return new BridgeComStream(stream); } diff --git a/src/common/platform/win/Win32FileStream.cpp b/src/common/platform/win/Win32FileStream.cpp index 92420bbe..a118dc02 100644 --- a/src/common/platform/win/Win32FileStream.cpp +++ b/src/common/platform/win/Win32FileStream.cpp @@ -1,50 +1,48 @@ #include "cru/common/platform/win/Win32FileStream.h" +#include "Win32FileStreamPrivate.h" #include "cru/common/io/OpenFileFlag.h" #include "cru/common/platform/win/Exception.h" #include <Windows.h> +#include <coml2api.h> +#include <shlwapi.h> #include <winnt.h> +#include <filesystem> namespace cru::platform::win { using 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; + : path_(std::move(path)), + flags_(flags), + p_(new details::Win32FileStreamPrivate()) { + DWORD grfMode = STGM_SHARE_DENY_NONE; + if (flags & io::OpenFileFlags::Read) { + if (flags & io::OpenFileFlags::Write) { + grfMode |= STGM_READWRITE; } else { - dwCreationDisposition = OPEN_ALWAYS; + grfMode |= STGM_READ; } } else { - dwCreationDisposition = OPEN_EXISTING; + if (flags & io::OpenFileFlags::Write) { + grfMode |= STGM_WRITE; + } else { + throw Exception(u"Stream must be readable or writable."); + } } - p_->handle = ::CreateFileW( - path_.WinCStr(), dwDesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr); - - if (p_->handle == INVALID_HANDLE_VALUE) { - throw Win32Error(u"Failed to call CreateFileW."); + if (flags & io::OpenFileFlags::Truncate) { + grfMode |= STGM_CREATE; } + + IStream* stream; + + ThrowIfFailed(SHCreateStreamOnFileEx( + path_.WinCStr(), grfMode, FILE_ATTRIBUTE_NORMAL, + flags & io::OpenFileFlags::Create ? TRUE : FALSE, NULL, &stream)); + + p_->stream_ = stream; } Win32FileStream::~Win32FileStream() { @@ -57,22 +55,21 @@ bool Win32FileStream::CanSeek() { return true; } Index Win32FileStream::Seek(Index offset, SeekOrigin origin) { CheckClosed(); - DWORD dwMoveMethod = 0; + DWORD dwOrigin = 0; if (origin == SeekOrigin::Current) { - dwMoveMethod = FILE_CURRENT; + dwOrigin = STREAM_SEEK_CUR; } else if (origin == SeekOrigin::End) { - dwMoveMethod = FILE_END; + dwOrigin = STREAM_SEEK_END; } else { - dwMoveMethod = FILE_BEGIN; + dwOrigin = STREAM_SEEK_SET; } LARGE_INTEGER n_offset; n_offset.QuadPart = offset; - LARGE_INTEGER n_new_offset; - if (!::SetFilePointerEx(p_->handle, n_offset, &n_new_offset, dwMoveMethod)) { - throw Win32Error(u"Failed to call SetFilePointerEx."); - } + ULARGE_INTEGER n_new_offset; + + ThrowIfFailed(p_->stream_->Seek(n_offset, dwOrigin, &n_new_offset)); return n_new_offset.QuadPart; } @@ -80,34 +77,40 @@ Index Win32FileStream::Seek(Index offset, SeekOrigin origin) { bool Win32FileStream::CanRead() { return true; } Index Win32FileStream::Read(std::byte* buffer, Index offset, Index size) { + if (size < 0) { + throw Exception(u"Size must be greater than 0."); + } + CheckClosed(); - DWORD dwRead; - if (::ReadFile(p_->handle, buffer + offset, size, &dwRead, nullptr) == 0) { - throw Win32Error(u"Failed to call ReadFile."); - } - return dwRead; + ULONG n_read; + ThrowIfFailed(p_->stream_->Read(buffer + offset, size, &n_read)); + return n_read; } bool Win32FileStream::CanWrite() { return true; } Index Win32FileStream::Write(const std::byte* buffer, Index offset, Index size) { + if (size < 0) { + throw Exception(u"Size must be greater than 0."); + } + CheckClosed(); - DWORD dwWritten; - if (::WriteFile(p_->handle, buffer + offset, size, &dwWritten, nullptr) == - 0) { - throw Win32Error(u"Failed to call WriteFile."); - } + ULONG n_written; + ThrowIfFailed(p_->stream_->Write(buffer + offset, size, &n_written)); - return dwWritten; + return n_written; } void Win32FileStream::Close() { if (closed_) return; - ::CloseHandle(p_->handle); + if (p_->stream_) { + p_->stream_->Release(); + p_->stream_ = nullptr; + } closed_ = true; } diff --git a/src/common/platform/win/Win32FileStreamPrivate.h b/src/common/platform/win/Win32FileStreamPrivate.h new file mode 100644 index 00000000..24492f8d --- /dev/null +++ b/src/common/platform/win/Win32FileStreamPrivate.h @@ -0,0 +1,13 @@ +#include "cru/common/platform/win/WinPreConfig.h" + +#include <objidl.h> + +namespace cru::platform::win { + +namespace details { +struct Win32FileStreamPrivate { + IStream* stream_ = nullptr; +}; +} // namespace details + +} // namespace cru::platform::win diff --git a/test/common/platform/win/Win32FileStreamTest.cpp b/test/common/platform/win/Win32FileStreamTest.cpp index cff349a2..e8b28cd6 100644 --- a/test/common/platform/win/Win32FileStreamTest.cpp +++ b/test/common/platform/win/Win32FileStreamTest.cpp @@ -19,12 +19,16 @@ TEST(Win32FileStream, Work) { String path = temp_file_path; Win32FileStream file(path, OpenFileFlags::Write | OpenFileFlags::Create); - file.Write("abc", 3); + auto write_count = file.Write("abc", 3); + ASSERT_EQ(write_count, 3); file.Close(); + ASSERT_EQ(std::filesystem::file_size(path.ToUtf8()), 3); + Win32FileStream file2(path, OpenFileFlags::Read); auto buffer = std::make_unique<std::byte[]>(3); - file2.Read(buffer.get(), 3); + auto read_count = file2.Read(buffer.get(), 3); + ASSERT_EQ(read_count, 3); ASSERT_EQ(std::string_view(reinterpret_cast<const char*>(buffer.get()), 3), "abc"); file2.Close(); |