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 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 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: 108 explicit CFGuard(T& rT) : rT_(rT) {} 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 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 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 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 223 LocaleBackend::LocaleBackend() 224 { 225 } 226 227 //------------------------------------------------------------------------------ 228 229 LocaleBackend::~LocaleBackend(void) 230 { 231 } 232 233 //------------------------------------------------------------------------------ 234 235 LocaleBackend* LocaleBackend::createInstance() 236 { 237 return new LocaleBackend; 238 } 239 240 // --------------------------------------------------------------------------------------- 241 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 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 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 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 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 322 rtl::OUString SAL_CALL LocaleBackend::getBackendName(void) { 323 return rtl::OUString::createFromAscii("com.sun.star.comp.configuration.backend.LocaleBackend") ; 324 } 325 326 //------------------------------------------------------------------------------ 327 328 rtl::OUString SAL_CALL LocaleBackend::getImplementationName(void) 329 throw (uno::RuntimeException) 330 { 331 return getBackendName() ; 332 } 333 334 //------------------------------------------------------------------------------ 335 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 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 359 uno::Sequence<rtl::OUString> SAL_CALL LocaleBackend::getSupportedServiceNames(void) 360 throw (uno::RuntimeException) 361 { 362 return getBackendServiceNames() ; 363 } 364