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