2 * Copyright (c) 2012 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-2012, Apple Inc. All rights reserved.
26 Responsibility: David Smith
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 #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>
50 #include <CoreFoundation/CFNumberFormatter.h>
55 #if DEPLOYMENT_TARGET_EMBEDDED_MINI
56 // Some compatability definitions
57 #define ULOC_FULLNAME_CAPACITY 157
58 #define ULOC_KEYWORD_AND_VALUES_CAPACITY 100
60 //typedef long UErrorCode;
61 //#define U_BUFFER_OVERFLOW_ERROR 15
62 //#define U_ZERO_ERROR 0
64 //typedef uint16_t UChar;
68 CONST_STRING_DECL(kCFLocaleCurrentLocaleDidChangeNotification
, "kCFLocaleCurrentLocaleDidChangeNotification")
70 static const char *kCalendarKeyword
= "calendar";
71 static const char *kCollationKeyword
= "collation";
72 #define kMaxICUNameSize 1024
74 typedef struct __CFLocale
*CFMutableLocaleRef
;
76 PE_CONST_STRING_DECL(__kCFLocaleCollatorID
, "locale:collator id")
80 __kCFLocaleKeyTableCount
= 21
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
*);
92 // Must forward decl. these functions:
93 static bool __CFLocaleCopyLocaleID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
94 static bool __CFLocaleSetNOP(CFMutableLocaleRef locale
, CFTypeRef cf
, CFStringRef context
);
95 static bool __CFLocaleFullName(const char *locale
, const char *value
, CFStringRef
*out
);
96 static bool __CFLocaleCopyCodes(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
97 static bool __CFLocaleCountryName(const char *locale
, const char *value
, CFStringRef
*out
);
98 static bool __CFLocaleScriptName(const char *locale
, const char *value
, CFStringRef
*out
);
99 static bool __CFLocaleLanguageName(const char *locale
, const char *value
, CFStringRef
*out
);
100 static bool __CFLocaleCurrencyShortName(const char *locale
, const char *value
, CFStringRef
*out
);
101 static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
102 static bool __CFLocaleVariantName(const char *locale
, const char *value
, CFStringRef
*out
);
103 static bool __CFLocaleNoName(const char *locale
, const char *value
, CFStringRef
*out
);
104 static bool __CFLocaleCopyCalendarID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
105 static bool __CFLocaleCalendarName(const char *locale
, const char *value
, CFStringRef
*out
);
106 static bool __CFLocaleCollationName(const char *locale
, const char *value
, CFStringRef
*out
);
107 static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
108 static bool __CFLocaleCopyCalendar(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
109 static bool __CFLocaleCopyCollationID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
110 static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
111 static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
112 static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
113 static bool __CFLocaleCurrencyFullName(const char *locale
, const char *value
, CFStringRef
*out
);
114 static bool __CFLocaleCopyCollatorID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
115 static bool __CFLocaleCopyDelimiter(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
);
117 // Note string members start with an extra &, and are fixed up at init time
118 static struct key_table __CFLocaleKeyTable
[__kCFLocaleKeyTableCount
] = {
119 {(CFStringRef
)&kCFLocaleIdentifierKey
, __CFLocaleCopyLocaleID
, __CFLocaleSetNOP
, __CFLocaleFullName
, NULL
},
120 {(CFStringRef
)&kCFLocaleLanguageCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleLanguageName
, (CFStringRef
)&kCFLocaleLanguageCodeKey
},
121 {(CFStringRef
)&kCFLocaleCountryCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleCountryName
, (CFStringRef
)&kCFLocaleCountryCodeKey
},
122 {(CFStringRef
)&kCFLocaleScriptCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleScriptName
, (CFStringRef
)&kCFLocaleScriptCodeKey
},
123 {(CFStringRef
)&kCFLocaleVariantCodeKey
, __CFLocaleCopyCodes
, __CFLocaleSetNOP
, __CFLocaleVariantName
, (CFStringRef
)&kCFLocaleVariantCodeKey
},
124 {(CFStringRef
)&kCFLocaleExemplarCharacterSetKey
, __CFLocaleCopyExemplarCharSet
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
125 {(CFStringRef
)&kCFLocaleCalendarIdentifierKey
, __CFLocaleCopyCalendarID
, __CFLocaleSetNOP
, __CFLocaleCalendarName
, NULL
},
126 {(CFStringRef
)&kCFLocaleCalendarKey
, __CFLocaleCopyCalendar
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
127 {(CFStringRef
)&kCFLocaleCollationIdentifierKey
, __CFLocaleCopyCollationID
, __CFLocaleSetNOP
, __CFLocaleCollationName
, NULL
},
128 {(CFStringRef
)&kCFLocaleUsesMetricSystemKey
, __CFLocaleCopyUsesMetric
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
129 {(CFStringRef
)&kCFLocaleMeasurementSystemKey
, __CFLocaleCopyMeasurementSystem
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
130 {(CFStringRef
)&kCFLocaleDecimalSeparatorKey
, __CFLocaleCopyNumberFormat
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFNumberFormatterDecimalSeparatorKey
},
131 {(CFStringRef
)&kCFLocaleGroupingSeparatorKey
, __CFLocaleCopyNumberFormat
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFNumberFormatterGroupingSeparatorKey
},
132 {(CFStringRef
)&kCFLocaleCurrencySymbolKey
, __CFLocaleCopyNumberFormat2
, __CFLocaleSetNOP
, __CFLocaleCurrencyShortName
, (CFStringRef
)&kCFNumberFormatterCurrencySymbolKey
},
133 {(CFStringRef
)&kCFLocaleCurrencyCodeKey
, __CFLocaleCopyNumberFormat2
, __CFLocaleSetNOP
, __CFLocaleCurrencyFullName
, (CFStringRef
)&kCFNumberFormatterCurrencyCodeKey
},
134 {(CFStringRef
)&kCFLocaleCollatorIdentifierKey
, __CFLocaleCopyCollatorID
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
135 {(CFStringRef
)&__kCFLocaleCollatorID
, __CFLocaleCopyCollatorID
, __CFLocaleSetNOP
, __CFLocaleNoName
, NULL
},
136 {(CFStringRef
)&kCFLocaleQuotationBeginDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleQuotationBeginDelimiterKey
},
137 {(CFStringRef
)&kCFLocaleQuotationEndDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleQuotationEndDelimiterKey
},
138 {(CFStringRef
)&kCFLocaleAlternateQuotationBeginDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleAlternateQuotationBeginDelimiterKey
},
139 {(CFStringRef
)&kCFLocaleAlternateQuotationEndDelimiterKey
, __CFLocaleCopyDelimiter
, __CFLocaleSetNOP
, __CFLocaleNoName
, (CFStringRef
)&kCFLocaleAlternateQuotationEndDelimiterKey
},
143 static CFLocaleRef __CFLocaleSystem
= NULL
;
144 static CFMutableDictionaryRef __CFLocaleCache
= NULL
;
145 static CFSpinLock_t __CFLocaleGlobalLock
= CFSpinLockInit
;
149 CFStringRef _identifier
; // canonical identifier, never NULL
150 CFMutableDictionaryRef _cache
;
151 CFMutableDictionaryRef _overrides
;
152 CFDictionaryRef _prefs
;
157 __private_extern__ Boolean
__CFLocaleGetNullLocale(struct __CFLocale
*locale
) {
158 return locale
->_nullLocale
;
161 __private_extern__
void __CFLocaleSetNullLocale(struct __CFLocale
*locale
) {
162 locale
->_nullLocale
= true;
166 enum { /* Bits 0-1 */
167 __kCFLocaleOrdinary
= 0,
168 __kCFLocaleSystem
= 1,
170 __kCFLocaleCustom
= 3
173 CF_INLINE CFIndex
__CFLocaleGetType(CFLocaleRef locale
) {
174 return __CFBitfieldGetValue(((const CFRuntimeBase
*)locale
)->_cfinfo
[CF_INFO_BITS
], 1, 0);
177 CF_INLINE
void __CFLocaleSetType(CFLocaleRef locale
, CFIndex type
) {
178 __CFBitfieldSetValue(((CFRuntimeBase
*)locale
)->_cfinfo
[CF_INFO_BITS
], 1, 0, (uint8_t)type
);
181 CF_INLINE
void __CFLocaleLockGlobal(void) {
182 __CFSpinLock(&__CFLocaleGlobalLock
);
185 CF_INLINE
void __CFLocaleUnlockGlobal(void) {
186 __CFSpinUnlock(&__CFLocaleGlobalLock
);
189 CF_INLINE
void __CFLocaleLock(CFLocaleRef locale
) {
190 __CFSpinLock(&((struct __CFLocale
*)locale
)->_lock
);
193 CF_INLINE
void __CFLocaleUnlock(CFLocaleRef locale
) {
194 __CFSpinUnlock(&((struct __CFLocale
*)locale
)->_lock
);
198 static 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
);
213 static CFHashCode
__CFLocaleHash(CFTypeRef cf
) {
214 CFLocaleRef locale
= (CFLocaleRef
)cf
;
215 return CFHash(locale
->_identifier
);
218 static 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;
227 return CFStringCreateWithFormat(CFGetAllocator(locale
), NULL
, CFSTR("<CFLocale %p [%p]>{type = %s, identifier = '%@'}"), cf
, CFGetAllocator(locale
), type
, locale
->_identifier
);
230 static 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
);
238 static CFTypeID __kCFLocaleTypeID
= _kCFRuntimeNotATypeID
;
240 static const CFRuntimeClass __CFLocaleClass
= {
245 __CFLocaleDeallocate
,
249 __CFLocaleCopyDescription
252 static void __CFLocaleInitialize(void) {
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
);
264 CFTypeID
CFLocaleGetTypeID(void) {
265 if (_kCFRuntimeNotATypeID
== __kCFLocaleTypeID
) __CFLocaleInitialize();
266 return __kCFLocaleTypeID
;
269 CFLocaleRef
CFLocaleGetSystem(void) {
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
;
281 if (locale
) CFRelease(locale
);
284 locale
= __CFLocaleSystem
? (CFLocaleRef
)CFRetain(__CFLocaleSystem
) : NULL
;
285 __CFLocaleUnlockGlobal();
289 extern CFDictionaryRef
__CFXPreferencesCopyCurrentApplicationState(void);
291 static CFLocaleRef __CFLocaleCurrent
= NULL
;
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")
302 CFLocaleRef
CFLocaleCopyCurrent(void) {
304 CFStringRef name
= NULL
, 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
309 #if 0 // DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
310 name
= (CFStringRef
)CFPreferencesCopyAppValue(CFSTR("AppleLocale"), kCFPreferencesCurrentApplication
);
312 if (name
&& (CFStringGetTypeID() == CFGetTypeID(name
))) {
313 ident
= CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault
, name
);
315 if (name
) CFRelease(name
);
316 CFLocaleRef oldLocale
= NULL
;
317 __CFLocaleLockGlobal();
318 if (__CFLocaleCurrent
) {
319 if (ident
&& !CFEqual(__CFLocaleCurrent
->_identifier
, ident
)) {
320 oldLocale
= __CFLocaleCurrent
;
321 __CFLocaleCurrent
= NULL
;
323 CFLocaleRef res
= __CFLocaleCurrent
;
325 __CFLocaleUnlockGlobal();
326 if (ident
) CFRelease(ident
);
330 __CFLocaleUnlockGlobal();
331 if (oldLocale
) CFRelease(oldLocale
);
332 if (ident
) CFRelease(ident
);
333 // We could *probably* re-use ident down below, but that would't
334 // get us out of querying CFPrefs for the current application state.
336 CFDictionaryRef prefs
= NULL
;
337 CFStringRef identifier
= NULL
;
339 struct __CFLocale
*locale
;
340 uint32_t size
= sizeof(struct __CFLocale
) - sizeof(CFRuntimeBase
);
341 locale
= (struct __CFLocale
*)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault
, CFLocaleGetTypeID(), size
, NULL
);
342 if (NULL
== locale
) {
343 if (prefs
) CFRelease(prefs
);
344 if (identifier
) CFRelease(identifier
);
347 __CFLocaleSetType(locale
, __kCFLocaleUser
);
348 if (NULL
== identifier
) identifier
= (CFStringRef
)CFRetain(FALLBACK_LOCALE_NAME
);
349 locale
->_identifier
= identifier
;
350 locale
->_cache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
351 locale
->_overrides
= NULL
;
352 locale
->_prefs
= prefs
;
353 locale
->_lock
= CFSpinLockInit
;
354 locale
->_nullLocale
= false;
356 __CFLocaleLockGlobal();
357 if (NULL
== __CFLocaleCurrent
) {
358 __CFLocaleCurrent
= locale
;
362 locale
= (struct __CFLocale
*)CFRetain(__CFLocaleCurrent
);
363 __CFLocaleUnlockGlobal();
367 __private_extern__ CFDictionaryRef
__CFLocaleGetPrefs(CFLocaleRef locale
) {
368 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFDictionaryRef
, (NSLocale
*)locale
, _prefs
);
369 return locale
->_prefs
;
372 CFLocaleRef
CFLocaleCreate(CFAllocatorRef allocator
, CFStringRef identifier
) {
373 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
374 __CFGenericValidateType(allocator
, CFAllocatorGetTypeID());
375 __CFGenericValidateType(identifier
, CFStringGetTypeID());
376 CFStringRef localeIdentifier
= NULL
;
378 localeIdentifier
= CFLocaleCreateCanonicalLocaleIdentifierFromString(allocator
, identifier
);
380 if (NULL
== localeIdentifier
) return NULL
;
381 CFStringRef old
= localeIdentifier
;
382 localeIdentifier
= (CFStringRef
)CFStringCreateCopy(allocator
, localeIdentifier
);
384 __CFLocaleLockGlobal();
385 // Look for cases where we can return a cached instance.
386 // We only use cached objects if the allocator is the system
387 // default allocator.
388 if (!allocator
) allocator
= __CFGetDefaultAllocator();
389 Boolean canCache
= _CFAllocatorIsSystemDefault(allocator
);
390 if (canCache
&& __CFLocaleCache
) {
391 CFLocaleRef locale
= (CFLocaleRef
)CFDictionaryGetValue(__CFLocaleCache
, localeIdentifier
);
394 __CFLocaleUnlockGlobal();
395 CFRelease(localeIdentifier
);
399 struct __CFLocale
*locale
= NULL
;
400 uint32_t size
= sizeof(struct __CFLocale
) - sizeof(CFRuntimeBase
);
401 locale
= (struct __CFLocale
*)_CFRuntimeCreateInstance(allocator
, CFLocaleGetTypeID(), size
, NULL
);
402 if (NULL
== locale
) {
405 __CFLocaleSetType(locale
, __kCFLocaleOrdinary
);
406 locale
->_identifier
= localeIdentifier
;
407 locale
->_cache
= CFDictionaryCreateMutable(allocator
, 0, NULL
, &kCFTypeDictionaryValueCallBacks
);
408 locale
->_overrides
= NULL
;
409 locale
->_prefs
= NULL
;
410 locale
->_lock
= CFSpinLockInit
;
412 if (NULL
== __CFLocaleCache
) {
413 __CFLocaleCache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
415 CFDictionarySetValue(__CFLocaleCache
, localeIdentifier
, locale
);
417 __CFLocaleUnlockGlobal();
418 return (CFLocaleRef
)locale
;
421 CFLocaleRef
CFLocaleCreateCopy(CFAllocatorRef allocator
, CFLocaleRef locale
) {
422 return (CFLocaleRef
)CFRetain(locale
);
425 CFStringRef
CFLocaleGetIdentifier(CFLocaleRef locale
) {
426 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFStringRef
, (NSLocale
*)locale
, localeIdentifier
);
427 return locale
->_identifier
;
430 CFTypeRef
CFLocaleGetValue(CFLocaleRef locale
, CFStringRef key
) {
431 #if DEPLOYMENT_TARGET_MACOSX
432 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
)) {
433 // Hack for Opera, which is using the hard-coded string value below instead of
434 // the perfectly good public kCFLocaleCountryCode constant, for whatever reason.
435 if (key
&& CFEqual(key
, CFSTR("locale:country code"))) {
436 key
= kCFLocaleCountryCodeKey
;
440 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFTypeRef
, (NSLocale
*)locale
, objectForKey
:(id
)key
);
441 CFIndex idx
, slot
= -1;
442 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
443 if (__CFLocaleKeyTable
[idx
].key
== key
) {
448 if (-1 == slot
&& NULL
!= key
) {
449 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
450 if (CFEqual(__CFLocaleKeyTable
[idx
].key
, key
)) {
460 if (NULL
!= locale
->_overrides
&& CFDictionaryGetValueIfPresent(locale
->_overrides
, __CFLocaleKeyTable
[slot
].key
, &value
)) {
463 __CFLocaleLock(locale
);
464 if (CFDictionaryGetValueIfPresent(locale
->_cache
, __CFLocaleKeyTable
[slot
].key
, &value
)) {
465 __CFLocaleUnlock(locale
);
468 if (__kCFLocaleUser
== __CFLocaleGetType(locale
) && __CFLocaleKeyTable
[slot
].get(locale
, true, &value
, __CFLocaleKeyTable
[slot
].context
)) {
469 if (value
) CFDictionarySetValue(locale
->_cache
, __CFLocaleKeyTable
[idx
].key
, value
);
470 if (value
) CFRelease(value
);
471 __CFLocaleUnlock(locale
);
474 if (__CFLocaleKeyTable
[slot
].get(locale
, false, &value
, __CFLocaleKeyTable
[slot
].context
)) {
475 if (value
) CFDictionarySetValue(locale
->_cache
, __CFLocaleKeyTable
[idx
].key
, value
);
476 if (value
) CFRelease(value
);
477 __CFLocaleUnlock(locale
);
480 __CFLocaleUnlock(locale
);
484 CFStringRef
CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale
, CFStringRef key
, CFStringRef value
) {
485 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFStringRef
, (NSLocale
*)displayLocale
, _copyDisplayNameForKey
:(id
)key value
:(id
)value
);
486 CFIndex idx
, slot
= -1;
487 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
488 if (__CFLocaleKeyTable
[idx
].key
== key
) {
493 if (-1 == slot
&& NULL
!= key
) {
494 for (idx
= 0; idx
< __kCFLocaleKeyTableCount
; idx
++) {
495 if (CFEqual(__CFLocaleKeyTable
[idx
].key
, key
)) {
501 if (-1 == slot
|| !value
) {
504 // Get the locale ID as a C string
505 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
506 char cValue
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
507 if (CFStringGetCString(displayLocale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(localeID
[0]), kCFStringEncodingASCII
) && CFStringGetCString(value
, cValue
, sizeof(cValue
)/sizeof(char), kCFStringEncodingASCII
)) {
509 if ((NULL
== displayLocale
->_prefs
) && __CFLocaleKeyTable
[slot
].name(localeID
, cValue
, &result
)) {
513 // We could not find a result using the requested language. Fall back through all preferred languages.
514 CFArrayRef langPref
= NULL
;
515 if (displayLocale
->_prefs
) {
516 langPref
= (CFArrayRef
)CFDictionaryGetValue(displayLocale
->_prefs
, CFSTR("AppleLanguages"));
517 if (langPref
) CFRetain(langPref
);
519 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
520 langPref
= (CFArrayRef
)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication
);
523 if (langPref
!= NULL
) {
524 CFIndex count
= CFArrayGetCount(langPref
);
526 bool success
= false;
527 for (i
= 0; i
< count
&& !success
; ++i
) {
528 CFStringRef language
= (CFStringRef
)CFArrayGetValueAtIndex(langPref
, i
);
529 CFStringRef cleanLanguage
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, language
);
530 if (CFStringGetCString(cleanLanguage
, localeID
, sizeof(localeID
)/sizeof(localeID
[0]), kCFStringEncodingASCII
)) {
531 success
= __CFLocaleKeyTable
[slot
].name(localeID
, cValue
, &result
);
533 CFRelease(cleanLanguage
);
543 CFArrayRef
CFLocaleCopyAvailableLocaleIdentifiers(void) {
544 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
545 int32_t locale
, localeCount
= uloc_countAvailable();
546 CFMutableSetRef working
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeSetCallBacks
);
547 for (locale
= 0; locale
< localeCount
; ++locale
) {
548 const char *localeID
= uloc_getAvailable(locale
);
549 CFStringRef string1
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, localeID
, kCFStringEncodingASCII
);
550 // do not include canonicalized version as IntlFormats cannot cope with that in its popup
551 CFSetAddValue(working
, string1
);
554 CFIndex cnt
= CFSetGetCount(working
);
555 STACK_BUFFER_DECL(const void *, buffer
, cnt
);
556 CFSetGetValues(working
, buffer
);
557 CFArrayRef result
= CFArrayCreate(kCFAllocatorSystemDefault
, buffer
, cnt
, &kCFTypeArrayCallBacks
);
561 return CFArrayCreate(kCFAllocatorSystemDefault
, NULL
, 0, &kCFTypeArrayCallBacks
);
565 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
566 static CFArrayRef
__CFLocaleCopyCStringsAsArray(const char* const* p
) {
567 CFMutableArrayRef working
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
569 CFStringRef string
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, *p
, kCFStringEncodingASCII
);
570 CFArrayAppendValue(working
, string
);
573 CFArrayRef result
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, working
);
578 static CFArrayRef
__CFLocaleCopyUEnumerationAsArray(UEnumeration
*enumer
, UErrorCode
*icuErr
) {
579 const UChar
*next
= NULL
;
581 CFMutableArrayRef working
= NULL
;
582 if (U_SUCCESS(*icuErr
)) {
583 working
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
585 while ((next
= uenum_unext(enumer
, &len
, icuErr
)) && U_SUCCESS(*icuErr
)) {
586 CFStringRef string
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)next
, (CFIndex
) len
);
587 CFArrayAppendValue(working
, string
);
590 if (*icuErr
== U_INDEX_OUTOFBOUNDS_ERROR
) {
591 *icuErr
= U_ZERO_ERROR
; // Temp: Work around bug (ICU 5220) in ucurr enumerator
593 CFArrayRef result
= NULL
;
594 if (U_SUCCESS(*icuErr
)) {
595 result
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, working
);
597 if (working
!= NULL
) {
604 CFArrayRef
CFLocaleCopyISOLanguageCodes(void) {
605 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
606 const char* const* p
= uloc_getISOLanguages();
607 return __CFLocaleCopyCStringsAsArray(p
);
609 return CFArrayCreate(kCFAllocatorSystemDefault
, NULL
, 0, &kCFTypeArrayCallBacks
);
613 CFArrayRef
CFLocaleCopyISOCountryCodes(void) {
614 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
615 const char* const* p
= uloc_getISOCountries();
616 return __CFLocaleCopyCStringsAsArray(p
);
618 return CFArrayCreate(kCFAllocatorSystemDefault
, NULL
, 0, &kCFTypeArrayCallBacks
);
622 CFArrayRef
CFLocaleCopyISOCurrencyCodes(void) {
623 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
624 UErrorCode icuStatus
= U_ZERO_ERROR
;
625 UEnumeration
*enumer
= ucurr_openISOCurrencies(UCURR_ALL
, &icuStatus
);
626 CFArrayRef result
= __CFLocaleCopyUEnumerationAsArray(enumer
, &icuStatus
);
629 CFArrayRef result
= CFArrayCreate(kCFAllocatorSystemDefault
, NULL
, 0, &kCFTypeArrayCallBacks
);
634 CFArrayRef
CFLocaleCopyCommonISOCurrencyCodes(void) {
635 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
636 UErrorCode icuStatus
= U_ZERO_ERROR
;
637 UEnumeration
*enumer
= ucurr_openISOCurrencies(UCURR_COMMON
|UCURR_NON_DEPRECATED
, &icuStatus
);
638 CFArrayRef result
= __CFLocaleCopyUEnumerationAsArray(enumer
, &icuStatus
);
641 CFArrayRef result
= CFArrayCreate(kCFAllocatorSystemDefault
, NULL
, 0, &kCFTypeArrayCallBacks
);
646 CFStringRef
CFLocaleCreateLocaleIdentifierFromWindowsLocaleCode(CFAllocatorRef allocator
, uint32_t lcid
) {
647 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
648 char buffer
[kMaxICUNameSize
];
649 UErrorCode status
= U_ZERO_ERROR
;
650 int32_t ret
= uloc_getLocaleForLCID(lcid
, buffer
, kMaxICUNameSize
, &status
);
651 if (U_FAILURE(status
) || kMaxICUNameSize
<= ret
) return NULL
;
652 CFStringRef str
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, buffer
, kCFStringEncodingASCII
);
653 CFStringRef ident
= CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault
, str
);
661 uint32_t CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier(CFStringRef localeIdentifier
) {
662 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
663 CFStringRef ident
= CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault
, localeIdentifier
);
664 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
665 Boolean b
= ident
? CFStringGetCString(ident
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
) : false;
666 if (ident
) CFRelease(ident
);
667 return b
? uloc_getLCID(localeID
) : 0;
673 CFLocaleLanguageDirection
CFLocaleGetLanguageCharacterDirection(CFStringRef isoLangCode
) {
674 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
675 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
676 Boolean b
= isoLangCode
? CFStringGetCString(isoLangCode
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
) : false;
677 CFLocaleLanguageDirection dir
;
678 UErrorCode status
= U_ZERO_ERROR
;
679 ULayoutType idir
= b
? uloc_getCharacterOrientation(localeID
, &status
) : ULOC_LAYOUT_UNKNOWN
;
681 case ULOC_LAYOUT_LTR
: dir
= kCFLocaleLanguageDirectionLeftToRight
; break;
682 case ULOC_LAYOUT_RTL
: dir
= kCFLocaleLanguageDirectionRightToLeft
; break;
683 case ULOC_LAYOUT_TTB
: dir
= kCFLocaleLanguageDirectionTopToBottom
; break;
684 case ULOC_LAYOUT_BTT
: dir
= kCFLocaleLanguageDirectionBottomToTop
; break;
685 default: dir
= kCFLocaleLanguageDirectionUnknown
; break;
689 return kCFLocaleLanguageDirectionLeftToRight
;
693 CFLocaleLanguageDirection
CFLocaleGetLanguageLineDirection(CFStringRef isoLangCode
) {
694 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
695 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
696 Boolean b
= isoLangCode
? CFStringGetCString(isoLangCode
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
) : false;
697 CFLocaleLanguageDirection dir
;
698 UErrorCode status
= U_ZERO_ERROR
;
699 ULayoutType idir
= b
? uloc_getLineOrientation(localeID
, &status
) : ULOC_LAYOUT_UNKNOWN
;
701 case ULOC_LAYOUT_LTR
: dir
= kCFLocaleLanguageDirectionLeftToRight
; break;
702 case ULOC_LAYOUT_RTL
: dir
= kCFLocaleLanguageDirectionRightToLeft
; break;
703 case ULOC_LAYOUT_TTB
: dir
= kCFLocaleLanguageDirectionTopToBottom
; break;
704 case ULOC_LAYOUT_BTT
: dir
= kCFLocaleLanguageDirectionBottomToTop
; break;
705 default: dir
= kCFLocaleLanguageDirectionUnknown
; break;
709 return kCFLocaleLanguageDirectionLeftToRight
;
713 CFArrayRef
CFLocaleCopyPreferredLanguages(void) {
714 CFMutableArrayRef newArray
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
715 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
716 CFArrayRef languagesArray
= (CFArrayRef
)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication
);
717 if (languagesArray
&& (CFArrayGetTypeID() == CFGetTypeID(languagesArray
))) {
718 for (CFIndex idx
= 0, cnt
= CFArrayGetCount(languagesArray
); idx
< cnt
; idx
++) {
719 CFStringRef str
= (CFStringRef
)CFArrayGetValueAtIndex(languagesArray
, idx
);
720 if (str
&& (CFStringGetTypeID() == CFGetTypeID(str
))) {
721 CFStringRef ident
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, str
);
722 CFArrayAppendValue(newArray
, ident
);
727 if (languagesArray
) CFRelease(languagesArray
);
732 // -------- -------- -------- -------- -------- --------
734 // These functions return true or false depending on the success or failure of the function.
735 // In the Copy case, this is failure to fill the *cf out parameter, and that out parameter is
736 // returned by reference WITH a retain on it.
737 static bool __CFLocaleSetNOP(CFMutableLocaleRef locale
, CFTypeRef cf
, CFStringRef context
) {
741 static bool __CFLocaleCopyLocaleID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
742 *cf
= CFRetain(locale
->_identifier
);
747 static bool __CFLocaleCopyCodes(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
748 CFDictionaryRef codes
= NULL
;
749 // this access of _cache is protected by the lock in CFLocaleGetValue()
750 if (!CFDictionaryGetValueIfPresent(locale
->_cache
, CFSTR("__kCFLocaleCodes"), (const void **)&codes
)) {
751 codes
= CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault
, locale
->_identifier
);
752 if (codes
) CFDictionarySetValue(locale
->_cache
, CFSTR("__kCFLocaleCodes"), codes
);
753 if (codes
) CFRelease(codes
);
756 CFStringRef value
= (CFStringRef
)CFDictionaryGetValue(codes
, context
); // context is one of kCFLocale*Code constants
757 if (value
) CFRetain(value
);
764 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
765 CFCharacterSetRef
_CFCreateCharacterSetFromUSet(USet
*set
) {
766 UErrorCode icuErr
= U_ZERO_ERROR
;
767 CFMutableCharacterSetRef working
= CFCharacterSetCreateMutable(NULL
);
768 UChar buffer
[2048]; // Suitable for most small sets
774 int32_t itemCount
= uset_getItemCount(set
);
776 for (i
= 0; i
< itemCount
; ++i
)
782 stringLen
= uset_getItem(set
, i
, &start
, &end
, buffer
, sizeof(buffer
)/sizeof(UChar
), &icuErr
);
783 if (icuErr
== U_BUFFER_OVERFLOW_ERROR
)
785 string
= (UChar
*) malloc(sizeof(UChar
)*(stringLen
+1));
791 icuErr
= U_ZERO_ERROR
;
792 (void) uset_getItem(set
, i
, &start
, &end
, string
, stringLen
+1, &icuErr
);
794 if (U_FAILURE(icuErr
))
796 if (string
!= buffer
)
802 CFCharacterSetAddCharactersInRange(working
, CFRangeMake(start
, end
-start
+1));
805 CFStringRef cfString
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, (UniChar
*)string
, stringLen
, kCFAllocatorNull
);
806 CFCharacterSetAddCharactersInString(working
, cfString
);
809 if (string
!= buffer
)
813 CFCharacterSetRef result
= CFCharacterSetCreateCopy(kCFAllocatorSystemDefault
, working
);
819 static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
820 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
821 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
822 if (CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
)) {
823 UErrorCode icuStatus
= U_ZERO_ERROR
;
824 ULocaleData
* uld
= ulocdata_open(localeID
, &icuStatus
);
825 USet
*set
= ulocdata_getExemplarSet(uld
, NULL
, USET_ADD_CASE_MAPPINGS
, ULOCDATA_ES_STANDARD
, &icuStatus
);
827 if (U_FAILURE(icuStatus
))
829 if (icuStatus
== U_USING_DEFAULT_WARNING
) // If default locale used, force to empty set
831 *cf
= (CFTypeRef
) _CFCreateCharacterSetFromUSet(set
);
833 return (*cf
!= NULL
);
839 static bool __CFLocaleCopyICUKeyword(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
, const char *keyword
)
841 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
842 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
843 if (CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
))
845 char value
[ULOC_KEYWORD_AND_VALUES_CAPACITY
];
846 UErrorCode icuStatus
= U_ZERO_ERROR
;
847 if (uloc_getKeywordValue(localeID
, keyword
, value
, sizeof(value
)/sizeof(char), &icuStatus
) > 0 && U_SUCCESS(icuStatus
))
849 *cf
= (CFTypeRef
) CFStringCreateWithCString(kCFAllocatorSystemDefault
, value
, kCFStringEncodingASCII
);
858 static bool __CFLocaleCopyICUCalendarID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
, const char *keyword
) {
859 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
860 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
861 if (CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
)) {
862 UErrorCode icuStatus
= U_ZERO_ERROR
;
863 UEnumeration
*en
= ucal_getKeywordValuesForLocale(keyword
, localeID
, TRUE
, &icuStatus
);
865 const char *value
= uenum_next(en
, &len
, &icuStatus
);
866 if (U_SUCCESS(icuStatus
)) {
867 *cf
= (CFTypeRef
) CFStringCreateWithCString(kCFAllocatorSystemDefault
, value
, kCFStringEncodingASCII
);
878 static bool __CFLocaleCopyCalendarID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
879 bool succeeded
= __CFLocaleCopyICUKeyword(locale
, user
, cf
, context
, kCalendarKeyword
);
881 succeeded
= __CFLocaleCopyICUCalendarID(locale
, user
, cf
, context
, kCalendarKeyword
);
884 if (CFEqual(*cf
, kCFCalendarIdentifierGregorian
)) {
886 *cf
= CFRetain(kCFCalendarIdentifierGregorian
);
887 } else if (CFEqual(*cf
, kCFCalendarIdentifierBuddhist
)) {
889 *cf
= CFRetain(kCFCalendarIdentifierBuddhist
);
890 } else if (CFEqual(*cf
, kCFCalendarIdentifierJapanese
)) {
892 *cf
= CFRetain(kCFCalendarIdentifierJapanese
);
893 } else if (CFEqual(*cf
, kCFCalendarIdentifierIslamic
)) {
895 *cf
= CFRetain(kCFCalendarIdentifierIslamic
);
896 } else if (CFEqual(*cf
, kCFCalendarIdentifierIslamicCivil
)) {
898 *cf
= CFRetain(kCFCalendarIdentifierIslamicCivil
);
899 } else if (CFEqual(*cf
, kCFCalendarIdentifierHebrew
)) {
901 *cf
= CFRetain(kCFCalendarIdentifierHebrew
);
902 } else if (CFEqual(*cf
, kCFCalendarIdentifierChinese
)) {
904 *cf
= CFRetain(kCFCalendarIdentifierChinese
);
905 } else if (CFEqual(*cf
, kCFCalendarIdentifierRepublicOfChina
)) {
907 *cf
= CFRetain(kCFCalendarIdentifierRepublicOfChina
);
908 } else if (CFEqual(*cf
, kCFCalendarIdentifierPersian
)) {
910 *cf
= CFRetain(kCFCalendarIdentifierPersian
);
911 } else if (CFEqual(*cf
, kCFCalendarIdentifierIndian
)) {
913 *cf
= CFRetain(kCFCalendarIdentifierIndian
);
914 } else if (CFEqual(*cf
, kCFCalendarIdentifierISO8601
)) {
916 *cf
= CFRetain(kCFCalendarIdentifierISO8601
);
917 } else if (CFEqual(*cf
, kCFCalendarIdentifierCoptic
)) {
919 *cf
= CFRetain(kCFCalendarIdentifierCoptic
);
920 } else if (CFEqual(*cf
, kCFCalendarIdentifierEthiopicAmeteMihret
)) {
922 *cf
= CFRetain(kCFCalendarIdentifierEthiopicAmeteMihret
);
923 } else if (CFEqual(*cf
, kCFCalendarIdentifierEthiopicAmeteAlem
)) {
925 *cf
= CFRetain(kCFCalendarIdentifierEthiopicAmeteAlem
);
932 *cf
= CFRetain(kCFCalendarIdentifierGregorian
);
937 static bool __CFLocaleCopyCalendar(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
938 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
939 if (__CFLocaleCopyCalendarID(locale
, user
, cf
, context
)) {
940 CFCalendarRef calendar
= CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault
, (CFStringRef
)*cf
);
941 CFCalendarSetLocale(calendar
, locale
);
942 CFDictionaryRef prefs
= __CFLocaleGetPrefs(locale
);
943 CFPropertyListRef metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleFirstWeekday")) : NULL
;
944 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
945 metapref
= (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, *cf
);
947 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFNumberGetTypeID()) {
949 if (CFNumberGetValue((CFNumberRef
)metapref
, kCFNumberCFIndexType
, &wkdy
)) {
950 CFCalendarSetFirstWeekday(calendar
, wkdy
);
953 metapref
= prefs
? CFDictionaryGetValue(prefs
, CFSTR("AppleMinDaysInFirstWeek")) : NULL
;
954 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFDictionaryGetTypeID()) {
955 metapref
= (CFNumberRef
)CFDictionaryGetValue((CFDictionaryRef
)metapref
, *cf
);
957 if (NULL
!= metapref
&& CFGetTypeID(metapref
) == CFNumberGetTypeID()) {
959 if (CFNumberGetValue((CFNumberRef
)metapref
, kCFNumberCFIndexType
, &mwd
)) {
960 CFCalendarSetMinimumDaysInFirstWeek(calendar
, mwd
);
971 static bool __CFLocaleCopyDelimiter(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
972 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
973 ULocaleDataDelimiterType type
= (ULocaleDataDelimiterType
)0;
974 if (context
== kCFLocaleQuotationBeginDelimiterKey
) {
975 type
= ULOCDATA_QUOTATION_START
;
976 } else if (context
== kCFLocaleQuotationEndDelimiterKey
) {
977 type
= ULOCDATA_QUOTATION_END
;
978 } else if (context
== kCFLocaleAlternateQuotationBeginDelimiterKey
) {
979 type
= ULOCDATA_ALT_QUOTATION_START
;
980 } else if (context
== kCFLocaleAlternateQuotationEndDelimiterKey
) {
981 type
= ULOCDATA_ALT_QUOTATION_END
;
986 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
987 if (!CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
)) {
992 UErrorCode status
= U_ZERO_ERROR
;
993 ULocaleData
*uld
= ulocdata_open(localeID
, &status
);
994 int32_t len
= ulocdata_getDelimiter(uld
, type
, buffer
, sizeof(buffer
) / sizeof(buffer
[0]), &status
);
996 if (U_FAILURE(status
) || sizeof(buffer
) / sizeof(buffer
[0]) < len
) {
1000 *cf
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)buffer
, len
);
1001 return (*cf
!= NULL
);
1003 if (context
== kCFLocaleQuotationBeginDelimiterKey
|| context
== kCFLocaleQuotationEndDelimiterKey
|| context
== kCFLocaleAlternateQuotationBeginDelimiterKey
|| context
== kCFLocaleAlternateQuotationEndDelimiterKey
) {
1004 *cf
= CFRetain(CFSTR("\""));
1012 static bool __CFLocaleCopyCollationID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
1013 return __CFLocaleCopyICUKeyword(locale
, user
, cf
, context
, kCollationKeyword
);
1016 static bool __CFLocaleCopyCollatorID(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
1017 CFStringRef canonLocaleCFStr
= NULL
;
1018 if (user
&& locale
->_prefs
) {
1019 CFStringRef pref
= (CFStringRef
)CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleCollationOrder"));
1021 // Canonicalize pref string in case it's not in the canonical format.
1022 canonLocaleCFStr
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, pref
);
1024 CFArrayRef languagesArray
= (CFArrayRef
)CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleLanguages"));
1025 if (languagesArray
&& (CFArrayGetTypeID() == CFGetTypeID(languagesArray
))) {
1026 if (0 < CFArrayGetCount(languagesArray
)) {
1027 CFStringRef str
= (CFStringRef
)CFArrayGetValueAtIndex(languagesArray
, 0);
1028 if (str
&& (CFStringGetTypeID() == CFGetTypeID(str
))) {
1029 canonLocaleCFStr
= CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault
, str
);
1035 if (!canonLocaleCFStr
) {
1036 canonLocaleCFStr
= CFLocaleGetIdentifier(locale
);
1037 CFRetain(canonLocaleCFStr
);
1039 *cf
= canonLocaleCFStr
;
1040 return canonLocaleCFStr
? true : false;
1043 static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
1044 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1045 bool us
= false; // Default is Metric
1047 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1049 CFTypeRef pref
= CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleMetricUnits"));
1051 us
= (kCFBooleanFalse
== pref
);
1054 pref
= CFDictionaryGetValue(locale
->_prefs
, CFSTR("AppleMeasurementUnits"));
1056 us
= CFEqual(pref
, CFSTR("Inches"));
1063 char localeID
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
1064 if (CFStringGetCString(locale
->_identifier
, localeID
, sizeof(localeID
)/sizeof(char), kCFStringEncodingASCII
)) {
1065 UErrorCode icuStatus
= U_ZERO_ERROR
;
1066 UMeasurementSystem ms
= UMS_SI
;
1067 ms
= ulocdata_getMeasurementSystem(localeID
, &icuStatus
);
1068 if (U_SUCCESS(icuStatus
)) {
1069 us
= (ms
== UMS_US
);
1076 *cf
= us
? CFRetain(kCFBooleanFalse
) : CFRetain(kCFBooleanTrue
);
1079 *cf
= CFRetain(kCFBooleanFalse
);
1084 static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
1085 if (__CFLocaleCopyUsesMetric(locale
, user
, cf
, context
)) {
1086 bool us
= (*cf
== kCFBooleanFalse
);
1088 *cf
= us
? CFRetain(CFSTR("U.S.")) : CFRetain(CFSTR("Metric"));
1094 static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
1095 CFStringRef str
= NULL
;
1096 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1097 CFNumberFormatterRef nf
= CFNumberFormatterCreate(kCFAllocatorSystemDefault
, locale
, kCFNumberFormatterDecimalStyle
);
1098 str
= nf
? (CFStringRef
)CFNumberFormatterCopyProperty(nf
, context
) : NULL
;
1099 if (nf
) CFRelease(nf
);
1108 // ICU does not reliably set up currency info for other than Currency-type formatters,
1109 // so we have to have another routine here which creates a Currency number formatter.
1110 static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale
, bool user
, CFTypeRef
*cf
, CFStringRef context
) {
1111 CFStringRef str
= NULL
;
1112 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1113 CFNumberFormatterRef nf
= CFNumberFormatterCreate(kCFAllocatorSystemDefault
, locale
, kCFNumberFormatterCurrencyStyle
);
1114 str
= nf
? (CFStringRef
)CFNumberFormatterCopyProperty(nf
, context
) : NULL
;
1115 if (nf
) CFRelease(nf
);
1124 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1125 typedef int32_t (*__CFICUFunction
)(const char *, const char *, UChar
*, int32_t, UErrorCode
*);
1127 static bool __CFLocaleICUName(const char *locale
, const char *valLocale
, CFStringRef
*out
, __CFICUFunction icu
) {
1128 UErrorCode icuStatus
= U_ZERO_ERROR
;
1130 UChar name
[kMaxICUNameSize
];
1132 size
= (*icu
)(valLocale
, locale
, name
, kMaxICUNameSize
, &icuStatus
);
1133 if (U_SUCCESS(icuStatus
) && size
> 0 && icuStatus
!= U_USING_DEFAULT_WARNING
) {
1134 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1135 return (*out
!= NULL
);
1140 static bool __CFLocaleICUKeywordValueName(const char *locale
, const char *value
, const char *keyword
, CFStringRef
*out
) {
1141 UErrorCode icuStatus
= U_ZERO_ERROR
;
1143 UChar name
[kMaxICUNameSize
];
1144 // Need to make a fake locale ID
1145 char lid
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
1146 if (strlen(value
) < ULOC_KEYWORD_AND_VALUES_CAPACITY
) {
1147 strlcpy(lid
, "en_US@", sizeof(lid
));
1148 strlcat(lid
, keyword
, sizeof(lid
));
1149 strlcat(lid
, "=", sizeof(lid
));
1150 strlcat(lid
, value
, sizeof(lid
));
1151 size
= uloc_getDisplayKeywordValue(lid
, keyword
, locale
, name
, kMaxICUNameSize
, &icuStatus
);
1152 if (U_SUCCESS(icuStatus
) && size
> 0 && icuStatus
!= U_USING_DEFAULT_WARNING
) {
1153 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1154 return (*out
!= NULL
);
1160 static bool __CFLocaleICUCurrencyName(const char *locale
, const char *value
, UCurrNameStyle style
, CFStringRef
*out
) {
1161 int valLen
= strlen(value
);
1162 if (valLen
!= 3) // not a valid ISO code
1165 UBool isChoice
= FALSE
;
1167 UErrorCode icuStatus
= U_ZERO_ERROR
;
1168 u_charsToUChars(value
, curr
, valLen
);
1169 curr
[valLen
] = '\0';
1171 name
= ucurr_getName(curr
, locale
, style
, &isChoice
, &size
, &icuStatus
);
1172 if (U_FAILURE(icuStatus
) || icuStatus
== U_USING_DEFAULT_WARNING
)
1174 UChar result
[kMaxICUNameSize
];
1177 UChar pattern
[kMaxICUNameSize
];
1178 CFStringRef patternRef
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("{0,choice,%S}"), name
);
1179 CFIndex pattlen
= CFStringGetLength(patternRef
);
1180 CFStringGetCharacters(patternRef
, CFRangeMake(0, pattlen
), (UniChar
*)pattern
);
1181 CFRelease(patternRef
);
1182 pattern
[pattlen
] = '\0'; // null terminate the pattern
1183 // Format the message assuming a large amount of the currency
1184 size
= u_formatMessage("en_US", pattern
, pattlen
, result
, kMaxICUNameSize
, &icuStatus
, 10.0);
1185 if (U_FAILURE(icuStatus
))
1190 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1191 return (*out
!= NULL
);
1195 static bool __CFLocaleFullName(const char *locale
, const char *value
, CFStringRef
*out
) {
1196 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1197 UErrorCode icuStatus
= U_ZERO_ERROR
;
1199 UChar name
[kMaxICUNameSize
];
1201 // First, try to get the full locale.
1202 size
= uloc_getDisplayName(value
, locale
, name
, kMaxICUNameSize
, &icuStatus
);
1203 if (U_FAILURE(icuStatus
) || size
<= 0)
1206 // Did we wind up using a default somewhere?
1207 if (icuStatus
== U_USING_DEFAULT_WARNING
) {
1208 // For some locale IDs, there may be no language which has a translation for every
1209 // piece. Rather than return nothing, see if we can at least handle
1210 // the language part of the locale.
1211 UErrorCode localStatus
= U_ZERO_ERROR
;
1213 UChar localName
[kMaxICUNameSize
];
1214 localSize
= uloc_getDisplayLanguage(value
, locale
, localName
, kMaxICUNameSize
, &localStatus
);
1215 if (U_FAILURE(localStatus
) || size
<= 0 || localStatus
== U_USING_DEFAULT_WARNING
)
1219 // This locale is OK, so use the result.
1220 *out
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)name
, size
);
1221 return (*out
!= NULL
);
1223 *out
= CFRetain(CFSTR("(none)"));
1228 static bool __CFLocaleLanguageName(const char *locale
, const char *value
, CFStringRef
*out
) {
1229 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1230 return __CFLocaleICUName(locale
, value
, out
, uloc_getDisplayLanguage
);
1232 *out
= CFRetain(CFSTR("(none)"));
1237 static bool __CFLocaleCountryName(const char *locale
, const char *value
, CFStringRef
*out
) {
1238 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1239 // Need to make a fake locale ID
1240 char lid
[ULOC_FULLNAME_CAPACITY
];
1241 if (strlen(value
) < sizeof(lid
) - 3) {
1242 strlcpy(lid
, "en_", sizeof(lid
));
1243 strlcat(lid
, value
, sizeof(lid
));
1244 return __CFLocaleICUName(locale
, lid
, out
, uloc_getDisplayCountry
);
1248 *out
= CFRetain(CFSTR("(none)"));
1253 static bool __CFLocaleScriptName(const char *locale
, const char *value
, CFStringRef
*out
) {
1254 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1255 // Need to make a fake locale ID
1256 char lid
[ULOC_FULLNAME_CAPACITY
];
1257 if (strlen(value
) == 4) {
1258 strlcpy(lid
, "en_", sizeof(lid
));
1259 strlcat(lid
, value
, sizeof(lid
));
1260 strlcat(lid
, "_US", sizeof(lid
));
1261 return __CFLocaleICUName(locale
, lid
, out
, uloc_getDisplayScript
);
1265 *out
= CFRetain(CFSTR("(none)"));
1270 static bool __CFLocaleVariantName(const char *locale
, const char *value
, CFStringRef
*out
) {
1271 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1272 // Need to make a fake locale ID
1273 char lid
[ULOC_FULLNAME_CAPACITY
+ULOC_KEYWORD_AND_VALUES_CAPACITY
];
1274 if (strlen(value
) < sizeof(lid
) - 6) {
1275 strlcpy(lid
, "en_US_", sizeof(lid
));
1276 strlcat(lid
, value
, sizeof(lid
));
1277 return __CFLocaleICUName(locale
, lid
, out
, uloc_getDisplayVariant
);
1281 *out
= CFRetain(CFSTR("(none)"));
1286 static bool __CFLocaleCalendarName(const char *locale
, const char *value
, CFStringRef
*out
) {
1287 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1288 return __CFLocaleICUKeywordValueName(locale
, value
, kCalendarKeyword
, out
);
1290 *out
= CFRetain(CFSTR("(none)"));
1295 static bool __CFLocaleCollationName(const char *locale
, const char *value
, CFStringRef
*out
) {
1296 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1297 return __CFLocaleICUKeywordValueName(locale
, value
, kCollationKeyword
, out
);
1299 *out
= CFRetain(CFSTR("(none)"));
1304 static bool __CFLocaleCurrencyShortName(const char *locale
, const char *value
, CFStringRef
*out
) {
1305 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1306 return __CFLocaleICUCurrencyName(locale
, value
, UCURR_SYMBOL_NAME
, out
);
1308 *out
= CFRetain(CFSTR("(none)"));
1313 static bool __CFLocaleCurrencyFullName(const char *locale
, const char *value
, CFStringRef
*out
) {
1314 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1315 return __CFLocaleICUCurrencyName(locale
, value
, UCURR_LONG_NAME
, out
);
1317 *out
= CFRetain(CFSTR("(none)"));
1322 static bool __CFLocaleNoName(const char *locale
, const char *value
, CFStringRef
*out
) {
1326 #undef kMaxICUNameSize