diff options
Diffstat (limited to '')
-rw-r--r-- | sal/osl/w32/nlsupport.cxx | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/sal/osl/w32/nlsupport.cxx b/sal/osl/w32/nlsupport.cxx new file mode 100644 index 000000000..f27b97aa7 --- /dev/null +++ b/sal/osl/w32/nlsupport.cxx @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +#include <wchar.h> + +#include "nlsupport.hxx" + +#include <osl/mutex.h> +#include <osl/nlsupport.h> +#include <osl/diagnose.h> +#include <osl/process.h> +#include <rtl/tencinfo.h> +#include <o3tl/char16_t2wchar_t.hxx> + +/* XXX NOTE: + * http://msdn.microsoft.com/en-us/library/windows/desktop/dd373848.aspx + * (retrieved 2013-02-13) has some weird description for the LOCALE_SISO* + * constants: "The maximum number of characters allowed for this string is + * 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 + +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 ) +{ + /* 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 ); +} + +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 ) + 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) ); + + /* save pointer to local structure in TLS */ + TlsSetValue( g_dwTLSLocaleEncId, ¶ms ); + + /* enum all locales known to Windows */ + EnumSystemLocalesW( EnumLocalesProcW, LCID_SUPPORTED ); + + /* use the LCID found in iteration */ + return GetTextEncodingFromLCID( params.Locale ); +} + +void imp_getProcessLocale( rtl_Locale ** ppLocale ) +{ + 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 ) ) + { + *ppLocale = rtl_locale_register( o3tl::toU(langCode), o3tl::toU(ctryCode), u"" ); + } + else + { + *ppLocale = rtl_locale_register( u"C", u"", u"" ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |