]> git.saurik.com Git - apple/cf.git/blob - CFLocale.c
CF-744.12.tar.gz
[apple/cf.git] / CFLocale.c
1 /*
2 * Copyright (c) 2012 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-2012, 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 __private_extern__ Boolean __CFLocaleGetNullLocale(struct __CFLocale *locale) {
158 return locale->_nullLocale;
159 }
160
161 __private_extern__ 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 CFLocaleRef CFLocaleCopyCurrent(void) {
303
304 CFStringRef name = NULL, ident = NULL;
305 // We cannot be helpful here, because it causes performance problems,
306 // even though the preference lookup is relatively quick, as there are
307 // things which call this function thousands or millions of times in
308 // a short period.
309 #if 0 // DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
310 name = (CFStringRef)CFPreferencesCopyAppValue(CFSTR("AppleLocale"), kCFPreferencesCurrentApplication);
311 #endif
312 if (name && (CFStringGetTypeID() == CFGetTypeID(name))) {
313 ident = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, name);
314 }
315 if (name) CFRelease(name);
316 CFLocaleRef oldLocale = NULL;
317 __CFLocaleLockGlobal();
318 if (__CFLocaleCurrent) {
319 if (ident && !CFEqual(__CFLocaleCurrent->_identifier, ident)) {
320 oldLocale = __CFLocaleCurrent;
321 __CFLocaleCurrent = NULL;
322 } else {
323 CFLocaleRef res = __CFLocaleCurrent;
324 CFRetain(res);
325 __CFLocaleUnlockGlobal();
326 if (ident) CFRelease(ident);
327 return res;
328 }
329 }
330 __CFLocaleUnlockGlobal();
331 if (oldLocale) CFRelease(oldLocale);
332 if (ident) CFRelease(ident);
333 // We could *probably* re-use ident down below, but that would't
334 // get us out of querying CFPrefs for the current application state.
335
336 CFDictionaryRef prefs = NULL;
337 CFStringRef identifier = NULL;
338
339 struct __CFLocale *locale;
340 uint32_t size = sizeof(struct __CFLocale) - sizeof(CFRuntimeBase);
341 locale = (struct __CFLocale *)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, CFLocaleGetTypeID(), size, NULL);
342 if (NULL == locale) {
343 if (prefs) CFRelease(prefs);
344 if (identifier) CFRelease(identifier);
345 return NULL;
346 }
347 __CFLocaleSetType(locale, __kCFLocaleUser);
348 if (NULL == identifier) identifier = (CFStringRef)CFRetain(FALLBACK_LOCALE_NAME);
349 locale->_identifier = identifier;
350 locale->_cache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
351 locale->_overrides = NULL;
352 locale->_prefs = prefs;
353 locale->_lock = CFSpinLockInit;
354 locale->_nullLocale = false;
355
356 __CFLocaleLockGlobal();
357 if (NULL == __CFLocaleCurrent) {
358 __CFLocaleCurrent = locale;
359 } else {
360 CFRelease(locale);
361 }
362 locale = (struct __CFLocale *)CFRetain(__CFLocaleCurrent);
363 __CFLocaleUnlockGlobal();
364 return locale;
365 }
366
367 __private_extern__ CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale) {
368 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFDictionaryRef, (NSLocale *)locale, _prefs);
369 return locale->_prefs;
370 }
371
372 CFLocaleRef CFLocaleCreate(CFAllocatorRef allocator, CFStringRef identifier) {
373 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
374 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
375 __CFGenericValidateType(identifier, CFStringGetTypeID());
376 CFStringRef localeIdentifier = NULL;
377 if (identifier) {
378 localeIdentifier = CFLocaleCreateCanonicalLocaleIdentifierFromString(allocator, identifier);
379 }
380 if (NULL == localeIdentifier) return NULL;
381 CFStringRef old = localeIdentifier;
382 localeIdentifier = (CFStringRef)CFStringCreateCopy(allocator, localeIdentifier);
383 CFRelease(old);
384 __CFLocaleLockGlobal();
385 // Look for cases where we can return a cached instance.
386 // We only use cached objects if the allocator is the system
387 // default allocator.
388 if (!allocator) allocator = __CFGetDefaultAllocator();
389 Boolean canCache = _CFAllocatorIsSystemDefault(allocator);
390 if (canCache && __CFLocaleCache) {
391 CFLocaleRef locale = (CFLocaleRef)CFDictionaryGetValue(__CFLocaleCache, localeIdentifier);
392 if (locale) {
393 CFRetain(locale);
394 __CFLocaleUnlockGlobal();
395 CFRelease(localeIdentifier);
396 return locale;
397 }
398 }
399 struct __CFLocale *locale = NULL;
400 uint32_t size = sizeof(struct __CFLocale) - sizeof(CFRuntimeBase);
401 locale = (struct __CFLocale *)_CFRuntimeCreateInstance(allocator, CFLocaleGetTypeID(), size, NULL);
402 if (NULL == locale) {
403 return NULL;
404 }
405 __CFLocaleSetType(locale, __kCFLocaleOrdinary);
406 locale->_identifier = localeIdentifier;
407 locale->_cache = CFDictionaryCreateMutable(allocator, 0, NULL, &kCFTypeDictionaryValueCallBacks);
408 locale->_overrides = NULL;
409 locale->_prefs = NULL;
410 locale->_lock = CFSpinLockInit;
411 if (canCache) {
412 if (NULL == __CFLocaleCache) {
413 __CFLocaleCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
414 }
415 CFDictionarySetValue(__CFLocaleCache, localeIdentifier, locale);
416 }
417 __CFLocaleUnlockGlobal();
418 return (CFLocaleRef)locale;
419 }
420
421 CFLocaleRef CFLocaleCreateCopy(CFAllocatorRef allocator, CFLocaleRef locale) {
422 return (CFLocaleRef)CFRetain(locale);
423 }
424
425 CFStringRef CFLocaleGetIdentifier(CFLocaleRef locale) {
426 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFStringRef, (NSLocale *)locale, localeIdentifier);
427 return locale->_identifier;
428 }
429
430 CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key) {
431 #if DEPLOYMENT_TARGET_MACOSX
432 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard)) {
433 // Hack for Opera, which is using the hard-coded string value below instead of
434 // the perfectly good public kCFLocaleCountryCode constant, for whatever reason.
435 if (key && CFEqual(key, CFSTR("locale:country code"))) {
436 key = kCFLocaleCountryCodeKey;
437 }
438 }
439 #endif
440 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFTypeRef, (NSLocale *)locale, objectForKey:(id)key);
441 CFIndex idx, slot = -1;
442 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) {
443 if (__CFLocaleKeyTable[idx].key == key) {
444 slot = idx;
445 break;
446 }
447 }
448 if (-1 == slot && NULL != key) {
449 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) {
450 if (CFEqual(__CFLocaleKeyTable[idx].key, key)) {
451 slot = idx;
452 break;
453 }
454 }
455 }
456 if (-1 == slot) {
457 return NULL;
458 }
459 CFTypeRef value;
460 if (NULL != locale->_overrides && CFDictionaryGetValueIfPresent(locale->_overrides, __CFLocaleKeyTable[slot].key, &value)) {
461 return value;
462 }
463 __CFLocaleLock(locale);
464 if (CFDictionaryGetValueIfPresent(locale->_cache, __CFLocaleKeyTable[slot].key, &value)) {
465 __CFLocaleUnlock(locale);
466 return value;
467 }
468 if (__kCFLocaleUser == __CFLocaleGetType(locale) && __CFLocaleKeyTable[slot].get(locale, true, &value, __CFLocaleKeyTable[slot].context)) {
469 if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value);
470 if (value) CFRelease(value);
471 __CFLocaleUnlock(locale);
472 return value;
473 }
474 if (__CFLocaleKeyTable[slot].get(locale, false, &value, __CFLocaleKeyTable[slot].context)) {
475 if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value);
476 if (value) CFRelease(value);
477 __CFLocaleUnlock(locale);
478 return value;
479 }
480 __CFLocaleUnlock(locale);
481 return NULL;
482 }
483
484 CFStringRef CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale, CFStringRef key, CFStringRef value) {
485 CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFStringRef, (NSLocale *)displayLocale, _copyDisplayNameForKey:(id)key value:(id)value);
486 CFIndex idx, slot = -1;
487 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) {
488 if (__CFLocaleKeyTable[idx].key == key) {
489 slot = idx;
490 break;
491 }
492 }
493 if (-1 == slot && NULL != key) {
494 for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) {
495 if (CFEqual(__CFLocaleKeyTable[idx].key, key)) {
496 slot = idx;
497 break;
498 }
499 }
500 }
501 if (-1 == slot || !value) {
502 return NULL;
503 }
504 // Get the locale ID as a C string
505 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
506 char cValue[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
507 if (CFStringGetCString(displayLocale->_identifier, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII) && CFStringGetCString(value, cValue, sizeof(cValue)/sizeof(char), kCFStringEncodingASCII)) {
508 CFStringRef result;
509 if ((NULL == displayLocale->_prefs) && __CFLocaleKeyTable[slot].name(localeID, cValue, &result)) {
510 return result;
511 }
512
513 // We could not find a result using the requested language. Fall back through all preferred languages.
514 CFArrayRef langPref = NULL;
515 if (displayLocale->_prefs) {
516 langPref = (CFArrayRef)CFDictionaryGetValue(displayLocale->_prefs, CFSTR("AppleLanguages"));
517 if (langPref) CFRetain(langPref);
518 } else {
519 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
520 langPref = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication);
521 #endif
522 }
523 if (langPref != NULL) {
524 CFIndex count = CFArrayGetCount(langPref);
525 CFIndex i;
526 bool success = false;
527 for (i = 0; i < count && !success; ++i) {
528 CFStringRef language = (CFStringRef)CFArrayGetValueAtIndex(langPref, i);
529 CFStringRef cleanLanguage = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, language);
530 if (CFStringGetCString(cleanLanguage, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII)) {
531 success = __CFLocaleKeyTable[slot].name(localeID, cValue, &result);
532 }
533 CFRelease(cleanLanguage);
534 }
535 CFRelease(langPref);
536 if (success)
537 return result;
538 }
539 }
540 return NULL;
541 }
542
543 CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void) {
544 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
545 int32_t locale, localeCount = uloc_countAvailable();
546 CFMutableSetRef working = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
547 for (locale = 0; locale < localeCount; ++locale) {
548 const char *localeID = uloc_getAvailable(locale);
549 CFStringRef string1 = CFStringCreateWithCString(kCFAllocatorSystemDefault, localeID, kCFStringEncodingASCII);
550 // do not include canonicalized version as IntlFormats cannot cope with that in its popup
551 CFSetAddValue(working, string1);
552 CFRelease(string1);
553 }
554 CFIndex cnt = CFSetGetCount(working);
555 STACK_BUFFER_DECL(const void *, buffer, cnt);
556 CFSetGetValues(working, buffer);
557 CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, buffer, cnt, &kCFTypeArrayCallBacks);
558 CFRelease(working);
559 return result;
560 #else
561 return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks);
562 #endif
563 }
564
565 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
566 static CFArrayRef __CFLocaleCopyCStringsAsArray(const char* const* p) {
567 CFMutableArrayRef working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
568 for (; *p; ++p) {
569 CFStringRef string = CFStringCreateWithCString(kCFAllocatorSystemDefault, *p, kCFStringEncodingASCII);
570 CFArrayAppendValue(working, string);
571 CFRelease(string);
572 }
573 CFArrayRef result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working);
574 CFRelease(working);
575 return result;
576 }
577
578 static CFArrayRef __CFLocaleCopyUEnumerationAsArray(UEnumeration *enumer, UErrorCode *icuErr) {
579 const UChar *next = NULL;
580 int32_t len = 0;
581 CFMutableArrayRef working = NULL;
582 if (U_SUCCESS(*icuErr)) {
583 working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
584 }
585 while ((next = uenum_unext(enumer, &len, icuErr)) && U_SUCCESS(*icuErr)) {
586 CFStringRef string = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)next, (CFIndex) len);
587 CFArrayAppendValue(working, string);
588 CFRelease(string);
589 }
590 if (*icuErr == U_INDEX_OUTOFBOUNDS_ERROR) {
591 *icuErr = U_ZERO_ERROR; // Temp: Work around bug (ICU 5220) in ucurr enumerator
592 }
593 CFArrayRef result = NULL;
594 if (U_SUCCESS(*icuErr)) {
595 result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working);
596 }
597 if (working != NULL) {
598 CFRelease(working);
599 }
600 return result;
601 }
602 #endif
603
604 CFArrayRef CFLocaleCopyISOLanguageCodes(void) {
605 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
606 const char* const* p = uloc_getISOLanguages();
607 return __CFLocaleCopyCStringsAsArray(p);
608 #else
609 return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks);
610 #endif
611 }
612
613 CFArrayRef CFLocaleCopyISOCountryCodes(void) {
614 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
615 const char* const* p = uloc_getISOCountries();
616 return __CFLocaleCopyCStringsAsArray(p);
617 #else
618 return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks);
619 #endif
620 }
621
622 CFArrayRef CFLocaleCopyISOCurrencyCodes(void) {
623 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
624 UErrorCode icuStatus = U_ZERO_ERROR;
625 UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_ALL, &icuStatus);
626 CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus);
627 uenum_close(enumer);
628 #else
629 CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks);
630 #endif
631 return result;
632 }
633
634 CFArrayRef CFLocaleCopyCommonISOCurrencyCodes(void) {
635 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
636 UErrorCode icuStatus = U_ZERO_ERROR;
637 UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &icuStatus);
638 CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus);
639 uenum_close(enumer);
640 #else
641 CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks);
642 #endif
643 return result;
644 }
645
646 CFStringRef CFLocaleCreateLocaleIdentifierFromWindowsLocaleCode(CFAllocatorRef allocator, uint32_t lcid) {
647 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
648 char buffer[kMaxICUNameSize];
649 UErrorCode status = U_ZERO_ERROR;
650 int32_t ret = uloc_getLocaleForLCID(lcid, buffer, kMaxICUNameSize, &status);
651 if (U_FAILURE(status) || kMaxICUNameSize <= ret) return NULL;
652 CFStringRef str = CFStringCreateWithCString(kCFAllocatorSystemDefault, buffer, kCFStringEncodingASCII);
653 CFStringRef ident = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, str);
654 CFRelease(str);
655 return ident;
656 #else
657 return CFSTR("");
658 #endif
659 }
660
661 uint32_t CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier(CFStringRef localeIdentifier) {
662 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
663 CFStringRef ident = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, localeIdentifier);
664 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
665 Boolean b = ident ? CFStringGetCString(ident, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false;
666 if (ident) CFRelease(ident);
667 return b ? uloc_getLCID(localeID) : 0;
668 #else
669 return 0;
670 #endif
671 }
672
673 CFLocaleLanguageDirection CFLocaleGetLanguageCharacterDirection(CFStringRef isoLangCode) {
674 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
675 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
676 Boolean b = isoLangCode ? CFStringGetCString(isoLangCode, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false;
677 CFLocaleLanguageDirection dir;
678 UErrorCode status = U_ZERO_ERROR;
679 ULayoutType idir = b ? uloc_getCharacterOrientation(localeID, &status) : ULOC_LAYOUT_UNKNOWN;
680 switch (idir) {
681 case ULOC_LAYOUT_LTR: dir = kCFLocaleLanguageDirectionLeftToRight; break;
682 case ULOC_LAYOUT_RTL: dir = kCFLocaleLanguageDirectionRightToLeft; break;
683 case ULOC_LAYOUT_TTB: dir = kCFLocaleLanguageDirectionTopToBottom; break;
684 case ULOC_LAYOUT_BTT: dir = kCFLocaleLanguageDirectionBottomToTop; break;
685 default: dir = kCFLocaleLanguageDirectionUnknown; break;
686 }
687 return dir;
688 #else
689 return kCFLocaleLanguageDirectionLeftToRight;
690 #endif
691 }
692
693 CFLocaleLanguageDirection CFLocaleGetLanguageLineDirection(CFStringRef isoLangCode) {
694 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
695 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
696 Boolean b = isoLangCode ? CFStringGetCString(isoLangCode, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false;
697 CFLocaleLanguageDirection dir;
698 UErrorCode status = U_ZERO_ERROR;
699 ULayoutType idir = b ? uloc_getLineOrientation(localeID, &status) : ULOC_LAYOUT_UNKNOWN;
700 switch (idir) {
701 case ULOC_LAYOUT_LTR: dir = kCFLocaleLanguageDirectionLeftToRight; break;
702 case ULOC_LAYOUT_RTL: dir = kCFLocaleLanguageDirectionRightToLeft; break;
703 case ULOC_LAYOUT_TTB: dir = kCFLocaleLanguageDirectionTopToBottom; break;
704 case ULOC_LAYOUT_BTT: dir = kCFLocaleLanguageDirectionBottomToTop; break;
705 default: dir = kCFLocaleLanguageDirectionUnknown; break;
706 }
707 return dir;
708 #else
709 return kCFLocaleLanguageDirectionLeftToRight;
710 #endif
711 }
712
713 CFArrayRef CFLocaleCopyPreferredLanguages(void) {
714 CFMutableArrayRef newArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
715 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
716 CFArrayRef languagesArray = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication);
717 if (languagesArray && (CFArrayGetTypeID() == CFGetTypeID(languagesArray))) {
718 for (CFIndex idx = 0, cnt = CFArrayGetCount(languagesArray); idx < cnt; idx++) {
719 CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(languagesArray, idx);
720 if (str && (CFStringGetTypeID() == CFGetTypeID(str))) {
721 CFStringRef ident = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, str);
722 CFArrayAppendValue(newArray, ident);
723 CFRelease(ident);
724 }
725 }
726 }
727 if (languagesArray) CFRelease(languagesArray);
728 #endif
729 return newArray;
730 }
731
732 // -------- -------- -------- -------- -------- --------
733
734 // These functions return true or false depending on the success or failure of the function.
735 // In the Copy case, this is failure to fill the *cf out parameter, and that out parameter is
736 // returned by reference WITH a retain on it.
737 static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context) {
738 return false;
739 }
740
741 static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
742 *cf = CFRetain(locale->_identifier);
743 return true;
744 }
745
746
747 static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
748 CFDictionaryRef codes = NULL;
749 // this access of _cache is protected by the lock in CFLocaleGetValue()
750 if (!CFDictionaryGetValueIfPresent(locale->_cache, CFSTR("__kCFLocaleCodes"), (const void **)&codes)) {
751 codes = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, locale->_identifier);
752 if (codes) CFDictionarySetValue(locale->_cache, CFSTR("__kCFLocaleCodes"), codes);
753 if (codes) CFRelease(codes);
754 }
755 if (codes) {
756 CFStringRef value = (CFStringRef)CFDictionaryGetValue(codes, context); // context is one of kCFLocale*Code constants
757 if (value) CFRetain(value);
758 *cf = value;
759 return true;
760 }
761 return false;
762 }
763
764 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
765 CFCharacterSetRef _CFCreateCharacterSetFromUSet(USet *set) {
766 UErrorCode icuErr = U_ZERO_ERROR;
767 CFMutableCharacterSetRef working = CFCharacterSetCreateMutable(NULL);
768 UChar buffer[2048]; // Suitable for most small sets
769 int32_t stringLen;
770
771 if (working == NULL)
772 return NULL;
773
774 int32_t itemCount = uset_getItemCount(set);
775 int32_t i;
776 for (i = 0; i < itemCount; ++i)
777 {
778 UChar32 start, end;
779 UChar * string;
780
781 string = buffer;
782 stringLen = uset_getItem(set, i, &start, &end, buffer, sizeof(buffer)/sizeof(UChar), &icuErr);
783 if (icuErr == U_BUFFER_OVERFLOW_ERROR)
784 {
785 string = (UChar *) malloc(sizeof(UChar)*(stringLen+1));
786 if (!string)
787 {
788 CFRelease(working);
789 return NULL;
790 }
791 icuErr = U_ZERO_ERROR;
792 (void) uset_getItem(set, i, &start, &end, string, stringLen+1, &icuErr);
793 }
794 if (U_FAILURE(icuErr))
795 {
796 if (string != buffer)
797 free(string);
798 CFRelease(working);
799 return NULL;
800 }
801 if (stringLen <= 0)
802 CFCharacterSetAddCharactersInRange(working, CFRangeMake(start, end-start+1));
803 else
804 {
805 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, (UniChar *)string, stringLen, kCFAllocatorNull);
806 CFCharacterSetAddCharactersInString(working, cfString);
807 CFRelease(cfString);
808 }
809 if (string != buffer)
810 free(string);
811 }
812
813 CFCharacterSetRef result = CFCharacterSetCreateCopy(kCFAllocatorSystemDefault, working);
814 CFRelease(working);
815 return result;
816 }
817 #endif
818
819 static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
820 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
821 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
822 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) {
823 UErrorCode icuStatus = U_ZERO_ERROR;
824 ULocaleData* uld = ulocdata_open(localeID, &icuStatus);
825 USet *set = ulocdata_getExemplarSet(uld, NULL, USET_ADD_CASE_MAPPINGS, ULOCDATA_ES_STANDARD, &icuStatus);
826 ulocdata_close(uld);
827 if (U_FAILURE(icuStatus))
828 return false;
829 if (icuStatus == U_USING_DEFAULT_WARNING) // If default locale used, force to empty set
830 uset_clear(set);
831 *cf = (CFTypeRef) _CFCreateCharacterSetFromUSet(set);
832 uset_close(set);
833 return (*cf != NULL);
834 }
835 #endif
836 return false;
837 }
838
839 static bool __CFLocaleCopyICUKeyword(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context, const char *keyword)
840 {
841 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
842 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
843 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII))
844 {
845 char value[ULOC_KEYWORD_AND_VALUES_CAPACITY];
846 UErrorCode icuStatus = U_ZERO_ERROR;
847 if (uloc_getKeywordValue(localeID, keyword, value, sizeof(value)/sizeof(char), &icuStatus) > 0 && U_SUCCESS(icuStatus))
848 {
849 *cf = (CFTypeRef) CFStringCreateWithCString(kCFAllocatorSystemDefault, value, kCFStringEncodingASCII);
850 return true;
851 }
852 }
853 #endif
854 *cf = NULL;
855 return false;
856 }
857
858 static bool __CFLocaleCopyICUCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context, const char *keyword) {
859 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
860 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
861 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) {
862 UErrorCode icuStatus = U_ZERO_ERROR;
863 UEnumeration *en = ucal_getKeywordValuesForLocale(keyword, localeID, TRUE, &icuStatus);
864 int32_t len;
865 const char *value = uenum_next(en, &len, &icuStatus);
866 if (U_SUCCESS(icuStatus)) {
867 *cf = (CFTypeRef) CFStringCreateWithCString(kCFAllocatorSystemDefault, value, kCFStringEncodingASCII);
868 uenum_close(en);
869 return true;
870 }
871 uenum_close(en);
872 }
873 #endif
874 *cf = NULL;
875 return false;
876 }
877
878 static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
879 bool succeeded = __CFLocaleCopyICUKeyword(locale, user, cf, context, kCalendarKeyword);
880 if (!succeeded) {
881 succeeded = __CFLocaleCopyICUCalendarID(locale, user, cf, context, kCalendarKeyword);
882 }
883 if (succeeded) {
884 if (CFEqual(*cf, kCFCalendarIdentifierGregorian)) {
885 CFRelease(*cf);
886 *cf = CFRetain(kCFCalendarIdentifierGregorian);
887 } else if (CFEqual(*cf, kCFCalendarIdentifierBuddhist)) {
888 CFRelease(*cf);
889 *cf = CFRetain(kCFCalendarIdentifierBuddhist);
890 } else if (CFEqual(*cf, kCFCalendarIdentifierJapanese)) {
891 CFRelease(*cf);
892 *cf = CFRetain(kCFCalendarIdentifierJapanese);
893 } else if (CFEqual(*cf, kCFCalendarIdentifierIslamic)) {
894 CFRelease(*cf);
895 *cf = CFRetain(kCFCalendarIdentifierIslamic);
896 } else if (CFEqual(*cf, kCFCalendarIdentifierIslamicCivil)) {
897 CFRelease(*cf);
898 *cf = CFRetain(kCFCalendarIdentifierIslamicCivil);
899 } else if (CFEqual(*cf, kCFCalendarIdentifierHebrew)) {
900 CFRelease(*cf);
901 *cf = CFRetain(kCFCalendarIdentifierHebrew);
902 } else if (CFEqual(*cf, kCFCalendarIdentifierChinese)) {
903 CFRelease(*cf);
904 *cf = CFRetain(kCFCalendarIdentifierChinese);
905 } else if (CFEqual(*cf, kCFCalendarIdentifierRepublicOfChina)) {
906 CFRelease(*cf);
907 *cf = CFRetain(kCFCalendarIdentifierRepublicOfChina);
908 } else if (CFEqual(*cf, kCFCalendarIdentifierPersian)) {
909 CFRelease(*cf);
910 *cf = CFRetain(kCFCalendarIdentifierPersian);
911 } else if (CFEqual(*cf, kCFCalendarIdentifierIndian)) {
912 CFRelease(*cf);
913 *cf = CFRetain(kCFCalendarIdentifierIndian);
914 } else if (CFEqual(*cf, kCFCalendarIdentifierISO8601)) {
915 CFRelease(*cf);
916 *cf = CFRetain(kCFCalendarIdentifierISO8601);
917 } else if (CFEqual(*cf, kCFCalendarIdentifierCoptic)) {
918 CFRelease(*cf);
919 *cf = CFRetain(kCFCalendarIdentifierCoptic);
920 } else if (CFEqual(*cf, kCFCalendarIdentifierEthiopicAmeteMihret)) {
921 CFRelease(*cf);
922 *cf = CFRetain(kCFCalendarIdentifierEthiopicAmeteMihret);
923 } else if (CFEqual(*cf, kCFCalendarIdentifierEthiopicAmeteAlem)) {
924 CFRelease(*cf);
925 *cf = CFRetain(kCFCalendarIdentifierEthiopicAmeteAlem);
926 } else {
927 CFRelease(*cf);
928 *cf = NULL;
929 return false;
930 }
931 } else {
932 *cf = CFRetain(kCFCalendarIdentifierGregorian);
933 }
934 return true;
935 }
936
937 static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
938 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
939 if (__CFLocaleCopyCalendarID(locale, user, cf, context)) {
940 CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, (CFStringRef)*cf);
941 CFCalendarSetLocale(calendar, locale);
942 CFDictionaryRef prefs = __CFLocaleGetPrefs(locale);
943 CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleFirstWeekday")) : NULL;
944 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
945 metapref = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)metapref, *cf);
946 }
947 if (NULL != metapref && CFGetTypeID(metapref) == CFNumberGetTypeID()) {
948 CFIndex wkdy;
949 if (CFNumberGetValue((CFNumberRef)metapref, kCFNumberCFIndexType, &wkdy)) {
950 CFCalendarSetFirstWeekday(calendar, wkdy);
951 }
952 }
953 metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleMinDaysInFirstWeek")) : NULL;
954 if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) {
955 metapref = (CFNumberRef)CFDictionaryGetValue((CFDictionaryRef)metapref, *cf);
956 }
957 if (NULL != metapref && CFGetTypeID(metapref) == CFNumberGetTypeID()) {
958 CFIndex mwd;
959 if (CFNumberGetValue((CFNumberRef)metapref, kCFNumberCFIndexType, &mwd)) {
960 CFCalendarSetMinimumDaysInFirstWeek(calendar, mwd);
961 }
962 }
963 CFRelease(*cf);
964 *cf = calendar;
965 return true;
966 }
967 #endif
968 return false;
969 }
970
971 static bool __CFLocaleCopyDelimiter(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
972 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
973 ULocaleDataDelimiterType type = (ULocaleDataDelimiterType)0;
974 if (context == kCFLocaleQuotationBeginDelimiterKey) {
975 type = ULOCDATA_QUOTATION_START;
976 } else if (context == kCFLocaleQuotationEndDelimiterKey) {
977 type = ULOCDATA_QUOTATION_END;
978 } else if (context == kCFLocaleAlternateQuotationBeginDelimiterKey) {
979 type = ULOCDATA_ALT_QUOTATION_START;
980 } else if (context == kCFLocaleAlternateQuotationEndDelimiterKey) {
981 type = ULOCDATA_ALT_QUOTATION_END;
982 } else {
983 return false;
984 }
985
986 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
987 if (!CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) {
988 return false;
989 }
990
991 UChar buffer[130];
992 UErrorCode status = U_ZERO_ERROR;
993 ULocaleData *uld = ulocdata_open(localeID, &status);
994 int32_t len = ulocdata_getDelimiter(uld, type, buffer, sizeof(buffer) / sizeof(buffer[0]), &status);
995 ulocdata_close(uld);
996 if (U_FAILURE(status) || sizeof(buffer) / sizeof(buffer[0]) < len) {
997 return false;
998 }
999
1000 *cf = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)buffer, len);
1001 return (*cf != NULL);
1002 #else
1003 if (context == kCFLocaleQuotationBeginDelimiterKey || context == kCFLocaleQuotationEndDelimiterKey || context == kCFLocaleAlternateQuotationBeginDelimiterKey || context == kCFLocaleAlternateQuotationEndDelimiterKey) {
1004 *cf = CFRetain(CFSTR("\""));
1005 return true;
1006 } else {
1007 return false;
1008 }
1009 #endif
1010 }
1011
1012 static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
1013 return __CFLocaleCopyICUKeyword(locale, user, cf, context, kCollationKeyword);
1014 }
1015
1016 static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
1017 CFStringRef canonLocaleCFStr = NULL;
1018 if (user && locale->_prefs) {
1019 CFStringRef pref = (CFStringRef)CFDictionaryGetValue(locale->_prefs, CFSTR("AppleCollationOrder"));
1020 if (pref) {
1021 // Canonicalize pref string in case it's not in the canonical format.
1022 canonLocaleCFStr = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, pref);
1023 } else {
1024 CFArrayRef languagesArray = (CFArrayRef)CFDictionaryGetValue(locale->_prefs, CFSTR("AppleLanguages"));
1025 if (languagesArray && (CFArrayGetTypeID() == CFGetTypeID(languagesArray))) {
1026 if (0 < CFArrayGetCount(languagesArray)) {
1027 CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(languagesArray, 0);
1028 if (str && (CFStringGetTypeID() == CFGetTypeID(str))) {
1029 canonLocaleCFStr = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, str);
1030 }
1031 }
1032 }
1033 }
1034 }
1035 if (!canonLocaleCFStr) {
1036 canonLocaleCFStr = CFLocaleGetIdentifier(locale);
1037 CFRetain(canonLocaleCFStr);
1038 }
1039 *cf = canonLocaleCFStr;
1040 return canonLocaleCFStr ? true : false;
1041 }
1042
1043 static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
1044 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1045 bool us = false; // Default is Metric
1046 bool done = false;
1047 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1048 if (user) {
1049 CFTypeRef pref = CFDictionaryGetValue(locale->_prefs, CFSTR("AppleMetricUnits"));
1050 if (pref) {
1051 us = (kCFBooleanFalse == pref);
1052 done = true;
1053 } else {
1054 pref = CFDictionaryGetValue(locale->_prefs, CFSTR("AppleMeasurementUnits"));
1055 if (pref) {
1056 us = CFEqual(pref, CFSTR("Inches"));
1057 done = true;
1058 }
1059 }
1060 }
1061 #endif
1062 if (!done) {
1063 char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
1064 if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) {
1065 UErrorCode icuStatus = U_ZERO_ERROR;
1066 UMeasurementSystem ms = UMS_SI;
1067 ms = ulocdata_getMeasurementSystem(localeID, &icuStatus);
1068 if (U_SUCCESS(icuStatus)) {
1069 us = (ms == UMS_US);
1070 done = true;
1071 }
1072 }
1073 }
1074 if (!done)
1075 us = false;
1076 *cf = us ? CFRetain(kCFBooleanFalse) : CFRetain(kCFBooleanTrue);
1077 return true;
1078 #else
1079 *cf = CFRetain(kCFBooleanFalse);
1080 return true;
1081 #endif
1082 }
1083
1084 static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
1085 if (__CFLocaleCopyUsesMetric(locale, user, cf, context)) {
1086 bool us = (*cf == kCFBooleanFalse);
1087 CFRelease(*cf);
1088 *cf = us ? CFRetain(CFSTR("U.S.")) : CFRetain(CFSTR("Metric"));
1089 return true;
1090 }
1091 return false;
1092 }
1093
1094 static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
1095 CFStringRef str = NULL;
1096 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1097 CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterDecimalStyle);
1098 str = nf ? (CFStringRef)CFNumberFormatterCopyProperty(nf, context) : NULL;
1099 if (nf) CFRelease(nf);
1100 #endif
1101 if (str) {
1102 *cf = str;
1103 return true;
1104 }
1105 return false;
1106 }
1107
1108 // ICU does not reliably set up currency info for other than Currency-type formatters,
1109 // so we have to have another routine here which creates a Currency number formatter.
1110 static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
1111 CFStringRef str = NULL;
1112 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1113 CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterCurrencyStyle);
1114 str = nf ? (CFStringRef)CFNumberFormatterCopyProperty(nf, context) : NULL;
1115 if (nf) CFRelease(nf);
1116 #endif
1117 if (str) {
1118 *cf = str;
1119 return true;
1120 }
1121 return false;
1122 }
1123
1124 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1125 typedef int32_t (*__CFICUFunction)(const char *, const char *, UChar *, int32_t, UErrorCode *);
1126
1127 static bool __CFLocaleICUName(const char *locale, const char *valLocale, CFStringRef *out, __CFICUFunction icu) {
1128 UErrorCode icuStatus = U_ZERO_ERROR;
1129 int32_t size;
1130 UChar name[kMaxICUNameSize];
1131
1132 size = (*icu)(valLocale, locale, name, kMaxICUNameSize, &icuStatus);
1133 if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) {
1134 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size);
1135 return (*out != NULL);
1136 }
1137 return false;
1138 }
1139
1140 static bool __CFLocaleICUKeywordValueName(const char *locale, const char *value, const char *keyword, CFStringRef *out) {
1141 UErrorCode icuStatus = U_ZERO_ERROR;
1142 int32_t size = 0;
1143 UChar name[kMaxICUNameSize];
1144 // Need to make a fake locale ID
1145 char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
1146 if (strlen(value) < ULOC_KEYWORD_AND_VALUES_CAPACITY) {
1147 strlcpy(lid, "en_US@", sizeof(lid));
1148 strlcat(lid, keyword, sizeof(lid));
1149 strlcat(lid, "=", sizeof(lid));
1150 strlcat(lid, value, sizeof(lid));
1151 size = uloc_getDisplayKeywordValue(lid, keyword, locale, name, kMaxICUNameSize, &icuStatus);
1152 if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) {
1153 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size);
1154 return (*out != NULL);
1155 }
1156 }
1157 return false;
1158 }
1159
1160 static bool __CFLocaleICUCurrencyName(const char *locale, const char *value, UCurrNameStyle style, CFStringRef *out) {
1161 int valLen = strlen(value);
1162 if (valLen != 3) // not a valid ISO code
1163 return false;
1164 UChar curr[4];
1165 UBool isChoice = FALSE;
1166 int32_t size = 0;
1167 UErrorCode icuStatus = U_ZERO_ERROR;
1168 u_charsToUChars(value, curr, valLen);
1169 curr[valLen] = '\0';
1170 const UChar *name;
1171 name = ucurr_getName(curr, locale, style, &isChoice, &size, &icuStatus);
1172 if (U_FAILURE(icuStatus) || icuStatus == U_USING_DEFAULT_WARNING)
1173 return false;
1174 UChar result[kMaxICUNameSize];
1175 if (isChoice)
1176 {
1177 UChar pattern[kMaxICUNameSize];
1178 CFStringRef patternRef = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{0,choice,%S}"), name);
1179 CFIndex pattlen = CFStringGetLength(patternRef);
1180 CFStringGetCharacters(patternRef, CFRangeMake(0, pattlen), (UniChar *)pattern);
1181 CFRelease(patternRef);
1182 pattern[pattlen] = '\0'; // null terminate the pattern
1183 // Format the message assuming a large amount of the currency
1184 size = u_formatMessage("en_US", pattern, pattlen, result, kMaxICUNameSize, &icuStatus, 10.0);
1185 if (U_FAILURE(icuStatus))
1186 return false;
1187 name = result;
1188
1189 }
1190 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size);
1191 return (*out != NULL);
1192 }
1193 #endif
1194
1195 static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out) {
1196 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1197 UErrorCode icuStatus = U_ZERO_ERROR;
1198 int32_t size;
1199 UChar name[kMaxICUNameSize];
1200
1201 // First, try to get the full locale.
1202 size = uloc_getDisplayName(value, locale, name, kMaxICUNameSize, &icuStatus);
1203 if (U_FAILURE(icuStatus) || size <= 0)
1204 return false;
1205
1206 // Did we wind up using a default somewhere?
1207 if (icuStatus == U_USING_DEFAULT_WARNING) {
1208 // For some locale IDs, there may be no language which has a translation for every
1209 // piece. Rather than return nothing, see if we can at least handle
1210 // the language part of the locale.
1211 UErrorCode localStatus = U_ZERO_ERROR;
1212 int32_t localSize;
1213 UChar localName[kMaxICUNameSize];
1214 localSize = uloc_getDisplayLanguage(value, locale, localName, kMaxICUNameSize, &localStatus);
1215 if (U_FAILURE(localStatus) || size <= 0 || localStatus == U_USING_DEFAULT_WARNING)
1216 return false;
1217 }
1218
1219 // This locale is OK, so use the result.
1220 *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size);
1221 return (*out != NULL);
1222 #else
1223 *out = CFRetain(CFSTR("(none)"));
1224 return true;
1225 #endif
1226 }
1227
1228 static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out) {
1229 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1230 return __CFLocaleICUName(locale, value, out, uloc_getDisplayLanguage);
1231 #else
1232 *out = CFRetain(CFSTR("(none)"));
1233 return true;
1234 #endif
1235 }
1236
1237 static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out) {
1238 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1239 // Need to make a fake locale ID
1240 char lid[ULOC_FULLNAME_CAPACITY];
1241 if (strlen(value) < sizeof(lid) - 3) {
1242 strlcpy(lid, "en_", sizeof(lid));
1243 strlcat(lid, value, sizeof(lid));
1244 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayCountry);
1245 }
1246 return false;
1247 #else
1248 *out = CFRetain(CFSTR("(none)"));
1249 return true;
1250 #endif
1251 }
1252
1253 static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out) {
1254 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1255 // Need to make a fake locale ID
1256 char lid[ULOC_FULLNAME_CAPACITY];
1257 if (strlen(value) == 4) {
1258 strlcpy(lid, "en_", sizeof(lid));
1259 strlcat(lid, value, sizeof(lid));
1260 strlcat(lid, "_US", sizeof(lid));
1261 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayScript);
1262 }
1263 return false;
1264 #else
1265 *out = CFRetain(CFSTR("(none)"));
1266 return true;
1267 #endif
1268 }
1269
1270 static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out) {
1271 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1272 // Need to make a fake locale ID
1273 char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY];
1274 if (strlen(value) < sizeof(lid) - 6) {
1275 strlcpy(lid, "en_US_", sizeof(lid));
1276 strlcat(lid, value, sizeof(lid));
1277 return __CFLocaleICUName(locale, lid, out, uloc_getDisplayVariant);
1278 }
1279 return false;
1280 #else
1281 *out = CFRetain(CFSTR("(none)"));
1282 return true;
1283 #endif
1284 }
1285
1286 static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out) {
1287 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1288 return __CFLocaleICUKeywordValueName(locale, value, kCalendarKeyword, out);
1289 #else
1290 *out = CFRetain(CFSTR("(none)"));
1291 return true;
1292 #endif
1293 }
1294
1295 static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out) {
1296 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1297 return __CFLocaleICUKeywordValueName(locale, value, kCollationKeyword, out);
1298 #else
1299 *out = CFRetain(CFSTR("(none)"));
1300 return true;
1301 #endif
1302 }
1303
1304 static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out) {
1305 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1306 return __CFLocaleICUCurrencyName(locale, value, UCURR_SYMBOL_NAME, out);
1307 #else
1308 *out = CFRetain(CFSTR("(none)"));
1309 return true;
1310 #endif
1311 }
1312
1313 static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out) {
1314 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1315 return __CFLocaleICUCurrencyName(locale, value, UCURR_LONG_NAME, out);
1316 #else
1317 *out = CFRetain(CFSTR("(none)"));
1318 return true;
1319 #endif
1320 }
1321
1322 static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out) {
1323 return false;
1324 }
1325
1326 #undef kMaxICUNameSize
1327