| /* |
| * Copyright (c) 2008-2009 Brent Fulgham <bfulgham@gmail.org>. All rights reserved. |
| * |
| * This source code is a modified version of the CoreFoundation sources released by Apple Inc. under |
| * the terms of the APSL version 2.0 (see below). |
| * |
| * For information about changes from the original Apple source release can be found by reviewing the |
| * source control system for the project at https://sourceforge.net/svn/?group_id=246198. |
| * |
| * The original license information is as follows: |
| * |
| * Copyright (c) 2008 Apple Inc. All rights reserved. |
| * |
| * @APPLE_LICENSE_HEADER_START@ |
| * |
| * This file contains Original Code and/or Modifications of Original Code |
| * as defined in and that are subject to the Apple Public Source License |
| * Version 2.0 (the 'License'). You may not use this file except in |
| * compliance with the License. Please obtain a copy of the License at |
| * http://www.opensource.apple.com/apsl/ and read it before using this |
| * file. |
| * |
| * The Original Code and all software distributed under the License are |
| * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
| * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
| * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
| * Please see the License for the specific language governing rights and |
| * limitations under the License. |
| * |
| * @APPLE_LICENSE_HEADER_END@ |
| */ |
| /* CFLocale.c |
| Copyright 2002-2003, Apple Computer, Inc. All rights reserved. |
| Responsibility: Christopher Kane |
| */ |
| |
| // Note the header file is in the OpenSource set (stripped to almost nothing), but not the .c file |
| |
| #include <CoreFoundation/CFLocale.h> |
| #include <CoreFoundation/CFString.h> |
| #include <CoreFoundation/CFArray.h> |
| #include <CoreFoundation/CFDictionary.h> |
| #include <CoreFoundation/CFPreferences.h> |
| #include <CoreFoundation/CFCalendar.h> |
| #include <CoreFoundation/CFNumber.h> |
| #include "CFInternal.h" |
| #include <unicode/uloc.h> // ICU locales |
| #include <unicode/ulocdata.h> // ICU locale data |
| #include <unicode/ucurr.h> // ICU currency functions |
| #include <unicode/uset.h> // ICU Unicode sets |
| #include <unicode/putil.h> // ICU low-level utilities |
| #include <unicode/umsg.h> // ICU message formatting |
| #include <CoreFoundation/CFNumberFormatter.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <unicode/ucol.h> |
| |
| #if DEPLOYMENT_TARGET_WINDOWS |
| #include <windows.h> // for GetLocaleInfo |
| #include <winnls.h> |
| #include <locale.h> |
| #endif |
| |
| #if _MSC_VER |
| #define snprintf _snprintf |
| #define BUFFER_SIZE 512 |
| #endif |
| |
| CONST_STRING_DECL(kCFLocaleCurrentLocaleDidChangeNotification, "kCFLocaleCurrentLocaleDidChangeNotification") |
| |
| static const char *kCalendarKeyword = "calendar"; |
| static const char *kCollationKeyword = "collation"; |
| #define kMaxICUNameSize 1024 |
| |
| typedef struct __CFLocale *CFMutableLocaleRef; |
| |
| __private_extern__ CONST_STRING_DECL(__kCFLocaleCollatorID, "locale:collator id") |
| |
| enum { |
| __kCFLocaleKeyTableCount = 16 |
| }; |
| |
| struct key_table { |
| CFStringRef key; |
| bool (*get)(CFLocaleRef, bool user, CFTypeRef *, CFStringRef context); // returns an immutable copy & reference |
| bool (*set)(CFMutableLocaleRef, CFTypeRef, CFStringRef context); |
| bool (*name)(const char *, const char *, CFStringRef *); |
| CFStringRef context; |
| }; |
| |
| |
| // Must forward decl. these functions: |
| static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); |
| static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context); |
| static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out); |
| static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); |
| static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out); |
| static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out); |
| static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out); |
| static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out); |
| static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); |
| static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out); |
| static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out); |
| static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); |
| static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out); |
| static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out); |
| static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); |
| static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); |
| static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); |
| static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); |
| static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); |
| static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); |
| static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out); |
| static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); |
| |
| // Note string members start with an extra &, and are fixed up at init time |
| static struct key_table __CFLocaleKeyTable[__kCFLocaleKeyTableCount] = { |
| {(CFStringRef)&kCFLocaleIdentifier, __CFLocaleCopyLocaleID, __CFLocaleSetNOP, __CFLocaleFullName, NULL}, |
| {(CFStringRef)&kCFLocaleLanguageCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleLanguageName, (CFStringRef)&kCFLocaleLanguageCode}, |
| {(CFStringRef)&kCFLocaleCountryCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleCountryName, (CFStringRef)&kCFLocaleCountryCode}, |
| {(CFStringRef)&kCFLocaleScriptCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleScriptName, (CFStringRef)&kCFLocaleScriptCode}, |
| {(CFStringRef)&kCFLocaleVariantCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleVariantName, (CFStringRef)&kCFLocaleVariantCode}, |
| {(CFStringRef)&kCFLocaleExemplarCharacterSet, __CFLocaleCopyExemplarCharSet, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, |
| {(CFStringRef)&kCFLocaleCalendarIdentifier, __CFLocaleCopyCalendarID, __CFLocaleSetNOP, __CFLocaleCalendarName, NULL}, |
| {(CFStringRef)&kCFLocaleCalendar, __CFLocaleCopyCalendar, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, |
| {(CFStringRef)&kCFLocaleCollationIdentifier, __CFLocaleCopyCollationID, __CFLocaleSetNOP, __CFLocaleCollationName, NULL}, |
| {(CFStringRef)&kCFLocaleUsesMetricSystem, __CFLocaleCopyUsesMetric, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, |
| {(CFStringRef)&kCFLocaleMeasurementSystem, __CFLocaleCopyMeasurementSystem, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, |
| {(CFStringRef)&kCFLocaleDecimalSeparator, __CFLocaleCopyNumberFormat, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFNumberFormatterDecimalSeparator}, |
| {(CFStringRef)&kCFLocaleGroupingSeparator, __CFLocaleCopyNumberFormat, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFNumberFormatterGroupingSeparator}, |
| {(CFStringRef)&kCFLocaleCurrencySymbol, __CFLocaleCopyNumberFormat2, __CFLocaleSetNOP, __CFLocaleCurrencyShortName, (CFStringRef)&kCFNumberFormatterCurrencySymbol}, |
| {(CFStringRef)&kCFLocaleCurrencyCode, __CFLocaleCopyNumberFormat2, __CFLocaleSetNOP, __CFLocaleCurrencyFullName, (CFStringRef)&kCFNumberFormatterCurrencyCode}, |
| {(CFStringRef)&__kCFLocaleCollatorID, __CFLocaleCopyCollatorID, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, |
| }; |
| |
| |
| static CFLocaleRef __CFLocaleSystem = NULL; |
| static CFMutableDictionaryRef __CFLocaleCache = NULL; |
| static CFSpinLock_t __CFLocaleGlobalLock = CFSpinLockInit; |
| |
| struct __CFLocale { |
| CFRuntimeBase _base; |
| CFStringRef _identifier; // canonical identifier, never NULL |
| CFMutableDictionaryRef _cache; |
| CFMutableDictionaryRef _overrides; |
| CFDictionaryRef _prefs; |
| CFSpinLock_t _lock; |
| }; |
| |
| /* Flag bits */ |
| enum { /* Bits 0-1 */ |
| __kCFLocaleOrdinary = 0, |
| __kCFLocaleSystem = 1, |
| __kCFLocaleUser = 2, |
| __kCFLocaleCustom = 3 |
| }; |
| |
| CF_INLINE CFIndex __CFLocaleGetType(CFLocaleRef locale) { |
| return __CFBitfieldGetValue(((const CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0); |
| } |
| |
| CF_INLINE void __CFLocaleSetType(CFLocaleRef locale, CFIndex type) { |
| __CFBitfieldSetValue(((CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0, (uint8_t)type); |
| } |
| |
| CF_INLINE void __CFLocaleLockGlobal(void) { |
| __CFSpinLock(&__CFLocaleGlobalLock); |
| } |
| |
| CF_INLINE void __CFLocaleUnlockGlobal(void) { |
| __CFSpinUnlock(&__CFLocaleGlobalLock); |
| } |
| |
| CF_INLINE void __CFLocaleLock(CFLocaleRef locale) { |
| __CFSpinLock((CFSpinLock_t *)(&locale->_lock)); |
| } |
| |
| CF_INLINE void __CFLocaleUnlock(CFLocaleRef locale) { |
| __CFSpinUnlock((CFSpinLock_t *)(&locale->_lock)); |
| } |
| |
| #ifdef DEPLOYMENT_TARGET_WINDOWS |
| __private_extern__ CFStringRef __CFLocaleWindowsLCIDToISOLocaleName(LCID id) |
| { |
| //XXXBS Windows Vista should use LCIDToLocaleName instead of this |
| char iso_localename[18], iso_lang_name[9], iso_region_name[9]; |
| GetLocaleInfoA(id, LOCALE_SISO639LANGNAME, iso_lang_name, 9); |
| GetLocaleInfoA(id, LOCALE_SISO3166CTRYNAME,iso_region_name, 9); |
| // implicitly protected from overflow because of guaranteed maximum size returned by GetLocaleInfoA/W |
| strcpy(iso_localename, iso_lang_name); |
| strcat(iso_localename, "_"); |
| strcat(iso_localename, iso_region_name); |
| return(CFStringCreateWithCString(kCFAllocatorSystemDefault, iso_localename, kCFStringEncodingASCII)); |
| } |
| |
| __private_extern__ CFStringRef __CFLocaleWindowsLCIDToISOLocaleNameUsingHyphen(LCID id) |
| { |
| char iso_localename[18], iso_lang_name[9], iso_region_name[9]; |
| GetLocaleInfoA(id, LOCALE_SISO639LANGNAME, iso_lang_name, 9); |
| GetLocaleInfoA(id, LOCALE_SISO3166CTRYNAME,iso_region_name, 9); |
| // implicitly protected from overflow because of guaranteed maximum size returned by GetLocaleInfoA/W |
| strcpy(iso_localename, iso_lang_name); |
| strcat(iso_localename, "-"); |
| strcat(iso_localename, iso_region_name); |
| return(CFStringCreateWithCString(kCFAllocatorSystemDefault, iso_localename, kCFStringEncodingASCII)); |
| } |
| |
| CFStringRef s_WindowsInstalledLocales[255]; |
| int s_num_installed_localesI = 0; |
| |
| static BOOL CALLBACK WindowsLocaleEnumProc(char *localeName) |
| { |
| s_WindowsInstalledLocales[s_num_installed_localesI] = CFStringCreateWithCString(kCFAllocatorDefault, localeName, kCFStringEncodingASCII); |
| s_num_installed_localesI++; |
| return (TRUE); |
| } |
| |
| __private_extern__ CFArrayRef CFLocaleWindowsGetInstalledLocales(void) |
| { |
| CFArrayRef WindowsLocales; |
| EnumSystemLocales((LOCALE_ENUMPROC)WindowsLocaleEnumProc, LCID_INSTALLED); |
| WindowsLocales = CFArrayCreate(kCFAllocatorSystemDefault, (const void**)s_WindowsInstalledLocales, s_num_installed_localesI, &kCFTypeArrayCallBacks); |
| return (WindowsLocales); |
| } |
| #elif DEPLOYMENT_TARGET_LINUX |
| static CFStringRef __CFLocaleCopyPOSIXLocaleName(void) |
| { |
| const char *p = NULL; |
| CFStringRef identifier = NULL; |
| |
| p = getenv("LC_ALL"); |
| |
| if (NULL == p) p = getenv("LANG"); |
| if (NULL != p) identifier = CFStringCreateWithCString(kCFAllocatorDefault, p, kCFStringEncodingASCII); |
| |
| return (identifier); |
| } |
| #endif // DEPLOYMENT_TARGET_WINDOWS |
| |
| static Boolean __CFLocaleEqual(CFTypeRef cf1, CFTypeRef cf2) { |
| CFLocaleRef locale1 = (CFLocaleRef)cf1; |
| CFLocaleRef locale2 = (CFLocaleRef)cf2; |
| // a user locale and a locale created with an ident are not the same even if their contents are |
| if (__CFLocaleGetType(locale1) != __CFLocaleGetType(locale2)) return false; |
| if (!CFEqual(locale1->_identifier, locale2->_identifier)) return false; |
| if (NULL == locale1->_overrides && NULL != locale2->_overrides) return false; |
| if (NULL != locale1->_overrides && NULL == locale2->_overrides) return false; |
| if (NULL != locale1->_overrides && !CFEqual(locale1->_overrides, locale2->_overrides)) return false; |
| if (__kCFLocaleUser == __CFLocaleGetType(locale1)) { |
| return CFEqual(locale1->_prefs, locale2->_prefs); |
| } |
| return true; |
| } |
| |
| static CFHashCode __CFLocaleHash(CFTypeRef cf) { |
| CFLocaleRef locale = (CFLocaleRef)cf; |
| return CFHash(locale->_identifier); |
| } |
| |
| static CFStringRef __CFLocaleCopyDescription(CFTypeRef cf) { |
| CFLocaleRef locale = (CFLocaleRef)cf; |
| const char *type = NULL; |
| switch (__CFLocaleGetType(locale)) { |
| case __kCFLocaleOrdinary: type = "ordinary"; break; |
| case __kCFLocaleSystem: type = "system"; break; |
| case __kCFLocaleUser: type = "user"; break; |
| case __kCFLocaleCustom: type = "custom"; break; |
| } |
| return CFStringCreateWithFormat(CFGetAllocator(locale), NULL, CFSTR("<CFLocale %p [%p]>{type = %s, identifier = '%@'}"), cf, CFGetAllocator(locale), type, locale->_identifier); |
| } |
| |
| static void __CFLocaleDeallocate(CFTypeRef cf) { |
| CFLocaleRef locale = (CFLocaleRef)cf; |
| CFRelease(locale->_identifier); |
| if (NULL != locale->_cache) CFRelease(locale->_cache); |
| if (NULL != locale->_overrides) CFRelease(locale->_overrides); |
| if (NULL != locale->_prefs) CFRelease(locale->_prefs); |
| } |
| |
| static CFTypeID __kCFLocaleTypeID = _kCFRuntimeNotATypeID; |
| |
| static const CFRuntimeClass __CFLocaleClass = { |
| 0, |
| "CFLocale", |
| NULL, // init |
| NULL, // copy |
| __CFLocaleDeallocate, |
| __CFLocaleEqual, |
| __CFLocaleHash, |
| NULL, // |
| __CFLocaleCopyDescription |
| }; |
| |
| __private_extern__ void __CFLocaleInitialize(void) { |
| CFIndex idx; |
| __kCFLocaleTypeID = _CFRuntimeRegisterClass(&__CFLocaleClass); |
| for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { |
| // table fixup to workaround compiler/language limitations |
| __CFLocaleKeyTable[idx].key = *((CFStringRef *)__CFLocaleKeyTable[idx].key); |
| if (NULL != __CFLocaleKeyTable[idx].context) { |
| __CFLocaleKeyTable[idx].context = *((CFStringRef *)__CFLocaleKeyTable[idx].context); |
| } |
| } |
| } |
| |
| CFTypeID CFLocaleGetTypeID(void) { |
| if (_kCFRuntimeNotATypeID == __kCFLocaleTypeID) __CFLocaleInitialize(); |
| return __kCFLocaleTypeID; |
| } |
| |
| CFLocaleRef CFLocaleGetSystem(void) { |
| CFLocaleRef locale; |
| __CFLocaleLockGlobal(); |
| if (NULL == __CFLocaleSystem) { |
| __CFLocaleUnlockGlobal(); |
| locale = CFLocaleCreate(kCFAllocatorSystemDefault, CFSTR("")); |
| if (!locale) return NULL; |
| __CFLocaleSetType(locale, __kCFLocaleSystem); |
| __CFLocaleLockGlobal(); |
| if (NULL == __CFLocaleSystem) { |
| __CFLocaleSystem = locale; |
| } else { |
| if (locale) CFRelease(locale); |
| } |
| } |
| locale = __CFLocaleSystem ? (CFLocaleRef)CFRetain(__CFLocaleSystem) : NULL; |
| __CFLocaleUnlockGlobal(); |
| return locale; |
| } |
| |
| static CFLocaleRef __CFLocaleCurrent = NULL; |
| |
| #define FALLBACK_LOCALE_NAME CFSTR("") |
| |
| CFLocaleRef CFLocaleCopyCurrent(void) { |
| |
| __CFLocaleLockGlobal(); |
| if (__CFLocaleCurrent) { |
| CFRetain(__CFLocaleCurrent); |
| __CFLocaleUnlockGlobal(); |
| return __CFLocaleCurrent; |
| } |
| __CFLocaleUnlockGlobal(); |
| |
| CFDictionaryRef prefs = NULL; |
| CFStringRef identifier = NULL; |
| |
| #ifdef DEPLOYMENT_TARGET_WINDOWS |
| identifier = __CFLocaleWindowsLCIDToISOLocaleName(LOCALE_USER_DEFAULT); |
| #elif DEPLOYMENT_TARGET_LINUX |
| identifier = __CFLocaleCopyPOSIXLocaleName(); |
| #endif |
| |
| struct __CFLocale *locale; |
| uint32_t size = sizeof(struct __CFLocale) - sizeof(CFRuntimeBase); |
| locale = (struct __CFLocale *)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, CFLocaleGetTypeID(), size, NULL); |
| if (NULL == locale) { |
| return NULL; |
| } |
| __CFLocaleSetType(locale, __kCFLocaleUser); |
| if (NULL == identifier) identifier = (CFStringRef)CFRetain(FALLBACK_LOCALE_NAME); |
| locale->_identifier = identifier; |
| locale->_cache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); |
| locale->_overrides = NULL; |
| locale->_prefs = prefs; |
| |
| CF_SPINLOCK_INIT_FOR_STRUCTS(locale->_lock); |
| |
| __CFLocaleLockGlobal(); |
| if (NULL == __CFLocaleCurrent) { |
| __CFLocaleCurrent = locale; |
| } else { |
| CFRelease(locale); |
| } |
| locale = (struct __CFLocale *)CFRetain(__CFLocaleCurrent); |
| __CFLocaleUnlockGlobal(); |
| return locale; |
| } |
| |
| __private_extern__ CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale) { |
| return locale->_prefs; |
| } |
| |
| CFLocaleRef CFLocaleCreate(CFAllocatorRef allocator, CFStringRef identifier) { |
| if (allocator == NULL) allocator = __CFGetDefaultAllocator(); |
| __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); |
| __CFGenericValidateType(identifier, CFStringGetTypeID()); |
| CFStringRef localeIdentifier = NULL; |
| if (identifier) { |
| localeIdentifier = CFLocaleCreateCanonicalLocaleIdentifierFromString(allocator, identifier); |
| } |
| if (NULL == localeIdentifier) return NULL; |
| CFStringRef old = localeIdentifier; |
| localeIdentifier = (CFStringRef)CFStringCreateCopy(allocator, localeIdentifier); |
| CFRelease(old); |
| __CFLocaleLockGlobal(); |
| // Look for cases where we can return a cached instance. |
| // We only use cached objects if the allocator is the system |
| // default allocator. |
| if (!allocator) allocator = __CFGetDefaultAllocator(); |
| Boolean canCache = (kCFAllocatorSystemDefault == allocator); |
| if (canCache && __CFLocaleCache) { |
| CFLocaleRef locale = (CFLocaleRef)CFDictionaryGetValue(__CFLocaleCache, localeIdentifier); |
| if (locale) { |
| CFRetain(locale); |
| __CFLocaleUnlockGlobal(); |
| CFRelease(localeIdentifier); |
| return locale; |
| } |
| } |
| struct __CFLocale *locale = NULL; |
| uint32_t size = sizeof(struct __CFLocale) - sizeof(CFRuntimeBase); |
| locale = (struct __CFLocale *)_CFRuntimeCreateInstance(allocator, CFLocaleGetTypeID(), size, NULL); |
| if (NULL == locale) { |
| return NULL; |
| } |
| __CFLocaleSetType(locale, __kCFLocaleOrdinary); |
| locale->_identifier = localeIdentifier; |
| locale->_cache = CFDictionaryCreateMutable(allocator, 0, NULL, &kCFTypeDictionaryValueCallBacks); |
| locale->_overrides = NULL; |
| locale->_prefs = NULL; |
| |
| CF_SPINLOCK_INIT_FOR_STRUCTS(locale->_lock); |
| |
| if (canCache) { |
| if (NULL == __CFLocaleCache) { |
| __CFLocaleCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
| } |
| CFDictionarySetValue(__CFLocaleCache, localeIdentifier, locale); |
| } |
| __CFLocaleUnlockGlobal(); |
| return (CFLocaleRef)locale; |
| } |
| |
| CFLocaleRef CFLocaleCreateCopy(CFAllocatorRef allocator, CFLocaleRef locale) { |
| return (CFLocaleRef)CFRetain(locale); |
| } |
| |
| CFStringRef CFLocaleGetIdentifier(CFLocaleRef locale) { |
| CF_OBJC_FUNCDISPATCH0(CFLocaleGetTypeID(), CFStringRef, locale, "localeIdentifier"); |
| return locale->_identifier; |
| } |
| |
| CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key) { |
| CF_OBJC_FUNCDISPATCH1(CFLocaleGetTypeID(), CFTypeRef, locale, "objectForKey:", key); |
| CFIndex idx, slot = -1; |
| for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { |
| if (__CFLocaleKeyTable[idx].key == key) { |
| slot = idx; |
| break; |
| } |
| } |
| if (-1 == slot && NULL != key) { |
| for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { |
| if (CFEqual(__CFLocaleKeyTable[idx].key, key)) { |
| slot = idx; |
| break; |
| } |
| } |
| } |
| if (-1 == slot) { |
| return NULL; |
| } |
| CFTypeRef value; |
| if (NULL != locale->_overrides && CFDictionaryGetValueIfPresent(locale->_overrides, __CFLocaleKeyTable[slot].key, &value)) { |
| return value; |
| } |
| __CFLocaleLock(locale); |
| if (CFDictionaryGetValueIfPresent(locale->_cache, __CFLocaleKeyTable[slot].key, &value)) { |
| __CFLocaleUnlock(locale); |
| return value; |
| } |
| if (__kCFLocaleUser == __CFLocaleGetType(locale) && __CFLocaleKeyTable[slot].get(locale, true, &value, __CFLocaleKeyTable[slot].context)) { |
| if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value); |
| if (value) CFRelease(value); |
| __CFLocaleUnlock(locale); |
| return value; |
| } |
| if (__CFLocaleKeyTable[slot].get(locale, false, &value, __CFLocaleKeyTable[slot].context)) { |
| if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value); |
| if (value) CFRelease(value); |
| __CFLocaleUnlock(locale); |
| return value; |
| } |
| __CFLocaleUnlock(locale); |
| return NULL; |
| } |
| |
| CFStringRef CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale, CFStringRef key, CFStringRef value) { |
| CF_OBJC_FUNCDISPATCH2(CFLocaleGetTypeID(), CFStringRef, displayLocale, "_copyDisplayNameForKey:value:", key, value); |
| CFIndex idx, slot = -1; |
| for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { |
| if (__CFLocaleKeyTable[idx].key == key) { |
| slot = idx; |
| break; |
| } |
| } |
| if (-1 == slot && NULL != key) { |
| for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { |
| if (CFEqual(__CFLocaleKeyTable[idx].key, key)) { |
| slot = idx; |
| break; |
| } |
| } |
| } |
| if (-1 == slot || !value) { |
| return NULL; |
| } |
| // Get the locale ID as a C string |
| char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; |
| char cValue[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; |
| if (CFStringGetCString(displayLocale->_identifier, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII) && CFStringGetCString(value, cValue, sizeof(cValue)/sizeof(char), kCFStringEncodingASCII)) { |
| CFStringRef result; |
| if ((NULL == displayLocale->_prefs) && __CFLocaleKeyTable[slot].name(localeID, cValue, &result)) { |
| return result; |
| } |
| |
| // We could not find a result using the requested language. Fall back through all preferred languages. |
| CFArrayRef langPref; |
| if (displayLocale->_prefs) { |
| langPref = (CFArrayRef)CFDictionaryGetValue(displayLocale->_prefs, CFSTR("AppleLanguages")); |
| if (langPref) CFRetain(langPref); |
| } else { |
| langPref = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); |
| } |
| if (langPref != NULL) { |
| CFIndex count = CFArrayGetCount(langPref); |
| CFIndex i; |
| bool success = false; |
| for (i = 0; i < count && !success; ++i) { |
| CFStringRef language = (CFStringRef)CFArrayGetValueAtIndex(langPref, i); |
| CFStringRef cleanLanguage = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, language); |
| if (CFStringGetCString(cleanLanguage, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII)) { |
| success = __CFLocaleKeyTable[slot].name(localeID, cValue, &result); |
| } |
| CFRelease(cleanLanguage); |
| } |
| CFRelease(langPref); |
| if (success) |
| return result; |
| } |
| } |
| return NULL; |
| } |
| |
| CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void) { |
| int32_t locale, localeCount = uloc_countAvailable(); |
| CFMutableSetRef working = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); |
| for (locale = 0; locale < localeCount; ++locale) { |
| const char *localeID = uloc_getAvailable(locale); |
| CFStringRef string1 = CFStringCreateWithCString(kCFAllocatorSystemDefault, localeID, kCFStringEncodingASCII); |
| CFStringRef string2 = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, string1); |
| CFSetAddValue(working, string1); |
| // do not include canonicalized version as IntlFormats cannot cope with that in its popup |
| CFRelease(string1); |
| CFRelease(string2); |
| } |
| CFIndex cnt = CFSetGetCount(working); |
| #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || (DEPLOYMENT_TARGET_WINDOWS && __GNUC__) |
| STACK_BUFFER_DECL(const void *, buffer, cnt); |
| #else |
| const void* buffer[BUFFER_SIZE]; |
| #endif |
| CFSetGetValues(working, buffer); |
| CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, buffer, cnt, &kCFTypeArrayCallBacks); |
| CFRelease(working); |
| return result; |
| } |
| |
| static CFArrayRef __CFLocaleCopyCStringsAsArray(const char* const* p) { |
| CFMutableArrayRef working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); |
| for (; *p; ++p) { |
| CFStringRef string = CFStringCreateWithCString(kCFAllocatorSystemDefault, *p, kCFStringEncodingASCII); |
| CFArrayAppendValue(working, string); |
| CFRelease(string); |
| } |
| CFArrayRef result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working); |
| CFRelease(working); |
| return result; |
| } |
| |
| static CFArrayRef __CFLocaleCopyUEnumerationAsArray(UEnumeration *enumer, UErrorCode *icuErr) { |
| const UChar *next = NULL; |
| int32_t len = 0; |
| CFMutableArrayRef working = NULL; |
| if (U_SUCCESS(*icuErr)) { |
| working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); |
| } |
| while ((next = uenum_unext(enumer, &len, icuErr)) && U_SUCCESS(*icuErr)) { |
| CFStringRef string = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)next, (CFIndex) len); |
| CFArrayAppendValue(working, string); |
| CFRelease(string); |
| } |
| if (*icuErr == U_INDEX_OUTOFBOUNDS_ERROR) { |
| *icuErr = U_ZERO_ERROR; // Temp: Work around bug (ICU 5220) in ucurr enumerator |
| } |
| CFArrayRef result = NULL; |
| if (U_SUCCESS(*icuErr)) { |
| result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working); |
| } |
| if (working != NULL) { |
| CFRelease(working); |
| } |
| return result; |
| } |
| |
| CFArrayRef CFLocaleCopyISOLanguageCodes(void) { |
| const char* const* p = uloc_getISOLanguages(); |
| return __CFLocaleCopyCStringsAsArray(p); |
| } |
| |
| CFArrayRef CFLocaleCopyISOCountryCodes(void) { |
| const char* const* p = uloc_getISOCountries(); |
| return __CFLocaleCopyCStringsAsArray(p); |
| } |
| |
| CFArrayRef CFLocaleCopyISOCurrencyCodes(void) { |
| UErrorCode icuStatus = U_ZERO_ERROR; |
| UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_ALL, &icuStatus); |
| CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus); |
| uenum_close(enumer); |
| return result; |
| } |
| |
| CFArrayRef CFLocaleCopyCommonISOCurrencyCodes(void) { |
| UErrorCode icuStatus = U_ZERO_ERROR; |
| UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &icuStatus); |
| CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus); |
| uenum_close(enumer); |
| return result; |
| } |
| |
| CFArrayRef CFLocaleCopyPreferredLanguages(void) { |
| CFMutableArrayRef newArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); |
| |
| #if DEPLOYMENT_TARGET_WINDOWS |
| LANGID langId = GetUserDefaultLangID(); |
| CFStringRef lang_name = __CFLocaleWindowsLCIDToISOLocaleName(langId); |
| CFArrayAppendValue(newArray, lang_name); |
| #else |
| CFArrayRef languagesArray = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); |
| if (languagesArray && (CFArrayGetTypeID() == CFGetTypeID(languagesArray))) { |
| for (CFIndex idx = 0, cnt = CFArrayGetCount(languagesArray); idx < cnt; idx++) { |
| CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(languagesArray, idx); |
| if (str && (CFStringGetTypeID() == CFGetTypeID(str))) { |
| CFStringRef ident = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, str); |
| CFArrayAppendValue(newArray, ident); |
| CFRelease(ident); |
| } |
| } |
| } |
| if (languagesArray) CFRelease(languagesArray); |
| #endif |
| return newArray; |
| } |
| |
| // -------- -------- -------- -------- -------- -------- |
| |
| // These functions return true or false depending on the success or failure of the function. |
| // In the Copy case, this is failure to fill the *cf out parameter, and that out parameter is |
| // returned by reference WITH a retain on it. |
| static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context) { |
| return false; |
| } |
| |
| static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { |
| *cf = CFRetain(locale->_identifier); |
| return true; |
| } |
| |
| |
| static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { |
| CFDictionaryRef codes = NULL; |
| // this access of _cache is protected by the lock in CFLocaleGetValue() |
| if (!CFDictionaryGetValueIfPresent(locale->_cache, CFSTR("__kCFLocaleCodes"), (const void **)&codes)) { |
| codes = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, locale->_identifier); |
| if (codes) CFDictionarySetValue(locale->_cache, CFSTR("__kCFLocaleCodes"), codes); |
| if (codes) CFRelease(codes); |
| } |
| if (codes) { |
| CFStringRef value = (CFStringRef)CFDictionaryGetValue(codes, context); // context is one of kCFLocale*Code constants |
| if (value) CFRetain(value); |
| *cf = value; |
| return true; |
| } |
| return false; |
| } |
| |
| CFCharacterSetRef _CFCreateCharacterSetFromUSet(USet *set) { |
| UErrorCode icuErr = U_ZERO_ERROR; |
| CFMutableCharacterSetRef working = CFCharacterSetCreateMutable(NULL); |
| UChar buffer[2048]; // Suitable for most small sets |
| int32_t stringLen; |
| |
| if (working == NULL) |
| return NULL; |
| |
| int32_t itemCount = uset_getItemCount(set); |
| int32_t i; |
| for (i = 0; i < itemCount; ++i) |
| { |
| UChar32 start, end; |
| UChar * string; |
| |
| string = buffer; |
| stringLen = uset_getItem(set, i, &start, &end, buffer, sizeof(buffer)/sizeof(UChar), &icuErr); |
| if (icuErr == U_BUFFER_OVERFLOW_ERROR) |
| { |
| string = (UChar *) malloc(sizeof(UChar)*(stringLen+1)); |
| if (!string) |
| { |
| CFRelease(working); |
| return NULL; |
| } |
| icuErr = U_ZERO_ERROR; |
| (void) uset_getItem(set, i, &start, &end, string, stringLen+1, &icuErr); |
| } |
| if (U_FAILURE(icuErr)) |
| { |
| if (string != buffer) |
| free(string); |
| CFRelease(working); |
| return NULL; |
| } |
| if (stringLen <= 0) |
| CFCharacterSetAddCharactersInRange(working, CFRangeMake(start, end-start+1)); |
| else |
| { |
| CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, (UniChar *)string, stringLen, kCFAllocatorNull); |
| CFCharacterSetAddCharactersInString(working, cfString); |
| CFRelease(cfString); |
| } |
| if (string != buffer) |
| free(string); |
| } |
| |
| CFCharacterSetRef result = CFCharacterSetCreateCopy(kCFAllocatorSystemDefault, working); |
| CFRelease(working); |
| return result; |
| } |
| |
| |
| static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { |
| char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; |
| if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { |
| UErrorCode icuStatus = U_ZERO_ERROR; |
| ULocaleData* uld = ulocdata_open(localeID, &icuStatus); |
| USet *set = ulocdata_getExemplarSet(uld, NULL, USET_ADD_CASE_MAPPINGS, ULOCDATA_ES_STANDARD, &icuStatus); |
| ulocdata_close(uld); |
| if (U_FAILURE(icuStatus)) |
| return false; |
| if (icuStatus == U_USING_DEFAULT_WARNING) // If default locale used, force to empty set |
| uset_clear(set); |
| *cf = (CFTypeRef) _CFCreateCharacterSetFromUSet(set); |
| uset_close(set); |
| return (*cf != NULL); |
| } |
| return false; |
| } |
| |
| static bool __CFLocaleCopyICUKeyword(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context, const char *keyword) |
| { |
| char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; |
| if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) |
| { |
| char value[ULOC_KEYWORD_AND_VALUES_CAPACITY]; |
| UErrorCode icuStatus = U_ZERO_ERROR; |
| if (uloc_getKeywordValue(localeID, keyword, value, sizeof(value)/sizeof(char), &icuStatus) > 0 && U_SUCCESS(icuStatus)) |
| { |
| *cf = (CFTypeRef) CFStringCreateWithCString(kCFAllocatorSystemDefault, value, kCFStringEncodingASCII); |
| return true; |
| } |
| } |
| *cf = NULL; |
| return false; |
| } |
| |
| static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { |
| bool succeeded = __CFLocaleCopyICUKeyword(locale, user, cf, context, kCalendarKeyword); |
| if (succeeded) { |
| if (CFEqual(*cf, kCFGregorianCalendar)) { |
| CFRelease(*cf); |
| *cf = CFRetain(kCFGregorianCalendar); |
| } else if (CFEqual(*cf, kCFBuddhistCalendar)) { |
| CFRelease(*cf); |
| *cf = CFRetain(kCFBuddhistCalendar); |
| } else if (CFEqual(*cf, kCFJapaneseCalendar)) { |
| CFRelease(*cf); |
| *cf = CFRetain(kCFJapaneseCalendar); |
| } else if (CFEqual(*cf, kCFIslamicCalendar)) { |
| CFRelease(*cf); |
| *cf = CFRetain(kCFIslamicCalendar); |
| } else if (CFEqual(*cf, kCFIslamicCivilCalendar)) { |
| CFRelease(*cf); |
| *cf = CFRetain(kCFIslamicCivilCalendar); |
| } else if (CFEqual(*cf, kCFHebrewCalendar)) { |
| CFRelease(*cf); |
| *cf = CFRetain(kCFHebrewCalendar); |
| } else if (CFEqual(*cf, kCFChineseCalendar)) { |
| CFRelease(*cf); |
| *cf = CFRetain(kCFChineseCalendar); |
| } |
| } else { |
| *cf = CFRetain(kCFGregorianCalendar); |
| } |
| return true; |
| } |
| |
| static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { |
| if (__CFLocaleCopyCalendarID(locale, user, cf, context)) { |
| CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, (CFStringRef)*cf); |
| CFCalendarSetLocale(calendar, locale); |
| CFRelease(*cf); |
| *cf = calendar; |
| return true; |
| } |
| return false; |
| } |
| |
| static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { |
| return __CFLocaleCopyICUKeyword(locale, user, cf, context, kCollationKeyword); |
| } |
| |
| static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { |
| CFStringRef canonLocaleCFStr = NULL; |
| if (!canonLocaleCFStr) { |
| canonLocaleCFStr = CFLocaleGetIdentifier(locale); |
| CFRetain(canonLocaleCFStr); |
| } |
| *cf = canonLocaleCFStr; |
| return canonLocaleCFStr ? true : false; |
| } |
| |
| static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { |
| bool us = false; // Default is Metric |
| bool done = false; |
| |
| if (!done) { |
| char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; |
| if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { |
| UErrorCode icuStatus = U_ZERO_ERROR; |
| UMeasurementSystem ms = UMS_SI; |
| ms = ulocdata_getMeasurementSystem(localeID, &icuStatus); |
| if (U_SUCCESS(icuStatus)) { |
| us = (ms == UMS_US); |
| done = true; |
| } |
| } |
| } |
| if (!done) |
| us = false; |
| *cf = us ? CFRetain(kCFBooleanFalse) : CFRetain(kCFBooleanTrue); |
| return true; |
| } |
| |
| static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { |
| if (__CFLocaleCopyUsesMetric(locale, user, cf, context)) { |
| bool us = (*cf == kCFBooleanFalse); |
| CFRelease(*cf); |
| *cf = us ? CFRetain(CFSTR("U.S.")) : CFRetain(CFSTR("Metric")); |
| return true; |
| } |
| return false; |
| } |
| |
| static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { |
| CFStringRef str = NULL; |
| CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterDecimalStyle); |
| str = nf ? (CFStringRef)CFNumberFormatterCopyProperty(nf, context) : NULL; |
| if (nf) CFRelease(nf); |
| if (str) { |
| *cf = str; |
| return true; |
| } |
| return false; |
| } |
| |
| // ICU does not reliably set up currency info for other than Currency-type formatters, |
| // so we have to have another routine here which creates a Currency number formatter. |
| static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { |
| CFStringRef str = NULL; |
| CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterCurrencyStyle); |
| str = nf ? (CFStringRef)CFNumberFormatterCopyProperty(nf, context) : NULL; |
| if (nf) CFRelease(nf); |
| if (str) { |
| *cf = str; |
| return true; |
| } |
| return false; |
| } |
| |
| typedef int32_t (*__CFICUFunction)(const char *, const char *, UChar *, int32_t, UErrorCode *); |
| |
| static bool __CFLocaleICUName(const char *locale, const char *valLocale, CFStringRef *out, __CFICUFunction icu) { |
| UErrorCode icuStatus = U_ZERO_ERROR; |
| int32_t size; |
| UChar name[kMaxICUNameSize]; |
| |
| size = (*icu)(valLocale, locale, name, kMaxICUNameSize, &icuStatus); |
| if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) { |
| *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); |
| return (*out != NULL); |
| } |
| return false; |
| } |
| |
| static bool __CFLocaleICUKeywordValueName(const char *locale, const char *value, const char *keyword, CFStringRef *out) { |
| UErrorCode icuStatus = U_ZERO_ERROR; |
| int32_t size = 0; |
| UChar name[kMaxICUNameSize]; |
| // Need to make a fake locale ID |
| char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; |
| if (strlen(value) < ULOC_KEYWORD_AND_VALUES_CAPACITY) { |
| snprintf(lid, sizeof(lid), "en_US@%s=%s", keyword, value); |
| size = uloc_getDisplayKeywordValue(lid, keyword, locale, name, kMaxICUNameSize, &icuStatus); |
| if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) { |
| *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); |
| return (*out != NULL); |
| } |
| } |
| return false; |
| } |
| |
| static bool __CFLocaleICUCurrencyName(const char *locale, const char *value, UCurrNameStyle style, CFStringRef *out) { |
| size_t valLen = strlen(value); |
| if (valLen != 3) // not a valid ISO code |
| return false; |
| UChar curr[4]; |
| UBool isChoice = FALSE; |
| int32_t size = 0; |
| UErrorCode icuStatus = U_ZERO_ERROR; |
| u_charsToUChars(value, curr, (int32_t)valLen); |
| curr[valLen] = '\0'; |
| const UChar *name; |
| name = ucurr_getName(curr, locale, style, &isChoice, &size, &icuStatus); |
| if (U_FAILURE(icuStatus) || icuStatus == U_USING_DEFAULT_WARNING) |
| return false; |
| UChar result[kMaxICUNameSize]; |
| if (isChoice) |
| { |
| UChar pattern[kMaxICUNameSize]; |
| CFStringRef patternRef = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{0,choice,%S}"), name); |
| CFIndex pattlen = CFStringGetLength(patternRef); |
| CFStringGetCharacters(patternRef, CFRangeMake(0, pattlen), (UniChar *)pattern); |
| CFRelease(patternRef); |
| pattern[pattlen] = '\0'; // null terminate the pattern |
| // Format the message assuming a large amount of the currency |
| size = u_formatMessage("en_US", pattern, pattlen, result, kMaxICUNameSize, &icuStatus, 10.0); |
| if (U_FAILURE(icuStatus)) |
| return false; |
| name = result; |
| |
| } |
| *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); |
| return (*out != NULL); |
| } |
| |
| static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out) { |
| UErrorCode icuStatus = U_ZERO_ERROR; |
| int32_t size; |
| UChar name[kMaxICUNameSize]; |
| |
| // First, try to get the full locale. |
| size = uloc_getDisplayName(value, locale, name, kMaxICUNameSize, &icuStatus); |
| if (U_FAILURE(icuStatus) || size <= 0) |
| return false; |
| |
| // Did we wind up using a default somewhere? |
| if (icuStatus == U_USING_DEFAULT_WARNING) { |
| // For some locale IDs, there may be no language which has a translation for every |
| // piece. Rather than return nothing, see if we can at least handle |
| // the language part of the locale. |
| UErrorCode localStatus = U_ZERO_ERROR; |
| int32_t localSize; |
| UChar localName[kMaxICUNameSize]; |
| localSize = uloc_getDisplayLanguage(value, locale, localName, kMaxICUNameSize, &localStatus); |
| if (U_FAILURE(localStatus) || size <= 0 || localStatus == U_USING_DEFAULT_WARNING) |
| return false; |
| } |
| |
| // This locale is OK, so use the result. |
| *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); |
| return (*out != NULL); |
| } |
| |
| static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out) { |
| size_t len = strlen(value); |
| if (len >= 2 && len <= 3) |
| return __CFLocaleICUName(locale, value, out, uloc_getDisplayLanguage); |
| return false; |
| } |
| |
| static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out) { |
| // Need to make a fake locale ID |
| char lid[ULOC_FULLNAME_CAPACITY]; |
| if (strlen(value) == 2) { |
| snprintf(lid, sizeof(lid), "en_%s", value); |
| return __CFLocaleICUName(locale, lid, out, uloc_getDisplayCountry); |
| } |
| return false; |
| } |
| |
| static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out) { |
| // Need to make a fake locale ID |
| char lid[ULOC_FULLNAME_CAPACITY]; |
| if (strlen(value) == 4) { |
| snprintf(lid, sizeof(lid), "en_%s_US", value); |
| return __CFLocaleICUName(locale, lid, out, uloc_getDisplayScript); |
| } |
| return false; |
| } |
| |
| static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out) { |
| // Need to make a fake locale ID |
| char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; |
| if (strlen(value) < ULOC_FULLNAME_CAPACITY) { |
| snprintf(lid, sizeof(lid), "en_US_%s", value); |
| return __CFLocaleICUName(locale, lid, out, uloc_getDisplayVariant); |
| } |
| return false; |
| } |
| |
| static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out) { |
| return __CFLocaleICUKeywordValueName(locale, value, kCalendarKeyword, out); |
| } |
| |
| static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out) { |
| return __CFLocaleICUKeywordValueName(locale, value, kCollationKeyword, out); |
| } |
| |
| static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out) { |
| return __CFLocaleICUCurrencyName(locale, value, UCURR_SYMBOL_NAME, out); |
| } |
| |
| static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out) { |
| return __CFLocaleICUCurrencyName(locale, value, UCURR_LONG_NAME, out); |
| } |
| |
| static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out) { |
| return false; |
| } |
| |
| // Remember to keep the names such that they would make sense for the user locale, |
| // in addition to the others; for example, it is "Currency", not "DefaultCurrency". |
| // (And besides, "Default" is almost always implied.) Words like "Default" and |
| // "Preferred" and so on should be left out of the names. |
| CONST_STRING_DECL(kCFLocaleIdentifier, "locale:id") |
| CONST_STRING_DECL(kCFLocaleLanguageCode, "locale:language code") |
| CONST_STRING_DECL(kCFLocaleCountryCode, "locale:country code") |
| CONST_STRING_DECL(kCFLocaleScriptCode, "locale:script code") |
| CONST_STRING_DECL(kCFLocaleVariantCode, "locale:variant code") |
| CONST_STRING_DECL(kCFLocaleExemplarCharacterSet, "locale:exemplar characters") |
| CONST_STRING_DECL(kCFLocaleCalendarIdentifier, "calendar") |
| CONST_STRING_DECL(kCFLocaleCalendar, "locale:calendarref") |
| CONST_STRING_DECL(kCFLocaleCollationIdentifier, "collation") |
| CONST_STRING_DECL(kCFLocaleUsesMetricSystem, "locale:uses metric") |
| CONST_STRING_DECL(kCFLocaleMeasurementSystem, "locale:measurement system") |
| CONST_STRING_DECL(kCFLocaleDecimalSeparator, "locale:decimal separator") |
| CONST_STRING_DECL(kCFLocaleGroupingSeparator, "locale:grouping separator") |
| CONST_STRING_DECL(kCFLocaleCurrencySymbol, "locale:currency symbol") |
| CONST_STRING_DECL(kCFLocaleCurrencyCode, "currency") |
| |
| CONST_STRING_DECL(kCFGregorianCalendar, "gregorian") |
| CONST_STRING_DECL(kCFBuddhistCalendar, "buddhist") |
| CONST_STRING_DECL(kCFJapaneseCalendar, "japanese") |
| CONST_STRING_DECL(kCFIslamicCalendar, "islamic") |
| CONST_STRING_DECL(kCFIslamicCivilCalendar, "islamic-civil") |
| CONST_STRING_DECL(kCFHebrewCalendar, "hebrew") |
| CONST_STRING_DECL(kCFChineseCalendar, "chinese") |
| |
| #undef kMaxICUNameSize |
| |