16f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/*
26f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *******************************************************************************
36f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Copyright (C) 2002-2011, International Business Machines Corporation and
46f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * others. All Rights Reserved.
56f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org *******************************************************************************
66f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
76f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/utypes.h"
86f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
96f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if !UCONFIG_NO_SERVICE || !UCONFIG_NO_TRANSLITERATION
106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "unicode/resbund.h"
126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "cmemory.h"
136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "ustrfmt.h"
146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "locutil.h"
156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "charstr.h"
166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "ucln_cmn.h"
176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "uassert.h"
186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#include "umutex.h"
196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org// see LocaleUtility::getAvailableLocaleNames
216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic icu::Hashtable * LocaleUtility_cache = NULL;
226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define UNDERSCORE_CHAR ((UChar)0x005f)
246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define AT_SIGN_CHAR    ((UChar)64)
256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#define PERIOD_CHAR     ((UChar)46)
266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/*
286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org ******************************************************************
296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/**
326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org * Release all static memory held by Locale Utility.
336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org */
346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CDECL_BEGIN
356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgstatic UBool U_CALLCONV service_cleanup(void) {
366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (LocaleUtility_cache) {
376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        delete LocaleUtility_cache;
386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        LocaleUtility_cache = NULL;
396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return TRUE;
416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_CDECL_END
436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_NAMESPACE_BEGIN
456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgLocaleUtility::canonicalLocaleString(const UnicodeString* id, UnicodeString& result)
486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  if (id == NULL) {
506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    result.setToBogus();
516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  } else {
526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // Fix case only (no other changes) up to the first '@' or '.' or
536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // end of string, whichever comes first.  In 3.0 I changed this to
546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // stop at first '@' or '.'.  It used to run out to the end of
556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // string.  My fix makes the tests pass but is probably
566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // structurally incorrect.  See below.  [alan 3.0]
576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // TODO: Doug, you might want to revise this...
596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    result = *id;
606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t i = 0;
616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t end = result.indexOf(AT_SIGN_CHAR);
626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    int32_t n = result.indexOf(PERIOD_CHAR);
636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (n >= 0 && n < end) {
646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        end = n;
656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (end < 0) {
676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        end = result.length();
686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    n = result.indexOf(UNDERSCORE_CHAR);
706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (n < 0) {
716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      n = end;
726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (; i < n; ++i) {
746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      UChar c = result.charAt(i);
756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      if (c >= 0x0041 && c <= 0x005a) {
766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        c += 0x20;
776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        result.setCharAt(i, c);
786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      }
796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    for (n = end; i < n; ++i) {
816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      UChar c = result.charAt(i);
826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      if (c >= 0x0061 && c <= 0x007a) {
836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        c -= 0x20;
846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        result.setCharAt(i, c);
856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      }
866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  }
886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org  return result;
896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#if 0
916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // This code does a proper full level 2 canonicalization of id.
926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // It's nasty to go from UChar to char to char to UChar -- but
936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // that's what you have to do to use the uloc_canonicalize
946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // function on UnicodeStrings.
956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // I ended up doing the alternate fix (see above) not for
976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // performance reasons, although performance will certainly be
986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // better, but because doing a full level 2 canonicalization
996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // causes some tests to fail.  [alan 3.0]
1006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // TODO: Doug, you might want to revisit this...
1026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    result.setToBogus();
1036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (id != 0) {
1046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t buflen = id->length() + 8; // space for NUL
1056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        char* buf = (char*) uprv_malloc(buflen);
1066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        char* canon = (buf == 0) ? 0 : (char*) uprv_malloc(buflen);
1076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (buf != 0 && canon != 0) {
1086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            U_ASSERT(id->extract(0, INT32_MAX, buf, buflen) < buflen);
1096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UErrorCode ec = U_ZERO_ERROR;
1106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            uloc_canonicalize(buf, canon, buflen, &ec);
1116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (U_SUCCESS(ec)) {
1126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                result = UnicodeString(canon);
1136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
1146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
1156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uprv_free(buf);
1166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        uprv_free(canon);
1176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
1196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
1206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgLocale&
1236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgLocaleUtility::initLocaleFromName(const UnicodeString& id, Locale& result)
1246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    enum { BUFLEN = 128 }; // larger than ever needed
1266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (id.isBogus() || id.length() >= BUFLEN) {
1286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        result.setToBogus();
1296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
1306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        /*
1316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * We need to convert from a UnicodeString to char * in order to
1326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * create a Locale.
1336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         *
1346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * Problem: Locale ID strings may contain '@' which is a variant
1356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * character and cannot be handled by invariant-character conversion.
1366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         *
1376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * Hack: Since ICU code can handle locale IDs with multiple encodings
1386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * of '@' (at least for EBCDIC; it's not known to be a problem for
1396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * ASCII-based systems),
1406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * we use regular invariant-character conversion for everything else
1416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * and manually convert U+0040 into a compiler-char-constant '@'.
1426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * While this compilation-time constant may not match the runtime
1436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * encoding of '@', it should be one of the encodings which ICU
1446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * recognizes.
1456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         *
1466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         * There should be only at most one '@' in a locale ID.
1476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org         */
1486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        char buffer[BUFLEN];
1496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        int32_t prev, i;
1506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        prev = 0;
1516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        for(;;) {
1526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            i = id.indexOf((UChar)0x40, prev);
1536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if(i < 0) {
1546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // no @ between prev and the rest of the string
1556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                id.extract(prev, INT32_MAX, buffer + prev, BUFLEN - prev, US_INV);
1566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                break; // done
1576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            } else {
1586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // normal invariant-character conversion for text between @s
1596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                id.extract(prev, i - prev, buffer + prev, BUFLEN - prev, US_INV);
1606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                // manually "convert" U+0040 at id[i] into '@' at buffer[i]
1616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                buffer[i] = '@';
1626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                prev = i + 1;
1636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
1646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
1656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        result = Locale::createFromName(buffer);
1666f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1676f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
1686f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1696f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1706f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUnicodeString&
1716f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgLocaleUtility::initNameFromLocale(const Locale& locale, UnicodeString& result)
1726f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1736f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (locale.isBogus()) {
1746f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        result.setToBogus();
1756f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    } else {
1766f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        result.append(UnicodeString(locale.getName(), -1, US_INV));
1776f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
1786f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return result;
1796f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
1806f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1816f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgconst Hashtable*
1826f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgLocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID)
1836f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
1846f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // LocaleUtility_cache is a hash-of-hashes.  The top-level keys
1856f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // are path strings ('bundleID') passed to
1866f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // ures_openAvailableLocales.  The top-level values are
1876f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // second-level hashes.  The second-level keys are result strings
1886f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // from ures_openAvailableLocales.  The second-level values are
1896f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    // garbage ((void*)1 or other random pointer).
1906f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1916f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    UErrorCode status = U_ZERO_ERROR;
1926f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Hashtable* cache;
1936f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    umtx_lock(NULL);
1946f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    cache = LocaleUtility_cache;
1956f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    umtx_unlock(NULL);
1966f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
1976f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (cache == NULL) {
1986f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        cache = new Hashtable(status);
1996f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (cache == NULL || U_FAILURE(status)) {
2006f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            return NULL; // catastrophic failure; e.g. out of memory
2016f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
2026f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        cache->setValueDeleter(uhash_deleteHashtable);
2036f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        Hashtable* h; // set this to final LocaleUtility_cache value
2046f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        umtx_lock(NULL);
2056f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        h = LocaleUtility_cache;
2066f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (h == NULL) {
2076f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            LocaleUtility_cache = h = cache;
2086f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            cache = NULL;
2096f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            ucln_common_registerCleanup(UCLN_COMMON_SERVICE, service_cleanup);
2106f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
2116f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        umtx_unlock(NULL);
2126f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if(cache != NULL) {
2136f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org          delete cache;
2146f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
2156f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        cache = h;
2166f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
2176f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2186f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    U_ASSERT(cache != NULL);
2196f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2206f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    Hashtable* htp;
2216f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    umtx_lock(NULL);
2226f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    htp = (Hashtable*) cache->get(bundleID);
2236f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    umtx_unlock(NULL);
2246f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2256f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    if (htp == NULL) {
2266f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        htp = new Hashtable(status);
2276f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        if (htp && U_SUCCESS(status)) {
2286f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            CharString cbundleID;
2296f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            cbundleID.appendInvariantChars(bundleID, status);
2306f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            const char* path = cbundleID.isEmpty() ? NULL : cbundleID.data();
2316f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            UEnumeration *uenum = ures_openAvailableLocales(path, &status);
2326f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            for (;;) {
2336f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                const UChar* id = uenum_unext(uenum, NULL, &status);
2346f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                if (id == NULL) {
2356f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                    break;
2366f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                }
2376f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                htp->put(UnicodeString(id), (void*)htp, status);
2386f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
2396f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            uenum_close(uenum);
2406f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            if (U_FAILURE(status)) {
2416f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                delete htp;
2426f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org                return NULL;
2436f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            }
2446f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            umtx_lock(NULL);
2456f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            cache->put(bundleID, (void*)htp, status);
2466f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org            umtx_unlock(NULL);
2476f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org        }
2486f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    }
2496f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return htp;
2506f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2516f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2526f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgUBool
2536f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgLocaleUtility::isFallbackOf(const UnicodeString& root, const UnicodeString& child)
2546f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org{
2556f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org    return child.indexOf(root) == 0 &&
2566f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org      (child.length() == root.length() ||
2576f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org       child.charAt(root.length()) == UNDERSCORE_CHAR);
2586f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org}
2596f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2606f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.orgU_NAMESPACE_END
2616f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2626f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org/* !UCONFIG_NO_SERVICE */
2636f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org#endif
2646f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
2656f31ac30b9092fd02a8c97e5216cf53f3e4fae4jshin@chromium.org
266