From 55560fbf21128cc8e89e2735319410766af7852f Mon Sep 17 00:00:00 2001 From: Vasili Galka Date: Mon, 12 Mar 2018 14:43:29 +0200 Subject: [PATCH 1/3] Fixed UTF8/16 converters to support empty string input Previously an exception was thrown since Win32 WideCharToMultiByte API returns error on zero-length input. --- include/fmt/format.cc | 18 ++++++++++++++++-- test/util-test.cc | 14 ++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/include/fmt/format.cc b/include/fmt/format.cc index 429657fb..6da96f71 100644 --- a/include/fmt/format.cc +++ b/include/fmt/format.cc @@ -280,9 +280,16 @@ const uint64_t internal::basic_data::POWERS_OF_10_64[] = { FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) { static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; - if (s.size() > INT_MAX) + if (s.size() > INT_MAX || s.data() == nullptr) FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG)); int s_size = static_cast(s.size()); + if (s_size == 0) // MultiByteToWideChar does not support zero length, handle separately + { + buffer_.resize(1); + buffer_[0] = 0; + return; + } + int length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); if (length == 0) @@ -303,9 +310,16 @@ FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) { } FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) { - if (s.size() > INT_MAX) + if (s.size() > INT_MAX || s.data() == nullptr) return ERROR_INVALID_PARAMETER; int s_size = static_cast(s.size()); + if (s_size == 0) // MultiByteToWideChar does not support zero length, handle separately + { + buffer_.resize(1); + buffer_[0] = 0; + return 0; + } + int length = WideCharToMultiByte( CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); if (length == 0) diff --git a/test/util-test.cc b/test/util-test.cc index 97dabfbb..c9db1ae1 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -665,6 +665,13 @@ TEST(UtilTest, UTF16ToUTF8) { EXPECT_EQ(s.size(), u.size()); } +TEST(UtilTest, UTF16ToUTF8EmptyString) { + std::string s = ""; + fmt::internal::UTF16ToUTF8 u(L""); + EXPECT_EQ(s, u.str()); + EXPECT_EQ(s.size(), u.size()); +} + TEST(UtilTest, UTF8ToUTF16) { std::string s = "лошадка"; fmt::internal::utf8_to_utf16 u(s.c_str()); @@ -672,6 +679,13 @@ TEST(UtilTest, UTF8ToUTF16) { EXPECT_EQ(7, u.size()); } +TEST(UtilTest, UTF8ToUTF16EmptyString) { + std::string s = ""; + fmt::internal::UTF8ToUTF16 u(s.c_str()); + EXPECT_EQ(L"", u.str()); + EXPECT_EQ(s.size(), u.size()); +} + template void check_utf_conversion_error( const char *message, From 1c3008393642c726d3a261cdad5424fdc911508f Mon Sep 17 00:00:00 2001 From: Vasili Galka Date: Mon, 12 Mar 2018 16:05:58 +0200 Subject: [PATCH 2/3] Fix build, match renames on master vs 4.1.0 branch --- test/util-test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/util-test.cc b/test/util-test.cc index c9db1ae1..5073dcf7 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -667,7 +667,7 @@ TEST(UtilTest, UTF16ToUTF8) { TEST(UtilTest, UTF16ToUTF8EmptyString) { std::string s = ""; - fmt::internal::UTF16ToUTF8 u(L""); + fmt::internal::utf16_to_utf8 u(L""); EXPECT_EQ(s, u.str()); EXPECT_EQ(s.size(), u.size()); } @@ -681,7 +681,7 @@ TEST(UtilTest, UTF8ToUTF16) { TEST(UtilTest, UTF8ToUTF16EmptyString) { std::string s = ""; - fmt::internal::UTF8ToUTF16 u(s.c_str()); + fmt::internal::utf8_to_utf16 u(s.c_str()); EXPECT_EQ(L"", u.str()); EXPECT_EQ(s.size(), u.size()); } From d37348ee06000d5e21dec290db339d8a4b0ab5d0 Mon Sep 17 00:00:00 2001 From: Vasili Galka Date: Tue, 13 Mar 2018 14:46:39 +0200 Subject: [PATCH 3/3] Code style adjustment --- include/fmt/format.cc | 18 ++++++++---------- test/util-test.cc | 16 ++++++++-------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/include/fmt/format.cc b/include/fmt/format.cc index 6da96f71..0eddaf8c 100644 --- a/include/fmt/format.cc +++ b/include/fmt/format.cc @@ -283,11 +283,10 @@ FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) { if (s.size() > INT_MAX || s.data() == nullptr) FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG)); int s_size = static_cast(s.size()); - if (s_size == 0) // MultiByteToWideChar does not support zero length, handle separately - { - buffer_.resize(1); - buffer_[0] = 0; - return; + if (s_size == 0) { // MultiByteToWideChar does not support zero length, handle separately + buffer_.resize(1); + buffer_[0] = 0; + return; } int length = MultiByteToWideChar( @@ -313,11 +312,10 @@ FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) { if (s.size() > INT_MAX || s.data() == nullptr) return ERROR_INVALID_PARAMETER; int s_size = static_cast(s.size()); - if (s_size == 0) // MultiByteToWideChar does not support zero length, handle separately - { - buffer_.resize(1); - buffer_[0] = 0; - return 0; + if (s_size == 0) { // MultiByteToWideChar does not support zero length, handle separately + buffer_.resize(1); + buffer_[0] = 0; + return 0; } int length = WideCharToMultiByte( diff --git a/test/util-test.cc b/test/util-test.cc index 5073dcf7..11957655 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -666,10 +666,10 @@ TEST(UtilTest, UTF16ToUTF8) { } TEST(UtilTest, UTF16ToUTF8EmptyString) { - std::string s = ""; - fmt::internal::utf16_to_utf8 u(L""); - EXPECT_EQ(s, u.str()); - EXPECT_EQ(s.size(), u.size()); + std::string s = ""; + fmt::internal::utf16_to_utf8 u(L""); + EXPECT_EQ(s, u.str()); + EXPECT_EQ(s.size(), u.size()); } TEST(UtilTest, UTF8ToUTF16) { @@ -680,10 +680,10 @@ TEST(UtilTest, UTF8ToUTF16) { } TEST(UtilTest, UTF8ToUTF16EmptyString) { - std::string s = ""; - fmt::internal::utf8_to_utf16 u(s.c_str()); - EXPECT_EQ(L"", u.str()); - EXPECT_EQ(s.size(), u.size()); + std::string s = ""; + fmt::internal::utf8_to_utf16 u(s.c_str()); + EXPECT_EQ(L"", u.str()); + EXPECT_EQ(s.size(), u.size()); } template