2 * Copyright (c) 2009 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@
24 Copyright (c) 2002-2009, Apple Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 // Note the header file is in the OpenSource set (stripped to almost nothing), but not the .c file
30 #include <CoreFoundation/CFLocale.h>
31 #include <CoreFoundation/CFString.h>
32 #include <CoreFoundation/CFArray.h>
33 #include <CoreFoundation/CFDictionary.h>
34 #include <CoreFoundation/CFPreferences.h>
35 #include <CoreFoundation/CFCalendar.h>
36 #include <CoreFoundation/CFNumber.h>
37 #include "CFInternal.h"
38 #include "CFLocaleInternal.h"
39 #include <unicode/uloc.h> // ICU locales
40 #include <unicode/ulocdata.h> // ICU locale data
41 #include <unicode/ucurr.h> // ICU currency functions
42 #include <unicode/uset.h> // ICU Unicode sets
43 #include <unicode/putil.h> // ICU low-level utilities
44 #include <unicode/umsg.h> // ICU message formatting
45 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
46 #include <CoreFoundation/CFNumberFormatter.h>
47 #include <dispatch/dispatch.h>
50 #include <unicode/ucol.h>
51 #elif DEPLOYMENT_TARGET_WINDOWS
54 #error Unknown or unspecified DEPLOYMENT_TARGET
57 CONST_STRING_DECL(kCFLocaleCurrentLocaleDidChangeNotification
, "kCFLocaleCurrentLocaleDidChangeNotification")
59 static const char *kCalendarKeyword
= "calendar";
60 static const char *kCollationKeyword
= "collation";
61 #define kMaxICUNameSize 1024
63 typedef struct __CFLocale
*CFMutableLocaleRef
;
65 PE_CONST_STRING_DECL(__kCFLocaleCollatorID
, "locale:collator id")
69 __kCFLocaleKeyTableCount
= 21
74 bool (*get
)(CFLocaleRef
, bool user
, CFTypeRef
*, CFStringRef context
); // returns an immutable copy & reference
75 bool (*set
)(CFMutableLocaleRef
, CFTypeRef
, CFStringRef context
);
76 bool (*name
)(const char *, const char *, CFStringRef
*);
81 // Must forward decl. these functions:
82 static bool __CFLocaleCopyLocaleID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
83 static bool __CFLocaleSetNOP(CFMutableLocaleRef locale
, CFTypeRef cf
, CFStringRef context
);
84 static bool __CFLocaleFullName(const char *locale
, const char *value
, CFStringRef
*out
);
85 static bool __CFLocaleCopyCodes(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
86 static bool __CFLocaleCountryName(const char *locale
, const char *value
, CFStringRef
*out
);
87 static bool __CFLocaleScriptName(const char *locale
, const char *value
, CFStringRef
*out
);
88 static bool __CFLocaleLanguageName(const char *locale
, const char *value
, CFStringRef
*out
);
89 static bool __CFLocaleCurrencyShortName(const char *locale
, const char *value
, CFStringRef
*out
);
90 static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
91 static bool __CFLocaleVariantName(const char *locale
, const char *value
, CFStringRef
*out
);
92 static bool __CFLocaleNoName(const char *locale
, const char *value
, CFStringRef
*out
);
93 static bool __CFLocaleCopyCalendarID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
94 static bool __CFLocaleCalendarName(const char *locale
, const char *value
, CFStringRef
*out
);
95 static bool __CFLocaleCollationName(const char *locale
, const char *value
, CFStringRef
*out
);
96 static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
97 static bool __CFLocaleCopyCalendar(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
98 static bool __CFLocaleCopyCollationID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
99 static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
100 static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
101 static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
102 static bool __CFLocaleCurrencyFullName(const char *locale
, const char *value
, CFStringRef
*out
);
103 static bool __CFLocaleCopyCollatorID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
104 static bool __CFLocaleCopyDelimiter(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
106 // Note string members start with an extra &, and are fixed up at init time
107 static struct key_table __CFLocaleKeyTable
[__kCFLocaleKeyTableCount
] = {
108 {(CFStringRef
)&kCFLocaleIdentifierKey
, __CFLocaleCopyLocaleID
, __CFLocaleSetNOP
, __CFLocaleFullName
, NULL
},
109 {(CFStringRef
)&kCFLocaleLanguageCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleLanguageName
, (CFStringRef
)&kCFLocaleLanguageCodeKey
},
110 {(CFStringRef
)&kCFLocaleCountryCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleCountryName
, (CFStringRef
)&kCFLocaleCountryCodeKey
},
111 {(CFStringRef
)&kCFLocaleScriptCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleScriptName
, (CFStringRef
)&kCFLocaleScriptCodeKey
},
112 {(CFStringRef
)&kCFLocaleVariantCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleVariantName
, (CFStringRef
)&kCFLocaleVariantCodeKey
},
113 {(CFStringRef
)&kCFLocaleExemplarCharacterSetKey
, __CFLocaleCopyExemplarCharSet
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
114 {(CFStringRef
)&kCFLocaleCalendarIdentifierKey
, __CFLocaleCopyCalendarID
, __CFLocaleSetNOP
, __CFLocaleCalendarName
, NULL
},
115 {(CFStringRef
)&kCFLocaleCalendarKey
, __CFLocaleCopyCalendar
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
116 {(CFStringRef
)&kCFLocaleCollationIdentifierKey
, __CFLocaleCopyCollationID
, __CFLocaleSetNOP
, __CFLocaleCollationName
, NULL
},
117 {(CFStringRef
)&kCFLocaleUsesMetricSystemKey
, __CFLocaleCopyUsesMetric
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
118 {(CFStringRef
)&kCFLocaleMeasurementSystemKey
, __CFLocaleCopyMeasurementSystem
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
119 {(CFStringRef
)&kCFLocaleDecimalSeparatorKey
, __CFLocaleCopyNumberFormat
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFNumberFormatterDecimalSeparatorKey
},
120 {(CFStringRef
)&kCFLocaleGroupingSeparatorKey
, __CFLocaleCopyNumberFormat
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFNumberFormatterGroupingSeparatorKey
},
121 {(CFStringRef
)&kCFLocaleCurrencySymbolKey
, __CFLocaleCopyNumberFormat2
, __CFLocaleSetNOP
, __CFLocaleCurrencyShortName
, (CFStringRef
)&kCFNumberFormatterCurrencySymbolKey
},
122 {(CFStringRef
)&kCFLocaleCurrencyCodeKey
, __CFLocaleCopyNumberFormat2
, __CFLocaleSetNOP
, __CFLocaleCurrencyFullName
, (CFStringRef
)&kCFNumberFormatterCurrencyCodeKey
},
123 {(CFStringRef
)&kCFLocaleCollatorIdentifierKey
, __CFLocaleCopyCollatorID
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
124 {(CFStringRef
)&__kCFLocaleCollatorID
, __CFLocaleCopyCollatorID
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
125 {(CFStringRef
)&kCFLocaleQuotationBeginDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleQuotationBeginDelimiterKey
},
126 {(CFStringRef
)&kCFLocaleQuotationEndDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleQuotationEndDelimiterKey
},
127 {(CFStringRef
)&kCFLocaleAlternateQuotationBeginDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleAlternateQuotationBeginDelimiterKey
},
128 {(CFStringRef
)&kCFLocaleAlternateQuotationEndDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleAlternateQuotationEndDelimiterKey
},
132 static CFLocaleRef __CFLocaleSystem
= NULL
;
133 static CFMutableDictionaryRef __CFLocaleCache
= NULL
;
134 static CFSpinLock_t __CFLocaleGlobalLock
= CFSpinLockInit
;
138 CFStringRef _identifier
; // canonical identifier, never NULL
139 CFMutableDictionaryRef _cache
;
140 CFMutableDictionaryRef _overrides
;
141 CFDictionaryRef _prefs
;
146 __private_extern__ Boolean
__CFLocaleGetNullLocale(struct __CFLocale
*locale
) {
147 return locale
->_nullLocale
;
150 __private_extern__
void __CFLocaleSetNullLocale(struct __CFLocale
*locale
) {
151 locale
->_nullLocale
= true;
155 enum { /* Bits 0-1 */
156 __kCFLocaleOrdinary
= 0,
157 __kCFLocaleSystem
= 1,
159 __kCFLocaleCustom
= 3
162 CF_INLINE CFIndex
__CFLocaleGetType(CFLocaleRef locale
) {
163 return __CFBitfieldGetValue(((const CFRuntimeBase
*)locale
)->_cfinfo
[CF_INFO_BITS
], 1, 0);
166 CF_INLINE
void __CFLocaleSetType(CFLocaleRef locale
, CFIndex type
) {
167 __CFBitfieldSetValue(((CFRuntimeBase
*)locale
)->_cfinfo
[CF_INFO_BITS
], 1, 0, (uint8_t)type
);
170 CF_INLINE
void __CFLocaleLockGlobal(void) {
171 __CFSpinLock(&__CFLocaleGlobalLock
);
174 CF_INLINE
void __CFLocaleUnlockGlobal(void) {
175 __CFSpinUnlock(&__CFLocaleGlobalLock
);
178 CF_INLINE
void __CFLocaleLock(CFLocaleRef locale
) {
179 __CFSpinLock(&((struct __CFLocale
*)locale
)->_lock
);
182 CF_INLINE
void __CFLocaleUnlock(CFLocaleRef locale
) {
183 __CFSpinUnlock(&((struct __CFLocale
*)locale
)->_lock
);
187 static Boolean
__CFLocaleEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
188 CFLocaleRef locale1
= (CFLocaleRef
)cf1
;
189 CFLocaleRef locale2
= (CFLocaleRef
)cf2
;
190 // a user locale and a locale created with an ident are not the same even if their contents are
191 if (__CFLocaleGetType(locale1
) != __CFLocaleGetType(locale2
)) return false;
192 if (!CFEqual(locale1
->_identifier
, locale2
->_identifier
)) return false;
193 if (NULL
== locale1
->_overrides
&& NULL
!= locale2
->_overrides
) return false;
194 if (NULL
!= locale1
->_overrides
&& NULL
== locale2
->_overrides
) return false;
195 if (NULL
!= locale1
->_overrides
&& !CFEqual(locale1
->_overrides
, locale2
->_overrides
)) return false;
196 if (__kCFLocaleUser
== __CFLocaleGetType(locale1
)) {
197 return CFEqual(locale1
->_prefs
, locale2
->_prefs
);
202 static CFHashCode
__CFLocaleHash(CFTypeRef cf
) {
203 CFLocaleRef locale
= (CFLocaleRef
)cf
;
204 return CFHash(locale
->_identifier
);
207 static CFStringRef
__CFLocaleCopyDescription(CFTypeRef cf
) {
208 CFLocaleRef locale
= (CFLocaleRef
)cf
;
209 const char *type
= NULL
;
210 switch (__CFLocaleGetType(locale
)) {
211 case __kCFLocaleOrdinary
: type
= "ordinary"; break;
212 case __kCFLocaleSystem
: type
= "system"; break;
213 case __kCFLocaleUser
: type
= "user"; break;
214 case __kCFLocaleCustom
: type
= "custom"; break;
216 return CFStringCreateWithFormat(CFGetAllocator(locale
), NULL
, CFSTR("<CFLocale %p [%p]>{type = %s, identifier = '%@'}"), cf
, CFGetAllocator(locale
), type
, locale
->_identifier
);
219 static void __CFLocaleDeallocate(CFTypeRef cf
) {
220 CFLocaleRef locale
= (CFLocaleRef
)cf
;
221 CFRelease(locale
->_identifier
);
222 if (NULL
!= locale
->_cache
) CFRelease(locale
->_cache
);
223 if (NULL
!= locale
->_overrides
) CFRelease(locale
->_overrides
);
224 if (NULL
!= locale
->_prefs
) CFRelease(locale
->_prefs
);
227 static CFTypeID __kCFLocaleTypeID
= _kCFRuntimeNotATypeID
;
229 static const CFRuntimeClass __CFLocaleClass
= {
234 __CFLocaleDeallocate
,
238 __CFLocaleCopyDescription
241 static void __CFLocaleInitialize(void) {
243 __kCFLocaleTypeID
= _CFRuntimeRegisterClass(&__CFLocaleClass
);
244 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
245 // table fixup to workaround compiler/language limitations
246 __CFLocaleKeyTable
[idx
].key
= *((CFStringRef
*)__CFLocaleKeyTable
[idx
].key
);
247 if (NULL
!= __CFLocaleKeyTable
[idx
].context
) {
248 __CFLocaleKeyTable
[idx
].context
= *((CFStringRef
*)__CFLocaleKeyTable
[idx
].context
);
253 CFTypeID
CFLocaleGetTypeID(void) {
254 if (_kCFRuntimeNotATypeID
== __kCFLocaleTypeID
) __CFLocaleInitialize();
255 return __kCFLocaleTypeID
;
258 CFLocaleRef
CFLocaleGetSystem(void) {
260 __CFLocaleLockGlobal();
261 if (NULL
== __CFLocaleSystem
) {
262 __CFLocaleUnlockGlobal();
263 locale
= CFLocaleCreate(kCFAllocatorSystemDefault
, CFSTR(""));
264 if (!locale
) return NULL
;
265 __CFLocaleSetType(locale
, __kCFLocaleSystem
);
266 __CFLocaleLockGlobal();
267 if (NULL
== __CFLocaleSystem
) {
268 __CFLocaleSystem
= locale
;
270 if (locale
) CFRelease(locale
);
273 locale
= __CFLocaleSystem
? (CFLocaleRef
)CFRetain(__CFLocaleSystem
) : NULL
;
274 __CFLocaleUnlockGlobal();
278 extern CFDictionaryRef
__CFXPreferencesCopyCurrentApplicationState(void);
280 static CFLocaleRef __CFLocaleCurrent
= NULL
;
283 #if DEPLOYMENT_TARGET_MACOSX
284 #define FALLBACK_LOCALE_NAME CFSTR("")
285 #elif DEPLOYMENT_TARGET_EMBEDDED
286 #define FALLBACK_LOCALE_NAME CFSTR("en_US")
287 #elif DEPLOYMENT_TARGET_WINDOWS
288 #define FALLBACK_LOCALE_NAME CFSTR("en_US")
290 #error Unknown or unspecified DEPLOYMENT_TARGET
293 CFLocaleRef
CFLocaleCopyCurrent(void) {
295 __CFLocaleLockGlobal();
296 if (__CFLocaleCurrent
) {
297 CFRetain(__CFLocaleCurrent
);
298 __CFLocaleUnlockGlobal();
299 return __CFLocaleCurrent
;
301 __CFLocaleUnlockGlobal();
303 CFDictionaryRef prefs
= NULL
;
304 CFStringRef identifier
= NULL
;
306 struct __CFLocale
*locale
;
307 uint32_t size
= sizeof(struct __CFLocale
) - sizeof(CFRuntimeBase
);
308 locale
= (struct __CFLocale
*)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, CFLocaleGetTypeID(), size
, NULL
);
309 if (NULL
== locale
) {
312 __CFLocaleSetType(locale
, __kCFLocaleUser
);
313 if (NULL
== identifier
) identifier
= (CFStringRef
)CFRetain(FALLBACK_LOCALE_NAME
);
314 locale
->_identifier
= identifier
;
315 locale
->_cache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
316 locale
->_overrides
= NULL
;
317 locale
->_prefs
= prefs
;
318 locale
->_lock
= CFSpinLockInit
;
319 locale
->_nullLocale
= false;
321 __CFLocaleLockGlobal();
322 if (NULL
== __CFLocaleCurrent
) {
323 __CFLocaleCurrent
= locale
;
327 locale
= (struct __CFLocale
*)CFRetain(__CFLocaleCurrent
);
328 __CFLocaleUnlockGlobal();
332 __private_extern__ CFDictionaryRef
__CFLocaleGetPrefs(CFLocaleRef locale
) {
333 return locale
->_prefs
;
336 CFLocaleRef
CFLocaleCreate(CFAllocatorRef allocator
, CFStringRef identifier
) {
337 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
338 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
339 __CFGenericValidateType(identifier
, CFStringGetTypeID());
340 CFStringRef localeIdentifier
= NULL
;
342 localeIdentifier
= CFLocaleCreateCanonicalLocaleIdentifierFromString(allocator
, identifier
);
344 if (NULL
== localeIdentifier
) return NULL
;
345 CFStringRef old
= localeIdentifier
;
346 localeIdentifier
= (CFStringRef
)CFStringCreateCopy(allocator
, localeIdentifier
);
348 __CFLocaleLockGlobal();
349 // Look for cases where we can return a cached instance.
350 // We only use cached objects if the allocator is the system
351 // default allocator.
352 if (!allocator
) allocator
= __CFGetDefaultAllocator();
353 Boolean canCache
= (kCFAllocatorSystemDefault
== allocator
);
354 if (canCache
&& __CFLocaleCache
) {
355 CFLocaleRef locale
= (CFLocaleRef
)CFDictionaryGetValue(__CFLocaleCache
, localeIdentifier
);
358 __CFLocaleUnlockGlobal();
359 CFRelease(localeIdentifier
);
363 struct __CFLocale
*locale
= NULL
;
364 uint32_t size
= sizeof(struct __CFLocale
) - sizeof(CFRuntimeBase
);
365 locale
= (struct __CFLocale
*)_CFRuntimeCreateInstance(allocator
, CFLocaleGetTypeID(), size
, NULL
);
366 if (NULL
== locale
) {
369 __CFLocaleSetType(locale
, __kCFLocaleOrdinary
);
370 locale
->_identifier
= localeIdentifier
;
371 locale
->_cache
= CFDictionaryCreateMutable(allocator
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
372 locale
->_overrides
= NULL
;
373 locale
->_prefs
= NULL
;
374 locale
->_lock
= CFSpinLockInit
;
376 if (NULL
== __CFLocaleCache
) {
377 __CFLocaleCache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
379 CFDictionarySetValue(__CFLocaleCache
, localeIdentifier
, locale
);
381 __CFLocaleUnlockGlobal();
382 return (CFLocaleRef
)locale
;
385 CFLocaleRef
CFLocaleCreateCopy(CFAllocatorRef allocator
, CFLocaleRef locale
) {
386 return (CFLocaleRef
)CFRetain(locale
);
389 CFStringRef
CFLocaleGetIdentifier(CFLocaleRef locale
) {
390 CF_OBJC_FUNCDISPATCH0(CFLocaleGetTypeID(), CFStringRef
, locale
, "localeIdentifier");
391 return locale
->_identifier
;
394 CFTypeRef
CFLocaleGetValue(CFLocaleRef locale
, CFStringRef key
) {
395 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
)) {
396 // Hack for Opera, which is using the hard-coded string value below instead of
397 // the perfectly good public kCFLocaleCountryCode constant, for whatever reason.
398 if (key
&& CFEqual(key
, CFSTR("locale:country code"))) {
399 key
= kCFLocaleCountryCodeKey
;
402 CF_OBJC_FUNCDISPATCH1(CFLocaleGetTypeID(), CFTypeRef
, locale
, "objectForKey:", key
);
403 CFIndex idx
, slot
= -1;
404 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
405 if (__CFLocaleKeyTable
[idx
].key
== key
) {
410 if (-1 == slot
&& NULL
!= key
) {
411 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
412 if (CFEqual(__CFLocaleKeyTable
[idx
].key
, key
)) {
422 if (NULL
!= locale
->_overrides
&& CFDictionaryGetValueIfPresent(locale
->_overrides
, __CFLocaleKeyTable
[slot
].key
, &value
)) {
425 __CFLocaleLock(locale
);
426 if (CFDictionaryGetValueIfPresent(locale
->_cache
, __CFLocaleKeyTable
[slot
].key
, &value
)) {
427 __CFLocaleUnlock(locale
);
430 if (__kCFLocaleUser
== __CFLocaleGetType(locale
) && __CFLocaleKeyTable
[slot
].get(locale
, true, &value
, __CFLocaleKeyTable
[slot
].context
)) {
431 if (value
) CFDictionarySetValue(locale
->_cache
, __CFLocaleKeyTable
[idx
].key
, value
);
432 if (value
) CFRelease(value
);
433 __CFLocaleUnlock(locale
);
436 if (__CFLocaleKeyTable
[slot
].get(locale
, false, &value
, __CFLocaleKeyTable
[slot
].context
)) {
437 if (value
) CFDictionarySetValue(locale
->_cache
, __CFLocaleKeyTable
[idx
].key
, value
);
438 if (value
) CFRelease(value
);
439 __CFLocaleUnlock(locale
);
442 __CFLocaleUnlock(locale
);
446 CFStringRef
CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale
, CFStringRef key
, CFStringRef value
) {
447 CF_OBJC_FUNCDISPATCH2(CFLocaleGetTypeID(), CFStringRef
, displayLocale
, "_copyDisplayNameForKey:value:", key
, value
);
448 CFIndex idx
, slot
= -1;
449 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
450 if (__CFLocaleKeyTable
[idx
].key
== key
) {
455 if (-1 == slot
&& NULL
!= key
) {
456 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
457 if (CFEqual(__CFLocaleKeyTable
[idx
].key
, key
)) {
463 if (-1 == slot
|| !value
) {
466 // Get the locale ID as a C string
467 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
468 char cValue
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
469 if (CFStringGetCString(displayLocale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(localeID
[0]), kCFStringEncodingASCII
) && CFStringGetCString(value
, cValue
, sizeof(cValue
)/sizeof(char), kCFStringEncodingASCII
)) {
471 if ((NULL
== displayLocale
->_prefs
) && __CFLocaleKeyTable
[slot
].name(localeID
, cValue
, &result
)) {
475 // We could not find a result using the requested language. Fall back through all preferred languages.
477 if (displayLocale
->_prefs
) {
478 langPref
= (CFArrayRef
)CFDictionaryGetValue(displayLocale
->_prefs
, CFSTR("AppleLanguages"));
479 if (langPref
) CFRetain(langPref
);
481 langPref
= (CFArrayRef
)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication
);
483 if (langPref
!= NULL
) {
484 CFIndex count
= CFArrayGetCount(langPref
);
486 bool success
= false;
487 for (i
= 0; i
< count
&& !success
; ++i
) {
488 CFStringRef language
= (CFStringRef
)CFArrayGetValueAtIndex(langPref
, i
);
489 CFStringRef cleanLanguage
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, language
);
490 if (CFStringGetCString(cleanLanguage
, localeID
, sizeof(localeID
)/sizeof(localeID
[0]), kCFStringEncodingASCII
)) {
491 success
= __CFLocaleKeyTable
[slot
].name(localeID
, cValue
, &result
);
493 CFRelease(cleanLanguage
);
503 CFArrayRef
CFLocaleCopyAvailableLocaleIdentifiers(void) {
504 int32_t locale
, localeCount
= uloc_countAvailable();
505 CFMutableSetRef working
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
506 for (locale
= 0; locale
< localeCount
; ++locale
) {
507 const char *localeID
= uloc_getAvailable(locale
);
508 CFStringRef string1
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, localeID
, kCFStringEncodingASCII
);
509 CFStringRef string2
= CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault
, string1
);
510 CFSetAddValue(working
, string1
);
511 // do not include canonicalized version as IntlFormats cannot cope with that in its popup
515 CFIndex cnt
= CFSetGetCount(working
);
516 STACK_BUFFER_DECL(const void *, buffer
, cnt
);
517 CFSetGetValues(working
, buffer
);
518 CFArrayRef result
= CFArrayCreate(kCFAllocatorSystemDefault
, buffer
, cnt
, &kCFTypeArrayCallBacks
);
523 static CFArrayRef
__CFLocaleCopyCStringsAsArray(const char* const* p
) {
524 CFMutableArrayRef working
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
526 CFStringRef string
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, *p
, kCFStringEncodingASCII
);
527 CFArrayAppendValue(working
, string
);
530 CFArrayRef result
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, working
);
535 static CFArrayRef
__CFLocaleCopyUEnumerationAsArray(UEnumeration
*enumer
, UErrorCode
*icuErr
) {
536 const UChar
*next
= NULL
;
538 CFMutableArrayRef working
= NULL
;
539 if (U_SUCCESS(*icuErr
)) {
540 working
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
542 while ((next
= uenum_unext(enumer
, &len
, icuErr
)) && U_SUCCESS(*icuErr
)) {
543 CFStringRef string
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)next
, (CFIndex
) len
);
544 CFArrayAppendValue(working
, string
);
547 if (*icuErr
== U_INDEX_OUTOFBOUNDS_ERROR
) {
548 *icuErr
= U_ZERO_ERROR
; // Temp: Work around bug (ICU 5220) in ucurr enumerator
550 CFArrayRef result
= NULL
;
551 if (U_SUCCESS(*icuErr
)) {
552 result
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, working
);
554 if (working
!= NULL
) {
560 CFArrayRef
CFLocaleCopyISOLanguageCodes(void) {
561 const char* const* p
= uloc_getISOLanguages();
562 return __CFLocaleCopyCStringsAsArray(p
);
565 CFArrayRef
CFLocaleCopyISOCountryCodes(void) {
566 const char* const* p
= uloc_getISOCountries();
567 return __CFLocaleCopyCStringsAsArray(p
);
570 CFArrayRef
CFLocaleCopyISOCurrencyCodes(void) {
571 UErrorCode icuStatus
= U_ZERO_ERROR
;
572 UEnumeration
*enumer
= ucurr_openISOCurrencies(UCURR_ALL
, &icuStatus
);
573 CFArrayRef result
= __CFLocaleCopyUEnumerationAsArray(enumer
, &icuStatus
);
578 CFArrayRef
CFLocaleCopyCommonISOCurrencyCodes(void) {
579 UErrorCode icuStatus
= U_ZERO_ERROR
;
580 UEnumeration
*enumer
= ucurr_openISOCurrencies(UCURR_COMMON
|UCURR_NON_DEPRECATED
, &icuStatus
);
581 CFArrayRef result
= __CFLocaleCopyUEnumerationAsArray(enumer
, &icuStatus
);
586 CFStringRef
CFLocaleCreateLocaleIdentifierFromWindowsLocaleCode(CFAllocatorRef allocator
, uint32_t lcid
) {
587 char buffer
[kMaxICUNameSize
];
588 UErrorCode status
= U_ZERO_ERROR
;
589 int32_t ret
= uloc_getLocaleForLCID(lcid
, buffer
, kMaxICUNameSize
, &status
);
590 if (U_FAILURE(status
) || kMaxICUNameSize
<= ret
) return NULL
;
591 CFStringRef str
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, buffer
, kCFStringEncodingASCII
);
592 CFStringRef ident
= CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault
, str
);
597 uint32_t CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier(CFStringRef localeIdentifier
) {
598 CFStringRef ident
= CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault
, localeIdentifier
);
599 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
600 Boolean b
= CFStringGetCString(ident
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
);
602 return b
? uloc_getLCID(localeID
) : 0;
605 CFLocaleLanguageDirection
CFLocaleGetLanguageCharacterDirection(CFStringRef isoLangCode
) {
606 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
607 Boolean b
= CFStringGetCString(isoLangCode
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
);
608 CFLocaleLanguageDirection dir
;
609 UErrorCode status
= U_ZERO_ERROR
;
610 ULayoutType idir
= b
? uloc_getCharacterOrientation(localeID
, &status
) : ULOC_LAYOUT_UNKNOWN
;
612 case ULOC_LAYOUT_LTR
: dir
= kCFLocaleLanguageDirectionLeftToRight
; break;
613 case ULOC_LAYOUT_RTL
: dir
= kCFLocaleLanguageDirectionRightToLeft
; break;
614 case ULOC_LAYOUT_TTB
: dir
= kCFLocaleLanguageDirectionTopToBottom
; break;
615 case ULOC_LAYOUT_BTT
: dir
= kCFLocaleLanguageDirectionBottomToTop
; break;
616 default: dir
= kCFLocaleLanguageDirectionUnknown
; break;
621 CFLocaleLanguageDirection
CFLocaleGetLanguageLineDirection(CFStringRef isoLangCode
) {
622 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
623 Boolean b
= CFStringGetCString(isoLangCode
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
);
624 CFLocaleLanguageDirection dir
;
625 UErrorCode status
= U_ZERO_ERROR
;
626 ULayoutType idir
= b
? uloc_getLineOrientation(localeID
, &status
) : ULOC_LAYOUT_UNKNOWN
;
628 case ULOC_LAYOUT_LTR
: dir
= kCFLocaleLanguageDirectionLeftToRight
; break;
629 case ULOC_LAYOUT_RTL
: dir
= kCFLocaleLanguageDirectionRightToLeft
; break;
630 case ULOC_LAYOUT_TTB
: dir
= kCFLocaleLanguageDirectionTopToBottom
; break;
631 case ULOC_LAYOUT_BTT
: dir
= kCFLocaleLanguageDirectionBottomToTop
; break;
632 default: dir
= kCFLocaleLanguageDirectionUnknown
; break;
637 CFArrayRef
CFLocaleCopyPreferredLanguages(void) {
638 CFMutableArrayRef newArray
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
639 CFArrayRef languagesArray
= (CFArrayRef
)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication
);
640 if (languagesArray
&& (CFArrayGetTypeID() == CFGetTypeID(languagesArray
))) {
641 for (CFIndex idx
= 0, cnt
= CFArrayGetCount(languagesArray
); idx
< cnt
; idx
++) {
642 CFStringRef str
= (CFStringRef
)CFArrayGetValueAtIndex(languagesArray
, idx
);
643 if (str
&& (CFStringGetTypeID() == CFGetTypeID(str
))) {
644 CFStringRef ident
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, str
);
645 CFArrayAppendValue(newArray
, ident
);
650 if (languagesArray
) CFRelease(languagesArray
);
654 // -------- -------- -------- -------- -------- --------
656 // These functions return true or false depending on the success or failure of the function.
657 // In the Copy case, this is failure to fill the *cf out parameter, and that out parameter is
658 // returned by reference WITH a retain on it.
659 static bool __CFLocaleSetNOP(CFMutableLocaleRef locale
, CFTypeRef cf
, CFStringRef context
) {
663 static bool __CFLocaleCopyLocaleID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
664 *cf
= CFRetain(locale
->_identifier
);
669 static bool __CFLocaleCopyCodes(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
670 CFDictionaryRef codes
= NULL
;
671 // this access of _cache is protected by the lock in CFLocaleGetValue()
672 if (!CFDictionaryGetValueIfPresent(locale
->_cache
, CFSTR("__kCFLocaleCodes"), (const void **)&codes
)) {
673 codes
= CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault
, locale
->_identifier
);
674 if (codes
) CFDictionarySetValue(locale
->_cache
, CFSTR("__kCFLocaleCodes"), codes
);
675 if (codes
) CFRelease(codes
);
678 CFStringRef value
= (CFStringRef
)CFDictionaryGetValue(codes
, context
); // context is one of kCFLocale*Code constants
679 if (value
) CFRetain(value
);
686 CFCharacterSetRef
_CFCreateCharacterSetFromUSet(USet
*set
) {
687 UErrorCode icuErr
= U_ZERO_ERROR
;
688 CFMutableCharacterSetRef working
= CFCharacterSetCreateMutable(NULL
);
689 UChar buffer
[2048]; // Suitable for most small sets
695 int32_t itemCount
= uset_getItemCount(set
);
697 for (i
= 0; i
< itemCount
; ++i
)
703 stringLen
= uset_getItem(set
, i
, &start
, &end
, buffer
, sizeof(buffer
)/sizeof(UChar
), &icuErr
);
704 if (icuErr
== U_BUFFER_OVERFLOW_ERROR
)
706 string
= (UChar
*) malloc(sizeof(UChar
)*(stringLen
+1));
712 icuErr
= U_ZERO_ERROR
;
713 (void) uset_getItem(set
, i
, &start
, &end
, string
, stringLen
+1, &icuErr
);
715 if (U_FAILURE(icuErr
))
717 if (string
!= buffer
)
723 CFCharacterSetAddCharactersInRange(working
, CFRangeMake(start
, end
-start
+1));
726 CFStringRef cfString
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, (UniChar
*)string
, stringLen
, kCFAllocatorNull
);
727 CFCharacterSetAddCharactersInString(working
, cfString
);
730 if (string
!= buffer
)
734 CFCharacterSetRef result
= CFCharacterSetCreateCopy(kCFAllocatorSystemDefault
, working
);
740 static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
741 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
742 if (CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
)) {
743 UErrorCode icuStatus
= U_ZERO_ERROR
;
744 ULocaleData
* uld
= ulocdata_open(localeID
, &icuStatus
);
745 USet
*set
= ulocdata_getExemplarSet(uld
, NULL
, USET_ADD_CASE_MAPPINGS
, ULOCDATA_ES_STANDARD
, &icuStatus
);
747 if (U_FAILURE(icuStatus
))
749 if (icuStatus
== U_USING_DEFAULT_WARNING
) // If default locale used, force to empty set
751 *cf
= (CFTypeRef
) _CFCreateCharacterSetFromUSet(set
);
753 return (*cf
!= NULL
);
758 static bool __CFLocaleCopyICUKeyword(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
, const char *keyword
)
760 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
761 if (CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
))
763 char value
[ULOC_KEYWORD_AND_VALUES_CAPACITY
];
764 UErrorCode icuStatus
= U_ZERO_ERROR
;
765 if (uloc_getKeywordValue(localeID
, keyword
, value
, sizeof(value
)/sizeof(char), &icuStatus
) > 0 && U_SUCCESS(icuStatus
))
767 *cf
= (CFTypeRef
) CFStringCreateWithCString(kCFAllocatorSystemDefault
, value
, kCFStringEncodingASCII
);
775 static bool __CFLocaleCopyCalendarID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
776 bool succeeded
= __CFLocaleCopyICUKeyword(locale
, user
, cf
, context
, kCalendarKeyword
);
778 if (CFEqual(*cf
, kCFCalendarIdentifierGregorian
)) {
780 *cf
= CFRetain(kCFCalendarIdentifierGregorian
);
781 } else if (CFEqual(*cf
, kCFCalendarIdentifierBuddhist
)) {
783 *cf
= CFRetain(kCFCalendarIdentifierBuddhist
);
784 } else if (CFEqual(*cf
, kCFCalendarIdentifierJapanese
)) {
786 *cf
= CFRetain(kCFCalendarIdentifierJapanese
);
787 } else if (CFEqual(*cf
, kCFCalendarIdentifierIslamic
)) {
789 *cf
= CFRetain(kCFCalendarIdentifierIslamic
);
790 } else if (CFEqual(*cf
, kCFCalendarIdentifierIslamicCivil
)) {
792 *cf
= CFRetain(kCFCalendarIdentifierIslamicCivil
);
793 } else if (CFEqual(*cf
, kCFCalendarIdentifierHebrew
)) {
795 *cf
= CFRetain(kCFCalendarIdentifierHebrew
);
796 } else if (CFEqual(*cf
, kCFCalendarIdentifierChinese
)) {
798 *cf
= CFRetain(kCFCalendarIdentifierChinese
);
799 } else if (CFEqual(*cf
, kCFCalendarIdentifierRepublicOfChina
)) {
801 *cf
= CFRetain(kCFCalendarIdentifierRepublicOfChina
);
802 } else if (CFEqual(*cf
, kCFCalendarIdentifierPersian
)) {
804 *cf
= CFRetain(kCFCalendarIdentifierPersian
);
805 } else if (CFEqual(*cf
, kCFCalendarIdentifierIndian
)) {
807 *cf
= CFRetain(kCFCalendarIdentifierIndian
);
808 } else if (CFEqual(*cf
, kCFCalendarIdentifierISO8601
)) {
810 *cf
= CFRetain(kCFCalendarIdentifierISO8601
);
811 } else if (CFEqual(*cf
, kCFCalendarIdentifierCoptic
)) {
813 *cf
= CFRetain(kCFCalendarIdentifierCoptic
);
814 } else if (CFEqual(*cf
, kCFCalendarIdentifierEthiopicAmeteMihret
)) {
816 *cf
= CFRetain(kCFCalendarIdentifierEthiopicAmeteMihret
);
817 } else if (CFEqual(*cf
, kCFCalendarIdentifierEthiopicAmeteAlem
)) {
819 *cf
= CFRetain(kCFCalendarIdentifierEthiopicAmeteAlem
);
826 *cf
= CFRetain(kCFCalendarIdentifierGregorian
);
831 static bool __CFLocaleCopyCalendar(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
832 if (__CFLocaleCopyCalendarID(locale
, user
, cf
, context
)) {
833 CFCalendarRef calendar
= CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault
, (CFStringRef
)*cf
);
834 CFCalendarSetLocale(calendar
, locale
);
835 CFDictionaryRef prefs
= __CFLocaleGetPrefs(locale
);
836 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleFirstWeekday")) : NULL
;
837 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
838 metapref
= (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, *cf
);
840 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFNumberGetTypeID()) {
842 if (CFNumberGetValue((CFNumberRef
)metapref
, kCFNumberCFIndexType
, &wkdy
)) {
843 CFCalendarSetFirstWeekday(calendar
, wkdy
);
846 metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleMinDaysInFirstWeek")) : NULL
;
847 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
848 metapref
= (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, *cf
);
850 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFNumberGetTypeID()) {
852 if (CFNumberGetValue((CFNumberRef
)metapref
, kCFNumberCFIndexType
, &mwd
)) {
853 CFCalendarSetMinimumDaysInFirstWeek(calendar
, mwd
);
863 static bool __CFLocaleCopyDelimiter(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
864 ULocaleDataDelimiterType type
= (ULocaleDataDelimiterType
)0;
865 if (context
== kCFLocaleQuotationBeginDelimiterKey
) {
866 type
= ULOCDATA_QUOTATION_START
;
867 } else if (context
== kCFLocaleQuotationEndDelimiterKey
) {
868 type
= ULOCDATA_QUOTATION_END
;
869 } else if (context
== kCFLocaleAlternateQuotationBeginDelimiterKey
) {
870 type
= ULOCDATA_ALT_QUOTATION_START
;
871 } else if (context
== kCFLocaleAlternateQuotationEndDelimiterKey
) {
872 type
= ULOCDATA_ALT_QUOTATION_END
;
877 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
878 if (!CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
)) {
883 UErrorCode status
= U_ZERO_ERROR
;
884 ULocaleData
*uld
= ulocdata_open(localeID
, &status
);
885 int32_t len
= ulocdata_getDelimiter(uld
, type
, buffer
, sizeof(buffer
) / sizeof(buffer
[0]), &status
);
887 if (U_FAILURE(status
) || sizeof(buffer
) / sizeof(buffer
[0]) < len
) {
891 *cf
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)buffer
, len
);
892 return (*cf
!= NULL
);
895 static bool __CFLocaleCopyCollationID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
896 return __CFLocaleCopyICUKeyword(locale
, user
, cf
, context
, kCollationKeyword
);
899 static bool __CFLocaleCopyCollatorID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
900 CFStringRef canonLocaleCFStr
= NULL
;
902 CFStringRef pref
= (CFStringRef
)CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleCollationOrder"));
904 // Canonicalize pref string in case it's not in the canonical format.
905 canonLocaleCFStr
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, pref
);
907 CFArrayRef languagesArray
= (CFArrayRef
)CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleLanguages"));
908 if (languagesArray
&& (CFArrayGetTypeID() == CFGetTypeID(languagesArray
))) {
909 if (0 < CFArrayGetCount(languagesArray
)) {
910 CFStringRef str
= (CFStringRef
)CFArrayGetValueAtIndex(languagesArray
, 0);
911 if (str
&& (CFStringGetTypeID() == CFGetTypeID(str
))) {
912 canonLocaleCFStr
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, str
);
918 if (!canonLocaleCFStr
) {
919 canonLocaleCFStr
= CFLocaleGetIdentifier(locale
);
920 CFRetain(canonLocaleCFStr
);
922 *cf
= canonLocaleCFStr
;
923 return canonLocaleCFStr
? true : false;
926 static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
927 bool us
= false; // Default is Metric
929 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
931 CFTypeRef pref
= CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleMetricUnits"));
933 us
= (kCFBooleanFalse
== pref
);
936 pref
= CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleMeasurementUnits"));
938 us
= CFEqual(pref
, CFSTR("Inches"));
943 #elif DEPLOYMENT_TARGET_WINDOWS
945 #error Unknown or unspecified DEPLOYMENT_TARGET
948 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
949 if (CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
)) {
950 UErrorCode icuStatus
= U_ZERO_ERROR
;
951 UMeasurementSystem ms
= UMS_SI
;
952 ms
= ulocdata_getMeasurementSystem(localeID
, &icuStatus
);
953 if (U_SUCCESS(icuStatus
)) {
961 *cf
= us
? CFRetain(kCFBooleanFalse
) : CFRetain(kCFBooleanTrue
);
965 static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
966 if (__CFLocaleCopyUsesMetric(locale
, user
, cf
, context
)) {
967 bool us
= (*cf
== kCFBooleanFalse
);
969 *cf
= us
? CFRetain(CFSTR("U.S.")) : CFRetain(CFSTR("Metric"));
975 static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
976 CFStringRef str
= NULL
;
977 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
978 CFNumberFormatterRef nf
= CFNumberFormatterCreate(kCFAllocatorSystemDefault
, locale
, kCFNumberFormatterDecimalStyle
);
979 str
= nf
? CFNumberFormatterCopyProperty(nf
, context
) : NULL
;
980 if (nf
) CFRelease(nf
);
981 #elif DEPLOYMENT_TARGET_WINDOWS
983 #error Unknown or unspecified DEPLOYMENT_TARGET
992 // ICU does not reliably set up currency info for other than Currency-type formatters,
993 // so we have to have another routine here which creates a Currency number formatter.
994 static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
995 CFStringRef str
= NULL
;
996 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
997 CFNumberFormatterRef nf
= CFNumberFormatterCreate(kCFAllocatorSystemDefault
, locale
, kCFNumberFormatterCurrencyStyle
);
998 str
= nf
? CFNumberFormatterCopyProperty(nf
, context
) : NULL
;
999 if (nf
) CFRelease(nf
);
1000 #elif DEPLOYMENT_TARGET_WINDOWS
1002 #error Unknown or unspecified DEPLOYMENT_TARGET
1011 typedef int32_t (*__CFICUFunction
)(const char *, const char *, UChar
*, int32_t, UErrorCode
*);
1013 static bool __CFLocaleICUName(const char *locale
, const char *valLocale
, CFStringRef
*out
, __CFICUFunction icu
) {
1014 UErrorCode icuStatus
= U_ZERO_ERROR
;
1016 UChar name
[kMaxICUNameSize
];
1018 size
= (*icu
)(valLocale
, locale
, name
, kMaxICUNameSize
, &icuStatus
);
1019 if (U_SUCCESS(icuStatus
) && size
> 0 && icuStatus
!= U_USING_DEFAULT_WARNING
) {
1020 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1021 return (*out
!= NULL
);
1026 static bool __CFLocaleICUKeywordValueName(const char *locale
, const char *value
, const char *keyword
, CFStringRef
*out
) {
1027 UErrorCode icuStatus
= U_ZERO_ERROR
;
1029 UChar name
[kMaxICUNameSize
];
1030 // Need to make a fake locale ID
1031 char lid
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
1032 if (strlen(value
) < ULOC_KEYWORD_AND_VALUES_CAPACITY
) {
1033 strlcpy(lid
, "en_US@", sizeof(lid
));
1034 strlcat(lid
, keyword
, sizeof(lid
));
1035 strlcat(lid
, "=", sizeof(lid
));
1036 strlcat(lid
, value
, sizeof(lid
));
1037 size
= uloc_getDisplayKeywordValue(lid
, keyword
, locale
, name
, kMaxICUNameSize
, &icuStatus
);
1038 if (U_SUCCESS(icuStatus
) && size
> 0 && icuStatus
!= U_USING_DEFAULT_WARNING
) {
1039 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1040 return (*out
!= NULL
);
1046 static bool __CFLocaleICUCurrencyName(const char *locale
, const char *value
, UCurrNameStyle style
, CFStringRef
*out
) {
1047 int valLen
= strlen(value
);
1048 if (valLen
!= 3) // not a valid ISO code
1051 UBool isChoice
= FALSE
;
1053 UErrorCode icuStatus
= U_ZERO_ERROR
;
1054 u_charsToUChars(value
, curr
, valLen
);
1055 curr
[valLen
] = '\0';
1057 name
= ucurr_getName(curr
, locale
, style
, &isChoice
, &size
, &icuStatus
);
1058 if (U_FAILURE(icuStatus
) || icuStatus
== U_USING_DEFAULT_WARNING
)
1060 UChar result
[kMaxICUNameSize
];
1063 UChar pattern
[kMaxICUNameSize
];
1064 CFStringRef patternRef
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("{0,choice,%S}"), name
);
1065 CFIndex pattlen
= CFStringGetLength(patternRef
);
1066 CFStringGetCharacters(patternRef
, CFRangeMake(0, pattlen
), (UniChar
*)pattern
);
1067 CFRelease(patternRef
);
1068 pattern
[pattlen
] = '\0'; // null terminate the pattern
1069 // Format the message assuming a large amount of the currency
1070 size
= u_formatMessage("en_US", pattern
, pattlen
, result
, kMaxICUNameSize
, &icuStatus
, 10.0);
1071 if (U_FAILURE(icuStatus
))
1076 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1077 return (*out
!= NULL
);
1080 static bool __CFLocaleFullName(const char *locale
, const char *value
, CFStringRef
*out
) {
1081 UErrorCode icuStatus
= U_ZERO_ERROR
;
1083 UChar name
[kMaxICUNameSize
];
1085 // First, try to get the full locale.
1086 size
= uloc_getDisplayName(value
, locale
, name
, kMaxICUNameSize
, &icuStatus
);
1087 if (U_FAILURE(icuStatus
) || size
<= 0)
1090 // Did we wind up using a default somewhere?
1091 if (icuStatus
== U_USING_DEFAULT_WARNING
) {
1092 // For some locale IDs, there may be no language which has a translation for every
1093 // piece. Rather than return nothing, see if we can at least handle
1094 // the language part of the locale.
1095 UErrorCode localStatus
= U_ZERO_ERROR
;
1097 UChar localName
[kMaxICUNameSize
];
1098 localSize
= uloc_getDisplayLanguage(value
, locale
, localName
, kMaxICUNameSize
, &localStatus
);
1099 if (U_FAILURE(localStatus
) || size
<= 0 || localStatus
== U_USING_DEFAULT_WARNING
)
1103 // This locale is OK, so use the result.
1104 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1105 return (*out
!= NULL
);
1108 static bool __CFLocaleLanguageName(const char *locale
, const char *value
, CFStringRef
*out
) {
1109 return __CFLocaleICUName(locale
, value
, out
, uloc_getDisplayLanguage
);
1112 static bool __CFLocaleCountryName(const char *locale
, const char *value
, CFStringRef
*out
) {
1113 // Need to make a fake locale ID
1114 char lid
[ULOC_FULLNAME_CAPACITY
];
1115 if (strlen(value
) < sizeof(lid
) - 3) {
1116 strlcpy(lid
, "en_", sizeof(lid
));
1117 strlcat(lid
, value
, sizeof(lid
));
1118 return __CFLocaleICUName(locale
, lid
, out
, uloc_getDisplayCountry
);
1123 static bool __CFLocaleScriptName(const char *locale
, const char *value
, CFStringRef
*out
) {
1124 // Need to make a fake locale ID
1125 char lid
[ULOC_FULLNAME_CAPACITY
];
1126 if (strlen(value
) == 4) {
1127 strlcpy(lid
, "en_", sizeof(lid
));
1128 strlcat(lid
, value
, sizeof(lid
));
1129 strlcat(lid
, "_US", sizeof(lid
));
1130 return __CFLocaleICUName(locale
, lid
, out
, uloc_getDisplayScript
);
1135 static bool __CFLocaleVariantName(const char *locale
, const char *value
, CFStringRef
*out
) {
1136 // Need to make a fake locale ID
1137 char lid
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
1138 if (strlen(value
) < sizeof(lid
) - 6) {
1139 strlcpy(lid
, "en_US_", sizeof(lid
));
1140 strlcat(lid
, value
, sizeof(lid
));
1141 return __CFLocaleICUName(locale
, lid
, out
, uloc_getDisplayVariant
);
1146 static bool __CFLocaleCalendarName(const char *locale
, const char *value
, CFStringRef
*out
) {
1147 return __CFLocaleICUKeywordValueName(locale
, value
, kCalendarKeyword
, out
);
1150 static bool __CFLocaleCollationName(const char *locale
, const char *value
, CFStringRef
*out
) {
1151 return __CFLocaleICUKeywordValueName(locale
, value
, kCollationKeyword
, out
);
1154 static bool __CFLocaleCurrencyShortName(const char *locale
, const char *value
, CFStringRef
*out
) {
1155 return __CFLocaleICUCurrencyName(locale
, value
, UCURR_SYMBOL_NAME
, out
);
1158 static bool __CFLocaleCurrencyFullName(const char *locale
, const char *value
, CFStringRef
*out
) {
1159 return __CFLocaleICUCurrencyName(locale
, value
, UCURR_LONG_NAME
, out
);
1162 static bool __CFLocaleNoName(const char *locale
, const char *value
, CFStringRef
*out
) {
1166 #undef kMaxICUNameSize