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