/ CFLocale.c
CFLocale.c
1 /* 2 * Copyright (c) 2015 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 /* CFLocale.c 25 Copyright (c) 2002-2014, Apple Inc. All rights reserved. 26 Responsibility: David Smith 27 */ 28 29 // Note the header file is in the OpenSource set (stripped to almost nothing), but not the .c file 30 31 #include <CoreFoundation/CFLocale.h> 32 #include <CoreFoundation/CFString.h> 33 #include <CoreFoundation/CFArray.h> 34 #include <CoreFoundation/CFDictionary.h> 35 #include <CoreFoundation/CFPreferences.h> 36 #include <CoreFoundation/CFCalendar.h> 37 #include <CoreFoundation/CFNumber.h> 38 #include "CFInternal.h" 39 #include "CFLocaleInternal.h" 40 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 41 #include <unicode/uloc.h> // ICU locales 42 #include <unicode/ulocdata.h> // ICU locale data 43 #include <unicode/ucal.h> 44 #include <unicode/ucurr.h> // ICU currency functions 45 #include <unicode/uset.h> // ICU Unicode sets 46 #include <unicode/putil.h> // ICU low-level utilities 47 #include <unicode/umsg.h> // ICU message formatting 48 #include <unicode/ucol.h> 49 #endif 50 #include <CoreFoundation/CFNumberFormatter.h> 51 #include <stdlib.h> 52 #include <stdio.h> 53 #include <string.h> 54 55 #if DEPLOYMENT_TARGET_EMBEDDED_MINI 56 // Some compatability definitions 57 #define ULOC_FULLNAME_CAPACITY 157 58 #define ULOC_KEYWORD_AND_VALUES_CAPACITY 100 59 60 //typedef long UErrorCode; 61 //#define U_BUFFER_OVERFLOW_ERROR 15 62 //#define U_ZERO_ERROR 0 63 // 64 //typedef uint16_t UChar; 65 #endif 66 67 68 CONST_STRING_DECL(kCFLocaleCurrentLocaleDidChangeNotification, "kCFLocaleCurrentLocaleDidChangeNotification") 69 70 static const char *kCalendarKeyword = "calendar"; 71 static const char *kCollationKeyword = "collation"; 72 #define kMaxICUNameSize 1024 73 74 typedef struct __CFLocale *CFMutableLocaleRef; 75 76 PE_CONST_STRING_DECL(__kCFLocaleCollatorID, "locale:collator id") 77 78 79 enum { 80 __kCFLocaleKeyTableCount = 21 81 }; 82 83 struct key_table { 84 CFStringRef key; 85 bool (*get)(CFLocaleRef, bool user, CFTypeRef *, CFStringRef context); // returns an immutable copy & reference 86 bool (*set)(CFMutableLocaleRef, CFTypeRef, CFStringRef context); 87 bool (*name)(const char *, const char *, CFStringRef *); 88 CFStringRef context; 89 }; 90 91 92 // Must forward decl. these functions: 93 static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 94 static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context); 95 static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out); 96 static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 97 static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out); 98 static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out); 99 static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out); 100 static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out); 101 static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 102 static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out); 103 static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out); 104 static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 105 static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out); 106 static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out); 107 static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 108 static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 109 static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 110 static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 111 static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 112 static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 113 static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out); 114 static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 115 static bool __CFLocaleCopyDelimiter(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 116 117 // Note string members start with an extra &, and are fixed up at init time 118 static struct key_table __CFLocaleKeyTable[__kCFLocaleKeyTableCount] = { 119 {(CFStringRef)&kCFLocaleIdentifierKey, __CFLocaleCopyLocaleID, __CFLocaleSetNOP, __CFLocaleFullName, NULL}, 120 {(CFStringRef)&kCFLocaleLanguageCodeKey, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleLanguageName, (CFStringRef)&kCFLocaleLanguageCodeKey}, 121 {(CFStringRef)&kCFLocaleCountryCodeKey, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleCountryName, (CFStringRef)&kCFLocaleCountryCodeKey}, 122 {(CFStringRef)&kCFLocaleScriptCodeKey, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleScriptName, (CFStringRef)&kCFLocaleScriptCodeKey}, 123 {(CFStringRef)&kCFLocaleVariantCodeKey, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleVariantName, (CFStringRef)&kCFLocaleVariantCodeKey}, 124 {(CFStringRef)&kCFLocaleExemplarCharacterSetKey, __CFLocaleCopyExemplarCharSet, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, 125 {(CFStringRef)&kCFLocaleCalendarIdentifierKey, __CFLocaleCopyCalendarID, __CFLocaleSetNOP, __CFLocaleCalendarName, NULL}, 126 {(CFStringRef)&kCFLocaleCalendarKey, __CFLocaleCopyCalendar, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, 127 {(CFStringRef)&kCFLocaleCollationIdentifierKey, __CFLocaleCopyCollationID, __CFLocaleSetNOP, __CFLocaleCollationName, NULL}, 128 {(CFStringRef)&kCFLocaleUsesMetricSystemKey, __CFLocaleCopyUsesMetric, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, 129 {(CFStringRef)&kCFLocaleMeasurementSystemKey, __CFLocaleCopyMeasurementSystem, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, 130 {(CFStringRef)&kCFLocaleDecimalSeparatorKey, __CFLocaleCopyNumberFormat, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFNumberFormatterDecimalSeparatorKey}, 131 {(CFStringRef)&kCFLocaleGroupingSeparatorKey, __CFLocaleCopyNumberFormat, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFNumberFormatterGroupingSeparatorKey}, 132 {(CFStringRef)&kCFLocaleCurrencySymbolKey, __CFLocaleCopyNumberFormat2, __CFLocaleSetNOP, __CFLocaleCurrencyShortName, (CFStringRef)&kCFNumberFormatterCurrencySymbolKey}, 133 {(CFStringRef)&kCFLocaleCurrencyCodeKey, __CFLocaleCopyNumberFormat2, __CFLocaleSetNOP, __CFLocaleCurrencyFullName, (CFStringRef)&kCFNumberFormatterCurrencyCodeKey}, 134 {(CFStringRef)&kCFLocaleCollatorIdentifierKey, __CFLocaleCopyCollatorID, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, 135 {(CFStringRef)&__kCFLocaleCollatorID, __CFLocaleCopyCollatorID, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, 136 {(CFStringRef)&kCFLocaleQuotationBeginDelimiterKey, __CFLocaleCopyDelimiter, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFLocaleQuotationBeginDelimiterKey}, 137 {(CFStringRef)&kCFLocaleQuotationEndDelimiterKey, __CFLocaleCopyDelimiter, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFLocaleQuotationEndDelimiterKey}, 138 {(CFStringRef)&kCFLocaleAlternateQuotationBeginDelimiterKey, __CFLocaleCopyDelimiter, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFLocaleAlternateQuotationBeginDelimiterKey}, 139 {(CFStringRef)&kCFLocaleAlternateQuotationEndDelimiterKey, __CFLocaleCopyDelimiter, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFLocaleAlternateQuotationEndDelimiterKey}, 140 }; 141 142 143 static CFLocaleRef __CFLocaleSystem = NULL; 144 static CFMutableDictionaryRef __CFLocaleCache = NULL; 145 static CFLock_t __CFLocaleGlobalLock = CFLockInit; 146 147 struct __CFLocale { 148 CFRuntimeBase _base; 149 CFStringRef _identifier; // canonical identifier, never NULL 150 CFMutableDictionaryRef _cache; 151 CFMutableDictionaryRef _overrides; 152 CFDictionaryRef _prefs; 153 CFLock_t _lock; 154 Boolean _nullLocale; 155 }; 156 157 CF_PRIVATE Boolean __CFLocaleGetNullLocale(struct __CFLocale *locale) { 158 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), Boolean, (NSLocale *)locale, _nullLocale); 159 return locale->_nullLocale; 160 } 161 162 CF_PRIVATE void __CFLocaleSetNullLocale(struct __CFLocale *locale) { 163 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), void, (NSLocale *)locale, _setNullLocale); 164 locale->_nullLocale = true; 165 } 166 167 /* Flag bits */ 168 enum { /* Bits 0-1 */ 169 __kCFLocaleOrdinary = 0, 170 __kCFLocaleSystem = 1, 171 __kCFLocaleUser = 2, 172 __kCFLocaleCustom = 3 173 }; 174 175 CF_INLINE CFIndex __CFLocaleGetType(CFLocaleRef locale) { 176 return __CFBitfieldGetValue(((const CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0); 177 } 178 179 CF_INLINE void __CFLocaleSetType(CFLocaleRef locale, CFIndex type) { 180 __CFBitfieldSetValue(((CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0, (uint8_t)type); 181 } 182 183 CF_INLINE void __CFLocaleLockGlobal(void) { 184 __CFLock(&__CFLocaleGlobalLock); 185 } 186 187 CF_INLINE void __CFLocaleUnlockGlobal(void) { 188 __CFUnlock(&__CFLocaleGlobalLock); 189 } 190 191 CF_INLINE void __CFLocaleLock(CFLocaleRef locale) { 192 __CFLock(&((struct __CFLocale *)locale)->_lock); 193 } 194 195 CF_INLINE void __CFLocaleUnlock(CFLocaleRef locale) { 196 __CFUnlock(&((struct __CFLocale *)locale)->_lock); 197 } 198 199 200 static Boolean __CFLocaleEqual(CFTypeRef cf1, CFTypeRef cf2) { 201 CFLocaleRef locale1 = (CFLocaleRef)cf1; 202 CFLocaleRef locale2 = (CFLocaleRef)cf2; 203 // a user locale and a locale created with an ident are not the same even if their contents are 204 if (__CFLocaleGetType(locale1) != __CFLocaleGetType(locale2)) return false; 205 if (!CFEqual(locale1->_identifier, locale2->_identifier)) return false; 206 if (NULL == locale1->_overrides && NULL != locale2->_overrides) return false; 207 if (NULL != locale1->_overrides && NULL == locale2->_overrides) return false; 208 if (NULL != locale1->_overrides && !CFEqual(locale1->_overrides, locale2->_overrides)) return false; 209 if (__kCFLocaleUser == __CFLocaleGetType(locale1)) { 210 return CFEqual(locale1->_prefs, locale2->_prefs); 211 } 212 return true; 213 } 214 215 static CFHashCode __CFLocaleHash(CFTypeRef cf) { 216 CFLocaleRef locale = (CFLocaleRef)cf; 217 return CFHash(locale->_identifier); 218 } 219 220 static CFStringRef __CFLocaleCopyDescription(CFTypeRef cf) { 221 CFLocaleRef locale = (CFLocaleRef)cf; 222 const char *type = NULL; 223 switch (__CFLocaleGetType(locale)) { 224 case __kCFLocaleOrdinary: type = "ordinary"; break; 225 case __kCFLocaleSystem: type = "system"; break; 226 case __kCFLocaleUser: type = "user"; break; 227 case __kCFLocaleCustom: type = "custom"; break; 228 } 229 return CFStringCreateWithFormat(CFGetAllocator(locale), NULL, CFSTR("<CFLocale %p [%p]>{type = %s, identifier = '%@'}"), cf, CFGetAllocator(locale), type, locale->_identifier); 230 } 231 232 static void __CFLocaleDeallocate(CFTypeRef cf) { 233 CFLocaleRef locale = (CFLocaleRef)cf; 234 CFRelease(locale->_identifier); 235 if (NULL != locale->_cache) CFRelease(locale->_cache); 236 if (NULL != locale->_overrides) CFRelease(locale->_overrides); 237 if (NULL != locale->_prefs) CFRelease(locale->_prefs); 238 } 239 240 static CFTypeID __kCFLocaleTypeID = _kCFRuntimeNotATypeID; 241 242 static const CFRuntimeClass __CFLocaleClass = { 243 0, 244 "CFLocale", 245 NULL, // init 246 NULL, // copy 247 __CFLocaleDeallocate, 248 __CFLocaleEqual, 249 __CFLocaleHash, 250 NULL, // 251 __CFLocaleCopyDescription 252 }; 253 254 CFTypeID CFLocaleGetTypeID(void) { 255 static dispatch_once_t initOnce; 256 dispatch_once(&initOnce, ^{ 257 __kCFLocaleTypeID = _CFRuntimeRegisterClass(&__CFLocaleClass); // initOnce covered 258 for (CFIndex idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { 259 // table fixup to workaround compiler/language limitations 260 __CFLocaleKeyTable[idx].key = *((CFStringRef *)__CFLocaleKeyTable[idx].key); 261 if (NULL != __CFLocaleKeyTable[idx].context) { 262 __CFLocaleKeyTable[idx].context = *((CFStringRef *)__CFLocaleKeyTable[idx].context); 263 } 264 } 265 }); 266 return __kCFLocaleTypeID; 267 } 268 269 CFLocaleRef CFLocaleGetSystem(void) { 270 CFLocaleRef locale; 271 __CFLocaleLockGlobal(); 272 if (NULL == __CFLocaleSystem) { 273 __CFLocaleUnlockGlobal(); 274 locale = CFLocaleCreate(kCFAllocatorSystemDefault, CFSTR("")); 275 if (!locale) return NULL; 276 __CFLocaleSetType(locale, __kCFLocaleSystem); 277 __CFLocaleLockGlobal(); 278 if (NULL == __CFLocaleSystem) { 279 __CFLocaleSystem = locale; 280 } else { 281 if (locale) CFRelease(locale); 282 } 283 } 284 locale = __CFLocaleSystem ? (CFLocaleRef)CFRetain(__CFLocaleSystem) : NULL; 285 __CFLocaleUnlockGlobal(); 286 return locale; 287 } 288 289 extern CFDictionaryRef __CFXPreferencesCopyCurrentApplicationState(void); 290 291 static CFLocaleRef __CFLocaleCurrent = NULL; 292 293 294 #if DEPLOYMENT_TARGET_MACOSX 295 #define FALLBACK_LOCALE_NAME CFSTR("") 296 #elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 297 #define FALLBACK_LOCALE_NAME CFSTR("en_US") 298 #elif DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 299 #define FALLBACK_LOCALE_NAME CFSTR("en_US") 300 #endif 301 302 static CFLocaleRef _CFLocaleCopyCurrentGuts(CFStringRef name, Boolean useCache, CFDictionaryRef overridePrefs) { 303 304 CFStringRef ident = NULL; 305 // We cannot be helpful here, because it causes performance problems, 306 // even though the preference lookup is relatively quick, as there are 307 // things which call this function thousands or millions of times in 308 // a short period. 309 if (!name) { 310 #if 0 // DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 311 name = (CFStringRef)CFPreferencesCopyAppValue(CFSTR("AppleLocale"), kCFPreferencesCurrentApplication); 312 #endif 313 } else { 314 CFRetain(name); 315 } 316 if (name && (CFStringGetTypeID() == CFGetTypeID(name))) { 317 ident = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, name); 318 } 319 if (name) CFRelease(name); 320 321 if (useCache) { 322 CFLocaleRef oldLocale = NULL; 323 __CFLocaleLockGlobal(); 324 if (__CFLocaleCurrent) { 325 if (ident && !CFEqual(__CFLocaleCurrent->_identifier, ident)) { 326 oldLocale = __CFLocaleCurrent; 327 __CFLocaleCurrent = NULL; 328 } else { 329 CFLocaleRef res = __CFLocaleCurrent; 330 CFRetain(res); 331 __CFLocaleUnlockGlobal(); 332 if (ident) CFRelease(ident); 333 return res; 334 } 335 } 336 __CFLocaleUnlockGlobal(); 337 if (oldLocale) CFRelease(oldLocale); 338 } 339 340 CFDictionaryRef prefs = NULL; 341 342 struct __CFLocale *locale; 343 uint32_t size = sizeof(struct __CFLocale) - sizeof(CFRuntimeBase); 344 locale = (struct __CFLocale *)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, CFLocaleGetTypeID(), size, NULL); 345 if (NULL == locale) { 346 if (prefs) CFRelease(prefs); 347 if (ident) CFRelease(ident); 348 return NULL; 349 } 350 __CFLocaleSetType(locale, __kCFLocaleUser); 351 if (NULL == ident) ident = (CFStringRef)CFRetain(FALLBACK_LOCALE_NAME); 352 locale->_identifier = ident; 353 locale->_cache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); 354 locale->_overrides = NULL; 355 locale->_prefs = prefs; 356 locale->_lock = CFLockInit; 357 locale->_nullLocale = false; 358 359 if (useCache) { 360 __CFLocaleLockGlobal(); 361 if (NULL == __CFLocaleCurrent) { 362 __CFLocaleCurrent = locale; 363 } else { 364 CFRelease(locale); 365 } 366 locale = (struct __CFLocale *)CFRetain(__CFLocaleCurrent); 367 __CFLocaleUnlockGlobal(); 368 } 369 return locale; 370 } 371 372 /* 373 <rdar://problem/13834276> NSDateFormatter: Cannot specify force12HourTime/force24HourTime 374 This returns an instance of CFLocale that's set up exactly like it would be if the user changed the current locale to that identifier, then called CFLocaleCopyCurrent() 375 */ 376 CFLocaleRef _CFLocaleCopyAsIfCurrent(CFStringRef name) { 377 return _CFLocaleCopyCurrentGuts(name, false, NULL); 378 } 379 380 /* 381 <rdar://problem/14032388> Need the ability to initialize a CFLocaleRef from a preferences dictionary 382 This returns an instance of CFLocale that's set up exactly like it would be if the user changed the current locale to that identifier, set the preferences keys in the overrides dictionary, then called CFLocaleCopyCurrent() 383 */ 384 CFLocaleRef _CFLocaleCopyAsIfCurrentWithOverrides(CFStringRef name, CFDictionaryRef overrides) { 385 return _CFLocaleCopyCurrentGuts(name, false, overrides); 386 } 387 388 CFLocaleRef CFLocaleCopyCurrent(void) { 389 return _CFLocaleCopyCurrentGuts(NULL, true, NULL); 390 } 391 392 CF_PRIVATE CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale) { 393 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFDictionaryRef, (NSLocale *)locale, _prefs); 394 return locale->_prefs; 395 } 396 397 CFLocaleRef CFLocaleCreate(CFAllocatorRef allocator, CFStringRef identifier) { 398 if (allocator == NULL) allocator = __CFGetDefaultAllocator(); 399 __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 400 __CFGenericValidateType(identifier, CFStringGetTypeID()); 401 CFStringRef localeIdentifier = NULL; 402 if (identifier) { 403 localeIdentifier = CFLocaleCreateCanonicalLocaleIdentifierFromString(allocator, identifier); 404 } 405 if (NULL == localeIdentifier) return NULL; 406 CFStringRef old = localeIdentifier; 407 localeIdentifier = (CFStringRef)CFStringCreateCopy(allocator, localeIdentifier); 408 CFRelease(old); 409 __CFLocaleLockGlobal(); 410 // Look for cases where we can return a cached instance. 411 // We only use cached objects if the allocator is the system 412 // default allocator. 413 if (!allocator) allocator = __CFGetDefaultAllocator(); 414 Boolean canCache = _CFAllocatorIsSystemDefault(allocator); 415 if (canCache && __CFLocaleCache) { 416 CFLocaleRef locale = (CFLocaleRef)CFDictionaryGetValue(__CFLocaleCache, localeIdentifier); 417 if (locale) { 418 CFRetain(locale); 419 __CFLocaleUnlockGlobal(); 420 CFRelease(localeIdentifier); 421 return locale; 422 } 423 } 424 struct __CFLocale *locale = NULL; 425 uint32_t size = sizeof(struct __CFLocale) - sizeof(CFRuntimeBase); 426 locale = (struct __CFLocale *)_CFRuntimeCreateInstance(allocator, CFLocaleGetTypeID(), size, NULL); 427 if (NULL == locale) { 428 return NULL; 429 } 430 __CFLocaleSetType(locale, __kCFLocaleOrdinary); 431 locale->_identifier = localeIdentifier; 432 locale->_cache = CFDictionaryCreateMutable(allocator, 0, NULL, &kCFTypeDictionaryValueCallBacks); 433 locale->_overrides = NULL; 434 locale->_prefs = NULL; 435 locale->_lock = CFLockInit; 436 if (canCache) { 437 if (NULL == __CFLocaleCache) { 438 __CFLocaleCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 439 } 440 CFDictionarySetValue(__CFLocaleCache, localeIdentifier, locale); 441 } 442 __CFLocaleUnlockGlobal(); 443 return (CFLocaleRef)locale; 444 } 445 446 CFLocaleRef CFLocaleCreateCopy(CFAllocatorRef allocator, CFLocaleRef locale) { 447 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFLocaleRef, (NSLocale *)locale, copy); 448 return (CFLocaleRef)CFRetain(locale); 449 } 450 451 CFStringRef CFLocaleGetIdentifier(CFLocaleRef locale) { 452 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFStringRef, (NSLocale *)locale, localeIdentifier); 453 return locale->_identifier; 454 } 455 456 CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key) { 457 #if DEPLOYMENT_TARGET_MACOSX 458 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard)) { 459 // Hack for Opera, which is using the hard-coded string value below instead of 460 // the perfectly good public kCFLocaleCountryCode constant, for whatever reason. 461 if (key && CFEqual(key, CFSTR("locale:country code"))) { 462 key = kCFLocaleCountryCodeKey; 463 } 464 } 465 #endif 466 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFTypeRef, (NSLocale *)locale, objectForKey:(id)key); 467 CFIndex idx, slot = -1; 468 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { 469 if (__CFLocaleKeyTable[idx].key == key) { 470 slot = idx; 471 break; 472 } 473 } 474 if (-1 == slot && NULL != key) { 475 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { 476 if (CFEqual(__CFLocaleKeyTable[idx].key, key)) { 477 slot = idx; 478 break; 479 } 480 } 481 } 482 if (-1 == slot) { 483 return NULL; 484 } 485 CFTypeRef value; 486 if (NULL != locale->_overrides && CFDictionaryGetValueIfPresent(locale->_overrides, __CFLocaleKeyTable[slot].key, &value)) { 487 return value; 488 } 489 __CFLocaleLock(locale); 490 if (CFDictionaryGetValueIfPresent(locale->_cache, __CFLocaleKeyTable[slot].key, &value)) { 491 __CFLocaleUnlock(locale); 492 return value; 493 } 494 if (__kCFLocaleUser == __CFLocaleGetType(locale) && __CFLocaleKeyTable[slot].get(locale, true, &value, __CFLocaleKeyTable[slot].context)) { 495 if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value); 496 if (value) CFRelease(value); 497 __CFLocaleUnlock(locale); 498 return value; 499 } 500 if (__CFLocaleKeyTable[slot].get(locale, false, &value, __CFLocaleKeyTable[slot].context)) { 501 if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value); 502 if (value) CFRelease(value); 503 __CFLocaleUnlock(locale); 504 return value; 505 } 506 __CFLocaleUnlock(locale); 507 return NULL; 508 } 509 510 CFStringRef CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale, CFStringRef key, CFStringRef value) { 511 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFStringRef, (NSLocale *)displayLocale, _copyDisplayNameForKey:(id)key value:(id)value); 512 CFIndex idx, slot = -1; 513 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { 514 if (__CFLocaleKeyTable[idx].key == key) { 515 slot = idx; 516 break; 517 } 518 } 519 if (-1 == slot && NULL != key) { 520 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { 521 if (CFEqual(__CFLocaleKeyTable[idx].key, key)) { 522 slot = idx; 523 break; 524 } 525 } 526 } 527 if (-1 == slot || !value) { 528 return NULL; 529 } 530 // Get the locale ID as a C string 531 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 532 char cValue[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 533 if (CFStringGetCString(displayLocale->_identifier, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII) && CFStringGetCString(value, cValue, sizeof(cValue)/sizeof(char), kCFStringEncodingASCII)) { 534 CFStringRef result; 535 if ((NULL == displayLocale->_prefs) && __CFLocaleKeyTable[slot].name(localeID, cValue, &result)) { 536 return result; 537 } 538 539 // We could not find a result using the requested language. Fall back through all preferred languages. 540 CFArrayRef langPref = NULL; 541 if (displayLocale->_prefs) { 542 langPref = (CFArrayRef)CFDictionaryGetValue(displayLocale->_prefs, CFSTR("AppleLanguages")); 543 if (langPref) CFRetain(langPref); 544 } else { 545 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 546 langPref = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); 547 #endif 548 } 549 if (langPref != NULL) { 550 CFIndex count = CFArrayGetCount(langPref); 551 CFIndex i; 552 bool success = false; 553 for (i = 0; i < count && !success; ++i) { 554 CFStringRef language = (CFStringRef)CFArrayGetValueAtIndex(langPref, i); 555 CFStringRef cleanLanguage = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, language); 556 if (CFStringGetCString(cleanLanguage, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII)) { 557 success = __CFLocaleKeyTable[slot].name(localeID, cValue, &result); 558 } 559 CFRelease(cleanLanguage); 560 } 561 CFRelease(langPref); 562 if (success) 563 return result; 564 } 565 } 566 return NULL; 567 } 568 569 CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void) { 570 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 571 int32_t locale, localeCount = uloc_countAvailable(); 572 CFMutableSetRef working = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); 573 for (locale = 0; locale < localeCount; ++locale) { 574 const char *localeID = uloc_getAvailable(locale); 575 CFStringRef string1 = CFStringCreateWithCString(kCFAllocatorSystemDefault, localeID, kCFStringEncodingASCII); 576 // do not include canonicalized version as IntlFormats cannot cope with that in its popup 577 CFSetAddValue(working, string1); 578 CFRelease(string1); 579 } 580 CFIndex cnt = CFSetGetCount(working); 581 STACK_BUFFER_DECL(const void *, buffer, cnt); 582 CFSetGetValues(working, buffer); 583 CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, buffer, cnt, &kCFTypeArrayCallBacks); 584 CFRelease(working); 585 return result; 586 #else 587 return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); 588 #endif 589 } 590 591 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 592 static CFArrayRef __CFLocaleCopyCStringsAsArray(const char* const* p) { 593 CFMutableArrayRef working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 594 for (; *p; ++p) { 595 CFStringRef string = CFStringCreateWithCString(kCFAllocatorSystemDefault, *p, kCFStringEncodingASCII); 596 CFArrayAppendValue(working, string); 597 CFRelease(string); 598 } 599 CFArrayRef result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working); 600 CFRelease(working); 601 return result; 602 } 603 604 static CFArrayRef __CFLocaleCopyUEnumerationAsArray(UEnumeration *enumer, UErrorCode *icuErr) { 605 const UChar *next = NULL; 606 int32_t len = 0; 607 CFMutableArrayRef working = NULL; 608 if (U_SUCCESS(*icuErr)) { 609 working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 610 } 611 while ((next = uenum_unext(enumer, &len, icuErr)) && U_SUCCESS(*icuErr)) { 612 CFStringRef string = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)next, (CFIndex) len); 613 CFArrayAppendValue(working, string); 614 CFRelease(string); 615 } 616 if (*icuErr == U_INDEX_OUTOFBOUNDS_ERROR) { 617 *icuErr = U_ZERO_ERROR; // Temp: Work around bug (ICU 5220) in ucurr enumerator 618 } 619 CFArrayRef result = NULL; 620 if (U_SUCCESS(*icuErr)) { 621 result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working); 622 } 623 if (working != NULL) { 624 CFRelease(working); 625 } 626 return result; 627 } 628 #endif 629 630 CFArrayRef CFLocaleCopyISOLanguageCodes(void) { 631 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 632 const char* const* p = uloc_getISOLanguages(); 633 return __CFLocaleCopyCStringsAsArray(p); 634 #else 635 return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); 636 #endif 637 } 638 639 CFArrayRef CFLocaleCopyISOCountryCodes(void) { 640 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 641 const char* const* p = uloc_getISOCountries(); 642 return __CFLocaleCopyCStringsAsArray(p); 643 #else 644 return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); 645 #endif 646 } 647 648 CFArrayRef CFLocaleCopyISOCurrencyCodes(void) { 649 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 650 UErrorCode icuStatus = U_ZERO_ERROR; 651 UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_ALL, &icuStatus); 652 CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus); 653 uenum_close(enumer); 654 #else 655 CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); 656 #endif 657 return result; 658 } 659 660 CFArrayRef CFLocaleCopyCommonISOCurrencyCodes(void) { 661 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 662 UErrorCode icuStatus = U_ZERO_ERROR; 663 UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &icuStatus); 664 CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus); 665 uenum_close(enumer); 666 #else 667 CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); 668 #endif 669 return result; 670 } 671 672 CFStringRef CFLocaleCreateLocaleIdentifierFromWindowsLocaleCode(CFAllocatorRef allocator, uint32_t lcid) { 673 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 674 char buffer[kMaxICUNameSize]; 675 UErrorCode status = U_ZERO_ERROR; 676 int32_t ret = uloc_getLocaleForLCID(lcid, buffer, kMaxICUNameSize, &status); 677 if (U_FAILURE(status) || kMaxICUNameSize <= ret) return NULL; 678 CFStringRef str = CFStringCreateWithCString(kCFAllocatorSystemDefault, buffer, kCFStringEncodingASCII); 679 CFStringRef ident = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, str); 680 CFRelease(str); 681 return ident; 682 #else 683 return CFSTR(""); 684 #endif 685 } 686 687 uint32_t CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier(CFStringRef localeIdentifier) { 688 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 689 CFStringRef ident = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, localeIdentifier); 690 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 691 Boolean b = ident ? CFStringGetCString(ident, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false; 692 if (ident) CFRelease(ident); 693 return b ? uloc_getLCID(localeID) : 0; 694 #else 695 return 0; 696 #endif 697 } 698 699 CFLocaleLanguageDirection CFLocaleGetLanguageCharacterDirection(CFStringRef isoLangCode) { 700 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 701 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 702 Boolean b = isoLangCode ? CFStringGetCString(isoLangCode, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false; 703 CFLocaleLanguageDirection dir; 704 UErrorCode status = U_ZERO_ERROR; 705 ULayoutType idir = b ? uloc_getCharacterOrientation(localeID, &status) : ULOC_LAYOUT_UNKNOWN; 706 switch (idir) { 707 case ULOC_LAYOUT_LTR: dir = kCFLocaleLanguageDirectionLeftToRight; break; 708 case ULOC_LAYOUT_RTL: dir = kCFLocaleLanguageDirectionRightToLeft; break; 709 case ULOC_LAYOUT_TTB: dir = kCFLocaleLanguageDirectionTopToBottom; break; 710 case ULOC_LAYOUT_BTT: dir = kCFLocaleLanguageDirectionBottomToTop; break; 711 default: dir = kCFLocaleLanguageDirectionUnknown; break; 712 } 713 return dir; 714 #else 715 return kCFLocaleLanguageDirectionLeftToRight; 716 #endif 717 } 718 719 CFLocaleLanguageDirection CFLocaleGetLanguageLineDirection(CFStringRef isoLangCode) { 720 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 721 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 722 Boolean b = isoLangCode ? CFStringGetCString(isoLangCode, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false; 723 CFLocaleLanguageDirection dir; 724 UErrorCode status = U_ZERO_ERROR; 725 ULayoutType idir = b ? uloc_getLineOrientation(localeID, &status) : ULOC_LAYOUT_UNKNOWN; 726 switch (idir) { 727 case ULOC_LAYOUT_LTR: dir = kCFLocaleLanguageDirectionLeftToRight; break; 728 case ULOC_LAYOUT_RTL: dir = kCFLocaleLanguageDirectionRightToLeft; break; 729 case ULOC_LAYOUT_TTB: dir = kCFLocaleLanguageDirectionTopToBottom; break; 730 case ULOC_LAYOUT_BTT: dir = kCFLocaleLanguageDirectionBottomToTop; break; 731 default: dir = kCFLocaleLanguageDirectionUnknown; break; 732 } 733 return dir; 734 #else 735 return kCFLocaleLanguageDirectionLeftToRight; 736 #endif 737 } 738 739 CFArrayRef CFLocaleCopyPreferredLanguages(void) { 740 CFMutableArrayRef newArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 741 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS 742 CFArrayRef languagesArray = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); 743 if (languagesArray && (CFArrayGetTypeID() == CFGetTypeID(languagesArray))) { 744 for (CFIndex idx = 0, cnt = CFArrayGetCount(languagesArray); idx < cnt; idx++) { 745 CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(languagesArray, idx); 746 if (str && (CFStringGetTypeID() == CFGetTypeID(str))) { 747 CFStringRef ident = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, str); 748 CFArrayAppendValue(newArray, ident); 749 CFRelease(ident); 750 } 751 } 752 } 753 if (languagesArray) CFRelease(languagesArray); 754 #endif 755 return newArray; 756 } 757 758 // -------- -------- -------- -------- -------- -------- 759 760 // These functions return true or false depending on the success or failure of the function. 761 // In the Copy case, this is failure to fill the *cf out parameter, and that out parameter is 762 // returned by reference WITH a retain on it. 763 static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context) { 764 return false; 765 } 766 767 static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 768 *cf = CFRetain(locale->_identifier); 769 return true; 770 } 771 772 773 static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 774 CFDictionaryRef codes = NULL; 775 // this access of _cache is protected by the lock in CFLocaleGetValue() 776 if (!CFDictionaryGetValueIfPresent(locale->_cache, CFSTR("__kCFLocaleCodes"), (const void **)&codes)) { 777 codes = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, locale->_identifier); 778 if (codes) CFDictionarySetValue(locale->_cache, CFSTR("__kCFLocaleCodes"), codes); 779 if (codes) CFRelease(codes); 780 } 781 if (codes) { 782 CFStringRef value = (CFStringRef)CFDictionaryGetValue(codes, context); // context is one of kCFLocale*Code constants 783 if (value) CFRetain(value); 784 *cf = value; 785 return true; 786 } 787 return false; 788 } 789 790 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 791 CFCharacterSetRef _CFCreateCharacterSetFromUSet(USet *set) { 792 UErrorCode icuErr = U_ZERO_ERROR; 793 CFMutableCharacterSetRef working = CFCharacterSetCreateMutable(NULL); 794 UChar buffer[2048]; // Suitable for most small sets 795 int32_t stringLen; 796 797 if (working == NULL) 798 return NULL; 799 800 int32_t itemCount = uset_getItemCount(set); 801 int32_t i; 802 for (i = 0; i < itemCount; ++i) 803 { 804 UChar32 start, end; 805 UChar * string; 806 807 string = buffer; 808 stringLen = uset_getItem(set, i, &start, &end, buffer, sizeof(buffer)/sizeof(UChar), &icuErr); 809 if (icuErr == U_BUFFER_OVERFLOW_ERROR) 810 { 811 string = (UChar *) malloc(sizeof(UChar)*(stringLen+1)); 812 if (!string) 813 { 814 CFRelease(working); 815 return NULL; 816 } 817 icuErr = U_ZERO_ERROR; 818 (void) uset_getItem(set, i, &start, &end, string, stringLen+1, &icuErr); 819 } 820 if (U_FAILURE(icuErr)) 821 { 822 if (string != buffer) 823 free(string); 824 CFRelease(working); 825 return NULL; 826 } 827 if (stringLen <= 0) 828 CFCharacterSetAddCharactersInRange(working, CFRangeMake(start, end-start+1)); 829 else 830 { 831 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, (UniChar *)string, stringLen, kCFAllocatorNull); 832 CFCharacterSetAddCharactersInString(working, cfString); 833 CFRelease(cfString); 834 } 835 if (string != buffer) 836 free(string); 837 } 838 839 CFCharacterSetRef result = CFCharacterSetCreateCopy(kCFAllocatorSystemDefault, working); 840 CFRelease(working); 841 return result; 842 } 843 #endif 844 845 static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 846 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 847 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 848 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { 849 UErrorCode icuStatus = U_ZERO_ERROR; 850 ULocaleData* uld = ulocdata_open(localeID, &icuStatus); 851 USet *set = ulocdata_getExemplarSet(uld, NULL, USET_ADD_CASE_MAPPINGS, ULOCDATA_ES_STANDARD, &icuStatus); 852 ulocdata_close(uld); 853 if (U_FAILURE(icuStatus)) 854 return false; 855 if (icuStatus == U_USING_DEFAULT_WARNING) // If default locale used, force to empty set 856 uset_clear(set); 857 *cf = (CFTypeRef) _CFCreateCharacterSetFromUSet(set); 858 uset_close(set); 859 return (*cf != NULL); 860 } 861 #endif 862 return false; 863 } 864 865 static bool __CFLocaleCopyICUKeyword(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context, const char *keyword) 866 { 867 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 868 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 869 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) 870 { 871 char value[ULOC_KEYWORD_AND_VALUES_CAPACITY]; 872 UErrorCode icuStatus = U_ZERO_ERROR; 873 if (uloc_getKeywordValue(localeID, keyword, value, sizeof(value)/sizeof(char), &icuStatus) > 0 && U_SUCCESS(icuStatus)) 874 { 875 *cf = (CFTypeRef) CFStringCreateWithCString(kCFAllocatorSystemDefault, value, kCFStringEncodingASCII); 876 return true; 877 } 878 } 879 #endif 880 *cf = NULL; 881 return false; 882 } 883 884 static bool __CFLocaleCopyICUCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context, const char *keyword) { 885 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 886 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 887 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { 888 UErrorCode icuStatus = U_ZERO_ERROR; 889 UEnumeration *en = ucal_getKeywordValuesForLocale(keyword, localeID, TRUE, &icuStatus); 890 int32_t len; 891 const char *value = uenum_next(en, &len, &icuStatus); 892 if (U_SUCCESS(icuStatus)) { 893 *cf = (CFTypeRef) CFStringCreateWithCString(kCFAllocatorSystemDefault, value, kCFStringEncodingASCII); 894 uenum_close(en); 895 return true; 896 } 897 uenum_close(en); 898 } 899 #endif 900 *cf = NULL; 901 return false; 902 } 903 904 static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 905 bool succeeded = __CFLocaleCopyICUKeyword(locale, user, cf, context, kCalendarKeyword); 906 if (!succeeded) { 907 succeeded = __CFLocaleCopyICUCalendarID(locale, user, cf, context, kCalendarKeyword); 908 } 909 if (succeeded) { 910 if (CFEqual(*cf, kCFCalendarIdentifierGregorian)) { 911 CFRelease(*cf); 912 *cf = CFRetain(kCFCalendarIdentifierGregorian); 913 } else if (CFEqual(*cf, kCFCalendarIdentifierBuddhist)) { 914 CFRelease(*cf); 915 *cf = CFRetain(kCFCalendarIdentifierBuddhist); 916 } else if (CFEqual(*cf, kCFCalendarIdentifierJapanese)) { 917 CFRelease(*cf); 918 *cf = CFRetain(kCFCalendarIdentifierJapanese); 919 } else if (CFEqual(*cf, kCFCalendarIdentifierIslamic)) { 920 CFRelease(*cf); 921 *cf = CFRetain(kCFCalendarIdentifierIslamic); 922 } else if (CFEqual(*cf, kCFCalendarIdentifierIslamicCivil)) { 923 CFRelease(*cf); 924 *cf = CFRetain(kCFCalendarIdentifierIslamicCivil); 925 } else if (CFEqual(*cf, kCFCalendarIdentifierHebrew)) { 926 CFRelease(*cf); 927 *cf = CFRetain(kCFCalendarIdentifierHebrew); 928 } else if (CFEqual(*cf, kCFCalendarIdentifierChinese)) { 929 CFRelease(*cf); 930 *cf = CFRetain(kCFCalendarIdentifierChinese); 931 } else if (CFEqual(*cf, kCFCalendarIdentifierRepublicOfChina)) { 932 CFRelease(*cf); 933 *cf = CFRetain(kCFCalendarIdentifierRepublicOfChina); 934 } else if (CFEqual(*cf, kCFCalendarIdentifierPersian)) { 935 CFRelease(*cf); 936 *cf = CFRetain(kCFCalendarIdentifierPersian); 937 } else if (CFEqual(*cf, kCFCalendarIdentifierIndian)) { 938 CFRelease(*cf); 939 *cf = CFRetain(kCFCalendarIdentifierIndian); 940 } else if (CFEqual(*cf, kCFCalendarIdentifierISO8601)) { 941 CFRelease(*cf); 942 *cf = CFRetain(kCFCalendarIdentifierISO8601); 943 } else if (CFEqual(*cf, kCFCalendarIdentifierCoptic)) { 944 CFRelease(*cf); 945 *cf = CFRetain(kCFCalendarIdentifierCoptic); 946 } else if (CFEqual(*cf, kCFCalendarIdentifierEthiopicAmeteMihret)) { 947 CFRelease(*cf); 948 *cf = CFRetain(kCFCalendarIdentifierEthiopicAmeteMihret); 949 } else if (CFEqual(*cf, kCFCalendarIdentifierEthiopicAmeteAlem)) { 950 CFRelease(*cf); 951 *cf = CFRetain(kCFCalendarIdentifierEthiopicAmeteAlem); 952 } else if (CFEqual(*cf, kCFCalendarIdentifierIslamicTabular)) { 953 CFRelease(*cf); 954 *cf = CFRetain(kCFCalendarIdentifierIslamicTabular); 955 } else if (CFEqual(*cf, kCFCalendarIdentifierIslamicUmmAlQura)) { 956 CFRelease(*cf); 957 *cf = CFRetain(kCFCalendarIdentifierIslamicUmmAlQura); 958 } else { 959 CFRelease(*cf); 960 *cf = NULL; 961 return false; 962 } 963 } else { 964 *cf = CFRetain(kCFCalendarIdentifierGregorian); 965 } 966 return true; 967 } 968 969 static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 970 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 971 if (__CFLocaleCopyCalendarID(locale, user, cf, context)) { 972 CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, (CFStringRef)*cf); 973 CFCalendarSetLocale(calendar, locale); 974 CFDictionaryRef prefs = __CFLocaleGetPrefs(locale); 975 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleFirstWeekday")) : NULL; 976 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { 977 metapref = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)metapref, *cf); 978 } 979 if (NULL != metapref && CFGetTypeID(metapref) == CFNumberGetTypeID()) { 980 CFIndex wkdy; 981 if (CFNumberGetValue((CFNumberRef)metapref, kCFNumberCFIndexType, &wkdy)) { 982 CFCalendarSetFirstWeekday(calendar, wkdy); 983 } 984 } 985 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleMinDaysInFirstWeek")) : NULL; 986 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { 987 metapref = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)metapref, *cf); 988 } 989 if (NULL != metapref && CFGetTypeID(metapref) == CFNumberGetTypeID()) { 990 CFIndex mwd; 991 if (CFNumberGetValue((CFNumberRef)metapref, kCFNumberCFIndexType, &mwd)) { 992 CFCalendarSetMinimumDaysInFirstWeek(calendar, mwd); 993 } 994 } 995 CFRelease(*cf); 996 *cf = calendar; 997 return true; 998 } 999 #endif 1000 return false; 1001 } 1002 1003 static bool __CFLocaleCopyDelimiter(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1004 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1005 ULocaleDataDelimiterType type = (ULocaleDataDelimiterType)0; 1006 if (context == kCFLocaleQuotationBeginDelimiterKey) { 1007 type = ULOCDATA_QUOTATION_START; 1008 } else if (context == kCFLocaleQuotationEndDelimiterKey) { 1009 type = ULOCDATA_QUOTATION_END; 1010 } else if (context == kCFLocaleAlternateQuotationBeginDelimiterKey) { 1011 type = ULOCDATA_ALT_QUOTATION_START; 1012 } else if (context == kCFLocaleAlternateQuotationEndDelimiterKey) { 1013 type = ULOCDATA_ALT_QUOTATION_END; 1014 } else { 1015 return false; 1016 } 1017 1018 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 1019 if (!CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { 1020 return false; 1021 } 1022 1023 UChar buffer[130]; 1024 UErrorCode status = U_ZERO_ERROR; 1025 ULocaleData *uld = ulocdata_open(localeID, &status); 1026 int32_t len = ulocdata_getDelimiter(uld, type, buffer, sizeof(buffer) / sizeof(buffer[0]), &status); 1027 ulocdata_close(uld); 1028 if (U_FAILURE(status) || sizeof(buffer) / sizeof(buffer[0]) < len) { 1029 return false; 1030 } 1031 1032 *cf = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)buffer, len); 1033 return (*cf != NULL); 1034 #else 1035 if (context == kCFLocaleQuotationBeginDelimiterKey || context == kCFLocaleQuotationEndDelimiterKey || context == kCFLocaleAlternateQuotationBeginDelimiterKey || context == kCFLocaleAlternateQuotationEndDelimiterKey) { 1036 *cf = CFRetain(CFSTR("\"")); 1037 return true; 1038 } else { 1039 return false; 1040 } 1041 #endif 1042 } 1043 1044 static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1045 return __CFLocaleCopyICUKeyword(locale, user, cf, context, kCollationKeyword); 1046 } 1047 1048 static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1049 CFStringRef canonLocaleCFStr = NULL; 1050 if (user && locale->_prefs) { 1051 CFStringRef pref = (CFStringRef)CFDictionaryGetValue(locale->_prefs, CFSTR("AppleCollationOrder")); 1052 if (pref) { 1053 // Canonicalize pref string in case it's not in the canonical format. 1054 canonLocaleCFStr = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, pref); 1055 } else { 1056 CFArrayRef languagesArray = (CFArrayRef)CFDictionaryGetValue(locale->_prefs, CFSTR("AppleLanguages")); 1057 if (languagesArray && (CFArrayGetTypeID() == CFGetTypeID(languagesArray))) { 1058 if (0 < CFArrayGetCount(languagesArray)) { 1059 CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(languagesArray, 0); 1060 if (str && (CFStringGetTypeID() == CFGetTypeID(str))) { 1061 canonLocaleCFStr = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, str); 1062 } 1063 } 1064 } 1065 } 1066 } 1067 if (!canonLocaleCFStr) { 1068 canonLocaleCFStr = CFLocaleGetIdentifier(locale); 1069 CFRetain(canonLocaleCFStr); 1070 } 1071 *cf = canonLocaleCFStr; 1072 return canonLocaleCFStr ? true : false; 1073 } 1074 1075 static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1076 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1077 bool us = false; // Default is Metric 1078 bool done = false; 1079 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 1080 if (user) { 1081 CFTypeRef pref = CFDictionaryGetValue(locale->_prefs, CFSTR("AppleMetricUnits")); 1082 if (pref) { 1083 us = (kCFBooleanFalse == pref); 1084 done = true; 1085 } else { 1086 pref = CFDictionaryGetValue(locale->_prefs, CFSTR("AppleMeasurementUnits")); 1087 if (pref) { 1088 us = CFEqual(pref, CFSTR("Inches")); 1089 done = true; 1090 } 1091 } 1092 } 1093 #endif 1094 if (!done) { 1095 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 1096 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { 1097 UErrorCode icuStatus = U_ZERO_ERROR; 1098 UMeasurementSystem ms = UMS_SI; 1099 ms = ulocdata_getMeasurementSystem(localeID, &icuStatus); 1100 if (U_SUCCESS(icuStatus)) { 1101 us = (ms == UMS_US); 1102 done = true; 1103 } 1104 } 1105 } 1106 if (!done) 1107 us = false; 1108 *cf = us ? CFRetain(kCFBooleanFalse) : CFRetain(kCFBooleanTrue); 1109 return true; 1110 #else 1111 *cf = CFRetain(kCFBooleanFalse); 1112 return true; 1113 #endif 1114 } 1115 1116 static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1117 if (__CFLocaleCopyUsesMetric(locale, user, cf, context)) { 1118 bool us = (*cf == kCFBooleanFalse); 1119 CFRelease(*cf); 1120 *cf = us ? CFRetain(CFSTR("U.S.")) : CFRetain(CFSTR("Metric")); 1121 return true; 1122 } 1123 return false; 1124 } 1125 1126 static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1127 CFStringRef str = NULL; 1128 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1129 CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterDecimalStyle); 1130 str = nf ? (CFStringRef)CFNumberFormatterCopyProperty(nf, context) : NULL; 1131 if (nf) CFRelease(nf); 1132 #endif 1133 if (str) { 1134 *cf = str; 1135 return true; 1136 } 1137 return false; 1138 } 1139 1140 // ICU does not reliably set up currency info for other than Currency-type formatters, 1141 // so we have to have another routine here which creates a Currency number formatter. 1142 static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1143 CFStringRef str = NULL; 1144 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1145 CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterCurrencyStyle); 1146 str = nf ? (CFStringRef)CFNumberFormatterCopyProperty(nf, context) : NULL; 1147 if (nf) CFRelease(nf); 1148 #endif 1149 if (str) { 1150 *cf = str; 1151 return true; 1152 } 1153 return false; 1154 } 1155 1156 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1157 typedef int32_t (*__CFICUFunction)(const char *, const char *, UChar *, int32_t, UErrorCode *); 1158 1159 static bool __CFLocaleICUName(const char *locale, const char *valLocale, CFStringRef *out, __CFICUFunction icu) { 1160 UErrorCode icuStatus = U_ZERO_ERROR; 1161 int32_t size; 1162 UChar name[kMaxICUNameSize]; 1163 1164 size = (*icu)(valLocale, locale, name, kMaxICUNameSize, &icuStatus); 1165 if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) { 1166 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); 1167 return (*out != NULL); 1168 } 1169 return false; 1170 } 1171 1172 static bool __CFLocaleICUKeywordValueName(const char *locale, const char *value, const char *keyword, CFStringRef *out) { 1173 UErrorCode icuStatus = U_ZERO_ERROR; 1174 int32_t size = 0; 1175 UChar name[kMaxICUNameSize]; 1176 // Need to make a fake locale ID 1177 char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 1178 if (strlen(value) < ULOC_KEYWORD_AND_VALUES_CAPACITY) { 1179 strlcpy(lid, "en_US@", sizeof(lid)); 1180 strlcat(lid, keyword, sizeof(lid)); 1181 strlcat(lid, "=", sizeof(lid)); 1182 strlcat(lid, value, sizeof(lid)); 1183 size = uloc_getDisplayKeywordValue(lid, keyword, locale, name, kMaxICUNameSize, &icuStatus); 1184 if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) { 1185 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); 1186 return (*out != NULL); 1187 } 1188 } 1189 return false; 1190 } 1191 1192 static bool __CFLocaleICUCurrencyName(const char *locale, const char *value, UCurrNameStyle style, CFStringRef *out) { 1193 int valLen = strlen(value); 1194 if (valLen != 3) // not a valid ISO code 1195 return false; 1196 UChar curr[4]; 1197 UBool isChoice = FALSE; 1198 int32_t size = 0; 1199 UErrorCode icuStatus = U_ZERO_ERROR; 1200 u_charsToUChars(value, curr, valLen); 1201 curr[valLen] = '\0'; 1202 const UChar *name; 1203 name = ucurr_getName(curr, locale, style, &isChoice, &size, &icuStatus); 1204 if (U_FAILURE(icuStatus) || icuStatus == U_USING_DEFAULT_WARNING) 1205 return false; 1206 UChar result[kMaxICUNameSize]; 1207 if (isChoice) 1208 { 1209 UChar pattern[kMaxICUNameSize]; 1210 CFStringRef patternRef = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{0,choice,%S}"), name); 1211 CFIndex pattlen = CFStringGetLength(patternRef); 1212 CFStringGetCharacters(patternRef, CFRangeMake(0, pattlen), (UniChar *)pattern); 1213 CFRelease(patternRef); 1214 pattern[pattlen] = '\0'; // null terminate the pattern 1215 // Format the message assuming a large amount of the currency 1216 size = u_formatMessage("en_US", pattern, pattlen, result, kMaxICUNameSize, &icuStatus, 10.0); 1217 if (U_FAILURE(icuStatus)) 1218 return false; 1219 name = result; 1220 1221 } 1222 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); 1223 return (*out != NULL); 1224 } 1225 #endif 1226 1227 static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out) { 1228 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1229 UErrorCode icuStatus = U_ZERO_ERROR; 1230 int32_t size; 1231 UChar name[kMaxICUNameSize]; 1232 1233 // First, try to get the full locale. 1234 size = uloc_getDisplayName(value, locale, name, kMaxICUNameSize, &icuStatus); 1235 if (U_FAILURE(icuStatus) || size <= 0) 1236 return false; 1237 1238 // Did we wind up using a default somewhere? 1239 if (icuStatus == U_USING_DEFAULT_WARNING) { 1240 // For some locale IDs, there may be no language which has a translation for every 1241 // piece. Rather than return nothing, see if we can at least handle 1242 // the language part of the locale. 1243 UErrorCode localStatus = U_ZERO_ERROR; 1244 int32_t localSize; 1245 UChar localName[kMaxICUNameSize]; 1246 localSize = uloc_getDisplayLanguage(value, locale, localName, kMaxICUNameSize, &localStatus); 1247 if (U_FAILURE(localStatus) || size <= 0 || localStatus == U_USING_DEFAULT_WARNING) 1248 return false; 1249 } 1250 1251 // This locale is OK, so use the result. 1252 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); 1253 return (*out != NULL); 1254 #else 1255 *out = CFRetain(CFSTR("(none)")); 1256 return true; 1257 #endif 1258 } 1259 1260 static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out) { 1261 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1262 return __CFLocaleICUName(locale, value, out, uloc_getDisplayLanguage); 1263 #else 1264 *out = CFRetain(CFSTR("(none)")); 1265 return true; 1266 #endif 1267 } 1268 1269 static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out) { 1270 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1271 // Need to make a fake locale ID 1272 char lid[ULOC_FULLNAME_CAPACITY]; 1273 if (strlen(value) < sizeof(lid) - 3) { 1274 strlcpy(lid, "en_", sizeof(lid)); 1275 strlcat(lid, value, sizeof(lid)); 1276 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayCountry); 1277 } 1278 return false; 1279 #else 1280 *out = CFRetain(CFSTR("(none)")); 1281 return true; 1282 #endif 1283 } 1284 1285 static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out) { 1286 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1287 // Need to make a fake locale ID 1288 char lid[ULOC_FULLNAME_CAPACITY]; 1289 if (strlen(value) == 4) { 1290 strlcpy(lid, "en_", sizeof(lid)); 1291 strlcat(lid, value, sizeof(lid)); 1292 strlcat(lid, "_US", sizeof(lid)); 1293 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayScript); 1294 } 1295 return false; 1296 #else 1297 *out = CFRetain(CFSTR("(none)")); 1298 return true; 1299 #endif 1300 } 1301 1302 static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out) { 1303 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1304 // Need to make a fake locale ID 1305 char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 1306 if (strlen(value) < sizeof(lid) - 6) { 1307 strlcpy(lid, "en_US_", sizeof(lid)); 1308 strlcat(lid, value, sizeof(lid)); 1309 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayVariant); 1310 } 1311 return false; 1312 #else 1313 *out = CFRetain(CFSTR("(none)")); 1314 return true; 1315 #endif 1316 } 1317 1318 static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out) { 1319 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1320 return __CFLocaleICUKeywordValueName(locale, value, kCalendarKeyword, out); 1321 #else 1322 *out = CFRetain(CFSTR("(none)")); 1323 return true; 1324 #endif 1325 } 1326 1327 static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out) { 1328 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1329 return __CFLocaleICUKeywordValueName(locale, value, kCollationKeyword, out); 1330 #else 1331 *out = CFRetain(CFSTR("(none)")); 1332 return true; 1333 #endif 1334 } 1335 1336 static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out) { 1337 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1338 return __CFLocaleICUCurrencyName(locale, value, UCURR_SYMBOL_NAME, out); 1339 #else 1340 *out = CFRetain(CFSTR("(none)")); 1341 return true; 1342 #endif 1343 } 1344 1345 static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out) { 1346 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1347 return __CFLocaleICUCurrencyName(locale, value, UCURR_LONG_NAME, out); 1348 #else 1349 *out = CFRetain(CFSTR("(none)")); 1350 return true; 1351 #endif 1352 } 1353 1354 static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out) { 1355 return false; 1356 } 1357 1358 #undef kMaxICUNameSize 1359