diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e9b78c..0925fdc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,6 @@ if(WIN32) endif() target_sources(kabufuda PRIVATE - include/kabufuda/winsupport.hpp lib/kabufuda/AsyncIOWin32.cpp ) elseif(NX) diff --git a/include/kabufuda/AsyncIO.hpp b/include/kabufuda/AsyncIO.hpp index def8334..242dcb3 100644 --- a/include/kabufuda/AsyncIO.hpp +++ b/include/kabufuda/AsyncIO.hpp @@ -9,8 +9,7 @@ using SizeReturn = ssize_t; using SizeReturn = ssize_t; #endif #else -#include -using SizeReturn = DWORD; +using SizeReturn = unsigned long; #endif #include @@ -19,6 +18,9 @@ using SizeReturn = DWORD; #include "kabufuda/Util.hpp" namespace kabufuda { +#if _WIN32 +struct AsyncIOInner; +#endif class AsyncIO { #ifdef __SWITCH__ @@ -27,11 +29,10 @@ class AsyncIO { int m_fd = -1; std::vector> m_queue; #else - HANDLE m_fh = INVALID_HANDLE_VALUE; - std::vector> m_queue; + AsyncIOInner* m_inner; #endif void _waitForOperation(size_t qIdx) const; - size_t m_maxBlock = 0; + mutable size_t m_maxBlock = 0; public: AsyncIO() = default; @@ -41,11 +42,7 @@ public: AsyncIO& operator=(AsyncIO&& other); AsyncIO(const AsyncIO* other) = delete; AsyncIO& operator=(const AsyncIO& other) = delete; - void resizeQueue(size_t queueSz) { -#ifndef __SWITCH__ - m_queue.resize(queueSz); -#endif - } + void resizeQueue(size_t queueSz); bool asyncRead(size_t qIdx, void* buf, size_t length, off_t offset); bool asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset); ECardResult pollStatus(size_t qIdx, SizeReturn* szRet = nullptr) const; @@ -56,7 +53,7 @@ public: #elif !defined(_WIN32) explicit operator bool() const { return m_fd != -1; } #else - explicit operator bool() const { return m_fh != INVALID_HANDLE_VALUE; } + explicit operator bool() const; #endif }; diff --git a/include/kabufuda/Util.hpp b/include/kabufuda/Util.hpp index 099225e..5144e7e 100644 --- a/include/kabufuda/Util.hpp +++ b/include/kabufuda/Util.hpp @@ -11,15 +11,6 @@ #include #include #include -#else -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -#include "winsupport.hpp" #endif #include @@ -188,35 +179,10 @@ uint64_t getGCTime(); #endif #if _WIN32 -class WStringConv { - std::wstring m_sys; - -public: - explicit WStringConv(std::string_view str) { - int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), nullptr, 0); - m_sys.assign(len, L'\0'); - MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), &m_sys[0], len); - } - [[nodiscard]] std::wstring str() const { return m_sys; } - [[nodiscard]] const wchar_t* c_str() const { return m_sys.c_str(); } -}; -#endif - -inline int Stat(const char* path, Sstat* statOut) { -#if _WIN32 - size_t pos; - WStringConv wpath(path); - const wchar_t* wpathP = wpath.c_str(); - for (pos = 0; pos < 3 && wpathP[pos] != L'\0'; ++pos) {} - if (pos == 2 && wpathP[1] == L':') { - wchar_t fixPath[4] = {wpathP[0], L':', L'/', L'\0'}; - return _wstat64(fixPath, statOut); - } - return _wstat64(wpath.c_str(), statOut); +int Stat(const char* path, Sstat* statOut); #else - return stat(path, statOut); +inline int Stat(const char* path, Sstat* statOut) { return stat(path, statOut); } #endif -} /** * @brief calculateChecksum diff --git a/include/kabufuda/winsupport.hpp b/include/kabufuda/winsupport.hpp deleted file mode 100644 index b66b9e9..0000000 --- a/include/kabufuda/winsupport.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#ifndef NOMINMAX -#define NOMINMAX 1 -#endif -#include "windows.h" -#include - -#ifndef DEF_INLINE_MEMMEM -#define DEF_INLINE_MEMMEM -inline void* memmem(const void* haystack, size_t hlen, const void* needle, size_t nlen) { - int needle_first; - const uint8_t* p = static_cast(haystack); - size_t plen = hlen; - - if (!nlen) - return NULL; - - needle_first = *(unsigned char*)needle; - - while (plen >= nlen && (p = static_cast(memchr(p, needle_first, plen - nlen + 1)))) { - if (!memcmp(p, needle, nlen)) - return (void*)p; - - p++; - plen = hlen - (p - static_cast(haystack)); - } - - return NULL; -} -#endif diff --git a/lib/kabufuda/AsyncIONX.cpp b/lib/kabufuda/AsyncIONX.cpp index cf1e87c..5075115 100644 --- a/lib/kabufuda/AsyncIONX.cpp +++ b/lib/kabufuda/AsyncIONX.cpp @@ -45,4 +45,6 @@ ECardResult AsyncIO::pollStatus() const { return ECardResult::READY; } void AsyncIO::waitForCompletion() const {} +void AsyncIO::resizeQueue(size_t queueSz) {} + } // namespace kabufuda diff --git a/lib/kabufuda/AsyncIOPosix.cpp b/lib/kabufuda/AsyncIOPosix.cpp index d9c8ef0..e429108 100644 --- a/lib/kabufuda/AsyncIOPosix.cpp +++ b/lib/kabufuda/AsyncIOPosix.cpp @@ -142,4 +142,8 @@ void AsyncIO::waitForCompletion() const { const_cast(this)->m_maxBlock = 0; } +void AsyncIO::resizeQueue(size_t queueSz) { + m_queue.resize(queueSz); +} + } // namespace kabufuda diff --git a/lib/kabufuda/AsyncIOWin32.cpp b/lib/kabufuda/AsyncIOWin32.cpp index aeaa791..3e80be9 100644 --- a/lib/kabufuda/AsyncIOWin32.cpp +++ b/lib/kabufuda/AsyncIOWin32.cpp @@ -1,12 +1,47 @@ #include "kabufuda/AsyncIO.hpp" +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#ifndef NOMINMAX +#define NOMINMAX 1 +#endif +#include + #include #include namespace kabufuda { -#undef min -#undef max +class WStringConv { + std::wstring m_sys; + +public: + explicit WStringConv(std::string_view str) { + int len = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), nullptr, 0); + m_sys.assign(len, L'\0'); + MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), &m_sys[0], len); + } + [[nodiscard]] std::wstring str() const { return m_sys; } + [[nodiscard]] const wchar_t* c_str() const { return m_sys.c_str(); } +}; + +int Stat(const char* path, Sstat* statOut) { + size_t pos; + WStringConv wpath(path); + const wchar_t* wpathP = wpath.c_str(); + for (pos = 0; pos < 3 && wpathP[pos] != L'\0'; ++pos) {} + if (pos == 2 && wpathP[1] == L':') { + wchar_t fixPath[4] = {wpathP[0], L':', L'/', L'\0'}; + return _wstat64(fixPath, statOut); + } + return _wstat64(wpath.c_str(), statOut); +} + +struct AsyncIOInner { + HANDLE m_fh = INVALID_HANDLE_VALUE; + std::vector> m_queue; +}; static void ResetOverlapped(OVERLAPPED& aio, DWORD offset = 0) { aio.Internal = 0; @@ -15,60 +50,70 @@ static void ResetOverlapped(OVERLAPPED& aio, DWORD offset = 0) { aio.OffsetHigh = 0; } -AsyncIO::AsyncIO(std::string_view filename, bool truncate) { +AsyncIO::AsyncIO(std::string_view filename, bool truncate) : m_inner(new AsyncIOInner) { #if WINDOWS_STORE CREATEFILE2_EXTENDED_PARAMETERS parms = {}; parms.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); parms.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; parms.dwFileFlags = FILE_FLAG_OVERLAPPED; - m_fh = CreateFile2(filename.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, - truncate ? CREATE_ALWAYS : OPEN_ALWAYS, &parms); + m_inner->m_fh = CreateFile2(filename.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + truncate ? CREATE_ALWAYS : OPEN_ALWAYS, &parms); #else WStringConv wfilename(filename); - m_fh = CreateFileW(wfilename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, - truncate ? CREATE_ALWAYS : OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, nullptr); + m_inner->m_fh = + CreateFileW(wfilename.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + truncate ? CREATE_ALWAYS : OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, nullptr); #endif } AsyncIO::~AsyncIO() { if (*this) { - if (CancelIoEx(m_fh, nullptr)) + if (CancelIoEx(m_inner->m_fh, nullptr)) waitForCompletion(); - CloseHandle(m_fh); + CloseHandle(m_inner->m_fh); } + delete m_inner; } AsyncIO::AsyncIO(AsyncIO&& other) { - m_fh = other.m_fh; - other.m_fh = INVALID_HANDLE_VALUE; - m_queue = std::move(other.m_queue); + if (*this) { + if (CancelIoEx(m_inner->m_fh, nullptr)) + waitForCompletion(); + CloseHandle(m_inner->m_fh); + } + delete m_inner; + m_inner = other.m_inner; + other.m_inner = nullptr; m_maxBlock = other.m_maxBlock; } AsyncIO& AsyncIO::operator=(AsyncIO&& other) { if (*this) { - if (CancelIoEx(m_fh, nullptr)) + if (CancelIoEx(m_inner->m_fh, nullptr)) waitForCompletion(); - CloseHandle(m_fh); + CloseHandle(m_inner->m_fh); } - m_fh = other.m_fh; - other.m_fh = INVALID_HANDLE_VALUE; - m_queue = std::move(other.m_queue); + delete m_inner; + m_inner = other.m_inner; + other.m_inner = nullptr; m_maxBlock = other.m_maxBlock; return *this; } void AsyncIO::_waitForOperation(size_t qIdx) const { - auto& aio = const_cast(this)->m_queue[qIdx]; + if (m_inner == nullptr) { + return; + } + auto& aio = m_inner->m_queue[qIdx]; if (aio.first.hEvent == 0) return; - GetOverlappedResult(m_fh, &aio.first, &aio.second, TRUE); + GetOverlappedResult(m_inner->m_fh, &aio.first, &aio.second, TRUE); CloseHandle(aio.first.hEvent); aio.first.hEvent = 0; } bool AsyncIO::asyncRead(size_t qIdx, void* buf, size_t length, off_t offset) { - OVERLAPPED& aio = m_queue[qIdx].first; + OVERLAPPED& aio = m_inner->m_queue[qIdx].first; if (aio.hEvent) { #ifndef NDEBUG fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n"); @@ -79,12 +124,12 @@ bool AsyncIO::asyncRead(size_t qIdx, void* buf, size_t length, off_t offset) { } ResetOverlapped(aio, DWORD(offset)); m_maxBlock = std::max(m_maxBlock, qIdx + 1); - BOOL res = ReadFile(m_fh, buf, length, nullptr, &aio); + BOOL res = ReadFile(m_inner->m_fh, buf, length, nullptr, &aio); return res == TRUE || GetLastError() == ERROR_IO_PENDING; } bool AsyncIO::asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset) { - OVERLAPPED& aio = m_queue[qIdx].first; + OVERLAPPED& aio = m_inner->m_queue[qIdx].first; if (aio.hEvent) { #ifndef NDEBUG fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n"); @@ -95,18 +140,18 @@ bool AsyncIO::asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offs } ResetOverlapped(aio, DWORD(offset)); m_maxBlock = std::max(m_maxBlock, qIdx + 1); - BOOL res = WriteFile(m_fh, buf, length, nullptr, &aio); + BOOL res = WriteFile(m_inner->m_fh, buf, length, nullptr, &aio); return res == TRUE || GetLastError() == ERROR_IO_PENDING; } ECardResult AsyncIO::pollStatus(size_t qIdx, SizeReturn* szRet) const { - auto& aio = const_cast(this)->m_queue[qIdx]; + auto& aio = m_inner->m_queue[qIdx]; if (aio.first.hEvent == 0) { if (szRet) *szRet = aio.second; return ECardResult::READY; } - if (GetOverlappedResult(m_fh, &aio.first, &aio.second, FALSE)) { + if (GetOverlappedResult(m_inner->m_fh, &aio.first, &aio.second, FALSE)) { CloseHandle(aio.first.hEvent); aio.first.hEvent = 0; if (szRet) @@ -124,12 +169,11 @@ ECardResult AsyncIO::pollStatus(size_t qIdx, SizeReturn* szRet) const { ECardResult AsyncIO::pollStatus() const { ECardResult result = ECardResult::READY; - for (auto it = const_cast(this)->m_queue.begin(); - it != const_cast(this)->m_queue.begin() + m_maxBlock; ++it) { + for (auto it = m_inner->m_queue.begin(); it != m_inner->m_queue.begin() + m_maxBlock; ++it) { auto& aio = *it; if (aio.first.hEvent == 0) continue; - if (GetOverlappedResult(m_fh, &aio.first, &aio.second, FALSE)) { + if (GetOverlappedResult(m_inner->m_fh, &aio.first, &aio.second, FALSE)) { CloseHandle(aio.first.hEvent); aio.first.hEvent = 0; } else { @@ -137,21 +181,30 @@ ECardResult AsyncIO::pollStatus() const { if (result > ECardResult::BUSY) result = ECardResult::BUSY; } else { - _waitForOperation(it - m_queue.cbegin()); + _waitForOperation(it - m_inner->m_queue.cbegin()); if (result > ECardResult::IOERROR) result = ECardResult::IOERROR; } } } if (result == ECardResult::READY) - const_cast(this)->m_maxBlock = 0; + m_maxBlock = 0; return result; } void AsyncIO::waitForCompletion() const { for (size_t i = 0; i < m_maxBlock; ++i) _waitForOperation(i); - const_cast(this)->m_maxBlock = 0; + m_maxBlock = 0; } +void AsyncIO::resizeQueue(size_t queueSz) { + if (m_inner == nullptr) { + return; + } + m_inner->m_queue.resize(queueSz); +} + +AsyncIO::operator bool() const { return m_inner != nullptr && m_inner->m_fh != INVALID_HANDLE_VALUE; } + } // namespace kabufuda