1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #define WIN32_LEAN_AND_MEAN
25 #include "nlsupport.hxx"
27 #include <osl/mutex.h>
28 #include <osl/nlsupport.h>
29 #include <osl/diagnose.h>
30 #include <osl/process.h>
31 #include <rtl/tencinfo.h>
32 #include <o3tl/char16_t2wchar_t.hxx>
35 * http://msdn.microsoft.com/en-us/library/windows/desktop/dd373848.aspx
36 * (retrieved 2013-02-13) has some weird description for the LOCALE_SISO*
37 * constants: "The maximum number of characters allowed for this string is
38 * nine, including a terminating null character." NINE?!? In ISO 639 and ISO
41 #define ELP_LANGUAGE_FIELD_LENGTH 4
42 #define ELP_COUNTRY_FIELD_LENGTH 3
44 /** Struct used in EnumLocalesProcW() called via EnumSystemLocalesW() to obtain
47 struct EnumLocalesParams
49 WCHAR Language
[ELP_LANGUAGE_FIELD_LENGTH
];
50 WCHAR Country
[ELP_COUNTRY_FIELD_LENGTH
];
54 static DWORD g_dwTLSLocaleEncId
= DWORD(-1);
56 /*****************************************************************************
57 * callback function test
58 *****************************************************************************/
60 static BOOL CALLBACK
EnumLocalesProcW( LPWSTR lpLocaleStringW
)
62 /* check params received via TLS */
63 EnumLocalesParams
* params
= static_cast<EnumLocalesParams
*>(TlsGetValue( g_dwTLSLocaleEncId
));
64 if( nullptr == params
|| '\0' == params
->Language
[0] )
68 WCHAR langCode
[ELP_LANGUAGE_FIELD_LENGTH
];
70 /* convert hex-string to LCID */
71 LCID localeId
= wcstol(lpLocaleStringW
, &pszEnd
, 16);
74 get the ISO language code for this locale
76 if( GetLocaleInfoW( localeId
, LOCALE_SISO639LANGNAME
, langCode
, ELP_LANGUAGE_FIELD_LENGTH
) )
78 WCHAR ctryCode
[ELP_COUNTRY_FIELD_LENGTH
];
80 /* continue if language code does not match */
81 if( 0 != wcscmp( langCode
, params
->Language
) )
84 /* check if country code is set and equals the current locale */
85 if( '\0' != params
->Country
[0] && GetLocaleInfoW( localeId
,
86 LOCALE_SISO3166CTRYNAME
, ctryCode
, ELP_COUNTRY_FIELD_LENGTH
) )
88 /* save return value in TLS and break if found desired locale */
89 if( 0 == wcscmp( ctryCode
, params
->Country
) )
91 params
->Locale
= localeId
;
97 /* fill with default values for that language */
98 LANGID langId
= LANGIDFROMLCID( localeId
);
100 /* exchange sublanguage with SUBLANG_NEUTRAL */
101 langId
= MAKELANGID( PRIMARYLANGID( langId
), SUBLANG_NEUTRAL
);
103 /* and use default sorting order */
104 params
->Locale
= MAKELCID( langId
, SORT_DEFAULT
);
110 /* retry by going on */
114 static rtl_TextEncoding
GetTextEncodingFromLCID( LCID localeId
)
116 rtl_TextEncoding Encoding
= RTL_TEXTENCODING_DONTKNOW
;
119 /* query ansi codepage for given locale */
120 if( localeId
&& GetLocaleInfoW( localeId
, LOCALE_IDEFAULTANSICODEPAGE
, ansiCP
, 6 ) )
122 /* if GetLocaleInfo returns "0", it is a UNICODE only locale */
123 if( 0 != wcscmp( ansiCP
, L
"0" ) )
128 /* values returned from GetLocaleInfo are decimal based */
129 codepage
= wcstol( ansiCP
, &pwcEnd
, 10 );
131 /* find matching rtl encoding */
132 Encoding
= rtl_getTextEncodingFromWindowsCodePage( codepage
);
135 Encoding
= RTL_TEXTENCODING_UNICODE
;
141 rtl_TextEncoding SAL_CALL
osl_getTextEncodingFromLocale( rtl_Locale
* pLocale
)
143 struct EnumLocalesParams params
= { L
"", L
"", 0 };
145 /* initialise global TLS id */
146 if( DWORD(-1) == g_dwTLSLocaleEncId
)
148 oslMutex globalMutex
= * osl_getGlobalMutex();
150 /* initializing must be thread save */
151 osl_acquireMutex( globalMutex
);
153 if( DWORD(-1) == g_dwTLSLocaleEncId
)
154 g_dwTLSLocaleEncId
= TlsAlloc();
156 osl_releaseMutex( globalMutex
);
159 /* if pLocale is NULL, use process locale as default */
160 if( nullptr == pLocale
)
161 osl_getProcessLocale( &pLocale
);
163 /* copy in parameters to structure */
164 if( pLocale
&& pLocale
->Language
&& pLocale
->Language
->length
< ELP_LANGUAGE_FIELD_LENGTH
)
166 wcscpy( params
.Language
, o3tl::toW(pLocale
->Language
->buffer
) );
168 if( pLocale
->Country
&& pLocale
->Country
->length
< ELP_COUNTRY_FIELD_LENGTH
)
169 wcscpy( params
.Country
, o3tl::toW(pLocale
->Country
->buffer
) );
171 /* save pointer to local structure in TLS */
172 TlsSetValue( g_dwTLSLocaleEncId
, ¶ms
);
174 /* enum all locales known to Windows */
175 EnumSystemLocalesW( EnumLocalesProcW
, LCID_SUPPORTED
);
177 /* use the LCID found in iteration */
178 return GetTextEncodingFromLCID( params
.Locale
);
181 return RTL_TEXTENCODING_DONTKNOW
;
184 void imp_getProcessLocale( rtl_Locale
** ppLocale
)
186 WCHAR langCode
[ELP_LANGUAGE_FIELD_LENGTH
];
187 WCHAR ctryCode
[ELP_COUNTRY_FIELD_LENGTH
];
190 OSL_ASSERT( ppLocale
);
192 /* get the LCID to retrieve information from */
193 localeId
= GetUserDefaultLCID();
195 /* call GetLocaleInfo to retrieve the iso codes */
196 if( GetLocaleInfoW( localeId
, LOCALE_SISO639LANGNAME
, langCode
, ELP_LANGUAGE_FIELD_LENGTH
) &&
197 GetLocaleInfoW( localeId
, LOCALE_SISO3166CTRYNAME
, ctryCode
, ELP_COUNTRY_FIELD_LENGTH
) )
199 *ppLocale
= rtl_locale_register( o3tl::toU(langCode
), o3tl::toU(ctryCode
), u
"" );
203 *ppLocale
= rtl_locale_register( u
"C", u
"", u
"" );
207 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */