183a171d1a62abf406f7f44ae671823d5ec20db7dCraig Cornelius/* 2ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru ******************************************************************************* 3f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius * Copyright (C) 2002-2014, International Business Machines Corporation and 427f654740f2a26ad62a5c155af9199af9e69b889claireho * others. All Rights Reserved. 5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru ******************************************************************************* 6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */ 7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/utypes.h" 8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#if !UCONFIG_NO_SERVICE || !UCONFIG_NO_TRANSLITERATION 10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/resbund.h" 12ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "cmemory.h" 13ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "ustrfmt.h" 14ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "locutil.h" 15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "charstr.h" 16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "ucln_cmn.h" 17ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "uassert.h" 18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "umutex.h" 19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 20ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// see LocaleUtility::getAvailableLocaleNames 21f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusstatic icu::UInitOnce LocaleUtilityInitOnce = U_INITONCE_INITIALIZER; 2283a171d1a62abf406f7f44ae671823d5ec20db7dCraig Corneliusstatic icu::Hashtable * LocaleUtility_cache = NULL; 23ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 24ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define UNDERSCORE_CHAR ((UChar)0x005f) 25ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define AT_SIGN_CHAR ((UChar)64) 26ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define PERIOD_CHAR ((UChar)46) 27ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 28ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/* 29ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru ****************************************************************** 30ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */ 31ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/** 33ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Release all static memory held by Locale Utility. 34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */ 35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_CDECL_BEGIN 36ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic UBool U_CALLCONV service_cleanup(void) { 37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (LocaleUtility_cache) { 38ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru delete LocaleUtility_cache; 39ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru LocaleUtility_cache = NULL; 40ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 41ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return TRUE; 42ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 43f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 44f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 45f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusstatic void U_CALLCONV locale_utility_init(UErrorCode &status) { 46f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius using namespace icu; 47f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius U_ASSERT(LocaleUtility_cache == NULL); 48f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius ucln_common_registerCleanup(UCLN_COMMON_SERVICE, service_cleanup); 49f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius LocaleUtility_cache = new Hashtable(status); 50f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius if (U_FAILURE(status)) { 51f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius delete LocaleUtility_cache; 52f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius LocaleUtility_cache = NULL; 53f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return; 54f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 55f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius if (LocaleUtility_cache == NULL) { 56f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius status = U_MEMORY_ALLOCATION_ERROR; 57f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return; 58f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 59f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius LocaleUtility_cache->setValueDeleter(uhash_deleteHashtable); 60f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius} 61f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius 62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_CDECL_END 63ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 64ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_BEGIN 65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUnicodeString& 67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruLocaleUtility::canonicalLocaleString(const UnicodeString* id, UnicodeString& result) 68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (id == NULL) { 70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru result.setToBogus(); 71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } else { 72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // Fix case only (no other changes) up to the first '@' or '.' or 73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // end of string, whichever comes first. In 3.0 I changed this to 74ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // stop at first '@' or '.'. It used to run out to the end of 75ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // string. My fix makes the tests pass but is probably 76ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // structurally incorrect. See below. [alan 3.0] 77ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 78ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // TODO: Doug, you might want to revise this... 79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru result = *id; 80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru int32_t i = 0; 81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru int32_t end = result.indexOf(AT_SIGN_CHAR); 82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru int32_t n = result.indexOf(PERIOD_CHAR); 83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (n >= 0 && n < end) { 84ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru end = n; 85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (end < 0) { 87ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru end = result.length(); 88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru n = result.indexOf(UNDERSCORE_CHAR); 90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (n < 0) { 91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru n = end; 92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 93ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru for (; i < n; ++i) { 94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru UChar c = result.charAt(i); 95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (c >= 0x0041 && c <= 0x005a) { 96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru c += 0x20; 97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru result.setCharAt(i, c); 98ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru for (n = end; i < n; ++i) { 101ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru UChar c = result.charAt(i); 102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (c >= 0x0061 && c <= 0x007a) { 103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru c -= 0x20; 104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru result.setCharAt(i, c); 105ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return result; 109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 110ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#if 0 111ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // This code does a proper full level 2 canonicalization of id. 112ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // It's nasty to go from UChar to char to char to UChar -- but 113ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // that's what you have to do to use the uloc_canonicalize 114ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // function on UnicodeStrings. 115ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 116ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // I ended up doing the alternate fix (see above) not for 117ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // performance reasons, although performance will certainly be 118ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // better, but because doing a full level 2 canonicalization 119ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // causes some tests to fail. [alan 3.0] 120ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // TODO: Doug, you might want to revisit this... 122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru result.setToBogus(); 123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (id != 0) { 124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru int32_t buflen = id->length() + 8; // space for NUL 125ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru char* buf = (char*) uprv_malloc(buflen); 126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru char* canon = (buf == 0) ? 0 : (char*) uprv_malloc(buflen); 127ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (buf != 0 && canon != 0) { 128ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru U_ASSERT(id->extract(0, INT32_MAX, buf, buflen) < buflen); 129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru UErrorCode ec = U_ZERO_ERROR; 130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uloc_canonicalize(buf, canon, buflen, &ec); 131ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (U_SUCCESS(ec)) { 132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru result = UnicodeString(canon); 133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uprv_free(buf); 136ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uprv_free(canon); 137ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 138ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return result; 139ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#endif 140ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 141ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 142ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruLocale& 143ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruLocaleUtility::initLocaleFromName(const UnicodeString& id, Locale& result) 144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 145ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru enum { BUFLEN = 128 }; // larger than ever needed 146ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 147ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (id.isBogus() || id.length() >= BUFLEN) { 148ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru result.setToBogus(); 149ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } else { 150ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru /* 151ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * We need to convert from a UnicodeString to char * in order to 152ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * create a Locale. 153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * 154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Problem: Locale ID strings may contain '@' which is a variant 155ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * character and cannot be handled by invariant-character conversion. 156ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * 157ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Hack: Since ICU code can handle locale IDs with multiple encodings 158ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * of '@' (at least for EBCDIC; it's not known to be a problem for 159ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * ASCII-based systems), 160ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * we use regular invariant-character conversion for everything else 161ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * and manually convert U+0040 into a compiler-char-constant '@'. 162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * While this compilation-time constant may not match the runtime 163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * encoding of '@', it should be one of the encodings which ICU 164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * recognizes. 165ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * 166ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * There should be only at most one '@' in a locale ID. 167ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */ 168ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru char buffer[BUFLEN]; 169ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru int32_t prev, i; 170ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru prev = 0; 171ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru for(;;) { 172ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru i = id.indexOf((UChar)0x40, prev); 173ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if(i < 0) { 174ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // no @ between prev and the rest of the string 175ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru id.extract(prev, INT32_MAX, buffer + prev, BUFLEN - prev, US_INV); 176ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru break; // done 177ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } else { 178ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // normal invariant-character conversion for text between @s 179ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru id.extract(prev, i - prev, buffer + prev, BUFLEN - prev, US_INV); 180ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // manually "convert" U+0040 at id[i] into '@' at buffer[i] 181ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru buffer[i] = '@'; 182ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru prev = i + 1; 183ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 184ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 185ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru result = Locale::createFromName(buffer); 186ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 187ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return result; 188ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 189ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 190ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUnicodeString& 191ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruLocaleUtility::initNameFromLocale(const Locale& locale, UnicodeString& result) 192ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 193ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (locale.isBogus()) { 194ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru result.setToBogus(); 195ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } else { 196ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru result.append(UnicodeString(locale.getName(), -1, US_INV)); 197ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 198ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return result; 199ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 200ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 201ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruconst Hashtable* 202ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruLocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID) 203ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 204ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // LocaleUtility_cache is a hash-of-hashes. The top-level keys 205ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // are path strings ('bundleID') passed to 206ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // ures_openAvailableLocales. The top-level values are 207ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // second-level hashes. The second-level keys are result strings 208ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // from ures_openAvailableLocales. The second-level values are 209ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru // garbage ((void*)1 or other random pointer). 210ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 211ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru UErrorCode status = U_ZERO_ERROR; 212f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius umtx_initOnce(LocaleUtilityInitOnce, locale_utility_init, status); 213f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius Hashtable *cache = LocaleUtility_cache; 214ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (cache == NULL) { 215f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius // Catastrophic failure. 216f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius return NULL; 217ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 218ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 219ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru Hashtable* htp; 220ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru umtx_lock(NULL); 221ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru htp = (Hashtable*) cache->get(bundleID); 222ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru umtx_unlock(NULL); 223ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 224ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (htp == NULL) { 225ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru htp = new Hashtable(status); 226ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (htp && U_SUCCESS(status)) { 22727f654740f2a26ad62a5c155af9199af9e69b889claireho CharString cbundleID; 22827f654740f2a26ad62a5c155af9199af9e69b889claireho cbundleID.appendInvariantChars(bundleID, status); 22927f654740f2a26ad62a5c155af9199af9e69b889claireho const char* path = cbundleID.isEmpty() ? NULL : cbundleID.data(); 230ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru UEnumeration *uenum = ures_openAvailableLocales(path, &status); 231ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru for (;;) { 232ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru const UChar* id = uenum_unext(uenum, NULL, &status); 233ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (id == NULL) { 234ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru break; 235ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 236ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru htp->put(UnicodeString(id), (void*)htp, status); 237ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 238ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru uenum_close(uenum); 239ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru if (U_FAILURE(status)) { 240ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru delete htp; 241ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return NULL; 242ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 243ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru umtx_lock(NULL); 244f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius Hashtable *t = static_cast<Hashtable *>(cache->get(bundleID)); 245f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius if (t != NULL) { 246f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius // Another thread raced through this code, creating the cache entry first. 247f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius // Discard ours and return theirs. 248f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius umtx_unlock(NULL); 249f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius delete htp; 250f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius htp = t; 251f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } else { 252f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius cache->put(bundleID, (void*)htp, status); 253f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius umtx_unlock(NULL); 254f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius } 255ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 256ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru } 257ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return htp; 258ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 259ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 260ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool 261ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruLocaleUtility::isFallbackOf(const UnicodeString& root, const UnicodeString& child) 262ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru{ 263ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru return child.indexOf(root) == 0 && 264ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru (child.length() == root.length() || 265ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru child.charAt(root.length()) == UNDERSCORE_CHAR); 266ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru} 267ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 268ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_END 269ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 270ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/* !UCONFIG_NO_SERVICE */ 271ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#endif 272ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 273ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru 274