2 * Copyright (c) 2010 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 2002-2009, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
29 // Note the header file is in the OpenSource set (stripped to almost nothing), but not the .c file
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 #include <unicode/uloc.h> // ICU locales
41 #include <unicode/ulocdata.h> // ICU locale data
42 #include <unicode/ucurr.h> // ICU currency functions
43 #include <unicode/uset.h> // ICU Unicode sets
44 #include <unicode/putil.h> // ICU low-level utilities
45 #include <unicode/umsg.h> // ICU message formatting
46 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
47 #include <CoreFoundation/CFNumberFormatter.h>
48 #include <dispatch/dispatch.h>
51 #include <unicode/ucol.h>
52 #elif DEPLOYMENT_TARGET_WINDOWS
55 #error Unknown or unspecified DEPLOYMENT_TARGET
58 CONST_STRING_DECL(kCFLocaleCurrentLocaleDidChangeNotification
, "kCFLocaleCurrentLocaleDidChangeNotification")
60 static const char *kCalendarKeyword
= "calendar";
61 static const char *kCollationKeyword
= "collation";
62 #define kMaxICUNameSize 1024
64 typedef struct __CFLocale
*CFMutableLocaleRef
;
66 PE_CONST_STRING_DECL(__kCFLocaleCollatorID
, "locale:collator id")
70 __kCFLocaleKeyTableCount
= 21
75 bool (*get
)(CFLocaleRef
, bool user
, CFTypeRef
*, CFStringRef context
); // returns an immutable copy & reference
76 bool (*set
)(CFMutableLocaleRef
, CFTypeRef
, CFStringRef context
);
77 bool (*name
)(const char *, const char *, CFStringRef
*);
82 // Must forward decl. these functions:
83 static bool __CFLocaleCopyLocaleID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
84 static bool __CFLocaleSetNOP(CFMutableLocaleRef locale
, CFTypeRef cf
, CFStringRef context
);
85 static bool __CFLocaleFullName(const char *locale
, const char *value
, CFStringRef
*out
);
86 static bool __CFLocaleCopyCodes(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
87 static bool __CFLocaleCountryName(const char *locale
, const char *value
, CFStringRef
*out
);
88 static bool __CFLocaleScriptName(const char *locale
, const char *value
, CFStringRef
*out
);
89 static bool __CFLocaleLanguageName(const char *locale
, const char *value
, CFStringRef
*out
);
90 static bool __CFLocaleCurrencyShortName(const char *locale
, const char *value
, CFStringRef
*out
);
91 static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
92 static bool __CFLocaleVariantName(const char *locale
, const char *value
, CFStringRef
*out
);
93 static bool __CFLocaleNoName(const char *locale
, const char *value
, CFStringRef
*out
);
94 static bool __CFLocaleCopyCalendarID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
95 static bool __CFLocaleCalendarName(const char *locale
, const char *value
, CFStringRef
*out
);
96 static bool __CFLocaleCollationName(const char *locale
, const char *value
, CFStringRef
*out
);
97 static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
98 static bool __CFLocaleCopyCalendar(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
99 static bool __CFLocaleCopyCollationID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
100 static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
101 static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
102 static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
103 static bool __CFLocaleCurrencyFullName(const char *locale
, const char *value
, CFStringRef
*out
);
104 static bool __CFLocaleCopyCollatorID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
105 static bool __CFLocaleCopyDelimiter(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
107 // Note string members start with an extra &, and are fixed up at init time
108 static struct key_table __CFLocaleKeyTable
[__kCFLocaleKeyTableCount
] = {
109 {(CFStringRef
)&kCFLocaleIdentifierKey
, __CFLocaleCopyLocaleID
, __CFLocaleSetNOP
, __CFLocaleFullName
, NULL
},
110 {(CFStringRef
)&kCFLocaleLanguageCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleLanguageName
, (CFStringRef
)&kCFLocaleLanguageCodeKey
},
111 {(CFStringRef
)&kCFLocaleCountryCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleCountryName
, (CFStringRef
)&kCFLocaleCountryCodeKey
},
112 {(CFStringRef
)&kCFLocaleScriptCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleScriptName
, (CFStringRef
)&kCFLocaleScriptCodeKey
},
113 {(CFStringRef
)&kCFLocaleVariantCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleVariantName
, (CFStringRef
)&kCFLocaleVariantCodeKey
},
114 {(CFStringRef
)&kCFLocaleExemplarCharacterSetKey
, __CFLocaleCopyExemplarCharSet
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
115 {(CFStringRef
)&kCFLocaleCalendarIdentifierKey
, __CFLocaleCopyCalendarID
, __CFLocaleSetNOP
, __CFLocaleCalendarName
, NULL
},
116 {(CFStringRef
)&kCFLocaleCalendarKey
, __CFLocaleCopyCalendar
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
117 {(CFStringRef
)&kCFLocaleCollationIdentifierKey
, __CFLocaleCopyCollationID
, __CFLocaleSetNOP
, __CFLocaleCollationName
, NULL
},
118 {(CFStringRef
)&kCFLocaleUsesMetricSystemKey
, __CFLocaleCopyUsesMetric
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
119 {(CFStringRef
)&kCFLocaleMeasurementSystemKey
, __CFLocaleCopyMeasurementSystem
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
120 {(CFStringRef
)&kCFLocaleDecimalSeparatorKey
, __CFLocaleCopyNumberFormat
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFNumberFormatterDecimalSeparatorKey
},
121 {(CFStringRef
)&kCFLocaleGroupingSeparatorKey
, __CFLocaleCopyNumberFormat
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFNumberFormatterGroupingSeparatorKey
},
122 {(CFStringRef
)&kCFLocaleCurrencySymbolKey
, __CFLocaleCopyNumberFormat2
, __CFLocaleSetNOP
, __CFLocaleCurrencyShortName
, (CFStringRef
)&kCFNumberFormatterCurrencySymbolKey
},
123 {(CFStringRef
)&kCFLocaleCurrencyCodeKey
, __CFLocaleCopyNumberFormat2
, __CFLocaleSetNOP
, __CFLocaleCurrencyFullName
, (CFStringRef
)&kCFNumberFormatterCurrencyCodeKey
},
124 {(CFStringRef
)&kCFLocaleCollatorIdentifierKey
, __CFLocaleCopyCollatorID
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
125 {(CFStringRef
)&__kCFLocaleCollatorID
, __CFLocaleCopyCollatorID
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
126 {(CFStringRef
)&kCFLocaleQuotationBeginDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleQuotationBeginDelimiterKey
},
127 {(CFStringRef
)&kCFLocaleQuotationEndDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleQuotationEndDelimiterKey
},
128 {(CFStringRef
)&kCFLocaleAlternateQuotationBeginDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleAlternateQuotationBeginDelimiterKey
},
129 {(CFStringRef
)&kCFLocaleAlternateQuotationEndDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleAlternateQuotationEndDelimiterKey
},
133 static CFLocaleRef __CFLocaleSystem
= NULL
;
134 static CFMutableDictionaryRef __CFLocaleCache
= NULL
;
135 static CFSpinLock_t __CFLocaleGlobalLock
= CFSpinLockInit
;
139 CFStringRef _identifier
; // canonical identifier, never NULL
140 CFMutableDictionaryRef _cache
;
141 CFMutableDictionaryRef _overrides
;
142 CFDictionaryRef _prefs
;
147 __private_extern__ Boolean
__CFLocaleGetNullLocale(struct __CFLocale
*locale
) {
148 return locale
->_nullLocale
;
151 __private_extern__
void __CFLocaleSetNullLocale(struct __CFLocale
*locale
) {
152 locale
->_nullLocale
= true;
156 enum { /* Bits 0-1 */
157 __kCFLocaleOrdinary
= 0,
158 __kCFLocaleSystem
= 1,
160 __kCFLocaleCustom
= 3
163 CF_INLINE CFIndex
__CFLocaleGetType(CFLocaleRef locale
) {
164 return __CFBitfieldGetValue(((const CFRuntimeBase
*)locale
)->_cfinfo
[CF_INFO_BITS
], 1, 0);
167 CF_INLINE
void __CFLocaleSetType(CFLocaleRef locale
, CFIndex type
) {
168 __CFBitfieldSetValue(((CFRuntimeBase
*)locale
)->_cfinfo
[CF_INFO_BITS
], 1, 0, (uint8_t)type
);
171 CF_INLINE
void __CFLocaleLockGlobal(void) {
172 __CFSpinLock(&__CFLocaleGlobalLock
);
175 CF_INLINE
void __CFLocaleUnlockGlobal(void) {
176 __CFSpinUnlock(&__CFLocaleGlobalLock
);
179 CF_INLINE
void __CFLocaleLock(CFLocaleRef locale
) {
180 __CFSpinLock(&((struct __CFLocale
*)locale
)->_lock
);
183 CF_INLINE
void __CFLocaleUnlock(CFLocaleRef locale
) {
184 __CFSpinUnlock(&((struct __CFLocale
*)locale
)->_lock
);
188 static Boolean
__CFLocaleEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
189 CFLocaleRef locale1
= (CFLocaleRef
)cf1
;
190 CFLocaleRef locale2
= (CFLocaleRef
)cf2
;
191 // a user locale and a locale created with an ident are not the same even if their contents are
192 if (__CFLocaleGetType(locale1
) != __CFLocaleGetType(locale2
)) return false;
193 if (!CFEqual(locale1
->_identifier
, locale2
->_identifier
)) return false;
194 if (NULL
== locale1
->_overrides
&& NULL
!= locale2
->_overrides
) return false;
195 if (NULL
!= locale1
->_overrides
&& NULL
== locale2
->_overrides
) return false;
196 if (NULL
!= locale1
->_overrides
&& !CFEqual(locale1
->_overrides
, locale2
->_overrides
)) return false;
197 if (__kCFLocaleUser
== __CFLocaleGetType(locale1
)) {
198 return CFEqual(locale1
->_prefs
, locale2
->_prefs
);
203 static CFHashCode
__CFLocaleHash(CFTypeRef cf
) {
204 CFLocaleRef locale
= (CFLocaleRef
)cf
;
205 return CFHash(locale
->_identifier
);
208 static CFStringRef
__CFLocaleCopyDescription(CFTypeRef cf
) {
209 CFLocaleRef locale
= (CFLocaleRef
)cf
;
210 const char *type
= NULL
;
211 switch (__CFLocaleGetType(locale
)) {
212 case __kCFLocaleOrdinary
: type
= "ordinary"; break;
213 case __kCFLocaleSystem
: type
= "system"; break;
214 case __kCFLocaleUser
: type
= "user"; break;
215 case __kCFLocaleCustom
: type
= "custom"; break;
217 return CFStringCreateWithFormat(CFGetAllocator(locale
), NULL
, CFSTR("<CFLocale %p [%p]>{type = %s, identifier = '%@'}"), cf
, CFGetAllocator(locale
), type
, locale
->_identifier
);
220 static void __CFLocaleDeallocate(CFTypeRef cf
) {
221 CFLocaleRef locale
= (CFLocaleRef
)cf
;
222 CFRelease(locale
->_identifier
);
223 if (NULL
!= locale
->_cache
) CFRelease(locale
->_cache
);
224 if (NULL
!= locale
->_overrides
) CFRelease(locale
->_overrides
);
225 if (NULL
!= locale
->_prefs
) CFRelease(locale
->_prefs
);
228 static CFTypeID __kCFLocaleTypeID
= _kCFRuntimeNotATypeID
;
230 static const CFRuntimeClass __CFLocaleClass
= {
235 __CFLocaleDeallocate
,
239 __CFLocaleCopyDescription
242 static void __CFLocaleInitialize(void) {
244 __kCFLocaleTypeID
= _CFRuntimeRegisterClass(&__CFLocaleClass
);
245 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
246 // table fixup to workaround compiler/language limitations
247 __CFLocaleKeyTable
[idx
].key
= *((CFStringRef
*)__CFLocaleKeyTable
[idx
].key
);
248 if (NULL
!= __CFLocaleKeyTable
[idx
].context
) {
249 __CFLocaleKeyTable
[idx
].context
= *((CFStringRef
*)__CFLocaleKeyTable
[idx
].context
);
254 CFTypeID
CFLocaleGetTypeID(void) {
255 if (_kCFRuntimeNotATypeID
== __kCFLocaleTypeID
) __CFLocaleInitialize();
256 return __kCFLocaleTypeID
;
259 CFLocaleRef
CFLocaleGetSystem(void) {
261 __CFLocaleLockGlobal();
262 if (NULL
== __CFLocaleSystem
) {
263 __CFLocaleUnlockGlobal();
264 locale
= CFLocaleCreate(kCFAllocatorSystemDefault
, CFSTR(""));
265 if (!locale
) return NULL
;
266 __CFLocaleSetType(locale
, __kCFLocaleSystem
);
267 __CFLocaleLockGlobal();
268 if (NULL
== __CFLocaleSystem
) {
269 __CFLocaleSystem
= locale
;
271 if (locale
) CFRelease(locale
);
274 locale
= __CFLocaleSystem
? (CFLocaleRef
)CFRetain(__CFLocaleSystem
) : NULL
;
275 __CFLocaleUnlockGlobal();
279 extern CFDictionaryRef
__CFXPreferencesCopyCurrentApplicationState(void);
281 static CFLocaleRef __CFLocaleCurrent
= NULL
;
284 #if DEPLOYMENT_TARGET_MACOSX
285 #define FALLBACK_LOCALE_NAME CFSTR("")
286 #elif DEPLOYMENT_TARGET_EMBEDDED
287 #define FALLBACK_LOCALE_NAME CFSTR("en_US")
288 #elif DEPLOYMENT_TARGET_WINDOWS
289 #define FALLBACK_LOCALE_NAME CFSTR("en_US")
291 #error Unknown or unspecified DEPLOYMENT_TARGET
294 CFLocaleRef
CFLocaleCopyCurrent(void) {
296 __CFLocaleLockGlobal();
297 if (__CFLocaleCurrent
) {
298 CFRetain(__CFLocaleCurrent
);
299 __CFLocaleUnlockGlobal();
300 return __CFLocaleCurrent
;
302 __CFLocaleUnlockGlobal();
304 CFDictionaryRef prefs
= NULL
;
305 CFStringRef identifier
= NULL
;
307 struct __CFLocale
*locale
;
308 uint32_t size
= sizeof(struct __CFLocale
) - sizeof(CFRuntimeBase
);
309 locale
= (struct __CFLocale
*)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, CFLocaleGetTypeID(), size
, NULL
);
310 if (NULL
== locale
) {
313 __CFLocaleSetType(locale
, __kCFLocaleUser
);
314 if (NULL
== identifier
) identifier
= (CFStringRef
)CFRetain(FALLBACK_LOCALE_NAME
);
315 locale
->_identifier
= identifier
;
316 locale
->_cache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
317 locale
->_overrides
= NULL
;
318 locale
->_prefs
= prefs
;
319 locale
->_lock
= CFSpinLockInit
;
320 locale
->_nullLocale
= false;
322 __CFLocaleLockGlobal();
323 if (NULL
== __CFLocaleCurrent
) {
324 __CFLocaleCurrent
= locale
;
328 locale
= (struct __CFLocale
*)CFRetain(__CFLocaleCurrent
);
329 __CFLocaleUnlockGlobal();
333 __private_extern__ CFDictionaryRef
__CFLocaleGetPrefs(CFLocaleRef locale
) {
334 return locale
->_prefs
;
337 CFLocaleRef
CFLocaleCreate(CFAllocatorRef allocator
, CFStringRef identifier
) {
338 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
339 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
340 __CFGenericValidateType(identifier
, CFStringGetTypeID());
341 CFStringRef localeIdentifier
= NULL
;
343 localeIdentifier
= CFLocaleCreateCanonicalLocaleIdentifierFromString(allocator
, identifier
);
345 if (NULL
== localeIdentifier
) return NULL
;
346 CFStringRef old
= localeIdentifier
;
347 localeIdentifier
= (CFStringRef
)CFStringCreateCopy(allocator
, localeIdentifier
);
349 __CFLocaleLockGlobal();
350 // Look for cases where we can return a cached instance.
351 // We only use cached objects if the allocator is the system
352 // default allocator.
353 if (!allocator
) allocator
= __CFGetDefaultAllocator();
354 Boolean canCache
= (kCFAllocatorSystemDefault
== allocator
);
355 if (canCache
&& __CFLocaleCache
) {
356 CFLocaleRef locale
= (CFLocaleRef
)CFDictionaryGetValue(__CFLocaleCache
, localeIdentifier
);
359 __CFLocaleUnlockGlobal();
360 CFRelease(localeIdentifier
);
364 struct __CFLocale
*locale
= NULL
;
365 uint32_t size
= sizeof(struct __CFLocale
) - sizeof(CFRuntimeBase
);
366 locale
= (struct __CFLocale
*)_CFRuntimeCreateInstance(allocator
, CFLocaleGetTypeID(), size
, NULL
);
367 if (NULL
== locale
) {
370 __CFLocaleSetType(locale
, __kCFLocaleOrdinary
);
371 locale
->_identifier
= localeIdentifier
;
372 locale
->_cache
= CFDictionaryCreateMutable(allocator
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
373 locale
->_overrides
= NULL
;
374 locale
->_prefs
= NULL
;
375 locale
->_lock
= CFSpinLockInit
;
377 if (NULL
== __CFLocaleCache
) {
378 __CFLocaleCache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
380 CFDictionarySetValue(__CFLocaleCache
, localeIdentifier
, locale
);
382 __CFLocaleUnlockGlobal();
383 return (CFLocaleRef
)locale
;
386 CFLocaleRef
CFLocaleCreateCopy(CFAllocatorRef allocator
, CFLocaleRef locale
) {
387 return (CFLocaleRef
)CFRetain(locale
);
390 CFStringRef
CFLocaleGetIdentifier(CFLocaleRef locale
) {
391 CF_OBJC_FUNCDISPATCH0(CFLocaleGetTypeID(), CFStringRef
, locale
, "localeIdentifier");
392 return locale
->_identifier
;
395 CFTypeRef
CFLocaleGetValue(CFLocaleRef locale
, CFStringRef key
) {
396 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
)) {
397 // Hack for Opera, which is using the hard-coded string value below instead of
398 // the perfectly good public kCFLocaleCountryCode constant, for whatever reason.
399 if (key
&& CFEqual(key
, CFSTR("locale:country code"))) {
400 key
= kCFLocaleCountryCodeKey
;
403 CF_OBJC_FUNCDISPATCH1(CFLocaleGetTypeID(), CFTypeRef
, locale
, "objectForKey:", key
);
404 CFIndex idx
, slot
= -1;
405 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
406 if (__CFLocaleKeyTable
[idx
].key
== key
) {
411 if (-1 == slot
&& NULL
!= key
) {
412 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
413 if (CFEqual(__CFLocaleKeyTable
[idx
].key
, key
)) {
423 if (NULL
!= locale
->_overrides
&& CFDictionaryGetValueIfPresent(locale
->_overrides
, __CFLocaleKeyTable
[slot
].key
, &value
)) {
426 __CFLocaleLock(locale
);
427 if (CFDictionaryGetValueIfPresent(locale
->_cache
, __CFLocaleKeyTable
[slot
].key
, &value
)) {
428 __CFLocaleUnlock(locale
);
431 if (__kCFLocaleUser
== __CFLocaleGetType(locale
) && __CFLocaleKeyTable
[slot
].get(locale
, true, &value
, __CFLocaleKeyTable
[slot
].context
)) {
432 if (value
) CFDictionarySetValue(locale
->_cache
, __CFLocaleKeyTable
[idx
].key
, value
);
433 if (value
) CFRelease(value
);
434 __CFLocaleUnlock(locale
);
437 if (__CFLocaleKeyTable
[slot
].get(locale
, false, &value
, __CFLocaleKeyTable
[slot
].context
)) {
438 if (value
) CFDictionarySetValue(locale
->_cache
, __CFLocaleKeyTable
[idx
].key
, value
);
439 if (value
) CFRelease(value
);
440 __CFLocaleUnlock(locale
);
443 __CFLocaleUnlock(locale
);
447 CFStringRef
CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale
, CFStringRef key
, CFStringRef value
) {
448 CF_OBJC_FUNCDISPATCH2(CFLocaleGetTypeID(), CFStringRef
, displayLocale
, "_copyDisplayNameForKey:value:", key
, value
);
449 CFIndex idx
, slot
= -1;
450 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
451 if (__CFLocaleKeyTable
[idx
].key
== key
) {
456 if (-1 == slot
&& NULL
!= key
) {
457 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
458 if (CFEqual(__CFLocaleKeyTable
[idx
].key
, key
)) {
464 if (-1 == slot
|| !value
) {
467 // Get the locale ID as a C string
468 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
469 char cValue
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
470 if (CFStringGetCString(displayLocale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(localeID
[0]), kCFStringEncodingASCII
) && CFStringGetCString(value
, cValue
, sizeof(cValue
)/sizeof(char), kCFStringEncodingASCII
)) {
472 if ((NULL
== displayLocale
->_prefs
) && __CFLocaleKeyTable
[slot
].name(localeID
, cValue
, &result
)) {
476 // We could not find a result using the requested language. Fall back through all preferred languages.
478 if (displayLocale
->_prefs
) {
479 langPref
= (CFArrayRef
)CFDictionaryGetValue(displayLocale
->_prefs
, CFSTR("AppleLanguages"));
480 if (langPref
) CFRetain(langPref
);
482 langPref
= (CFArrayRef
)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication
);
484 if (langPref
!= NULL
) {
485 CFIndex count
= CFArrayGetCount(langPref
);
487 bool success
= false;
488 for (i
= 0; i
< count
&& !success
; ++i
) {
489 CFStringRef language
= (CFStringRef
)CFArrayGetValueAtIndex(langPref
, i
);
490 CFStringRef cleanLanguage
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, language
);
491 if (CFStringGetCString(cleanLanguage
, localeID
, sizeof(localeID
)/sizeof(localeID
[0]), kCFStringEncodingASCII
)) {
492 success
= __CFLocaleKeyTable
[slot
].name(localeID
, cValue
, &result
);
494 CFRelease(cleanLanguage
);
504 CFArrayRef
CFLocaleCopyAvailableLocaleIdentifiers(void) {
505 int32_t locale
, localeCount
= uloc_countAvailable();
506 CFMutableSetRef working
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
507 for (locale
= 0; locale
< localeCount
; ++locale
) {
508 const char *localeID
= uloc_getAvailable(locale
);
509 CFStringRef string1
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, localeID
, kCFStringEncodingASCII
);
510 CFStringRef string2
= CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault
, string1
);
511 CFSetAddValue(working
, string1
);
512 // do not include canonicalized version as IntlFormats cannot cope with that in its popup
516 CFIndex cnt
= CFSetGetCount(working
);
517 STACK_BUFFER_DECL(const void *, buffer
, cnt
);
518 CFSetGetValues(working
, buffer
);
519 CFArrayRef result
= CFArrayCreate(kCFAllocatorSystemDefault
, buffer
, cnt
, &kCFTypeArrayCallBacks
);
524 static CFArrayRef
__CFLocaleCopyCStringsAsArray(const char* const* p
) {
525 CFMutableArrayRef working
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
527 CFStringRef string
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, *p
, kCFStringEncodingASCII
);
528 CFArrayAppendValue(working
, string
);
531 CFArrayRef result
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, working
);
536 static CFArrayRef
__CFLocaleCopyUEnumerationAsArray(UEnumeration
*enumer
, UErrorCode
*icuErr
) {
537 const UChar
*next
= NULL
;
539 CFMutableArrayRef working
= NULL
;
540 if (U_SUCCESS(*icuErr
)) {
541 working
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
543 while ((next
= uenum_unext(enumer
, &len
, icuErr
)) && U_SUCCESS(*icuErr
)) {
544 CFStringRef string
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)next
, (CFIndex
) len
);
545 CFArrayAppendValue(working
, string
);
548 if (*icuErr
== U_INDEX_OUTOFBOUNDS_ERROR
) {
549 *icuErr
= U_ZERO_ERROR
; // Temp: Work around bug (ICU 5220) in ucurr enumerator
551 CFArrayRef result
= NULL
;
552 if (U_SUCCESS(*icuErr
)) {
553 result
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, working
);
555 if (working
!= NULL
) {
561 CFArrayRef
CFLocaleCopyISOLanguageCodes(void) {
562 const char* const* p
= uloc_getISOLanguages();
563 return __CFLocaleCopyCStringsAsArray(p
);
566 CFArrayRef
CFLocaleCopyISOCountryCodes(void) {
567 const char* const* p
= uloc_getISOCountries();
568 return __CFLocaleCopyCStringsAsArray(p
);
571 CFArrayRef
CFLocaleCopyISOCurrencyCodes(void) {
572 UErrorCode icuStatus
= U_ZERO_ERROR
;
573 UEnumeration
*enumer
= ucurr_openISOCurrencies(UCURR_ALL
, &icuStatus
);
574 CFArrayRef result
= __CFLocaleCopyUEnumerationAsArray(enumer
, &icuStatus
);
579 CFArrayRef
CFLocaleCopyCommonISOCurrencyCodes(void) {
580 UErrorCode icuStatus
= U_ZERO_ERROR
;
581 UEnumeration
*enumer
= ucurr_openISOCurrencies(UCURR_COMMON
|UCURR_NON_DEPRECATED
, &icuStatus
);
582 CFArrayRef result
= __CFLocaleCopyUEnumerationAsArray(enumer
, &icuStatus
);
587 CFStringRef
CFLocaleCreateLocaleIdentifierFromWindowsLocaleCode(CFAllocatorRef allocator
, uint32_t lcid
) {
588 char buffer
[kMaxICUNameSize
];
589 UErrorCode status
= U_ZERO_ERROR
;
590 int32_t ret
= uloc_getLocaleForLCID(lcid
, buffer
, kMaxICUNameSize
, &status
);
591 if (U_FAILURE(status
) || kMaxICUNameSize
<= ret
) return NULL
;
592 CFStringRef str
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, buffer
, kCFStringEncodingASCII
);
593 CFStringRef ident
= CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault
, str
);
598 uint32_t CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier(CFStringRef localeIdentifier
) {
599 CFStringRef ident
= CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault
, localeIdentifier
);
600 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
601 Boolean b
= CFStringGetCString(ident
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
);
603 return b
? uloc_getLCID(localeID
) : 0;
606 CFLocaleLanguageDirection
CFLocaleGetLanguageCharacterDirection(CFStringRef isoLangCode
) {
607 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
608 Boolean b
= CFStringGetCString(isoLangCode
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
);
609 CFLocaleLanguageDirection dir
;
610 UErrorCode status
= U_ZERO_ERROR
;
611 ULayoutType idir
= b
? uloc_getCharacterOrientation(localeID
, &status
) : ULOC_LAYOUT_UNKNOWN
;
613 case ULOC_LAYOUT_LTR
: dir
= kCFLocaleLanguageDirectionLeftToRight
; break;
614 case ULOC_LAYOUT_RTL
: dir
= kCFLocaleLanguageDirectionRightToLeft
; break;
615 case ULOC_LAYOUT_TTB
: dir
= kCFLocaleLanguageDirectionTopToBottom
; break;
616 case ULOC_LAYOUT_BTT
: dir
= kCFLocaleLanguageDirectionBottomToTop
; break;
617 default: dir
= kCFLocaleLanguageDirectionUnknown
; break;
622 CFLocaleLanguageDirection
CFLocaleGetLanguageLineDirection(CFStringRef isoLangCode
) {
623 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
624 Boolean b
= CFStringGetCString(isoLangCode
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
);
625 CFLocaleLanguageDirection dir
;
626 UErrorCode status
= U_ZERO_ERROR
;
627 ULayoutType idir
= b
? uloc_getLineOrientation(localeID
, &status
) : ULOC_LAYOUT_UNKNOWN
;
629 case ULOC_LAYOUT_LTR
: dir
= kCFLocaleLanguageDirectionLeftToRight
; break;
630 case ULOC_LAYOUT_RTL
: dir
= kCFLocaleLanguageDirectionRightToLeft
; break;
631 case ULOC_LAYOUT_TTB
: dir
= kCFLocaleLanguageDirectionTopToBottom
; break;
632 case ULOC_LAYOUT_BTT
: dir
= kCFLocaleLanguageDirectionBottomToTop
; break;
633 default: dir
= kCFLocaleLanguageDirectionUnknown
; break;
638 CFArrayRef
CFLocaleCopyPreferredLanguages(void) {
639 CFMutableArrayRef newArray
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
640 CFArrayRef languagesArray
= (CFArrayRef
)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication
);
641 if (languagesArray
&& (CFArrayGetTypeID() == CFGetTypeID(languagesArray
))) {
642 for (CFIndex idx
= 0, cnt
= CFArrayGetCount(languagesArray
); idx
< cnt
; idx
++) {
643 CFStringRef str
= (CFStringRef
)CFArrayGetValueAtIndex(languagesArray
, idx
);
644 if (str
&& (CFStringGetTypeID() == CFGetTypeID(str
))) {
645 CFStringRef ident
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, str
);
646 CFArrayAppendValue(newArray
, ident
);
651 if (languagesArray
) CFRelease(languagesArray
);
655 // -------- -------- -------- -------- -------- --------
657 // These functions return true or false depending on the success or failure of the function.
658 // In the Copy case, this is failure to fill the *cf out parameter, and that out parameter is
659 // returned by reference WITH a retain on it.
660 static bool __CFLocaleSetNOP(CFMutableLocaleRef locale
, CFTypeRef cf
, CFStringRef context
) {
664 static bool __CFLocaleCopyLocaleID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
665 *cf
= CFRetain(locale
->_identifier
);
670 static bool __CFLocaleCopyCodes(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
671 CFDictionaryRef codes
= NULL
;
672 // this access of _cache is protected by the lock in CFLocaleGetValue()
673 if (!CFDictionaryGetValueIfPresent(locale
->_cache
, CFSTR("__kCFLocaleCodes"), (const void **)&codes
)) {
674 codes
= CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault
, locale
->_identifier
);
675 if (codes
) CFDictionarySetValue(locale
->_cache
, CFSTR("__kCFLocaleCodes"), codes
);
676 if (codes
) CFRelease(codes
);
679 CFStringRef value
= (CFStringRef
)CFDictionaryGetValue(codes
, context
); // context is one of kCFLocale*Code constants
680 if (value
) CFRetain(value
);
687 CFCharacterSetRef
_CFCreateCharacterSetFromUSet(USet
*set
) {
688 UErrorCode icuErr
= U_ZERO_ERROR
;
689 CFMutableCharacterSetRef working
= CFCharacterSetCreateMutable(NULL
);
690 UChar buffer
[2048]; // Suitable for most small sets
696 int32_t itemCount
= uset_getItemCount(set
);
698 for (i
= 0; i
< itemCount
; ++i
)
704 stringLen
= uset_getItem(set
, i
, &start
, &end
, buffer
, sizeof(buffer
)/sizeof(UChar
), &icuErr
);
705 if (icuErr
== U_BUFFER_OVERFLOW_ERROR
)
707 string
= (UChar
*) malloc(sizeof(UChar
)*(stringLen
+1));
713 icuErr
= U_ZERO_ERROR
;
714 (void) uset_getItem(set
, i
, &start
, &end
, string
, stringLen
+1, &icuErr
);
716 if (U_FAILURE(icuErr
))
718 if (string
!= buffer
)
724 CFCharacterSetAddCharactersInRange(working
, CFRangeMake(start
, end
-start
+1));
727 CFStringRef cfString
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, (UniChar
*)string
, stringLen
, kCFAllocatorNull
);
728 CFCharacterSetAddCharactersInString(working
, cfString
);
731 if (string
!= buffer
)
735 CFCharacterSetRef result
= CFCharacterSetCreateCopy(kCFAllocatorSystemDefault
, working
);
741 static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
742 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
743 if (CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
)) {
744 UErrorCode icuStatus
= U_ZERO_ERROR
;
745 ULocaleData
* uld
= ulocdata_open(localeID
, &icuStatus
);
746 USet
*set
= ulocdata_getExemplarSet(uld
, NULL
, USET_ADD_CASE_MAPPINGS
, ULOCDATA_ES_STANDARD
, &icuStatus
);
748 if (U_FAILURE(icuStatus
))
750 if (icuStatus
== U_USING_DEFAULT_WARNING
) // If default locale used, force to empty set
752 *cf
= (CFTypeRef
) _CFCreateCharacterSetFromUSet(set
);
754 return (*cf
!= NULL
);
759 static bool __CFLocaleCopyICUKeyword(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
, const char *keyword
)
761 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
762 if (CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
))
764 char value
[ULOC_KEYWORD_AND_VALUES_CAPACITY
];
765 UErrorCode icuStatus
= U_ZERO_ERROR
;
766 if (uloc_getKeywordValue(localeID
, keyword
, value
, sizeof(value
)/sizeof(char), &icuStatus
) > 0 && U_SUCCESS(icuStatus
))
768 *cf
= (CFTypeRef
) CFStringCreateWithCString(kCFAllocatorSystemDefault
, value
, kCFStringEncodingASCII
);
776 static bool __CFLocaleCopyCalendarID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
777 bool succeeded
= __CFLocaleCopyICUKeyword(locale
, user
, cf
, context
, kCalendarKeyword
);
779 if (CFEqual(*cf
, kCFCalendarIdentifierGregorian
)) {
781 *cf
= CFRetain(kCFCalendarIdentifierGregorian
);
782 } else if (CFEqual(*cf
, kCFCalendarIdentifierBuddhist
)) {
784 *cf
= CFRetain(kCFCalendarIdentifierBuddhist
);
785 } else if (CFEqual(*cf
, kCFCalendarIdentifierJapanese
)) {
787 *cf
= CFRetain(kCFCalendarIdentifierJapanese
);
788 } else if (CFEqual(*cf
, kCFCalendarIdentifierIslamic
)) {
790 *cf
= CFRetain(kCFCalendarIdentifierIslamic
);
791 } else if (CFEqual(*cf
, kCFCalendarIdentifierIslamicCivil
)) {
793 *cf
= CFRetain(kCFCalendarIdentifierIslamicCivil
);
794 } else if (CFEqual(*cf
, kCFCalendarIdentifierHebrew
)) {
796 *cf
= CFRetain(kCFCalendarIdentifierHebrew
);
797 } else if (CFEqual(*cf
, kCFCalendarIdentifierChinese
)) {
799 *cf
= CFRetain(kCFCalendarIdentifierChinese
);
800 } else if (CFEqual(*cf
, kCFCalendarIdentifierRepublicOfChina
)) {
802 *cf
= CFRetain(kCFCalendarIdentifierRepublicOfChina
);
803 } else if (CFEqual(*cf
, kCFCalendarIdentifierPersian
)) {
805 *cf
= CFRetain(kCFCalendarIdentifierPersian
);
806 } else if (CFEqual(*cf
, kCFCalendarIdentifierIndian
)) {
808 *cf
= CFRetain(kCFCalendarIdentifierIndian
);
809 } else if (CFEqual(*cf
, kCFCalendarIdentifierISO8601
)) {
811 *cf
= CFRetain(kCFCalendarIdentifierISO8601
);
812 } else if (CFEqual(*cf
, kCFCalendarIdentifierCoptic
)) {
814 *cf
= CFRetain(kCFCalendarIdentifierCoptic
);
815 } else if (CFEqual(*cf
, kCFCalendarIdentifierEthiopicAmeteMihret
)) {
817 *cf
= CFRetain(kCFCalendarIdentifierEthiopicAmeteMihret
);
818 } else if (CFEqual(*cf
, kCFCalendarIdentifierEthiopicAmeteAlem
)) {
820 *cf
= CFRetain(kCFCalendarIdentifierEthiopicAmeteAlem
);
827 *cf
= CFRetain(kCFCalendarIdentifierGregorian
);
832 static bool __CFLocaleCopyCalendar(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
833 if (__CFLocaleCopyCalendarID(locale
, user
, cf
, context
)) {
834 CFCalendarRef calendar
= CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault
, (CFStringRef
)*cf
);
835 CFCalendarSetLocale(calendar
, locale
);
836 CFDictionaryRef prefs
= __CFLocaleGetPrefs(locale
);
837 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleFirstWeekday")) : NULL
;
838 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
839 metapref
= (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, *cf
);
841 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFNumberGetTypeID()) {
843 if (CFNumberGetValue((CFNumberRef
)metapref
, kCFNumberCFIndexType
, &wkdy
)) {
844 CFCalendarSetFirstWeekday(calendar
, wkdy
);
847 metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleMinDaysInFirstWeek")) : NULL
;
848 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
849 metapref
= (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, *cf
);
851 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFNumberGetTypeID()) {
853 if (CFNumberGetValue((CFNumberRef
)metapref
, kCFNumberCFIndexType
, &mwd
)) {
854 CFCalendarSetMinimumDaysInFirstWeek(calendar
, mwd
);
864 static bool __CFLocaleCopyDelimiter(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
865 ULocaleDataDelimiterType type
= (ULocaleDataDelimiterType
)0;
866 if (context
== kCFLocaleQuotationBeginDelimiterKey
) {
867 type
= ULOCDATA_QUOTATION_START
;
868 } else if (context
== kCFLocaleQuotationEndDelimiterKey
) {
869 type
= ULOCDATA_QUOTATION_END
;
870 } else if (context
== kCFLocaleAlternateQuotationBeginDelimiterKey
) {
871 type
= ULOCDATA_ALT_QUOTATION_START
;
872 } else if (context
== kCFLocaleAlternateQuotationEndDelimiterKey
) {
873 type
= ULOCDATA_ALT_QUOTATION_END
;
878 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
879 if (!CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
)) {
884 UErrorCode status
= U_ZERO_ERROR
;
885 ULocaleData
*uld
= ulocdata_open(localeID
, &status
);
886 int32_t len
= ulocdata_getDelimiter(uld
, type
, buffer
, sizeof(buffer
) / sizeof(buffer
[0]), &status
);
888 if (U_FAILURE(status
) || sizeof(buffer
) / sizeof(buffer
[0]) < len
) {
892 *cf
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)buffer
, len
);
893 return (*cf
!= NULL
);
896 static bool __CFLocaleCopyCollationID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
897 return __CFLocaleCopyICUKeyword(locale
, user
, cf
, context
, kCollationKeyword
);
900 static bool __CFLocaleCopyCollatorID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
901 CFStringRef canonLocaleCFStr
= NULL
;
903 CFStringRef pref
= (CFStringRef
)CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleCollationOrder"));
905 // Canonicalize pref string in case it's not in the canonical format.
906 canonLocaleCFStr
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, pref
);
908 CFArrayRef languagesArray
= (CFArrayRef
)CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleLanguages"));
909 if (languagesArray
&& (CFArrayGetTypeID() == CFGetTypeID(languagesArray
))) {
910 if (0 < CFArrayGetCount(languagesArray
)) {
911 CFStringRef str
= (CFStringRef
)CFArrayGetValueAtIndex(languagesArray
, 0);
912 if (str
&& (CFStringGetTypeID() == CFGetTypeID(str
))) {
913 canonLocaleCFStr
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, str
);
919 if (!canonLocaleCFStr
) {
920 canonLocaleCFStr
= CFLocaleGetIdentifier(locale
);
921 CFRetain(canonLocaleCFStr
);
923 *cf
= canonLocaleCFStr
;
924 return canonLocaleCFStr
? true : false;
927 static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
928 bool us
= false; // Default is Metric
930 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
932 CFTypeRef pref
= CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleMetricUnits"));
934 us
= (kCFBooleanFalse
== pref
);
937 pref
= CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleMeasurementUnits"));
939 us
= CFEqual(pref
, CFSTR("Inches"));
944 #elif DEPLOYMENT_TARGET_WINDOWS
946 #error Unknown or unspecified DEPLOYMENT_TARGET
949 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
950 if (CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
)) {
951 UErrorCode icuStatus
= U_ZERO_ERROR
;
952 UMeasurementSystem ms
= UMS_SI
;
953 ms
= ulocdata_getMeasurementSystem(localeID
, &icuStatus
);
954 if (U_SUCCESS(icuStatus
)) {
962 *cf
= us
? CFRetain(kCFBooleanFalse
) : CFRetain(kCFBooleanTrue
);
966 static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
967 if (__CFLocaleCopyUsesMetric(locale
, user
, cf
, context
)) {
968 bool us
= (*cf
== kCFBooleanFalse
);
970 *cf
= us
? CFRetain(CFSTR("U.S.")) : CFRetain(CFSTR("Metric"));
976 static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
977 CFStringRef str
= NULL
;
978 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
979 CFNumberFormatterRef nf
= CFNumberFormatterCreate(kCFAllocatorSystemDefault
, locale
, kCFNumberFormatterDecimalStyle
);
980 str
= nf
? CFNumberFormatterCopyProperty(nf
, context
) : NULL
;
981 if (nf
) CFRelease(nf
);
982 #elif DEPLOYMENT_TARGET_WINDOWS
984 #error Unknown or unspecified DEPLOYMENT_TARGET
993 // ICU does not reliably set up currency info for other than Currency-type formatters,
994 // so we have to have another routine here which creates a Currency number formatter.
995 static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
996 CFStringRef str
= NULL
;
997 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
998 CFNumberFormatterRef nf
= CFNumberFormatterCreate(kCFAllocatorSystemDefault
, locale
, kCFNumberFormatterCurrencyStyle
);
999 str
= nf
? CFNumberFormatterCopyProperty(nf
, context
) : NULL
;
1000 if (nf
) CFRelease(nf
);
1001 #elif DEPLOYMENT_TARGET_WINDOWS
1003 #error Unknown or unspecified DEPLOYMENT_TARGET
1012 typedef int32_t (*__CFICUFunction
)(const char *, const char *, UChar
*, int32_t, UErrorCode
*);
1014 static bool __CFLocaleICUName(const char *locale
, const char *valLocale
, CFStringRef
*out
, __CFICUFunction icu
) {
1015 UErrorCode icuStatus
= U_ZERO_ERROR
;
1017 UChar name
[kMaxICUNameSize
];
1019 size
= (*icu
)(valLocale
, locale
, name
, kMaxICUNameSize
, &icuStatus
);
1020 if (U_SUCCESS(icuStatus
) && size
> 0 && icuStatus
!= U_USING_DEFAULT_WARNING
) {
1021 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1022 return (*out
!= NULL
);
1027 static bool __CFLocaleICUKeywordValueName(const char *locale
, const char *value
, const char *keyword
, CFStringRef
*out
) {
1028 UErrorCode icuStatus
= U_ZERO_ERROR
;
1030 UChar name
[kMaxICUNameSize
];
1031 // Need to make a fake locale ID
1032 char lid
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
1033 if (strlen(value
) < ULOC_KEYWORD_AND_VALUES_CAPACITY
) {
1034 strlcpy(lid
, "en_US@", sizeof(lid
));
1035 strlcat(lid
, keyword
, sizeof(lid
));
1036 strlcat(lid
, "=", sizeof(lid
));
1037 strlcat(lid
, value
, sizeof(lid
));
1038 size
= uloc_getDisplayKeywordValue(lid
, keyword
, locale
, name
, kMaxICUNameSize
, &icuStatus
);
1039 if (U_SUCCESS(icuStatus
) && size
> 0 && icuStatus
!= U_USING_DEFAULT_WARNING
) {
1040 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1041 return (*out
!= NULL
);
1047 static bool __CFLocaleICUCurrencyName(const char *locale
, const char *value
, UCurrNameStyle style
, CFStringRef
*out
) {
1048 int valLen
= strlen(value
);
1049 if (valLen
!= 3) // not a valid ISO code
1052 UBool isChoice
= FALSE
;
1054 UErrorCode icuStatus
= U_ZERO_ERROR
;
1055 u_charsToUChars(value
, curr
, valLen
);
1056 curr
[valLen
] = '\0';
1058 name
= ucurr_getName(curr
, locale
, style
, &isChoice
, &size
, &icuStatus
);
1059 if (U_FAILURE(icuStatus
) || icuStatus
== U_USING_DEFAULT_WARNING
)
1061 UChar result
[kMaxICUNameSize
];
1064 UChar pattern
[kMaxICUNameSize
];
1065 CFStringRef patternRef
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("{0,choice,%S}"), name
);
1066 CFIndex pattlen
= CFStringGetLength(patternRef
);
1067 CFStringGetCharacters(patternRef
, CFRangeMake(0, pattlen
), (UniChar
*)pattern
);
1068 CFRelease(patternRef
);
1069 pattern
[pattlen
] = '\0'; // null terminate the pattern
1070 // Format the message assuming a large amount of the currency
1071 size
= u_formatMessage("en_US", pattern
, pattlen
, result
, kMaxICUNameSize
, &icuStatus
, 10.0);
1072 if (U_FAILURE(icuStatus
))
1077 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1078 return (*out
!= NULL
);
1081 static bool __CFLocaleFullName(const char *locale
, const char *value
, CFStringRef
*out
) {
1082 UErrorCode icuStatus
= U_ZERO_ERROR
;
1084 UChar name
[kMaxICUNameSize
];
1086 // First, try to get the full locale.
1087 size
= uloc_getDisplayName(value
, locale
, name
, kMaxICUNameSize
, &icuStatus
);
1088 if (U_FAILURE(icuStatus
) || size
<= 0)
1091 // Did we wind up using a default somewhere?
1092 if (icuStatus
== U_USING_DEFAULT_WARNING
) {
1093 // For some locale IDs, there may be no language which has a translation for every
1094 // piece. Rather than return nothing, see if we can at least handle
1095 // the language part of the locale.
1096 UErrorCode localStatus
= U_ZERO_ERROR
;
1098 UChar localName
[kMaxICUNameSize
];
1099 localSize
= uloc_getDisplayLanguage(value
, locale
, localName
, kMaxICUNameSize
, &localStatus
);
1100 if (U_FAILURE(localStatus
) || size
<= 0 || localStatus
== U_USING_DEFAULT_WARNING
)
1104 // This locale is OK, so use the result.
1105 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1106 return (*out
!= NULL
);
1109 static bool __CFLocaleLanguageName(const char *locale
, const char *value
, CFStringRef
*out
) {
1110 return __CFLocaleICUName(locale
, value
, out
, uloc_getDisplayLanguage
);
1113 static bool __CFLocaleCountryName(const char *locale
, const char *value
, CFStringRef
*out
) {
1114 // Need to make a fake locale ID
1115 char lid
[ULOC_FULLNAME_CAPACITY
];
1116 if (strlen(value
) < sizeof(lid
) - 3) {
1117 strlcpy(lid
, "en_", sizeof(lid
));
1118 strlcat(lid
, value
, sizeof(lid
));
1119 return __CFLocaleICUName(locale
, lid
, out
, uloc_getDisplayCountry
);
1124 static bool __CFLocaleScriptName(const char *locale
, const char *value
, CFStringRef
*out
) {
1125 // Need to make a fake locale ID
1126 char lid
[ULOC_FULLNAME_CAPACITY
];
1127 if (strlen(value
) == 4) {
1128 strlcpy(lid
, "en_", sizeof(lid
));
1129 strlcat(lid
, value
, sizeof(lid
));
1130 strlcat(lid
, "_US", sizeof(lid
));
1131 return __CFLocaleICUName(locale
, lid
, out
, uloc_getDisplayScript
);
1136 static bool __CFLocaleVariantName(const char *locale
, const char *value
, CFStringRef
*out
) {
1137 // Need to make a fake locale ID
1138 char lid
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
1139 if (strlen(value
) < sizeof(lid
) - 6) {
1140 strlcpy(lid
, "en_US_", sizeof(lid
));
1141 strlcat(lid
, value
, sizeof(lid
));
1142 return __CFLocaleICUName(locale
, lid
, out
, uloc_getDisplayVariant
);
1147 static bool __CFLocaleCalendarName(const char *locale
, const char *value
, CFStringRef
*out
) {
1148 return __CFLocaleICUKeywordValueName(locale
, value
, kCalendarKeyword
, out
);
1151 static bool __CFLocaleCollationName(const char *locale
, const char *value
, CFStringRef
*out
) {
1152 return __CFLocaleICUKeywordValueName(locale
, value
, kCollationKeyword
, out
);
1155 static bool __CFLocaleCurrencyShortName(const char *locale
, const char *value
, CFStringRef
*out
) {
1156 return __CFLocaleICUCurrencyName(locale
, value
, UCURR_SYMBOL_NAME
, out
);
1159 static bool __CFLocaleCurrencyFullName(const char *locale
, const char *value
, CFStringRef
*out
) {
1160 return __CFLocaleICUCurrencyName(locale
, value
, UCURR_LONG_NAME
, out
);
1163 static bool __CFLocaleNoName(const char *locale
, const char *value
, CFStringRef
*out
) {
1167 #undef kMaxICUNameSize