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