unicode: fix and cleanup Windows support

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2025-06-11 09:57:30 +02:00
parent b5cc4c01a9
commit db91035b42

View File

@ -214,7 +214,7 @@ namespace stdex
// Try to convert to stack buffer first. // Try to convert to stack buffer first.
WCHAR szStackBuffer[1024 / sizeof(WCHAR)]; WCHAR szStackBuffer[1024 / sizeof(WCHAR)];
#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpMultiByteStr parameter wrong? #pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpMultiByteStr parameter wrong?
int cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer)); int cch = MultiByteToWideChar(m_from_wincp, 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer));
if (cch) { if (cch) {
// Append from stack. // Append from stack.
dst.append(reinterpret_cast<const T_to*>(szStackBuffer), count_src != SIZE_MAX ? wcsnlen(szStackBuffer, cch) : static_cast<size_t>(cch) - 1); dst.append(reinterpret_cast<const T_to*>(szStackBuffer), count_src != SIZE_MAX ? wcsnlen(szStackBuffer, cch) : static_cast<size_t>(cch) - 1);
@ -223,10 +223,10 @@ namespace stdex
DWORD dwResult = GetLastError(); DWORD dwResult = GetLastError();
if (dwResult == ERROR_INSUFFICIENT_BUFFER) { if (dwResult == ERROR_INSUFFICIENT_BUFFER) {
// Query the required output size. Allocate buffer. Then convert again. // Query the required output size. Allocate buffer. Then convert again.
cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), NULL, 0); cch = MultiByteToWideChar(m_from_wincp, 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), NULL, 0);
size_t offset = dst.size(); size_t offset = dst.size();
dst.resize(offset + static_cast<size_t>(cch)); dst.resize(offset + static_cast<size_t>(cch));
cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), &dst[offset], cch); cch = MultiByteToWideChar(m_from_wincp, 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), &dst[offset], cch);
dst.resize(offset + (count_src != SIZE_MAX ? wcsnlen(&dst[offset], cch) : static_cast<size_t>(cch) - 1)); dst.resize(offset + (count_src != SIZE_MAX ? wcsnlen(&dst[offset], cch) : static_cast<size_t>(cch) - 1));
return; return;
} }
@ -236,12 +236,12 @@ namespace stdex
#pragma warning(suppress: 4127) // Can't use precompiler #if on template arguments, using "if" makes MSVC warnings. #pragma warning(suppress: 4127) // Can't use precompiler #if on template arguments, using "if" makes MSVC warnings.
if constexpr (sizeof(T_from) == sizeof(wchar_t) && sizeof(T_to) == sizeof(char)) { if constexpr (sizeof(T_from) == sizeof(wchar_t) && sizeof(T_to) == sizeof(char)) {
stdex_assert(count_src < INT_MAX || count_src == SIZE_MAX); stdex_assert(count_src < INT_MAX || count_src == SIZE_MAX);
LPCCH lpDefaultChar = m_to_wincp == charset_id::utf8 || m_to_wincp == charset_id::utf7 ? NULL : &m_invalid; LPCCH lpDefaultChar = m_to_wincp == CP_UTF8 || m_to_wincp == CP_UTF7 ? NULL : &m_invalid;
// Try to convert to stack buffer first. // Try to convert to stack buffer first.
CHAR szStackBuffer[1024 / sizeof(CHAR)]; CHAR szStackBuffer[1024 / sizeof(CHAR)];
#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpWideCharStr parameter wrong? #pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpWideCharStr parameter wrong?
int cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, reinterpret_cast<LPCWCH>(src), static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, NULL); int cch = WideCharToMultiByte(m_to_wincp, dwFlagsWCMB, reinterpret_cast<LPCWCH>(src), static_cast<int>(count_src), szStackBuffer, _countof(szStackBuffer), lpDefaultChar, NULL);
if (cch) { if (cch) {
// Copy from stack. Be careful not to include zero terminator. // Copy from stack. Be careful not to include zero terminator.
dst.append(reinterpret_cast<const T_to*>(szStackBuffer), count_src != SIZE_MAX ? strnlen(szStackBuffer, cch) : static_cast<size_t>(cch) - 1); dst.append(reinterpret_cast<const T_to*>(szStackBuffer), count_src != SIZE_MAX ? strnlen(szStackBuffer, cch) : static_cast<size_t>(cch) - 1);
@ -250,10 +250,10 @@ namespace stdex
DWORD dwResult = GetLastError(); DWORD dwResult = GetLastError();
if (dwResult == ERROR_INSUFFICIENT_BUFFER) { if (dwResult == ERROR_INSUFFICIENT_BUFFER) {
// Query the required output size. Allocate buffer. Then convert again. // Query the required output size. Allocate buffer. Then convert again.
cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, reinterpret_cast<LPCWCH>(src), static_cast<int>(count_src), NULL, 0, lpDefaultChar, NULL); cch = WideCharToMultiByte(m_to_wincp, dwFlagsWCMB, reinterpret_cast<LPCWCH>(src), static_cast<int>(count_src), NULL, 0, lpDefaultChar, NULL);
size_t offset = dst.size(); size_t offset = dst.size();
dst.resize(offset + static_cast<size_t>(cch)); dst.resize(offset + static_cast<size_t>(cch));
cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, reinterpret_cast<LPCWCH>(src), static_cast<int>(count_src), &dst[offset], cch, lpDefaultChar, NULL); cch = WideCharToMultiByte(m_to_wincp, dwFlagsWCMB, reinterpret_cast<LPCWCH>(src), static_cast<int>(count_src), &dst[offset], cch, lpDefaultChar, NULL);
dst.resize(offset + (count_src != SIZE_MAX ? strnlen(&dst[offset], cch) : static_cast<size_t>(cch) - 1)); dst.resize(offset + (count_src != SIZE_MAX ? strnlen(&dst[offset], cch) : static_cast<size_t>(cch) - 1));
return; return;
} }
@ -263,13 +263,13 @@ namespace stdex
#pragma warning(suppress: 4127) // Can't use precompiler #if on template arguments, using "if" makes MSVC warnings. #pragma warning(suppress: 4127) // Can't use precompiler #if on template arguments, using "if" makes MSVC warnings.
if constexpr (sizeof(T_from) == sizeof(char) && sizeof(T_to) == sizeof(char)) { if constexpr (sizeof(T_from) == sizeof(char) && sizeof(T_to) == sizeof(char)) {
stdex_assert(count_src < INT_MAX || count_src == SIZE_MAX); stdex_assert(count_src < INT_MAX || count_src == SIZE_MAX);
LPCCH lpDefaultChar = m_to_wincp == charset_id::utf8 || m_to_wincp == charset_id::utf7 ? NULL : &m_invalid; LPCCH lpDefaultChar = m_to_wincp == CP_UTF8 || m_to_wincp == CP_UTF7 ? NULL : &m_invalid;
// Try to convert to stack buffer first. // Try to convert to stack buffer first.
DWORD dwResult; DWORD dwResult;
WCHAR szStackBufferMBWC[512 / sizeof(WCHAR)]; WCHAR szStackBufferMBWC[512 / sizeof(WCHAR)];
#pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpMultiByteStr parameter wrong? #pragma warning(suppress: 6387) // Testing indicates src may be NULL when count_src is also 0. Is SAL of the lpMultiByteStr parameter wrong?
int cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szStackBufferMBWC, _countof(szStackBufferMBWC)); int cch = MultiByteToWideChar(m_from_wincp, 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szStackBufferMBWC, _countof(szStackBufferMBWC));
if (cch) { if (cch) {
// Append from stack. // Append from stack.
size_t count_inter = count_src != SIZE_MAX ? wcsnlen(szStackBufferMBWC, cch) : static_cast<size_t>(cch) - 1; size_t count_inter = count_src != SIZE_MAX ? wcsnlen(szStackBufferMBWC, cch) : static_cast<size_t>(cch) - 1;
@ -278,7 +278,7 @@ namespace stdex
// Try to convert to stack buffer first. // Try to convert to stack buffer first.
CHAR szStackBufferWCMB[512 / sizeof(CHAR)]; CHAR szStackBufferWCMB[512 / sizeof(CHAR)];
#pragma warning(suppress: 6387) // Testing indicates szStackBufferMBWC may be NULL when count_inter is also 0. Is SAL of the lpWideCharStr parameter wrong? #pragma warning(suppress: 6387) // Testing indicates szStackBufferMBWC may be NULL when count_inter is also 0. Is SAL of the lpWideCharStr parameter wrong?
cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC, static_cast<int>(count_inter), szStackBufferWCMB, _countof(szStackBufferWCMB), lpDefaultChar, NULL); cch = WideCharToMultiByte(m_to_wincp, dwFlagsWCMB, szStackBufferMBWC, static_cast<int>(count_inter), szStackBufferWCMB, _countof(szStackBufferWCMB), lpDefaultChar, NULL);
if (cch) { if (cch) {
// Copy from stack. Be careful not to include zero terminator. // Copy from stack. Be careful not to include zero terminator.
dst.append(reinterpret_cast<const T_to*>(szStackBufferWCMB), strnlen(szStackBufferWCMB, cch)); dst.append(reinterpret_cast<const T_to*>(szStackBufferWCMB), strnlen(szStackBufferWCMB, cch));
@ -287,10 +287,10 @@ namespace stdex
dwResult = GetLastError(); dwResult = GetLastError();
if (dwResult == ERROR_INSUFFICIENT_BUFFER) { if (dwResult == ERROR_INSUFFICIENT_BUFFER) {
// Query the required output size. Allocate buffer. Then convert again. // Query the required output size. Allocate buffer. Then convert again.
cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC, static_cast<int>(count_inter), NULL, 0, lpDefaultChar, NULL); cch = WideCharToMultiByte(m_to_wincp, dwFlagsWCMB, szStackBufferMBWC, static_cast<int>(count_inter), NULL, 0, lpDefaultChar, NULL);
size_t offset = dst.size(); size_t offset = dst.size();
dst.resize(offset + cch); dst.resize(offset + cch);
cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, szStackBufferMBWC, static_cast<int>(count_inter), &dst[offset], cch, lpDefaultChar, NULL); cch = WideCharToMultiByte(m_to_wincp, dwFlagsWCMB, szStackBufferMBWC, static_cast<int>(count_inter), &dst[offset], cch, lpDefaultChar, NULL);
dst.resize(offset + strnlen(&dst[offset], cch)); dst.resize(offset + strnlen(&dst[offset], cch));
return; return;
} }
@ -299,16 +299,16 @@ namespace stdex
dwResult = GetLastError(); dwResult = GetLastError();
if (dwResult == ERROR_INSUFFICIENT_BUFFER) { if (dwResult == ERROR_INSUFFICIENT_BUFFER) {
// Query the required output size. Allocate buffer. Then convert again. // Query the required output size. Allocate buffer. Then convert again.
cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), NULL, 0); cch = MultiByteToWideChar(m_from_wincp, 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), NULL, 0);
std::unique_ptr<WCHAR[]> szBufferMBWC(new WCHAR[cch]); std::unique_ptr<WCHAR[]> szBufferMBWC(new WCHAR[cch]);
cch = MultiByteToWideChar(static_cast<UINT>(m_from_wincp), 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szBufferMBWC.get(), cch); cch = MultiByteToWideChar(m_from_wincp, 0, reinterpret_cast<LPCCH>(src), static_cast<int>(count_src), szBufferMBWC.get(), cch);
size_t count_inter = count_src != SIZE_MAX ? wcsnlen(szBufferMBWC.get(), cch) : static_cast<size_t>(cch) - 1; size_t count_inter = count_src != SIZE_MAX ? wcsnlen(szBufferMBWC.get(), cch) : static_cast<size_t>(cch) - 1;
// Query the required output size. Allocate buffer. Then convert again. // Query the required output size. Allocate buffer. Then convert again.
cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, szBufferMBWC.get(), static_cast<int>(count_inter), NULL, 0, lpDefaultChar, NULL); cch = WideCharToMultiByte(m_to_wincp, dwFlagsWCMB, szBufferMBWC.get(), static_cast<int>(count_inter), NULL, 0, lpDefaultChar, NULL);
size_t offset = dst.size(); size_t offset = dst.size();
dst.resize(offset + cch); dst.resize(offset + cch);
cch = WideCharToMultiByte(static_cast<UINT>(m_to_wincp), dwFlagsWCMB, szBufferMBWC.get(), static_cast<int>(count_inter), &dst[offset], cch, lpDefaultChar, NULL); cch = WideCharToMultiByte(m_to_wincp, dwFlagsWCMB, szBufferMBWC.get(), static_cast<int>(count_inter), &dst[offset], cch, lpDefaultChar, NULL);
dst.resize(offset + strnlen(&dst[offset], cch)); dst.resize(offset + strnlen(&dst[offset], cch));
return; return;
} }