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
68CONST_STRING_DECL(kCFLocaleCurrentLocaleDidChangeNotification, "kCFLocaleCurrentLocaleDidChangeNotification")
69
70static const char *kCalendarKeyword = "calendar";
71static const char *kCollationKeyword = "collation";
72#define kMaxICUNameSize 1024
73
74typedef struct __CFLocale *CFMutableLocaleRef;
75
76PE_CONST_STRING_DECL(__kCFLocaleCollatorID, "locale:collator id")
77
78
79enum {
80    __kCFLocaleKeyTableCount = 21
81};
82
83struct 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:
93static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
94static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context);
95static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out);
96static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
97static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out);
98static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out);
99static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out);
100static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out);
101static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
102static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out);
103static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out);
104static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
105static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out);
106static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out);
107static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
108static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
109static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
110static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
111static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
112static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
113static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out);
114static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context);
115static 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
118static 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
143static CFLocaleRef __CFLocaleSystem = NULL;
144static CFMutableDictionaryRef __CFLocaleCache = NULL;
145static CFSpinLock_t __CFLocaleGlobalLock = CFSpinLockInit;
146
147struct __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
157CF_PRIVATE Boolean __CFLocaleGetNullLocale(struct __CFLocale *locale) {
158    return locale->_nullLocale;
159}
160
161CF_PRIVATE void __CFLocaleSetNullLocale(struct __CFLocale *locale) {
162    locale->_nullLocale = true;
163}
164
165/* Flag bits */
166enum {      /* Bits 0-1 */
167    __kCFLocaleOrdinary = 0,
168    __kCFLocaleSystem = 1,
169    __kCFLocaleUser = 2,
170    __kCFLocaleCustom = 3
171};
172
173CF_INLINE CFIndex __CFLocaleGetType(CFLocaleRef locale) {
174    return __CFBitfieldGetValue(((const CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0);
175}
176
177CF_INLINE void __CFLocaleSetType(CFLocaleRef locale, CFIndex type) {
178    __CFBitfieldSetValue(((CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0, (uint8_t)type);
179}
180
181CF_INLINE void __CFLocaleLockGlobal(void) {
182    __CFSpinLock(&__CFLocaleGlobalLock);
183}
184
185CF_INLINE void __CFLocaleUnlockGlobal(void) {
186    __CFSpinUnlock(&__CFLocaleGlobalLock);
187}
188
189CF_INLINE void __CFLocaleLock(CFLocaleRef locale) {
190    __CFSpinLock(&((struct __CFLocale *)locale)->_lock);
191}
192
193CF_INLINE void __CFLocaleUnlock(CFLocaleRef locale) {
194    __CFSpinUnlock(&((struct __CFLocale *)locale)->_lock);
195}
196
197
198static 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
213static CFHashCode __CFLocaleHash(CFTypeRef cf) {
214    CFLocaleRef locale = (CFLocaleRef)cf;
215    return CFHash(locale->_identifier);
216}
217
218static 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
230static 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
238static CFTypeID __kCFLocaleTypeID = _kCFRuntimeNotATypeID;
239
240static 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
252static 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
264CFTypeID CFLocaleGetTypeID(void) {
265    if (_kCFRuntimeNotATypeID == __kCFLocaleTypeID) __CFLocaleInitialize();
266    return __kCFLocaleTypeID;
267}
268
269CFLocaleRef 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
289extern CFDictionaryRef __CFXPreferencesCopyCurrentApplicationState(void);
290
291static 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
302static 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 */
376CFLocaleRef _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 */
384CFLocaleRef _CFLocaleCopyAsIfCurrentWithOverrides(CFStringRef name, CFDictionaryRef overrides) {
385    return _CFLocaleCopyCurrentGuts(name, false, overrides);
386}
387
388CFLocaleRef CFLocaleCopyCurrent(void) {
389    return _CFLocaleCopyCurrentGuts(NULL, true, NULL);
390}
391
392CF_PRIVATE CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale) {
393    CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFDictionaryRef, (NSLocale *)locale, _prefs);
394    return locale->_prefs;
395}
396
397CFLocaleRef 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
446CFLocaleRef CFLocaleCreateCopy(CFAllocatorRef allocator, CFLocaleRef locale) {
447    return (CFLocaleRef)CFRetain(locale);
448}
449
450CFStringRef CFLocaleGetIdentifier(CFLocaleRef locale) {
451    CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFStringRef, (NSLocale *)locale, localeIdentifier);
452    return locale->_identifier;
453}
454
455CFTypeRef 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
509CFStringRef 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
568CFArrayRef 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
591static 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
603static 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
629CFArrayRef 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
638CFArrayRef 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
647CFArrayRef 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
659CFArrayRef 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
671CFStringRef 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
686uint32_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
698CFLocaleLanguageDirection 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
718CFLocaleLanguageDirection 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
738CFArrayRef 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.
762static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context) {
763    return false;
764}
765
766static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
767    *cf = CFRetain(locale->_identifier);
768    return true;
769}
770
771
772static 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
790CFCharacterSetRef _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
844static 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
864static 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
883static 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
903static 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
962static 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
996static 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
1037static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) {
1038    return __CFLocaleCopyICUKeyword(locale, user, cf, context, kCollationKeyword);
1039}
1040
1041static 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
1068static 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
1109static 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
1119static 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.
1135static 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
1150typedef int32_t (*__CFICUFunction)(const char *, const char *, UChar *, int32_t, UErrorCode *);
1151
1152static 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
1165static 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
1185static 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
1220static 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
1253static 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
1262static 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
1278static 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
1295static 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
1311static 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
1320static 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
1329static 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
1338static 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
1347static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out) {
1348    return false;
1349}
1350
1351#undef kMaxICUNameSize
1352
1353