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