1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_shell.hxx"
26
27 #include "localebackend.hxx"
28 #include <com/sun/star/beans/Optional.hpp>
29 #include <osl/time.h>
30
31 #include <stdio.h>
32
33 #if defined(LINUX) || defined(SOLARIS) || defined(NETBSD) || defined(FREEBSD) || defined(OS2)
34
35 #include <rtl/ustrbuf.hxx>
36 #include <locale.h>
37 #include <string.h>
38
39 /*
40 * Note: setlocale is not at all thread safe, so is this code. It could
41 * especially interfere with the stuff VCL is doing, so make sure this
42 * is called from the main thread only.
43 */
44
ImplGetLocale(int category)45 static rtl::OUString ImplGetLocale(int category)
46 {
47 const char *locale = setlocale(category, "");
48
49 // Return "en-US" for C locales
50 if( (locale == NULL) || ( locale[0] == 'C' && locale[1] == '\0' ) )
51 return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "en-US" ) );
52
53
54 const char *cp;
55 const char *uscore = NULL;
56
57 // locale string have the format lang[_ctry][.encoding][@modifier]
58 // we are only interested in the first two items, so we handle
59 // '.' and '@' as string end.
60 for (cp = locale; *cp; cp++)
61 {
62 if (*cp == '_')
63 uscore = cp;
64 if (*cp == '.' || *cp == '@')
65 break;
66 }
67
68 rtl::OUStringBuffer aLocaleBuffer;
69 if( uscore != NULL )
70 {
71 aLocaleBuffer.appendAscii(locale, uscore++ - locale);
72 aLocaleBuffer.appendAscii("-");
73 aLocaleBuffer.appendAscii(uscore, cp - uscore);
74 }
75 else
76 {
77 aLocaleBuffer.appendAscii(locale, cp - locale);
78 }
79
80 return aLocaleBuffer.makeStringAndClear();
81 }
82
83 #elif defined(MACOSX)
84
85 #include <rtl/ustrbuf.hxx>
86 #include <locale.h>
87 #include <string.h>
88
89 #include <premac.h>
90 #include <CoreServices/CoreServices.h>
91 #include <CoreFoundation/CoreFoundation.h>
92 #include <postmac.h>
93
94 namespace /* private */
95 {
96
OUStringBufferAppendCFString(rtl::OUStringBuffer & buffer,const CFStringRef s)97 void OUStringBufferAppendCFString(rtl::OUStringBuffer& buffer, const CFStringRef s)
98 {
99 CFIndex lstr = CFStringGetLength(s);
100 for (CFIndex i = 0; i < lstr; i++)
101 buffer.append(CFStringGetCharacterAtIndex(s, i));
102 }
103
104 template <typename T>
105 class CFGuard
106 {
107 public:
CFGuard(T & rT)108 explicit CFGuard(T& rT) : rT_(rT) {}
~CFGuard()109 ~CFGuard() { if (rT_) CFRelease(rT_); }
110 private:
111 T& rT_;
112 };
113
114 typedef CFGuard<CFArrayRef> CFArrayGuard;
115 typedef CFGuard<CFStringRef> CFStringGuard;
116 typedef CFGuard<CFTypeRef> CFTypeRefGuard;
117
118 /* For more information on the Apple locale concept please refer to
119 http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFLocales/Articles/CFLocaleConcepts.html
120 According to this documentation a locale identifier has the format: language[_country][_variant]*
121 e.g. es_ES_PREEURO -> spain prior Euro support
122 Note: The calling code should be able to handle locales with only language information e.g. 'en' for certain
123 UI languages just the language code will be returned.
124 */
125
ImplGetAppPreference(const char * pref)126 CFStringRef ImplGetAppPreference(const char* pref)
127 {
128 CFStringRef csPref = CFStringCreateWithCString(NULL, pref, kCFStringEncodingASCII);
129 CFStringGuard csRefGuard(csPref);
130
131 CFTypeRef ref = CFPreferencesCopyAppValue(csPref, kCFPreferencesCurrentApplication);
132 CFTypeRefGuard refGuard(ref);
133
134 if (ref == NULL)
135 return NULL;
136
137 CFStringRef sref = (CFGetTypeID(ref) == CFArrayGetTypeID()) ? (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)ref, 0) : (CFStringRef)ref;
138
139 // NOTE: this API is only available with Mac OS X >=10.3. We need to use it because
140 // Apple used non-ISO values on systems <10.2 like "German" for instance but didn't
141 // upgrade those values during upgrade to newer Mac OS X versions. See also #i54337#
142 return CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, sref);
143 }
144
ImplGetLocale(const char * pref)145 rtl::OUString ImplGetLocale(const char* pref)
146 {
147 CFStringRef sref = ImplGetAppPreference(pref);
148 CFStringGuard srefGuard(sref);
149
150 rtl::OUStringBuffer aLocaleBuffer;
151 aLocaleBuffer.appendAscii("en-US"); // initialize with fallback value
152
153 if (sref != NULL)
154 {
155 // split the string into substrings; the first two (if there are two) substrings
156 // are language and country
157 CFArrayRef subs = CFStringCreateArrayBySeparatingStrings(NULL, sref, CFSTR("_"));
158 CFArrayGuard subsGuard(subs);
159
160 if (subs != NULL)
161 {
162 aLocaleBuffer.setLength(0); // clear buffer which still contains fallback value
163
164 CFStringRef lang = (CFStringRef)CFArrayGetValueAtIndex(subs, 0);
165 OUStringBufferAppendCFString(aLocaleBuffer, lang);
166
167 // country also available? Assumption: if the array contains more than one
168 // value the second value is always the country!
169 if (CFArrayGetCount(subs) > 1)
170 {
171 aLocaleBuffer.appendAscii("-");
172 CFStringRef country = (CFStringRef)CFArrayGetValueAtIndex(subs, 1);
173 OUStringBufferAppendCFString(aLocaleBuffer, country);
174 }
175 }
176 }
177 return aLocaleBuffer.makeStringAndClear();
178 }
179
180 } // namespace /* private */
181
182 #endif
183
184 // -------------------------------------------------------------------------------
185
186 #ifdef WNT
187
188 #ifdef WINVER
189 #undef WINVER
190 #endif
191 #define WINVER 0x0501
192
193 #if defined _MSC_VER
194 #pragma warning(push, 1)
195 #endif
196 #include <windows.h>
197 #if defined _MSC_VER
198 #pragma warning(pop)
199 #endif
200
ImplGetLocale(LCID lcid)201 rtl::OUString ImplGetLocale(LCID lcid)
202 {
203 TCHAR buffer[8];
204 LPTSTR cp = buffer;
205
206 cp += GetLocaleInfo( lcid, LOCALE_SISO639LANGNAME , buffer, 4 );
207 if( cp > buffer )
208 {
209 if( 0 < GetLocaleInfo( lcid, LOCALE_SISO3166CTRYNAME, cp, buffer + 8 - cp) )
210 // #i50822# minus character must be written before cp
211 *(cp - 1) = '-';
212
213 return rtl::OUString::createFromAscii(buffer);
214 }
215
216 return rtl::OUString();
217 }
218
219 #endif // WNT
220
221 // -------------------------------------------------------------------------------
222
LocaleBackend()223 LocaleBackend::LocaleBackend()
224 {
225 }
226
227 //------------------------------------------------------------------------------
228
~LocaleBackend(void)229 LocaleBackend::~LocaleBackend(void)
230 {
231 }
232
233 //------------------------------------------------------------------------------
234
createInstance()235 LocaleBackend* LocaleBackend::createInstance()
236 {
237 return new LocaleBackend;
238 }
239
240 // ---------------------------------------------------------------------------------------
241
getLocale(void)242 rtl::OUString LocaleBackend::getLocale(void)
243 {
244 #if defined(LINUX) || defined(SOLARIS) || defined(NETBSD) || defined(FREEBSD) || defined(OS2)
245 return ImplGetLocale(LC_CTYPE);
246 #elif defined (MACOSX)
247 return ImplGetLocale("AppleLocale");
248 #elif defined WNT
249 return ImplGetLocale( GetUserDefaultLCID() );
250 #endif
251 }
252
253 //------------------------------------------------------------------------------
254
getUILocale(void)255 rtl::OUString LocaleBackend::getUILocale(void)
256 {
257 #if defined(LINUX) || defined(SOLARIS) || defined(NETBSD) || defined(FREEBSD) || defined(OS2)
258 return ImplGetLocale(LC_MESSAGES);
259 #elif defined(MACOSX)
260 return ImplGetLocale("AppleLanguages");
261 #elif defined WNT
262 return ImplGetLocale( MAKELCID(GetUserDefaultUILanguage(), SORT_DEFAULT) );
263 #endif
264 }
265
266 // ---------------------------------------------------------------------------------------
267
getSystemLocale(void)268 rtl::OUString LocaleBackend::getSystemLocale(void)
269 {
270 // note: the implementation differs from getLocale() only on Windows
271 #if defined WNT
272 return ImplGetLocale( GetSystemDefaultLCID() );
273 #else
274 return getLocale();
275 #endif
276 }
277 //------------------------------------------------------------------------------
278
setPropertyValue(rtl::OUString const &,css::uno::Any const &)279 void LocaleBackend::setPropertyValue(
280 rtl::OUString const &, css::uno::Any const &)
281 throw (
282 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
283 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
284 css::uno::RuntimeException)
285 {
286 throw css::lang::IllegalArgumentException(
287 rtl::OUString(
288 RTL_CONSTASCII_USTRINGPARAM("setPropertyValue not supported")),
289 static_cast< cppu::OWeakObject * >(this), -1);
290 }
291
getPropertyValue(rtl::OUString const & PropertyName)292 css::uno::Any LocaleBackend::getPropertyValue(
293 rtl::OUString const & PropertyName)
294 throw (
295 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
296 css::uno::RuntimeException)
297 {
298 if (PropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Locale"))) {
299 return css::uno::makeAny(
300 css::beans::Optional< css::uno::Any >(
301 true, css::uno::makeAny(getLocale())));
302 } else if (PropertyName.equalsAsciiL(
303 RTL_CONSTASCII_STRINGPARAM("SystemLocale")))
304 {
305 return css::uno::makeAny(
306 css::beans::Optional< css::uno::Any >(
307 true, css::uno::makeAny(getSystemLocale())));
308 } else if (PropertyName.equalsAsciiL(
309 RTL_CONSTASCII_STRINGPARAM("UILocale")))
310 {
311 return css::uno::makeAny(
312 css::beans::Optional< css::uno::Any >(
313 true, css::uno::makeAny(getUILocale())));
314 } else {
315 throw css::beans::UnknownPropertyException(
316 PropertyName, static_cast< cppu::OWeakObject * >(this));
317 }
318 }
319
320 //------------------------------------------------------------------------------
321
getBackendName(void)322 rtl::OUString SAL_CALL LocaleBackend::getBackendName(void) {
323 return rtl::OUString::createFromAscii("com.sun.star.comp.configuration.backend.LocaleBackend") ;
324 }
325
326 //------------------------------------------------------------------------------
327
getImplementationName(void)328 rtl::OUString SAL_CALL LocaleBackend::getImplementationName(void)
329 throw (uno::RuntimeException)
330 {
331 return getBackendName() ;
332 }
333
334 //------------------------------------------------------------------------------
335
getBackendServiceNames(void)336 uno::Sequence<rtl::OUString> SAL_CALL LocaleBackend::getBackendServiceNames(void)
337 {
338 uno::Sequence<rtl::OUString> aServiceNameList(1);
339 aServiceNameList[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.backend.LocaleBackend")) ;
340 return aServiceNameList ;
341 }
342
343 //------------------------------------------------------------------------------
344
supportsService(const rtl::OUString & aServiceName)345 sal_Bool SAL_CALL LocaleBackend::supportsService(const rtl::OUString& aServiceName)
346 throw (uno::RuntimeException)
347 {
348 uno::Sequence< rtl::OUString > const svc = getBackendServiceNames();
349
350 for(sal_Int32 i = 0; i < svc.getLength(); ++i )
351 if(svc[i] == aServiceName)
352 return true;
353
354 return false;
355 }
356
357 //------------------------------------------------------------------------------
358
getSupportedServiceNames(void)359 uno::Sequence<rtl::OUString> SAL_CALL LocaleBackend::getSupportedServiceNames(void)
360 throw (uno::RuntimeException)
361 {
362 return getBackendServiceNames() ;
363 }
364