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