lib/icu/Compare: add Windows implementation

Using CompareStringEx() and FindNLSStringEx().

Implements a missing piece for
https://github.com/MusicPlayerDaemon/MPD/issues/820
This commit is contained in:
Max Kellermann 2020-04-22 19:43:29 +02:00
parent f3fd2eb618
commit 8f00dbea45
2 changed files with 60 additions and 0 deletions

View File

@ -22,6 +22,11 @@
#include "util/StringAPI.hxx" #include "util/StringAPI.hxx"
#include "config.h" #include "config.h"
#ifdef _WIN32
#include "Win32.hxx"
#include <windows.h>
#endif
#include <string.h> #include <string.h>
#ifdef HAVE_ICU_CASE_FOLD #ifdef HAVE_ICU_CASE_FOLD
@ -29,6 +34,17 @@
IcuCompare::IcuCompare(const char *_needle) noexcept IcuCompare::IcuCompare(const char *_needle) noexcept
:needle(IcuCaseFold(_needle)) {} :needle(IcuCaseFold(_needle)) {}
#elif defined(_WIN32)
IcuCompare::IcuCompare(const char *_needle) noexcept
:needle(nullptr)
{
try {
needle = MultiByteToWideChar(CP_UTF8, _needle);
} catch (...) {
}
}
#else #else
IcuCompare::IcuCompare(const char *_needle) noexcept IcuCompare::IcuCompare(const char *_needle) noexcept
@ -41,6 +57,22 @@ IcuCompare::operator==(const char *haystack) const noexcept
{ {
#ifdef HAVE_ICU_CASE_FOLD #ifdef HAVE_ICU_CASE_FOLD
return StringIsEqual(IcuCaseFold(haystack).c_str(), needle.c_str()); 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 #else
return strcasecmp(haystack, needle.c_str()); return strcasecmp(haystack, needle.c_str());
#endif #endif
@ -52,6 +84,24 @@ IcuCompare::IsIn(const char *haystack) const noexcept
#ifdef HAVE_ICU_CASE_FOLD #ifdef HAVE_ICU_CASE_FOLD
return StringFind(IcuCaseFold(haystack).c_str(), return StringFind(IcuCaseFold(haystack).c_str(),
needle.c_str()) != nullptr; 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) #elif defined(HAVE_STRCASESTR)
return strcasestr(haystack, needle.c_str()) != nullptr; return strcasestr(haystack, needle.c_str()) != nullptr;
#else #else

View File

@ -23,13 +23,23 @@
#include "util/Compiler.h" #include "util/Compiler.h"
#include "util/AllocatedString.hxx" #include "util/AllocatedString.hxx"
#ifdef _WIN32
#include <wchar.h>
#endif
/** /**
* This class can compare one string ("needle") with lots of other * This class can compare one string ("needle") with lots of other
* strings ("haystacks") efficiently, ignoring case. With some * strings ("haystacks") efficiently, ignoring case. With some
* configurations, it can prepare a case-folded version of the needle. * configurations, it can prepare a case-folded version of the needle.
*/ */
class IcuCompare { class IcuCompare {
#ifdef _WIN32
/* Windows API functions work with wchar_t strings, so let's
cache the MultiByteToWideChar() result for performance */
AllocatedString<wchar_t> needle;
#else
AllocatedString<> needle; AllocatedString<> needle;
#endif
public: public:
IcuCompare():needle(nullptr) {} IcuCompare():needle(nullptr) {}