Skip to content

Commit

Permalink
String tools: make WidenString and NarrowString work with multibyte c…
Browse files Browse the repository at this point in the history
…haracters
  • Loading branch information
WangHoi committed Jan 2, 2025
1 parent 977d540 commit c1b66de
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 7 deletions.
46 changes: 39 additions & 7 deletions Common/interface/StringTools.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,36 @@
#include "StringTools.h"
#include "ParsingTools.hpp"

#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4996) // 'This function or variable may be unsafe': mbtowc, wctomb
#endif

namespace Diligent
{

// See also: https://en.cppreference.com/w/cpp/string/multibyte/wctomb
inline std::string NarrowString(const wchar_t* WideStr, size_t Len = 0)
{
if (Len == 0)
Len = wcslen(WideStr);
else
VERIFY_EXPR(Len <= wcslen(WideStr));

std::string NarrowStr(Len, '\0');
std::string NarrowStr;
NarrowStr.reserve(Len * 4); /* MB_CUR_MAX = 4 */

const std::ctype<wchar_t>& ctfacet = std::use_facet<std::ctype<wchar_t>>(std::wstringstream().getloc());
size_t Offset = 0;
for (size_t i = 0; i < Len; ++i)
NarrowStr[i] = ctfacet.narrow(WideStr[i], 0);
{
char mb[4];
int n = wctomb(mb, WideStr[i]);

Check warning

Code scanning / PREfast

Buffer overrun while writing to 'mb'. Warning

Buffer overrun while writing to 'mb'.
if (n > 0)
{
Offset += n;
NarrowStr.append(mb, mb + n);
}
}

return NarrowStr;
}
Expand All @@ -62,18 +77,31 @@ inline std::string NarrowString(const std::wstring& WideStr)
return NarrowString(WideStr.c_str(), WideStr.length());
}

// See also: https://en.cppreference.com/w/cpp/string/multibyte/mbtowc
inline std::wstring WidenString(const char* Str, size_t Len = 0)
{
if (Len == 0)
Len = strlen(Str);
else
VERIFY_EXPR(Len <= strlen(Str));

std::wstring WideStr(Len, L'\0');
std::wstring WideStr;
WideStr.reserve(Len);

const std::ctype<wchar_t>& ctfacet = std::use_facet<std::ctype<wchar_t>>(std::wstringstream().getloc());
for (size_t i = 0; i < Len; ++i)
WideStr[i] = ctfacet.widen(Str[i]);
for (size_t Offset = 0; Offset < Len;)
{
wchar_t wc;
int n = mbtowc(&wc, Str + Offset, Len - Offset);
if (n > 0)
{
WideStr += wc;
Offset += n;
}
else
{
break;
}
}

return WideStr;
}
Expand Down Expand Up @@ -294,3 +322,7 @@ size_t GetPrintWidth(Type Num, Type Base = 10)
}

} // namespace Diligent

#ifdef _MSC_VER
# pragma warning(pop)
#endif
10 changes: 10 additions & 0 deletions Tests/DiligentCoreTest/src/Common/StringToolsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,11 @@ TEST(Common_StringTools, WidenString)

EXPECT_EQ(WidenString(std::string{""}), std::wstring{L""});
EXPECT_EQ(WidenString(std::string{"abc"}), std::wstring{L"abc"});

constexpr char locale_name[] = "en_US.UTF-8";
std::setlocale(LC_ALL, locale_name);
std::locale::global(std::locale(locale_name));
EXPECT_STREQ(WidenString("Bézier").c_str(), L"Bézier");
}

TEST(Common_StringTools, NarrowString)
Expand All @@ -250,6 +255,11 @@ TEST(Common_StringTools, NarrowString)

EXPECT_EQ(NarrowString(std::wstring{L""}), std::string{""});
EXPECT_EQ(NarrowString(std::wstring{L"abc"}), std::string{"abc"});

constexpr char locale_name[] = "en_US.UTF-8";
std::setlocale(LC_ALL, locale_name);
std::locale::global(std::locale(locale_name));
EXPECT_STREQ(NarrowString(L"Bézier").c_str(), u8"Bézier");
}

TEST(Common_StringTools, GetPrintWidth)
Expand Down

0 comments on commit c1b66de

Please sign in to comment.