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