Fix #11402: Make string filter locale-aware.
This commit is contained in:
@@ -336,6 +336,31 @@ int MacOSStringCompare(std::string_view s1, std::string_view s2)
|
||||
return (int)CFStringCompareWithOptionsAndLocale(cf1.get(), cf2.get(), CFRangeMake(0, CFStringGetLength(cf1.get())), flags, _osx_locale.get()) + 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search if a string is contained in another string using the current locale.
|
||||
*
|
||||
* @param str String to search in.
|
||||
* @param value String to search for.
|
||||
* @param case_insensitive Search case-insensitive.
|
||||
* @return 1 if value was found, 0 if it was not found, or -1 if not supported by the OS.
|
||||
*/
|
||||
int MacOSStringContains(const std::string_view str, const std::string_view value, bool case_insensitive)
|
||||
{
|
||||
static bool supported = MacOSVersionIsAtLeast(10, 5, 0);
|
||||
if (!supported) return -1;
|
||||
|
||||
CFStringCompareFlags flags = kCFCompareLocalized | kCFCompareWidthInsensitive;
|
||||
if (case_insensitive) flags |= kCFCompareCaseInsensitive;
|
||||
|
||||
CFAutoRelease<CFStringRef> cf_str(CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)str.data(), str.size(), kCFStringEncodingUTF8, false));
|
||||
CFAutoRelease<CFStringRef> cf_value(CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)value.data(), value.size(), kCFStringEncodingUTF8, false));
|
||||
|
||||
/* If any CFString could not be created (e.g., due to UTF8 invalid chars), return OS unsupported functionality */
|
||||
if (cf_str == nullptr || cf_value == nullptr) return -1;
|
||||
|
||||
return CFStringFindWithOptionsAndLocale(cf_str.get(), cf_value.get(), CFRangeMake(0, CFStringGetLength(cf_str.get())), flags, _osx_locale.get(), nullptr) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/* virtual */ void OSXStringIterator::SetString(const char *s)
|
||||
{
|
||||
|
@@ -84,6 +84,7 @@ public:
|
||||
void MacOSResetScriptCache(FontSize size);
|
||||
void MacOSSetCurrentLocaleName(const char *iso_code);
|
||||
int MacOSStringCompare(std::string_view s1, std::string_view s2);
|
||||
int MacOSStringContains(const std::string_view str, const std::string_view value, bool case_insensitive);
|
||||
|
||||
void MacOSRegisterExternalFont(const char *file_path);
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#define NO_SHOBJIDL_SORTDIRECTION // Avoid multiple definition of SORT_ASCENDING
|
||||
#include <shlobj.h> /* SHGetFolderPath */
|
||||
#include <shellapi.h>
|
||||
#include <WinNls.h>
|
||||
#include "win32.h"
|
||||
#include "../../fios.h"
|
||||
#include "../../core/alloc_func.hpp"
|
||||
@@ -601,6 +602,44 @@ int OTTDStringCompare(std::string_view s1, std::string_view s2)
|
||||
return CompareString(MAKELCID(_current_language->winlangid, SORT_DEFAULT), NORM_IGNORECASE, s1_buf, -1, s2_buf, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search if a string is contained in another string using the current locale.
|
||||
*
|
||||
* @param str String to search in.
|
||||
* @param value String to search for.
|
||||
* @param case_insensitive Search case-insensitive.
|
||||
* @return 1 if value was found, 0 if it was not found, or -1 if not supported by the OS.
|
||||
*/
|
||||
int Win32StringContains(const std::string_view str, const std::string_view value, bool case_insensitive)
|
||||
{
|
||||
typedef int (WINAPI *PFNFINDNLSSTRINGEX)(LPCWSTR, DWORD, LPCWSTR, int, LPCWSTR, int, LPINT, LPNLSVERSIONINFO, LPVOID, LPARAM);
|
||||
static PFNFINDNLSSTRINGEX _FindNLSStringEx = nullptr;
|
||||
static bool first_time = true;
|
||||
|
||||
if (first_time) {
|
||||
static DllLoader _kernel32(L"Kernel32.dll");
|
||||
_FindNLSStringEx = _kernel32.GetProcAddress("FindNLSStringEx");
|
||||
first_time = false;
|
||||
}
|
||||
|
||||
if (_FindNLSStringEx != nullptr) {
|
||||
int len_str = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0);
|
||||
int len_value = MultiByteToWideChar(CP_UTF8, 0, value.data(), (int)value.size(), nullptr, 0);
|
||||
|
||||
if (len_str != 0 && len_value != 0) {
|
||||
std::wstring str_str(len_str, L'\0'); // len includes terminating null
|
||||
std::wstring str_value(len_value, L'\0');
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), str_str.data(), len_str);
|
||||
MultiByteToWideChar(CP_UTF8, 0, value.data(), (int)value.size(), str_value.data(), len_value);
|
||||
|
||||
return _FindNLSStringEx(_cur_iso_locale, FIND_FROMSTART | (case_insensitive ? LINGUISTIC_IGNORECASE : 0), str_str.data(), -1, str_value.data(), -1, nullptr, nullptr, nullptr, 0) >= 0 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1; // Failure indication.
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* Based on code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
|
||||
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||
|
@@ -60,5 +60,6 @@ wchar_t *convert_to_fs(const std::string_view name, wchar_t *utf16_buf, size_t b
|
||||
|
||||
void Win32SetCurrentLocaleName(const char *iso_code);
|
||||
int OTTDStringCompare(std::string_view s1, std::string_view s2);
|
||||
int Win32StringContains(const std::string_view str, const std::string_view value, bool case_insensitive);
|
||||
|
||||
#endif /* WIN32_H */
|
||||
|
Reference in New Issue
Block a user