1/* 2 * Copyright (c) 2014 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-2013, 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 68CONST_STRING_DECL(kCFLocaleCurrentLocaleDidChangeNotification, "kCFLocaleCurrentLocaleDidChangeNotification") 69 70static const char *kCalendarKeyword = "calendar"; 71static const char *kCollationKeyword = "collation"; 72#define kMaxICUNameSize 1024 73 74typedef struct __CFLocale *CFMutableLocaleRef; 75 76PE_CONST_STRING_DECL(__kCFLocaleCollatorID, "locale:collator id") 77 78 79enum { 80 __kCFLocaleKeyTableCount = 21 81}; 82 83struct 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: 93static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 94static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context); 95static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out); 96static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 97static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out); 98static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out); 99static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out); 100static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out); 101static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 102static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out); 103static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out); 104static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 105static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out); 106static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out); 107static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 108static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 109static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 110static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 111static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 112static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 113static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out); 114static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); 115static 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 118static 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 143static CFLocaleRef __CFLocaleSystem = NULL; 144static CFMutableDictionaryRef __CFLocaleCache = NULL; 145static CFSpinLock_t __CFLocaleGlobalLock = CFSpinLockInit; 146 147struct __CFLocale { 148 CFRuntimeBase _base; 149 CFStringRef _identifier; // canonical identifier, never NULL 150 CFMutableDictionaryRef _cache; 151 CFMutableDictionaryRef _overrides; 152 CFDictionaryRef _prefs; 153 CFSpinLock_t _lock; 154 Boolean _nullLocale; 155}; 156 157CF_PRIVATE Boolean __CFLocaleGetNullLocale(struct __CFLocale *locale) { 158 return locale->_nullLocale; 159} 160 161CF_PRIVATE void __CFLocaleSetNullLocale(struct __CFLocale *locale) { 162 locale->_nullLocale = true; 163} 164 165/* Flag bits */ 166enum { /* Bits 0-1 */ 167 __kCFLocaleOrdinary = 0, 168 __kCFLocaleSystem = 1, 169 __kCFLocaleUser = 2, 170 __kCFLocaleCustom = 3 171}; 172 173CF_INLINE CFIndex __CFLocaleGetType(CFLocaleRef locale) { 174 return __CFBitfieldGetValue(((const CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0); 175} 176 177CF_INLINE void __CFLocaleSetType(CFLocaleRef locale, CFIndex type) { 178 __CFBitfieldSetValue(((CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0, (uint8_t)type); 179} 180 181CF_INLINE void __CFLocaleLockGlobal(void) { 182 __CFSpinLock(&__CFLocaleGlobalLock); 183} 184 185CF_INLINE void __CFLocaleUnlockGlobal(void) { 186 __CFSpinUnlock(&__CFLocaleGlobalLock); 187} 188 189CF_INLINE void __CFLocaleLock(CFLocaleRef locale) { 190 __CFSpinLock(&((struct __CFLocale *)locale)->_lock); 191} 192 193CF_INLINE void __CFLocaleUnlock(CFLocaleRef locale) { 194 __CFSpinUnlock(&((struct __CFLocale *)locale)->_lock); 195} 196 197 198static Boolean __CFLocaleEqual(CFTypeRef cf1, CFTypeRef cf2) { 199 CFLocaleRef locale1 = (CFLocaleRef)cf1; 200 CFLocaleRef locale2 = (CFLocaleRef)cf2; 201 // a user locale and a locale created with an ident are not the same even if their contents are 202 if (__CFLocaleGetType(locale1) != __CFLocaleGetType(locale2)) return false; 203 if (!CFEqual(locale1->_identifier, locale2->_identifier)) return false; 204 if (NULL == locale1->_overrides && NULL != locale2->_overrides) return false; 205 if (NULL != locale1->_overrides && NULL == locale2->_overrides) return false; 206 if (NULL != locale1->_overrides && !CFEqual(locale1->_overrides, locale2->_overrides)) return false; 207 if (__kCFLocaleUser == __CFLocaleGetType(locale1)) { 208 return CFEqual(locale1->_prefs, locale2->_prefs); 209 } 210 return true; 211} 212 213static CFHashCode __CFLocaleHash(CFTypeRef cf) { 214 CFLocaleRef locale = (CFLocaleRef)cf; 215 return CFHash(locale->_identifier); 216} 217 218static CFStringRef __CFLocaleCopyDescription(CFTypeRef cf) { 219 CFLocaleRef locale = (CFLocaleRef)cf; 220 const char *type = NULL; 221 switch (__CFLocaleGetType(locale)) { 222 case __kCFLocaleOrdinary: type = "ordinary"; break; 223 case __kCFLocaleSystem: type = "system"; break; 224 case __kCFLocaleUser: type = "user"; break; 225 case __kCFLocaleCustom: type = "custom"; break; 226 } 227 return CFStringCreateWithFormat(CFGetAllocator(locale), NULL, CFSTR("<CFLocale %p [%p]>{type = %s, identifier = '%@'}"), cf, CFGetAllocator(locale), type, locale->_identifier); 228} 229 230static void __CFLocaleDeallocate(CFTypeRef cf) { 231 CFLocaleRef locale = (CFLocaleRef)cf; 232 CFRelease(locale->_identifier); 233 if (NULL != locale->_cache) CFRelease(locale->_cache); 234 if (NULL != locale->_overrides) CFRelease(locale->_overrides); 235 if (NULL != locale->_prefs) CFRelease(locale->_prefs); 236} 237 238static CFTypeID __kCFLocaleTypeID = _kCFRuntimeNotATypeID; 239 240static const CFRuntimeClass __CFLocaleClass = { 241 0, 242 "CFLocale", 243 NULL, // init 244 NULL, // copy 245 __CFLocaleDeallocate, 246 __CFLocaleEqual, 247 __CFLocaleHash, 248 NULL, // 249 __CFLocaleCopyDescription 250}; 251 252static void __CFLocaleInitialize(void) { 253 CFIndex idx; 254 __kCFLocaleTypeID = _CFRuntimeRegisterClass(&__CFLocaleClass); 255 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { 256 // table fixup to workaround compiler/language limitations 257 __CFLocaleKeyTable[idx].key = *((CFStringRef *)__CFLocaleKeyTable[idx].key); 258 if (NULL != __CFLocaleKeyTable[idx].context) { 259 __CFLocaleKeyTable[idx].context = *((CFStringRef *)__CFLocaleKeyTable[idx].context); 260 } 261 } 262} 263 264CFTypeID CFLocaleGetTypeID(void) { 265 if (_kCFRuntimeNotATypeID == __kCFLocaleTypeID) __CFLocaleInitialize(); 266 return __kCFLocaleTypeID; 267} 268 269CFLocaleRef 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 289extern CFDictionaryRef __CFXPreferencesCopyCurrentApplicationState(void); 290 291static 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 302static 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 = CFSpinLockInit; 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 */ 376CFLocaleRef _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 */ 384CFLocaleRef _CFLocaleCopyAsIfCurrentWithOverrides(CFStringRef name, CFDictionaryRef overrides) { 385 return _CFLocaleCopyCurrentGuts(name, false, overrides); 386} 387 388CFLocaleRef CFLocaleCopyCurrent(void) { 389 return _CFLocaleCopyCurrentGuts(NULL, true, NULL); 390} 391 392CF_PRIVATE CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale) { 393 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFDictionaryRef, (NSLocale *)locale, _prefs); 394 return locale->_prefs; 395} 396 397CFLocaleRef 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 = CFSpinLockInit; 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 446CFLocaleRef CFLocaleCreateCopy(CFAllocatorRef allocator, CFLocaleRef locale) { 447 return (CFLocaleRef)CFRetain(locale); 448} 449 450CFStringRef CFLocaleGetIdentifier(CFLocaleRef locale) { 451 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFStringRef, (NSLocale *)locale, localeIdentifier); 452 return locale->_identifier; 453} 454 455CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key) { 456#if DEPLOYMENT_TARGET_MACOSX 457 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard)) { 458 // Hack for Opera, which is using the hard-coded string value below instead of 459 // the perfectly good public kCFLocaleCountryCode constant, for whatever reason. 460 if (key && CFEqual(key, CFSTR("locale:country code"))) { 461 key = kCFLocaleCountryCodeKey; 462 } 463 } 464#endif 465 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFTypeRef, (NSLocale *)locale, objectForKey:(id)key); 466 CFIndex idx, slot = -1; 467 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { 468 if (__CFLocaleKeyTable[idx].key == key) { 469 slot = idx; 470 break; 471 } 472 } 473 if (-1 == slot && NULL != key) { 474 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { 475 if (CFEqual(__CFLocaleKeyTable[idx].key, key)) { 476 slot = idx; 477 break; 478 } 479 } 480 } 481 if (-1 == slot) { 482 return NULL; 483 } 484 CFTypeRef value; 485 if (NULL != locale->_overrides && CFDictionaryGetValueIfPresent(locale->_overrides, __CFLocaleKeyTable[slot].key, &value)) { 486 return value; 487 } 488 __CFLocaleLock(locale); 489 if (CFDictionaryGetValueIfPresent(locale->_cache, __CFLocaleKeyTable[slot].key, &value)) { 490 __CFLocaleUnlock(locale); 491 return value; 492 } 493 if (__kCFLocaleUser == __CFLocaleGetType(locale) && __CFLocaleKeyTable[slot].get(locale, true, &value, __CFLocaleKeyTable[slot].context)) { 494 if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value); 495 if (value) CFRelease(value); 496 __CFLocaleUnlock(locale); 497 return value; 498 } 499 if (__CFLocaleKeyTable[slot].get(locale, false, &value, __CFLocaleKeyTable[slot].context)) { 500 if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value); 501 if (value) CFRelease(value); 502 __CFLocaleUnlock(locale); 503 return value; 504 } 505 __CFLocaleUnlock(locale); 506 return NULL; 507} 508 509CFStringRef CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale, CFStringRef key, CFStringRef value) { 510 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFStringRef, (NSLocale *)displayLocale, _copyDisplayNameForKey:(id)key value:(id)value); 511 CFIndex idx, slot = -1; 512 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { 513 if (__CFLocaleKeyTable[idx].key == key) { 514 slot = idx; 515 break; 516 } 517 } 518 if (-1 == slot && NULL != key) { 519 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { 520 if (CFEqual(__CFLocaleKeyTable[idx].key, key)) { 521 slot = idx; 522 break; 523 } 524 } 525 } 526 if (-1 == slot || !value) { 527 return NULL; 528 } 529 // Get the locale ID as a C string 530 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 531 char cValue[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 532 if (CFStringGetCString(displayLocale->_identifier, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII) && CFStringGetCString(value, cValue, sizeof(cValue)/sizeof(char), kCFStringEncodingASCII)) { 533 CFStringRef result; 534 if ((NULL == displayLocale->_prefs) && __CFLocaleKeyTable[slot].name(localeID, cValue, &result)) { 535 return result; 536 } 537 538 // We could not find a result using the requested language. Fall back through all preferred languages. 539 CFArrayRef langPref = NULL; 540 if (displayLocale->_prefs) { 541 langPref = (CFArrayRef)CFDictionaryGetValue(displayLocale->_prefs, CFSTR("AppleLanguages")); 542 if (langPref) CFRetain(langPref); 543 } else { 544#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 545 langPref = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); 546#endif 547 } 548 if (langPref != NULL) { 549 CFIndex count = CFArrayGetCount(langPref); 550 CFIndex i; 551 bool success = false; 552 for (i = 0; i < count && !success; ++i) { 553 CFStringRef language = (CFStringRef)CFArrayGetValueAtIndex(langPref, i); 554 CFStringRef cleanLanguage = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, language); 555 if (CFStringGetCString(cleanLanguage, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII)) { 556 success = __CFLocaleKeyTable[slot].name(localeID, cValue, &result); 557 } 558 CFRelease(cleanLanguage); 559 } 560 CFRelease(langPref); 561 if (success) 562 return result; 563 } 564 } 565 return NULL; 566} 567 568CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void) { 569#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 570 int32_t locale, localeCount = uloc_countAvailable(); 571 CFMutableSetRef working = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); 572 for (locale = 0; locale < localeCount; ++locale) { 573 const char *localeID = uloc_getAvailable(locale); 574 CFStringRef string1 = CFStringCreateWithCString(kCFAllocatorSystemDefault, localeID, kCFStringEncodingASCII); 575 // do not include canonicalized version as IntlFormats cannot cope with that in its popup 576 CFSetAddValue(working, string1); 577 CFRelease(string1); 578 } 579 CFIndex cnt = CFSetGetCount(working); 580 STACK_BUFFER_DECL(const void *, buffer, cnt); 581 CFSetGetValues(working, buffer); 582 CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, buffer, cnt, &kCFTypeArrayCallBacks); 583 CFRelease(working); 584 return result; 585#else 586 return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); 587#endif 588} 589 590#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 591static CFArrayRef __CFLocaleCopyCStringsAsArray(const char* const* p) { 592 CFMutableArrayRef working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 593 for (; *p; ++p) { 594 CFStringRef string = CFStringCreateWithCString(kCFAllocatorSystemDefault, *p, kCFStringEncodingASCII); 595 CFArrayAppendValue(working, string); 596 CFRelease(string); 597 } 598 CFArrayRef result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working); 599 CFRelease(working); 600 return result; 601} 602 603static CFArrayRef __CFLocaleCopyUEnumerationAsArray(UEnumeration *enumer, UErrorCode *icuErr) { 604 const UChar *next = NULL; 605 int32_t len = 0; 606 CFMutableArrayRef working = NULL; 607 if (U_SUCCESS(*icuErr)) { 608 working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 609 } 610 while ((next = uenum_unext(enumer, &len, icuErr)) && U_SUCCESS(*icuErr)) { 611 CFStringRef string = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)next, (CFIndex) len); 612 CFArrayAppendValue(working, string); 613 CFRelease(string); 614 } 615 if (*icuErr == U_INDEX_OUTOFBOUNDS_ERROR) { 616 *icuErr = U_ZERO_ERROR; // Temp: Work around bug (ICU 5220) in ucurr enumerator 617 } 618 CFArrayRef result = NULL; 619 if (U_SUCCESS(*icuErr)) { 620 result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working); 621 } 622 if (working != NULL) { 623 CFRelease(working); 624 } 625 return result; 626} 627#endif 628 629CFArrayRef CFLocaleCopyISOLanguageCodes(void) { 630#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 631 const char* const* p = uloc_getISOLanguages(); 632 return __CFLocaleCopyCStringsAsArray(p); 633#else 634 return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); 635#endif 636} 637 638CFArrayRef CFLocaleCopyISOCountryCodes(void) { 639#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 640 const char* const* p = uloc_getISOCountries(); 641 return __CFLocaleCopyCStringsAsArray(p); 642#else 643 return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); 644#endif 645} 646 647CFArrayRef CFLocaleCopyISOCurrencyCodes(void) { 648#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 649 UErrorCode icuStatus = U_ZERO_ERROR; 650 UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_ALL, &icuStatus); 651 CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus); 652 uenum_close(enumer); 653#else 654 CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); 655#endif 656 return result; 657} 658 659CFArrayRef CFLocaleCopyCommonISOCurrencyCodes(void) { 660#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 661 UErrorCode icuStatus = U_ZERO_ERROR; 662 UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &icuStatus); 663 CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus); 664 uenum_close(enumer); 665#else 666 CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); 667#endif 668 return result; 669} 670 671CFStringRef CFLocaleCreateLocaleIdentifierFromWindowsLocaleCode(CFAllocatorRef allocator, uint32_t lcid) { 672#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 673 char buffer[kMaxICUNameSize]; 674 UErrorCode status = U_ZERO_ERROR; 675 int32_t ret = uloc_getLocaleForLCID(lcid, buffer, kMaxICUNameSize, &status); 676 if (U_FAILURE(status) || kMaxICUNameSize <= ret) return NULL; 677 CFStringRef str = CFStringCreateWithCString(kCFAllocatorSystemDefault, buffer, kCFStringEncodingASCII); 678 CFStringRef ident = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, str); 679 CFRelease(str); 680 return ident; 681#else 682 return CFSTR(""); 683#endif 684} 685 686uint32_t CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier(CFStringRef localeIdentifier) { 687#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 688 CFStringRef ident = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, localeIdentifier); 689 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 690 Boolean b = ident ? CFStringGetCString(ident, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false; 691 if (ident) CFRelease(ident); 692 return b ? uloc_getLCID(localeID) : 0; 693#else 694 return 0; 695#endif 696} 697 698CFLocaleLanguageDirection CFLocaleGetLanguageCharacterDirection(CFStringRef isoLangCode) { 699#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 700 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 701 Boolean b = isoLangCode ? CFStringGetCString(isoLangCode, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false; 702 CFLocaleLanguageDirection dir; 703 UErrorCode status = U_ZERO_ERROR; 704 ULayoutType idir = b ? uloc_getCharacterOrientation(localeID, &status) : ULOC_LAYOUT_UNKNOWN; 705 switch (idir) { 706 case ULOC_LAYOUT_LTR: dir = kCFLocaleLanguageDirectionLeftToRight; break; 707 case ULOC_LAYOUT_RTL: dir = kCFLocaleLanguageDirectionRightToLeft; break; 708 case ULOC_LAYOUT_TTB: dir = kCFLocaleLanguageDirectionTopToBottom; break; 709 case ULOC_LAYOUT_BTT: dir = kCFLocaleLanguageDirectionBottomToTop; break; 710 default: dir = kCFLocaleLanguageDirectionUnknown; break; 711 } 712 return dir; 713#else 714 return kCFLocaleLanguageDirectionLeftToRight; 715#endif 716} 717 718CFLocaleLanguageDirection CFLocaleGetLanguageLineDirection(CFStringRef isoLangCode) { 719#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 720 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 721 Boolean b = isoLangCode ? CFStringGetCString(isoLangCode, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false; 722 CFLocaleLanguageDirection dir; 723 UErrorCode status = U_ZERO_ERROR; 724 ULayoutType idir = b ? uloc_getLineOrientation(localeID, &status) : ULOC_LAYOUT_UNKNOWN; 725 switch (idir) { 726 case ULOC_LAYOUT_LTR: dir = kCFLocaleLanguageDirectionLeftToRight; break; 727 case ULOC_LAYOUT_RTL: dir = kCFLocaleLanguageDirectionRightToLeft; break; 728 case ULOC_LAYOUT_TTB: dir = kCFLocaleLanguageDirectionTopToBottom; break; 729 case ULOC_LAYOUT_BTT: dir = kCFLocaleLanguageDirectionBottomToTop; break; 730 default: dir = kCFLocaleLanguageDirectionUnknown; break; 731 } 732 return dir; 733#else 734 return kCFLocaleLanguageDirectionLeftToRight; 735#endif 736} 737 738CFArrayRef CFLocaleCopyPreferredLanguages(void) { 739 CFMutableArrayRef newArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 740#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS 741 CFArrayRef languagesArray = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); 742 if (languagesArray && (CFArrayGetTypeID() == CFGetTypeID(languagesArray))) { 743 for (CFIndex idx = 0, cnt = CFArrayGetCount(languagesArray); idx < cnt; idx++) { 744 CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(languagesArray, idx); 745 if (str && (CFStringGetTypeID() == CFGetTypeID(str))) { 746 CFStringRef ident = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, str); 747 CFArrayAppendValue(newArray, ident); 748 CFRelease(ident); 749 } 750 } 751 } 752 if (languagesArray) CFRelease(languagesArray); 753#endif 754 return newArray; 755} 756 757// -------- -------- -------- -------- -------- -------- 758 759// These functions return true or false depending on the success or failure of the function. 760// In the Copy case, this is failure to fill the *cf out parameter, and that out parameter is 761// returned by reference WITH a retain on it. 762static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context) { 763 return false; 764} 765 766static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 767 *cf = CFRetain(locale->_identifier); 768 return true; 769} 770 771 772static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 773 CFDictionaryRef codes = NULL; 774 // this access of _cache is protected by the lock in CFLocaleGetValue() 775 if (!CFDictionaryGetValueIfPresent(locale->_cache, CFSTR("__kCFLocaleCodes"), (const void **)&codes)) { 776 codes = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, locale->_identifier); 777 if (codes) CFDictionarySetValue(locale->_cache, CFSTR("__kCFLocaleCodes"), codes); 778 if (codes) CFRelease(codes); 779 } 780 if (codes) { 781 CFStringRef value = (CFStringRef)CFDictionaryGetValue(codes, context); // context is one of kCFLocale*Code constants 782 if (value) CFRetain(value); 783 *cf = value; 784 return true; 785 } 786 return false; 787} 788 789#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 790CFCharacterSetRef _CFCreateCharacterSetFromUSet(USet *set) { 791 UErrorCode icuErr = U_ZERO_ERROR; 792 CFMutableCharacterSetRef working = CFCharacterSetCreateMutable(NULL); 793 UChar buffer[2048]; // Suitable for most small sets 794 int32_t stringLen; 795 796 if (working == NULL) 797 return NULL; 798 799 int32_t itemCount = uset_getItemCount(set); 800 int32_t i; 801 for (i = 0; i < itemCount; ++i) 802 { 803 UChar32 start, end; 804 UChar * string; 805 806 string = buffer; 807 stringLen = uset_getItem(set, i, &start, &end, buffer, sizeof(buffer)/sizeof(UChar), &icuErr); 808 if (icuErr == U_BUFFER_OVERFLOW_ERROR) 809 { 810 string = (UChar *) malloc(sizeof(UChar)*(stringLen+1)); 811 if (!string) 812 { 813 CFRelease(working); 814 return NULL; 815 } 816 icuErr = U_ZERO_ERROR; 817 (void) uset_getItem(set, i, &start, &end, string, stringLen+1, &icuErr); 818 } 819 if (U_FAILURE(icuErr)) 820 { 821 if (string != buffer) 822 free(string); 823 CFRelease(working); 824 return NULL; 825 } 826 if (stringLen <= 0) 827 CFCharacterSetAddCharactersInRange(working, CFRangeMake(start, end-start+1)); 828 else 829 { 830 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, (UniChar *)string, stringLen, kCFAllocatorNull); 831 CFCharacterSetAddCharactersInString(working, cfString); 832 CFRelease(cfString); 833 } 834 if (string != buffer) 835 free(string); 836 } 837 838 CFCharacterSetRef result = CFCharacterSetCreateCopy(kCFAllocatorSystemDefault, working); 839 CFRelease(working); 840 return result; 841} 842#endif 843 844static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 845#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 846 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 847 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { 848 UErrorCode icuStatus = U_ZERO_ERROR; 849 ULocaleData* uld = ulocdata_open(localeID, &icuStatus); 850 USet *set = ulocdata_getExemplarSet(uld, NULL, USET_ADD_CASE_MAPPINGS, ULOCDATA_ES_STANDARD, &icuStatus); 851 ulocdata_close(uld); 852 if (U_FAILURE(icuStatus)) 853 return false; 854 if (icuStatus == U_USING_DEFAULT_WARNING) // If default locale used, force to empty set 855 uset_clear(set); 856 *cf = (CFTypeRef) _CFCreateCharacterSetFromUSet(set); 857 uset_close(set); 858 return (*cf != NULL); 859 } 860#endif 861 return false; 862} 863 864static bool __CFLocaleCopyICUKeyword(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context, const char *keyword) 865{ 866#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 867 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 868 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) 869 { 870 char value[ULOC_KEYWORD_AND_VALUES_CAPACITY]; 871 UErrorCode icuStatus = U_ZERO_ERROR; 872 if (uloc_getKeywordValue(localeID, keyword, value, sizeof(value)/sizeof(char), &icuStatus) > 0 && U_SUCCESS(icuStatus)) 873 { 874 *cf = (CFTypeRef) CFStringCreateWithCString(kCFAllocatorSystemDefault, value, kCFStringEncodingASCII); 875 return true; 876 } 877 } 878#endif 879 *cf = NULL; 880 return false; 881} 882 883static bool __CFLocaleCopyICUCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context, const char *keyword) { 884#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 885 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 886 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { 887 UErrorCode icuStatus = U_ZERO_ERROR; 888 UEnumeration *en = ucal_getKeywordValuesForLocale(keyword, localeID, TRUE, &icuStatus); 889 int32_t len; 890 const char *value = uenum_next(en, &len, &icuStatus); 891 if (U_SUCCESS(icuStatus)) { 892 *cf = (CFTypeRef) CFStringCreateWithCString(kCFAllocatorSystemDefault, value, kCFStringEncodingASCII); 893 uenum_close(en); 894 return true; 895 } 896 uenum_close(en); 897 } 898#endif 899 *cf = NULL; 900 return false; 901} 902 903static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 904 bool succeeded = __CFLocaleCopyICUKeyword(locale, user, cf, context, kCalendarKeyword); 905 if (!succeeded) { 906 succeeded = __CFLocaleCopyICUCalendarID(locale, user, cf, context, kCalendarKeyword); 907 } 908 if (succeeded) { 909 if (CFEqual(*cf, kCFCalendarIdentifierGregorian)) { 910 CFRelease(*cf); 911 *cf = CFRetain(kCFCalendarIdentifierGregorian); 912 } else if (CFEqual(*cf, kCFCalendarIdentifierBuddhist)) { 913 CFRelease(*cf); 914 *cf = CFRetain(kCFCalendarIdentifierBuddhist); 915 } else if (CFEqual(*cf, kCFCalendarIdentifierJapanese)) { 916 CFRelease(*cf); 917 *cf = CFRetain(kCFCalendarIdentifierJapanese); 918 } else if (CFEqual(*cf, kCFCalendarIdentifierIslamic)) { 919 CFRelease(*cf); 920 *cf = CFRetain(kCFCalendarIdentifierIslamic); 921 } else if (CFEqual(*cf, kCFCalendarIdentifierIslamicCivil)) { 922 CFRelease(*cf); 923 *cf = CFRetain(kCFCalendarIdentifierIslamicCivil); 924 } else if (CFEqual(*cf, kCFCalendarIdentifierHebrew)) { 925 CFRelease(*cf); 926 *cf = CFRetain(kCFCalendarIdentifierHebrew); 927 } else if (CFEqual(*cf, kCFCalendarIdentifierChinese)) { 928 CFRelease(*cf); 929 *cf = CFRetain(kCFCalendarIdentifierChinese); 930 } else if (CFEqual(*cf, kCFCalendarIdentifierRepublicOfChina)) { 931 CFRelease(*cf); 932 *cf = CFRetain(kCFCalendarIdentifierRepublicOfChina); 933 } else if (CFEqual(*cf, kCFCalendarIdentifierPersian)) { 934 CFRelease(*cf); 935 *cf = CFRetain(kCFCalendarIdentifierPersian); 936 } else if (CFEqual(*cf, kCFCalendarIdentifierIndian)) { 937 CFRelease(*cf); 938 *cf = CFRetain(kCFCalendarIdentifierIndian); 939 } else if (CFEqual(*cf, kCFCalendarIdentifierISO8601)) { 940 CFRelease(*cf); 941 *cf = CFRetain(kCFCalendarIdentifierISO8601); 942 } else if (CFEqual(*cf, kCFCalendarIdentifierCoptic)) { 943 CFRelease(*cf); 944 *cf = CFRetain(kCFCalendarIdentifierCoptic); 945 } else if (CFEqual(*cf, kCFCalendarIdentifierEthiopicAmeteMihret)) { 946 CFRelease(*cf); 947 *cf = CFRetain(kCFCalendarIdentifierEthiopicAmeteMihret); 948 } else if (CFEqual(*cf, kCFCalendarIdentifierEthiopicAmeteAlem)) { 949 CFRelease(*cf); 950 *cf = CFRetain(kCFCalendarIdentifierEthiopicAmeteAlem); 951 } else { 952 CFRelease(*cf); 953 *cf = NULL; 954 return false; 955 } 956 } else { 957 *cf = CFRetain(kCFCalendarIdentifierGregorian); 958 } 959 return true; 960} 961 962static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 963#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 964 if (__CFLocaleCopyCalendarID(locale, user, cf, context)) { 965 CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, (CFStringRef)*cf); 966 CFCalendarSetLocale(calendar, locale); 967 CFDictionaryRef prefs = __CFLocaleGetPrefs(locale); 968 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleFirstWeekday")) : NULL; 969 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { 970 metapref = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)metapref, *cf); 971 } 972 if (NULL != metapref && CFGetTypeID(metapref) == CFNumberGetTypeID()) { 973 CFIndex wkdy; 974 if (CFNumberGetValue((CFNumberRef)metapref, kCFNumberCFIndexType, &wkdy)) { 975 CFCalendarSetFirstWeekday(calendar, wkdy); 976 } 977 } 978 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleMinDaysInFirstWeek")) : NULL; 979 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { 980 metapref = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)metapref, *cf); 981 } 982 if (NULL != metapref && CFGetTypeID(metapref) == CFNumberGetTypeID()) { 983 CFIndex mwd; 984 if (CFNumberGetValue((CFNumberRef)metapref, kCFNumberCFIndexType, &mwd)) { 985 CFCalendarSetMinimumDaysInFirstWeek(calendar, mwd); 986 } 987 } 988 CFRelease(*cf); 989 *cf = calendar; 990 return true; 991 } 992#endif 993 return false; 994} 995 996static bool __CFLocaleCopyDelimiter(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 997#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 998 ULocaleDataDelimiterType type = (ULocaleDataDelimiterType)0; 999 if (context == kCFLocaleQuotationBeginDelimiterKey) { 1000 type = ULOCDATA_QUOTATION_START; 1001 } else if (context == kCFLocaleQuotationEndDelimiterKey) { 1002 type = ULOCDATA_QUOTATION_END; 1003 } else if (context == kCFLocaleAlternateQuotationBeginDelimiterKey) { 1004 type = ULOCDATA_ALT_QUOTATION_START; 1005 } else if (context == kCFLocaleAlternateQuotationEndDelimiterKey) { 1006 type = ULOCDATA_ALT_QUOTATION_END; 1007 } else { 1008 return false; 1009 } 1010 1011 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 1012 if (!CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { 1013 return false; 1014 } 1015 1016 UChar buffer[130]; 1017 UErrorCode status = U_ZERO_ERROR; 1018 ULocaleData *uld = ulocdata_open(localeID, &status); 1019 int32_t len = ulocdata_getDelimiter(uld, type, buffer, sizeof(buffer) / sizeof(buffer[0]), &status); 1020 ulocdata_close(uld); 1021 if (U_FAILURE(status) || sizeof(buffer) / sizeof(buffer[0]) < len) { 1022 return false; 1023 } 1024 1025 *cf = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)buffer, len); 1026 return (*cf != NULL); 1027#else 1028 if (context == kCFLocaleQuotationBeginDelimiterKey || context == kCFLocaleQuotationEndDelimiterKey || context == kCFLocaleAlternateQuotationBeginDelimiterKey || context == kCFLocaleAlternateQuotationEndDelimiterKey) { 1029 *cf = CFRetain(CFSTR("\"")); 1030 return true; 1031 } else { 1032 return false; 1033 } 1034#endif 1035} 1036 1037static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1038 return __CFLocaleCopyICUKeyword(locale, user, cf, context, kCollationKeyword); 1039} 1040 1041static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1042 CFStringRef canonLocaleCFStr = NULL; 1043 if (user && locale->_prefs) { 1044 CFStringRef pref = (CFStringRef)CFDictionaryGetValue(locale->_prefs, CFSTR("AppleCollationOrder")); 1045 if (pref) { 1046 // Canonicalize pref string in case it's not in the canonical format. 1047 canonLocaleCFStr = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, pref); 1048 } else { 1049 CFArrayRef languagesArray = (CFArrayRef)CFDictionaryGetValue(locale->_prefs, CFSTR("AppleLanguages")); 1050 if (languagesArray && (CFArrayGetTypeID() == CFGetTypeID(languagesArray))) { 1051 if (0 < CFArrayGetCount(languagesArray)) { 1052 CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(languagesArray, 0); 1053 if (str && (CFStringGetTypeID() == CFGetTypeID(str))) { 1054 canonLocaleCFStr = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, str); 1055 } 1056 } 1057 } 1058 } 1059 } 1060 if (!canonLocaleCFStr) { 1061 canonLocaleCFStr = CFLocaleGetIdentifier(locale); 1062 CFRetain(canonLocaleCFStr); 1063 } 1064 *cf = canonLocaleCFStr; 1065 return canonLocaleCFStr ? true : false; 1066} 1067 1068static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1069#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1070 bool us = false; // Default is Metric 1071 bool done = false; 1072#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 1073 if (user) { 1074 CFTypeRef pref = CFDictionaryGetValue(locale->_prefs, CFSTR("AppleMetricUnits")); 1075 if (pref) { 1076 us = (kCFBooleanFalse == pref); 1077 done = true; 1078 } else { 1079 pref = CFDictionaryGetValue(locale->_prefs, CFSTR("AppleMeasurementUnits")); 1080 if (pref) { 1081 us = CFEqual(pref, CFSTR("Inches")); 1082 done = true; 1083 } 1084 } 1085 } 1086#endif 1087 if (!done) { 1088 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 1089 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { 1090 UErrorCode icuStatus = U_ZERO_ERROR; 1091 UMeasurementSystem ms = UMS_SI; 1092 ms = ulocdata_getMeasurementSystem(localeID, &icuStatus); 1093 if (U_SUCCESS(icuStatus)) { 1094 us = (ms == UMS_US); 1095 done = true; 1096 } 1097 } 1098 } 1099 if (!done) 1100 us = false; 1101 *cf = us ? CFRetain(kCFBooleanFalse) : CFRetain(kCFBooleanTrue); 1102 return true; 1103#else 1104 *cf = CFRetain(kCFBooleanFalse); 1105 return true; 1106#endif 1107} 1108 1109static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1110 if (__CFLocaleCopyUsesMetric(locale, user, cf, context)) { 1111 bool us = (*cf == kCFBooleanFalse); 1112 CFRelease(*cf); 1113 *cf = us ? CFRetain(CFSTR("U.S.")) : CFRetain(CFSTR("Metric")); 1114 return true; 1115 } 1116 return false; 1117} 1118 1119static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1120 CFStringRef str = NULL; 1121#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1122 CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterDecimalStyle); 1123 str = nf ? (CFStringRef)CFNumberFormatterCopyProperty(nf, context) : NULL; 1124 if (nf) CFRelease(nf); 1125#endif 1126 if (str) { 1127 *cf = str; 1128 return true; 1129 } 1130 return false; 1131} 1132 1133// ICU does not reliably set up currency info for other than Currency-type formatters, 1134// so we have to have another routine here which creates a Currency number formatter. 1135static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { 1136 CFStringRef str = NULL; 1137#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1138 CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterCurrencyStyle); 1139 str = nf ? (CFStringRef)CFNumberFormatterCopyProperty(nf, context) : NULL; 1140 if (nf) CFRelease(nf); 1141#endif 1142 if (str) { 1143 *cf = str; 1144 return true; 1145 } 1146 return false; 1147} 1148 1149#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1150typedef int32_t (*__CFICUFunction)(const char *, const char *, UChar *, int32_t, UErrorCode *); 1151 1152static bool __CFLocaleICUName(const char *locale, const char *valLocale, CFStringRef *out, __CFICUFunction icu) { 1153 UErrorCode icuStatus = U_ZERO_ERROR; 1154 int32_t size; 1155 UChar name[kMaxICUNameSize]; 1156 1157 size = (*icu)(valLocale, locale, name, kMaxICUNameSize, &icuStatus); 1158 if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) { 1159 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); 1160 return (*out != NULL); 1161 } 1162 return false; 1163} 1164 1165static bool __CFLocaleICUKeywordValueName(const char *locale, const char *value, const char *keyword, CFStringRef *out) { 1166 UErrorCode icuStatus = U_ZERO_ERROR; 1167 int32_t size = 0; 1168 UChar name[kMaxICUNameSize]; 1169 // Need to make a fake locale ID 1170 char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 1171 if (strlen(value) < ULOC_KEYWORD_AND_VALUES_CAPACITY) { 1172 strlcpy(lid, "en_US@", sizeof(lid)); 1173 strlcat(lid, keyword, sizeof(lid)); 1174 strlcat(lid, "=", sizeof(lid)); 1175 strlcat(lid, value, sizeof(lid)); 1176 size = uloc_getDisplayKeywordValue(lid, keyword, locale, name, kMaxICUNameSize, &icuStatus); 1177 if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) { 1178 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); 1179 return (*out != NULL); 1180 } 1181 } 1182 return false; 1183} 1184 1185static bool __CFLocaleICUCurrencyName(const char *locale, const char *value, UCurrNameStyle style, CFStringRef *out) { 1186 int valLen = strlen(value); 1187 if (valLen != 3) // not a valid ISO code 1188 return false; 1189 UChar curr[4]; 1190 UBool isChoice = FALSE; 1191 int32_t size = 0; 1192 UErrorCode icuStatus = U_ZERO_ERROR; 1193 u_charsToUChars(value, curr, valLen); 1194 curr[valLen] = '\0'; 1195 const UChar *name; 1196 name = ucurr_getName(curr, locale, style, &isChoice, &size, &icuStatus); 1197 if (U_FAILURE(icuStatus) || icuStatus == U_USING_DEFAULT_WARNING) 1198 return false; 1199 UChar result[kMaxICUNameSize]; 1200 if (isChoice) 1201 { 1202 UChar pattern[kMaxICUNameSize]; 1203 CFStringRef patternRef = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{0,choice,%S}"), name); 1204 CFIndex pattlen = CFStringGetLength(patternRef); 1205 CFStringGetCharacters(patternRef, CFRangeMake(0, pattlen), (UniChar *)pattern); 1206 CFRelease(patternRef); 1207 pattern[pattlen] = '\0'; // null terminate the pattern 1208 // Format the message assuming a large amount of the currency 1209 size = u_formatMessage("en_US", pattern, pattlen, result, kMaxICUNameSize, &icuStatus, 10.0); 1210 if (U_FAILURE(icuStatus)) 1211 return false; 1212 name = result; 1213 1214 } 1215 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); 1216 return (*out != NULL); 1217} 1218#endif 1219 1220static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out) { 1221#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1222 UErrorCode icuStatus = U_ZERO_ERROR; 1223 int32_t size; 1224 UChar name[kMaxICUNameSize]; 1225 1226 // First, try to get the full locale. 1227 size = uloc_getDisplayName(value, locale, name, kMaxICUNameSize, &icuStatus); 1228 if (U_FAILURE(icuStatus) || size <= 0) 1229 return false; 1230 1231 // Did we wind up using a default somewhere? 1232 if (icuStatus == U_USING_DEFAULT_WARNING) { 1233 // For some locale IDs, there may be no language which has a translation for every 1234 // piece. Rather than return nothing, see if we can at least handle 1235 // the language part of the locale. 1236 UErrorCode localStatus = U_ZERO_ERROR; 1237 int32_t localSize; 1238 UChar localName[kMaxICUNameSize]; 1239 localSize = uloc_getDisplayLanguage(value, locale, localName, kMaxICUNameSize, &localStatus); 1240 if (U_FAILURE(localStatus) || size <= 0 || localStatus == U_USING_DEFAULT_WARNING) 1241 return false; 1242 } 1243 1244 // This locale is OK, so use the result. 1245 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); 1246 return (*out != NULL); 1247#else 1248 *out = CFRetain(CFSTR("(none)")); 1249 return true; 1250#endif 1251} 1252 1253static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out) { 1254#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1255 return __CFLocaleICUName(locale, value, out, uloc_getDisplayLanguage); 1256#else 1257 *out = CFRetain(CFSTR("(none)")); 1258 return true; 1259#endif 1260} 1261 1262static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out) { 1263#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1264 // Need to make a fake locale ID 1265 char lid[ULOC_FULLNAME_CAPACITY]; 1266 if (strlen(value) < sizeof(lid) - 3) { 1267 strlcpy(lid, "en_", sizeof(lid)); 1268 strlcat(lid, value, sizeof(lid)); 1269 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayCountry); 1270 } 1271 return false; 1272#else 1273 *out = CFRetain(CFSTR("(none)")); 1274 return true; 1275#endif 1276} 1277 1278static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out) { 1279#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1280 // Need to make a fake locale ID 1281 char lid[ULOC_FULLNAME_CAPACITY]; 1282 if (strlen(value) == 4) { 1283 strlcpy(lid, "en_", sizeof(lid)); 1284 strlcat(lid, value, sizeof(lid)); 1285 strlcat(lid, "_US", sizeof(lid)); 1286 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayScript); 1287 } 1288 return false; 1289#else 1290 *out = CFRetain(CFSTR("(none)")); 1291 return true; 1292#endif 1293} 1294 1295static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out) { 1296#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1297 // Need to make a fake locale ID 1298 char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; 1299 if (strlen(value) < sizeof(lid) - 6) { 1300 strlcpy(lid, "en_US_", sizeof(lid)); 1301 strlcat(lid, value, sizeof(lid)); 1302 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayVariant); 1303 } 1304 return false; 1305#else 1306 *out = CFRetain(CFSTR("(none)")); 1307 return true; 1308#endif 1309} 1310 1311static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out) { 1312#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1313 return __CFLocaleICUKeywordValueName(locale, value, kCalendarKeyword, out); 1314#else 1315 *out = CFRetain(CFSTR("(none)")); 1316 return true; 1317#endif 1318} 1319 1320static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out) { 1321#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1322 return __CFLocaleICUKeywordValueName(locale, value, kCollationKeyword, out); 1323#else 1324 *out = CFRetain(CFSTR("(none)")); 1325 return true; 1326#endif 1327} 1328 1329static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out) { 1330#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1331 return __CFLocaleICUCurrencyName(locale, value, UCURR_SYMBOL_NAME, out); 1332#else 1333 *out = CFRetain(CFSTR("(none)")); 1334 return true; 1335#endif 1336} 1337 1338static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out) { 1339#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 1340 return __CFLocaleICUCurrencyName(locale, value, UCURR_LONG_NAME, out); 1341#else 1342 *out = CFRetain(CFSTR("(none)")); 1343 return true; 1344#endif 1345} 1346 1347static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out) { 1348 return false; 1349} 1350 1351#undef kMaxICUNameSize 1352 1353