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