diff options
Diffstat (limited to 'src/base/platform/win')
-rw-r--r-- | src/base/platform/win/BridgeComStream.cpp | 106 | ||||
-rw-r--r-- | src/base/platform/win/BrigdeComStream.h | 43 | ||||
-rw-r--r-- | src/base/platform/win/ComAutoInit.cpp | 15 | ||||
-rw-r--r-- | src/base/platform/win/DebugLogTarget.cpp | 10 | ||||
-rw-r--r-- | src/base/platform/win/Exception.cpp | 38 | ||||
-rw-r--r-- | src/base/platform/win/StreamConvert.cpp | 28 | ||||
-rw-r--r-- | src/base/platform/win/Win32FileStream.cpp | 122 | ||||
-rw-r--r-- | src/base/platform/win/Win32FileStreamPrivate.h | 13 |
8 files changed, 375 insertions, 0 deletions
diff --git a/src/base/platform/win/BridgeComStream.cpp b/src/base/platform/win/BridgeComStream.cpp new file mode 100644 index 00000000..c6987ab2 --- /dev/null +++ b/src/base/platform/win/BridgeComStream.cpp @@ -0,0 +1,106 @@ +#include "BrigdeComStream.h" +#include "cru/base/io/Stream.h" + +namespace cru::platform::win { +BridgeComStream::BridgeComStream(io::Stream *stream) + : stream_(stream), ref_count_(1) {} + +BridgeComStream::~BridgeComStream() {} + +ULONG BridgeComStream::AddRef() { return ++ref_count_; } + +ULONG BridgeComStream::Release() { + --ref_count_; + + if (ref_count_ == 0) { + delete this; + return 0; + } + + return ref_count_; +} + +HRESULT BridgeComStream::QueryInterface(const IID &riid, void **ppvObject) { + if (riid == IID_IStream) { + *ppvObject = static_cast<IStream *>(this); + AddRef(); + return S_OK; + } else if (riid == IID_ISequentialStream) { + *ppvObject = static_cast<ISequentialStream *>(this); + AddRef(); + return S_OK; + } else if (riid == IID_IUnknown) { + *ppvObject = static_cast<IUnknown *>(this); + AddRef(); + return S_OK; + } else { + return E_NOINTERFACE; + } +} + +HRESULT BridgeComStream::Read(void *pv, ULONG cb, ULONG *pcbRead) { + *pcbRead = stream_->Read(static_cast<std::byte *>(pv), cb); + return S_OK; +} + +HRESULT BridgeComStream::Write(const void *pv, ULONG cb, ULONG *pcbWritten) { + *pcbWritten = stream_->Write(static_cast<const std::byte *>(pv), cb); + return S_OK; +} + +HRESULT BridgeComStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, + ULARGE_INTEGER *plibNewPosition) { + io::Stream::SeekOrigin so; + + switch (dwOrigin) { + case STREAM_SEEK_SET: + so = io::Stream::SeekOrigin::Begin; + break; + case STREAM_SEEK_CUR: + so = io::Stream::SeekOrigin::Current; + break; + case STREAM_SEEK_END: + so = io::Stream::SeekOrigin::End; + break; + default: + return STG_E_INVALIDFUNCTION; + }; + + plibNewPosition->QuadPart = stream_->Seek(dlibMove.QuadPart, so); + return S_OK; +} + +HRESULT BridgeComStream::SetSize(ULARGE_INTEGER libNewSize) { + return E_NOTIMPL; +} + +HRESULT BridgeComStream::CopyTo(IStream *pstm, ULARGE_INTEGER cb, + ULARGE_INTEGER *pcbRead, + ULARGE_INTEGER *pcbWritten) { + return E_NOTIMPL; +} + +HRESULT BridgeComStream::Commit(DWORD grfCommitFlags) { return S_OK; } + +HRESULT BridgeComStream::Revert() { return S_OK; } + +HRESULT BridgeComStream::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, + DWORD dwLockType) { + return S_OK; +} + +HRESULT BridgeComStream::UnlockRegion(ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, DWORD dwLockType) { + return S_OK; +} + +HRESULT BridgeComStream::Stat(STATSTG *pstatstg, DWORD grfStatFlag) { + return E_NOTIMPL; +} + +HRESULT BridgeComStream::Clone(IStream **ppstm) { + *ppstm = new BridgeComStream(stream_); + return S_OK; +} + +} // namespace cru::platform::win diff --git a/src/base/platform/win/BrigdeComStream.h b/src/base/platform/win/BrigdeComStream.h new file mode 100644 index 00000000..1621b567 --- /dev/null +++ b/src/base/platform/win/BrigdeComStream.h @@ -0,0 +1,43 @@ +#pragma once +#include "cru/base/platform/win/WinPreConfig.h" + +#include "cru/base/io/Stream.h" + +#include <objidlbase.h> + +namespace cru::platform::win { +class BridgeComStream : public IStream { + public: + explicit BridgeComStream(io::Stream* stream); + + CRU_DELETE_COPY(BridgeComStream) + CRU_DELETE_MOVE(BridgeComStream) + + ~BridgeComStream(); + + public: + ULONG AddRef() override; + ULONG Release() override; + HRESULT QueryInterface(REFIID riid, void** ppvObject) override; + + HRESULT Read(void* pv, ULONG cb, ULONG* pcbRead) override; + HRESULT Write(const void* pv, ULONG cb, ULONG* pcbWritten) override; + HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, + ULARGE_INTEGER* plibNewPosition) override; + HRESULT SetSize(ULARGE_INTEGER libNewSize) override; + HRESULT CopyTo(IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, + ULARGE_INTEGER* pcbWritten) override; + HRESULT Commit(DWORD grfCommitFlags) override; + HRESULT Revert() override; + HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, + DWORD dwLockType) override; + HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, + DWORD dwLockType) override; + HRESULT Stat(STATSTG* pstatstg, DWORD grfStatFlag) override; + HRESULT Clone(IStream** ppstm) override; + + private: + io::Stream* stream_; + ULONG ref_count_; +}; +} // namespace cru::platform::win diff --git a/src/base/platform/win/ComAutoInit.cpp b/src/base/platform/win/ComAutoInit.cpp new file mode 100644 index 00000000..548a7bea --- /dev/null +++ b/src/base/platform/win/ComAutoInit.cpp @@ -0,0 +1,15 @@ +#include "cru/base/platform/win/ComAutoInit.h" +#include "cru/base/platform/win/Exception.h" + +#include <combaseapi.h> + +namespace cru::platform::win { +ComAutoInit::ComAutoInit() { + const auto hresult = ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + if (FAILED(hresult)) { + throw HResultError(hresult, "Failed to call CoInitializeEx."); + } +} + +ComAutoInit::~ComAutoInit() { ::CoUninitialize(); } +} // namespace cru::platform::win diff --git a/src/base/platform/win/DebugLogTarget.cpp b/src/base/platform/win/DebugLogTarget.cpp new file mode 100644 index 00000000..89bd3d19 --- /dev/null +++ b/src/base/platform/win/DebugLogTarget.cpp @@ -0,0 +1,10 @@ +#include "cru/base/platform/win/DebugLogTarget.h" + +namespace cru::platform::win { +void WinDebugLogTarget::Write(::cru::log::LogLevel level, StringView s) { + CRU_UNUSED(level) + + String m = s.ToString(); + ::OutputDebugStringW(reinterpret_cast<const wchar_t*>(m.c_str())); +} +} // namespace cru::platform::win diff --git a/src/base/platform/win/Exception.cpp b/src/base/platform/win/Exception.cpp new file mode 100644 index 00000000..5ff6146b --- /dev/null +++ b/src/base/platform/win/Exception.cpp @@ -0,0 +1,38 @@ +#include "cru/base/platform/win/Exception.h" +#include "cru/base/Format.h" + +#include <optional> + +namespace cru::platform::win { + +inline String HResultMakeMessage(HRESULT h_result, + std::optional<String> message) { + if (message.has_value()) + return Format(u"HRESULT: {}. Message: {}", h_result, message->WinCStr()); + else + return Format(u"HRESULT: {}.", h_result); +} + +HResultError::HResultError(HRESULT h_result) + : PlatformException(HResultMakeMessage(h_result, std::nullopt)), + h_result_(h_result) {} + +HResultError::HResultError(HRESULT h_result, + std::string_view additional_message) + : PlatformException(HResultMakeMessage( + h_result, String::FromUtf8(additional_message.data(), + additional_message.size()))), + h_result_(h_result) {} + +inline String Win32MakeMessage(DWORD error_code, String message) { + return Format(u"Last error code: {}.\nMessage: {}\n", error_code, + message.WinCStr()); +} + +Win32Error::Win32Error(String message) + : Win32Error(::GetLastError(), message) {} + +Win32Error::Win32Error(DWORD error_code, String message) + : PlatformException(Win32MakeMessage(error_code, message)), + error_code_(error_code) {} +} // namespace cru::platform::win diff --git a/src/base/platform/win/StreamConvert.cpp b/src/base/platform/win/StreamConvert.cpp new file mode 100644 index 00000000..f7a0537c --- /dev/null +++ b/src/base/platform/win/StreamConvert.cpp @@ -0,0 +1,28 @@ +#include "cru/base/platform/win/StreamConvert.h" +#include "BrigdeComStream.h" +#include "Win32FileStreamPrivate.h" +#include "cru/base/Exception.h" +#include "cru/base/io/MemoryStream.h" +#include "cru/base/io/OpenFileFlag.h" +#include "cru/base/platform/win/ComAutoInit.h" +#include "cru/base/platform/win/Exception.h" +#include "cru/base/platform/win/Win32FileStream.h" + +#include <shlwapi.h> +#include <winnt.h> + +namespace cru::platform::win { +IStream* ConvertStreamToComStream(io::Stream* stream) { + static ComAutoInit com_auto_init; + + if (auto memory_stream = dynamic_cast<io::MemoryStream*>(stream)) { + return SHCreateMemStream( + reinterpret_cast<const BYTE*>(memory_stream->GetBuffer()), + memory_stream->GetSize()); + } else if (auto file_stream = dynamic_cast<Win32FileStream*>(stream)) { + return file_stream->GetPrivate_()->stream_; + } else { + return new BridgeComStream(stream); + } +} +} // namespace cru::platform::win diff --git a/src/base/platform/win/Win32FileStream.cpp b/src/base/platform/win/Win32FileStream.cpp new file mode 100644 index 00000000..54e6ae45 --- /dev/null +++ b/src/base/platform/win/Win32FileStream.cpp @@ -0,0 +1,122 @@ +#include "cru/base/platform/win/Win32FileStream.h" + +#include "Win32FileStreamPrivate.h" +#include "cru/base/io/OpenFileFlag.h" +#include "cru/base/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; + +Win32FileStream::Win32FileStream(String path, OpenFileFlag flags) + : 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 { + grfMode |= STGM_READ; + } + } else { + if (flags & io::OpenFileFlags::Write) { + grfMode |= STGM_WRITE; + } else { + throw Exception(u"Stream must be readable or writable."); + } + } + + 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() { + Close(); + delete p_; +} + +bool Win32FileStream::CanSeek() { return true; } + +Index Win32FileStream::Seek(Index offset, SeekOrigin origin) { + CheckClosed(); + + DWORD dwOrigin = 0; + + if (origin == SeekOrigin::Current) { + dwOrigin = STREAM_SEEK_CUR; + } else if (origin == SeekOrigin::End) { + dwOrigin = STREAM_SEEK_END; + } else { + dwOrigin = STREAM_SEEK_SET; + } + + LARGE_INTEGER n_offset; + n_offset.QuadPart = offset; + ULARGE_INTEGER n_new_offset; + + ThrowIfFailed(p_->stream_->Seek(n_offset, dwOrigin, &n_new_offset)); + + return n_new_offset.QuadPart; +} + +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(); + + 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(); + + ULONG n_written; + ThrowIfFailed(p_->stream_->Write(buffer + offset, size, &n_written)); + + return n_written; +} + +void Win32FileStream::Close() { + if (closed_) return; + + if (p_->stream_) { + p_->stream_->Release(); + p_->stream_ = nullptr; + } + + closed_ = true; +} + +void Win32FileStream::CheckClosed() { + if (closed_) throw Exception(u"Stream is closed."); +} + +} // namespace cru::platform::win diff --git a/src/base/platform/win/Win32FileStreamPrivate.h b/src/base/platform/win/Win32FileStreamPrivate.h new file mode 100644 index 00000000..718f8d9a --- /dev/null +++ b/src/base/platform/win/Win32FileStreamPrivate.h @@ -0,0 +1,13 @@ +#include "cru/base/platform/win/WinPreConfig.h" + +#include <objidl.h> + +namespace cru::platform::win { + +namespace details { +struct Win32FileStreamPrivate { + IStream* stream_ = nullptr; +}; +} // namespace details + +} // namespace cru::platform::win |