diff --git a/src/lib/icu/Compare.cxx b/src/lib/icu/Compare.cxx index 5af297404..b0c817897 100644 --- a/src/lib/icu/Compare.cxx +++ b/src/lib/icu/Compare.cxx @@ -22,6 +22,11 @@ #include "util/StringAPI.hxx" #include "config.h" +#ifdef _WIN32 +#include "Win32.hxx" +#include +#endif + #include #ifdef HAVE_ICU_CASE_FOLD @@ -29,6 +34,17 @@ IcuCompare::IcuCompare(const char *_needle) noexcept :needle(IcuCaseFold(_needle)) {} +#elif defined(_WIN32) + +IcuCompare::IcuCompare(const char *_needle) noexcept + :needle(nullptr) +{ + try { + needle = MultiByteToWideChar(CP_UTF8, _needle); + } catch (...) { + } +} + #else IcuCompare::IcuCompare(const char *_needle) noexcept @@ -41,6 +57,22 @@ IcuCompare::operator==(const char *haystack) const noexcept { #ifdef HAVE_ICU_CASE_FOLD return StringIsEqual(IcuCaseFold(haystack).c_str(), needle.c_str()); +#elif defined(_WIN32) + if (needle.IsNull()) + /* the MultiByteToWideChar() call in the constructor + has failed, so let's always fail the comparison */ + return false; + + try { + auto w_haystack = MultiByteToWideChar(CP_UTF8, haystack); + return CompareStringEx(LOCALE_NAME_INVARIANT, + NORM_IGNORECASE, + w_haystack.c_str(), -1, + needle.c_str(), -1, + nullptr, nullptr, 0) == CSTR_EQUAL; + } catch (...) { + return false; + } #else return strcasecmp(haystack, needle.c_str()); #endif @@ -52,6 +84,24 @@ IcuCompare::IsIn(const char *haystack) const noexcept #ifdef HAVE_ICU_CASE_FOLD return StringFind(IcuCaseFold(haystack).c_str(), needle.c_str()) != nullptr; +#elif defined(_WIN32) + if (needle.IsNull()) + /* the MultiByteToWideChar() call in the constructor + has failed, so let's always fail the comparison */ + return false; + + try { + auto w_haystack = MultiByteToWideChar(CP_UTF8, haystack); + return FindNLSStringEx(LOCALE_NAME_INVARIANT, + FIND_FROMSTART|NORM_IGNORECASE, + w_haystack.c_str(), -1, + needle.c_str(), -1, + nullptr, + nullptr, nullptr, 0) >= 0; + } catch (...) { + /* MultiByteToWideChar() has failed */ + return false; + } #elif defined(HAVE_STRCASESTR) return strcasestr(haystack, needle.c_str()) != nullptr; #else diff --git a/src/lib/icu/Compare.hxx b/src/lib/icu/Compare.hxx index ee079a56f..39522b5d5 100644 --- a/src/lib/icu/Compare.hxx +++ b/src/lib/icu/Compare.hxx @@ -23,13 +23,23 @@ #include "util/Compiler.h" #include "util/AllocatedString.hxx" +#ifdef _WIN32 +#include +#endif + /** * This class can compare one string ("needle") with lots of other * strings ("haystacks") efficiently, ignoring case. With some * configurations, it can prepare a case-folded version of the needle. */ class IcuCompare { +#ifdef _WIN32 + /* Windows API functions work with wchar_t strings, so let's + cache the MultiByteToWideChar() result for performance */ + AllocatedString needle; +#else AllocatedString<> needle; +#endif public: IcuCompare():needle(nullptr) {}