diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2023-02-21 17:55:26 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2023-02-24 17:50:14 +0000 |
commit | d7fd46b5155bda021b09faecdefba26f6a59e997 (patch) | |
tree | 46f2866cdc5dd62319b08eee61d47dbb35fbc2cd /sal/osl | |
parent | e403bf00af7767060f624077840921ceab04895d (diff) |
Simplify osl_getTextEncodingFromLocale on Windows
Drop all the complexity of thread-local storage used only to make
EnumSystemLocalesW thread-safe. Just create a BCP47 tag, and use
GetLocaleInfoEx to get the codepage.
Also use locale name API in imp_getProcessLocale, and avoid the
deprecated LCID API.
Change-Id: I223564cc6d2cc919b0e5aadda1c12beee21e49f9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147625
Tested-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'sal/osl')
-rw-r--r-- | sal/osl/w32/nlsupport.cxx | 162 |
1 files changed, 33 insertions, 129 deletions
diff --git a/sal/osl/w32/nlsupport.cxx b/sal/osl/w32/nlsupport.cxx index f27b97aa7101..1c3648d5a09c 100644 --- a/sal/osl/w32/nlsupport.cxx +++ b/sal/osl/w32/nlsupport.cxx @@ -24,11 +24,11 @@ #include "nlsupport.hxx" -#include <osl/mutex.h> #include <osl/nlsupport.h> #include <osl/diagnose.h> #include <osl/process.h> #include <rtl/tencinfo.h> +#include <rtl/ustrbuf.hxx> #include <o3tl/char16_t2wchar_t.hxx> /* XXX NOTE: @@ -38,158 +38,62 @@ * nine, including a terminating null character." NINE?!? In ISO 639 and ISO * 3166? */ -#define ELP_LANGUAGE_FIELD_LENGTH 4 -#define ELP_COUNTRY_FIELD_LENGTH 3 +constexpr int ELP_LANGUAGE_FIELD_LENGTH = 4; +constexpr int ELP_COUNTRY_FIELD_LENGTH = 3; -namespace { - -/** Struct used in EnumLocalesProcW() called via EnumSystemLocalesW() to obtain - available locales. -*/ -struct EnumLocalesParams -{ - WCHAR Language[ELP_LANGUAGE_FIELD_LENGTH]; - WCHAR Country[ELP_COUNTRY_FIELD_LENGTH]; - LCID Locale; -}; - -} - -static DWORD g_dwTLSLocaleEncId = DWORD(-1); - -/***************************************************************************** - * callback function test - *****************************************************************************/ - -static BOOL CALLBACK EnumLocalesProcW( LPWSTR lpLocaleStringW ) -{ - /* check params received via TLS */ - EnumLocalesParams * params = static_cast<EnumLocalesParams *>(TlsGetValue( g_dwTLSLocaleEncId )); - if( nullptr == params || '\0' == params->Language[0] ) - return FALSE; - - LPWSTR pszEnd; - WCHAR langCode[ELP_LANGUAGE_FIELD_LENGTH]; - - /* convert hex-string to LCID */ - LCID localeId = wcstol(lpLocaleStringW, &pszEnd, 16); - - /* - get the ISO language code for this locale - */ - if( !GetLocaleInfoW( localeId, LOCALE_SISO639LANGNAME , langCode, ELP_LANGUAGE_FIELD_LENGTH ) ) - /* retry by going on */ - return TRUE; - - WCHAR ctryCode[ELP_COUNTRY_FIELD_LENGTH]; - - /* continue if language code does not match */ - if( 0 != wcscmp( langCode, params->Language ) ) - return TRUE; - - /* check if country code is set and equals the current locale */ - if( '\0' != params->Country[0] && GetLocaleInfoW( localeId, - LOCALE_SISO3166CTRYNAME , ctryCode, ELP_COUNTRY_FIELD_LENGTH ) ) - { - /* save return value in TLS and break if found desired locale */ - if( 0 == wcscmp( ctryCode, params->Country ) ) - { - params->Locale = localeId; - return FALSE; - } - } - else - { - /* fill with default values for that language */ - LANGID langId = LANGIDFROMLCID( localeId ); - - /* exchange sublanguage with SUBLANG_NEUTRAL */ - langId = MAKELANGID( PRIMARYLANGID( langId ), SUBLANG_NEUTRAL ); - - /* and use default sorting order */ - params->Locale = MAKELCID( langId, SORT_DEFAULT ); - - return FALSE; - } - - /* retry by going on */ - return TRUE; -} - -static rtl_TextEncoding GetTextEncodingFromLCID( LCID localeId ) +static int GetLocaleInfoN(LPCWSTR l, LCTYPE t, DWORD& n) { - /* query ansi codepage for given locale */ - WCHAR ansiCP[6]; - if( !localeId || !GetLocaleInfoW( localeId, LOCALE_IDEFAULTANSICODEPAGE, ansiCP, 6 ) ) - return RTL_TEXTENCODING_DONTKNOW; - - /* if GetLocaleInfo returns "0", it is a UNICODE only locale */ - if( 0 == wcscmp( ansiCP, L"0" ) ) - return RTL_TEXTENCODING_UNICODE; - - /* values returned from GetLocaleInfo are decimal based */ - WCHAR *pwcEnd; - UINT codepage = wcstol( ansiCP, &pwcEnd, 10 ); - - /* find matching rtl encoding */ - return rtl_getTextEncodingFromWindowsCodePage( codepage ); + return GetLocaleInfoEx(l, t | LOCALE_RETURN_NUMBER, reinterpret_cast<LPWSTR>(&n), + sizeof(n) / sizeof(WCHAR)); } rtl_TextEncoding SAL_CALL osl_getTextEncodingFromLocale( rtl_Locale * pLocale ) { - struct EnumLocalesParams params = { L"", L"", 0 }; - - /* initialise global TLS id */ - if( DWORD(-1) == g_dwTLSLocaleEncId ) - { - oslMutex globalMutex = * osl_getGlobalMutex(); - - /* initializing must be thread save */ - osl_acquireMutex( globalMutex ); - - if( DWORD(-1) == g_dwTLSLocaleEncId ) - g_dwTLSLocaleEncId = TlsAlloc(); - - osl_releaseMutex( globalMutex ); - } - /* if pLocale is NULL, use process locale as default */ if( nullptr == pLocale ) osl_getProcessLocale( &pLocale ); - /* copy in parameters to structure */ - if( !pLocale || !pLocale->Language || pLocale->Language->length >= ELP_LANGUAGE_FIELD_LENGTH ) + if (!pLocale || !pLocale->Language || !pLocale->Language->length) return RTL_TEXTENCODING_DONTKNOW; - wcscpy( params.Language, o3tl::toW(pLocale->Language->buffer) ); - - if( pLocale->Country && pLocale->Country->length < ELP_COUNTRY_FIELD_LENGTH ) - wcscpy( params.Country, o3tl::toW(pLocale->Country->buffer) ); + /* Build a BCP47 tag */ + OUStringBuffer sLocale(OUString::unacquired(&pLocale->Language)); + if (pLocale->Country && pLocale->Country->length > 0) + sLocale.append("-" + OUString::unacquired(&pLocale->Country)); + sLocale.append('\0'); - /* save pointer to local structure in TLS */ - TlsSetValue( g_dwTLSLocaleEncId, ¶ms ); + /* query ansi codepage for given locale */ + DWORD codepage; + if (!GetLocaleInfoN(o3tl::toW(sLocale.getStr()), LOCALE_IDEFAULTANSICODEPAGE, codepage)) + { + WCHAR resolved[LOCALE_NAME_MAX_LENGTH]; + if (!ResolveLocaleName(o3tl::toW(sLocale.getStr()), resolved, std::size(resolved))) + return RTL_TEXTENCODING_DONTKNOW; + if (!GetLocaleInfoN(resolved, LOCALE_IDEFAULTANSICODEPAGE, codepage)) + return RTL_TEXTENCODING_DONTKNOW; + } - /* enum all locales known to Windows */ - EnumSystemLocalesW( EnumLocalesProcW, LCID_SUPPORTED ); + /* if GetLocaleInfo returns 0, it is a UNICODE only locale */ + if (0 == codepage) + return RTL_TEXTENCODING_UNICODE; - /* use the LCID found in iteration */ - return GetTextEncodingFromLCID( params.Locale ); + /* find matching rtl encoding */ + return rtl_getTextEncodingFromWindowsCodePage(codepage); } void imp_getProcessLocale( rtl_Locale ** ppLocale ) { + WCHAR locale[LOCALE_NAME_MAX_LENGTH]; WCHAR langCode[ELP_LANGUAGE_FIELD_LENGTH]; WCHAR ctryCode[ELP_COUNTRY_FIELD_LENGTH]; - LCID localeId; OSL_ASSERT( ppLocale ); - /* get the LCID to retrieve information from */ - localeId = GetUserDefaultLCID(); - - /* call GetLocaleInfo to retrieve the iso codes */ - if( GetLocaleInfoW( localeId, LOCALE_SISO639LANGNAME , langCode, ELP_LANGUAGE_FIELD_LENGTH ) && - GetLocaleInfoW( localeId, LOCALE_SISO3166CTRYNAME , ctryCode, ELP_COUNTRY_FIELD_LENGTH ) ) + /* get the locale name to retrieve information from */ + /* and call GetLocaleInfo to retrieve the iso codes */ + if( GetUserDefaultLocaleName(locale, std::size(locale)) && + GetLocaleInfoEx( locale, LOCALE_SISO639LANGNAME , langCode, std::size(langCode) ) && + GetLocaleInfoEx( locale, LOCALE_SISO3166CTRYNAME , ctryCode, std::size(ctryCode) ) ) { *ppLocale = rtl_locale_register( o3tl::toU(langCode), o3tl::toU(ctryCode), u"" ); } |