Example #1
0
UnifiedCache::UnifiedCache(UErrorCode &status) :
        fHashtable(NULL),
        fEvictPos(UHASH_FIRST),
        fNumValuesTotal(0),
        fNumValuesInUse(0),
        fMaxUnused(DEFAULT_MAX_UNUSED),
        fMaxPercentageOfInUse(DEFAULT_PERCENTAGE_OF_IN_USE),
        fAutoEvictedCount(0),
        fNoValue(nullptr) {
    if (U_FAILURE(status)) {
        return;
    }
    fNoValue = new SharedObject();
    if (fNoValue == nullptr) {
        status = U_MEMORY_ALLOCATION_ERROR;
        return;
    }
    fNoValue->softRefCount = 1;  // Add fake references to prevent fNoValue from being deleted
    fNoValue->hardRefCount = 1;  // when other references to it are removed.
    fNoValue->cachePtr = this;

    fHashtable = uhash_open(
            &ucache_hashKeys,
            &ucache_compareKeys,
            NULL,
            &status);
    if (U_FAILURE(status)) {
        return;
    }
    uhash_setKeyDeleter(fHashtable, &ucache_deleteKey);
}
Example #2
0
static void U_CALLCONV initAvailableMetaZoneIDs () {
    U_ASSERT(gMetaZoneIDs == NULL);
    U_ASSERT(gMetaZoneIDTable == NULL);
    ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);

    UErrorCode status = U_ZERO_ERROR;
    gMetaZoneIDTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status);
    if (U_FAILURE(status) || gMetaZoneIDTable == NULL) {
        gMetaZoneIDTable = NULL;
        return;
    }
    uhash_setKeyDeleter(gMetaZoneIDTable, uprv_deleteUObject);
    // No valueDeleter, because the vector maintain the value objects
    gMetaZoneIDs = new UVector(NULL, uhash_compareUChars, status);
    if (U_FAILURE(status) || gMetaZoneIDs == NULL) {
        gMetaZoneIDs = NULL;
        uhash_close(gMetaZoneIDTable);
        gMetaZoneIDTable = NULL;
        return;
    }
    gMetaZoneIDs->setDeleter(uprv_free);

    UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
    UResourceBundle *bundle = ures_getByKey(rb, gMapTimezonesTag, NULL, &status);
    UResourceBundle res;
    ures_initStackObject(&res);
    while (U_SUCCESS(status) && ures_hasNext(bundle)) {
        ures_getNextResource(bundle, &res, &status);
        if (U_FAILURE(status)) {
            break;
        }
        const char *mzID = ures_getKey(&res);
        int32_t len = uprv_strlen(mzID);
        UChar *uMzID = (UChar*)uprv_malloc(sizeof(UChar) * (len + 1));
        if (uMzID == NULL) {
            status = U_MEMORY_ALLOCATION_ERROR;
            break;
        }
        u_charsToUChars(mzID, uMzID, len);
        uMzID[len] = 0;
        UnicodeString *usMzID = new UnicodeString(uMzID);
        if (uhash_get(gMetaZoneIDTable, usMzID) == NULL) {
            gMetaZoneIDs->addElement((void *)uMzID, status);
            uhash_put(gMetaZoneIDTable, (void *)usMzID, (void *)uMzID, &status);
        } else {
            uprv_free(uMzID);
            delete usMzID;
        }
    }
    ures_close(&res);
    ures_close(bundle);
    ures_close(rb);

    if (U_FAILURE(status)) {
        uhash_close(gMetaZoneIDTable);
        delete gMetaZoneIDs;
        gMetaZoneIDTable = NULL;
        gMetaZoneIDs = NULL;
    }
}
Example #3
0
U_CDECL_END

U_NAMESPACE_BEGIN

void U_CALLCONV GenderInfo_initCache(UErrorCode &status) {
  ucln_i18n_registerCleanup(UCLN_I18N_GENDERINFO, gender_cleanup);
  U_ASSERT(gGenderInfoCache == NULL);
  if (U_FAILURE(status)) {
      return;
  }
  gObjs = new GenderInfo[GENDER_STYLE_LENGTH];
  if (gObjs == NULL) {
    status = U_MEMORY_ALLOCATION_ERROR;
    return;
  }
  for (int i = 0; i < GENDER_STYLE_LENGTH; i++) {
    gObjs[i]._style = i;
  }
  gGenderInfoCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
  if (U_FAILURE(status)) {
    delete [] gObjs;
    return;
  }
  uhash_setKeyDeleter(gGenderInfoCache, uprv_free);
}
Example #4
0
static void U_CALLCONV olsonToMetaInit(UErrorCode &status) {
    U_ASSERT(gOlsonToMeta == NULL);
    ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
    gOlsonToMeta = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
    if (U_FAILURE(status)) {
        gOlsonToMeta = NULL;
    } else {
        uhash_setKeyDeleter(gOlsonToMeta, deleteUCharString);
        uhash_setValueDeleter(gOlsonToMeta, deleteUVector);
    }
}
void CDFLocaleStyleData::Init(UErrorCode& status) {
  if (unitsByVariant != NULL) {
    return;
  }
  unitsByVariant = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
  if (U_FAILURE(status)) {
    return;
  }
  uhash_setKeyDeleter(unitsByVariant, uprv_free);
  uhash_setValueDeleter(unitsByVariant, deleteCDFUnits);
}
void AlphabeticIndex::init(UErrorCode &status) {
    // Initialize statics if needed.
    AlphabeticIndex::staticInit(status);

    // Put the object into a known state so that the destructor will function.

    alreadyIn_             = NULL;
    bucketList_            = NULL;
    collator_              = NULL;
    collatorPrimaryOnly_   = NULL;
    currentBucket_         = NULL;
    firstScriptCharacters_ = NULL;
    initialLabels_         = NULL;
    indexBuildRequired_    = TRUE;
    inputRecords_          = NULL;
    itemsIterIndex_        = 0;
    labels_                = NULL;
    labelsIterIndex_       = 0;
    maxLabelCount_         = 99;
    noDistinctSorting_     = NULL;
    notAlphabetic_         = NULL;
    recordCounter_         = 0;

    if (U_FAILURE(status)) {
        return;
    }
    alreadyIn_             = uhash_open(uhash_hashUnicodeString,    // Key Hash,
                                        uhash_compareUnicodeString, // key Comparator,
                                        NULL,                       // value Comparator
                                        &status);
    uhash_setKeyDeleter(alreadyIn_, uprv_deleteUObject);
    uhash_setValueDeleter(alreadyIn_, uprv_deleteUObject);

    bucketList_            = new UVector(status);
    bucketList_->setDeleter(alphaIndex_deleteBucket);
    labels_                = new UVector(status);
    labels_->setDeleter(uprv_deleteUObject);
    labels_->setComparer(uhash_compareUnicodeString);
    inputRecords_          = new UVector(status);
    inputRecords_->setDeleter(alphaIndex_deleteRecord);

    noDistinctSorting_     = new UnicodeSet();
    notAlphabetic_         = new UnicodeSet();
    initialLabels_         = new UnicodeSet();

    inflowLabel_.remove();
    inflowLabel_.append((UChar)0x2026);    // Ellipsis
    overflowLabel_ = inflowLabel_;
    underflowLabel_ = inflowLabel_;

    // TODO:  check for memory allocation failures.
}
Example #7
0
void
StringTrieBuilder::createCompactBuilder(int32_t sizeGuess, UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return;
    }
    nodes=uhash_openSize(hashStringTrieNode, equalStringTrieNodes, NULL,
                         sizeGuess, &errorCode);
    if(U_SUCCESS(errorCode) && nodes==NULL) {
        errorCode=U_MEMORY_ALLOCATION_ERROR;
    }
    if(U_SUCCESS(errorCode)) {
        uhash_setKeyDeleter(nodes, uprv_deleteUObject);
    }
}
Example #8
0
UnifiedCache::UnifiedCache(UErrorCode &status) {
    if (U_FAILURE(status)) {
        return;
    }
    U_ASSERT(gNoValue != NULL);
    fHashtable = uhash_open(
            &ucache_hashKeys,
            &ucache_compareKeys,
            NULL,
            &status);
    if (U_FAILURE(status)) {
        return;
    }
    uhash_setKeyDeleter(fHashtable, &ucache_deleteKey);
}
Example #9
0
//--------------------------------------------------------------------------
//
//    init        Shared initialization for use by constructors.
//                Bring an uninitialized RegexPattern up to a default state.
//
//--------------------------------------------------------------------------
void RegexPattern::init() {
    fFlags            = 0;
    fCompiledPat      = 0;
    fLiteralText.remove();
    fSets             = NULL;
    fSets8            = NULL;
    fDeferredStatus   = U_ZERO_ERROR;
    fMinMatchLen      = 0;
    fFrameSize        = 0;
    fDataSize         = 0;
    fGroupMap         = NULL;
    fStaticSets       = NULL;
    fStaticSets8      = NULL;
    fStartType        = START_NO_INFO;
    fInitialStringIdx = 0;
    fInitialStringLen = 0;
    fInitialChars     = NULL;
    fInitialChar      = 0;
    fInitialChars8    = NULL;
    fNeedsAltInput    = FALSE;
    fNamedCaptureMap  = NULL;

    fPattern          = NULL; // will be set later
    fPatternString    = NULL; // may be set later
    fCompiledPat      = new UVector64(fDeferredStatus);
    fGroupMap         = new UVector32(fDeferredStatus);
    fSets             = new UVector(fDeferredStatus);
    fInitialChars     = new UnicodeSet;
    fInitialChars8    = new Regex8BitSet;
    fNamedCaptureMap  = uhash_open(uhash_hashUnicodeString,     // Key hash function
                                   uhash_compareUnicodeString,  // Key comparator function
                                   uhash_compareLong,           // Value comparator function
                                   &fDeferredStatus);
    if (U_FAILURE(fDeferredStatus)) {
        return;
    }
    if (fCompiledPat == NULL  || fGroupMap == NULL || fSets == NULL ||
            fInitialChars == NULL || fInitialChars8 == NULL || fNamedCaptureMap == NULL) {
        fDeferredStatus = U_MEMORY_ALLOCATION_ERROR;
        return;
    }

    // Slot zero of the vector of sets is reserved.  Fill it here.
    fSets->addElement((int32_t)0, fDeferredStatus);

    // fNamedCaptureMap owns its key strings, type (UnicodeString *)
    uhash_setKeyDeleter(fNamedCaptureMap, uprv_deleteUObject);
}
Example #10
0
CollDataCache::CollDataCache(UErrorCode &status)
    : cache(NULL)
{
    if (U_FAILURE(status)) {
        return;
    }

    cache = uhash_open(uhash_hashChars, uhash_compareChars, uhash_compareLong, &status);

    if (U_FAILURE(status)) {
        return;
    }

    uhash_setValueDeleter(cache, deleteCollDataCacheEntry);
    uhash_setKeyDeleter(cache, deleteChars);
}
U_CDECL_END


IdentifierInfo::IdentifierInfo(UErrorCode &status):
         fIdentifier(NULL), fRequiredScripts(NULL), fScriptSetSet(NULL),
         fCommonAmongAlternates(NULL), fNumerics(NULL), fIdentifierProfile(NULL) {
    if (U_FAILURE(status)) {
        return;
    }
    {
        Mutex lock(&gInitMutex);
        if (!gStaticsAreInitialized) {
            ASCII    = new UnicodeSet(0, 0x7f);
            JAPANESE = new ScriptSet();
            CHINESE  = new ScriptSet();
            KOREAN   = new ScriptSet();
            CONFUSABLE_WITH_LATIN = new ScriptSet();
            if (ASCII == NULL || JAPANESE == NULL || CHINESE == NULL || KOREAN == NULL
                    || CONFUSABLE_WITH_LATIN == NULL) {
                status = U_MEMORY_ALLOCATION_ERROR;
                return;
            }
            ASCII->freeze();
            JAPANESE->set(USCRIPT_LATIN, status).set(USCRIPT_HAN, status).set(USCRIPT_HIRAGANA, status)
                     .set(USCRIPT_KATAKANA, status);
            CHINESE->set(USCRIPT_LATIN, status).set(USCRIPT_HAN, status).set(USCRIPT_BOPOMOFO, status);
            KOREAN->set(USCRIPT_LATIN, status).set(USCRIPT_HAN, status).set(USCRIPT_HANGUL, status);
            CONFUSABLE_WITH_LATIN->set(USCRIPT_CYRILLIC, status).set(USCRIPT_GREEK, status)
                      .set(USCRIPT_CHEROKEE, status);
            ucln_i18n_registerCleanup(UCLN_I18N_IDENTIFIER_INFO, IdentifierInfo_cleanup);
            gStaticsAreInitialized = TRUE;
        }
    }
    fIdentifier = new UnicodeString();
    fRequiredScripts = new ScriptSet();
    fScriptSetSet = uhash_open(uhash_hashScriptSet, uhash_compareScriptSet, NULL, &status);
    uhash_setKeyDeleter(fScriptSetSet, uhash_deleteScriptSet);
    fCommonAmongAlternates = new ScriptSet();
    fNumerics = new UnicodeSet();
    fIdentifierProfile = new UnicodeSet(0, 0x10FFFF);

    if (U_SUCCESS(status) && (fIdentifier == NULL || fRequiredScripts == NULL || fScriptSetSet == NULL ||
                              fCommonAmongAlternates == NULL || fNumerics == NULL || fIdentifierProfile == NULL)) {
        status = U_MEMORY_ALLOCATION_ERROR;
    }
}
// getCDFLocaleStyleData returns pointer to formatting data for given locale and 
// style within the global cache. On cache miss, getCDFLocaleStyleData loads
// the data from CLDR into the global cache before returning the pointer. If a
// UNUM_LONG data is requested for a locale, and that locale does not have
// UNUM_LONG data, getCDFLocaleStyleData will fall back to UNUM_SHORT data for
// that locale.
static const CDFLocaleStyleData* getCDFLocaleStyleData(const Locale& inLocale, UNumberCompactStyle style, UErrorCode& status) {
  if (U_FAILURE(status)) {
    return NULL;
  }
  CDFLocaleData* result = NULL;
  const char* key = inLocale.getName();
  {
    Mutex lock(&gCompactDecimalMetaLock);
    if (gCompactDecimalData == NULL) {
      gCompactDecimalData = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
      if (U_FAILURE(status)) {
        return NULL;
      }
      uhash_setKeyDeleter(gCompactDecimalData, uprv_free);
      uhash_setValueDeleter(gCompactDecimalData, deleteCDFLocaleData);
      ucln_i18n_registerCleanup(UCLN_I18N_CDFINFO, cdf_cleanup);
    } else {
      result = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
    }
  }
  if (result != NULL) {
    return extractDataByStyleEnum(*result, style, status);
  }

  result = loadCDFLocaleData(inLocale, status);
  if (U_FAILURE(status)) {
    return NULL;
  }

  {
    Mutex lock(&gCompactDecimalMetaLock);
    CDFLocaleData* temp = (CDFLocaleData*) uhash_get(gCompactDecimalData, key);
    if (temp != NULL) {
      delete result;
      result = temp;
    } else {
      uhash_put(gCompactDecimalData, uprv_strdup(key), (void*) result, &status);
      if (U_FAILURE(status)) {
        return NULL;
      }
    }
  }
  return extractDataByStyleEnum(*result, style, status);
}
Example #13
0
StringToCEsMap::StringToCEsMap(UErrorCode &status)
    : map(NULL)
{
    if (U_FAILURE(status)) {
        return;
    }

    map = uhash_open(uhash_hashUnicodeString,
                     uhash_compareUnicodeString,
                     uhash_compareLong,
                     &status);

    if (U_FAILURE(status)) {
        return;
    }

    uhash_setValueDeleter(map, deleteCEList);
    uhash_setKeyDeleter(map, deleteUnicodeStringKey);
}
Example #14
0
UnifiedCache::UnifiedCache(UErrorCode &status) :
        fHashtable(NULL),
        fEvictPos(UHASH_FIRST),
        fItemsInUseCount(0),
        fMaxUnused(DEFAULT_MAX_UNUSED),
        fMaxPercentageOfInUse(DEFAULT_PERCENTAGE_OF_IN_USE),
        fAutoEvictedCount(0) {
    if (U_FAILURE(status)) {
        return;
    }
    U_ASSERT(gNoValue != NULL);
    fHashtable = uhash_open(
            &ucache_hashKeys,
            &ucache_compareKeys,
            NULL,
            &status);
    if (U_FAILURE(status)) {
        return;
    }
    uhash_setKeyDeleter(fHashtable, &ucache_deleteKey);
}
Example #15
0
U_CDECL_END


IdentifierInfo::IdentifierInfo(UErrorCode &status):
         fIdentifier(NULL), fRequiredScripts(NULL), fScriptSetSet(NULL), 
         fCommonAmongAlternates(NULL), fNumerics(NULL), fIdentifierProfile(NULL) {
    umtx_initOnce(gIdentifierInfoInitOnce, &IdentifierInfo_init, status);
    if (U_FAILURE(status)) {
        return;
    }
    
    fIdentifier = new UnicodeString();
    fRequiredScripts = new ScriptSet();
    fScriptSetSet = uhash_open(uhash_hashScriptSet, uhash_compareScriptSet, NULL, &status);
    uhash_setKeyDeleter(fScriptSetSet, uhash_deleteScriptSet);
    fCommonAmongAlternates = new ScriptSet();
    fNumerics = new UnicodeSet();
    fIdentifierProfile = new UnicodeSet(0, 0x10FFFF);

    if (U_SUCCESS(status) && (fIdentifier == NULL || fRequiredScripts == NULL || fScriptSetSet == NULL ||
                              fCommonAmongAlternates == NULL || fNumerics == NULL || fIdentifierProfile == NULL)) {
        status = U_MEMORY_ALLOCATION_ERROR;
    }
}
void PluralRulesTest::testAvailbleLocales() {
    
    // Hash set of (char *) strings.
    UErrorCode status = U_ZERO_ERROR;
    UHashtable *localeSet = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, uhash_compareLong, &status);
    uhash_setKeyDeleter(localeSet, uprv_deleteUObject);
    if (U_FAILURE(status)) {
        errln("file %s,  line %d: Error status = %s", __FILE__, __LINE__, u_errorName(status));
        return;
    }

    // Check that each locale returned by the iterator is unique.
    StringEnumeration *localesEnum = PluralRules::getAvailableLocales(status);
    int localeCount = 0;
    for (;;) {
        const char *locale = localesEnum->next(NULL, status);
        if (U_FAILURE(status)) {
            dataerrln("file %s,  line %d: Error status = %s", __FILE__, __LINE__, u_errorName(status));
            return;
        }
        if (locale == NULL) {
            break;
        }
        localeCount++;
        int32_t oldVal = uhash_puti(localeSet, new UnicodeString(locale), 1, &status);
        if (oldVal != 0) {
            errln("file %s,  line %d: locale %s was seen before.", __FILE__, __LINE__, locale);
        }
    }

    // Reset the iterator, verify that we get the same count.
    localesEnum->reset(status);
    int32_t localeCount2 = 0;
    while (localesEnum->next(NULL, status) != NULL) {
        if (U_FAILURE(status)) {
            errln("file %s,  line %d: Error status = %s", __FILE__, __LINE__, u_errorName(status));
            break;
        }
        localeCount2++;
    }
    if (localeCount != localeCount2) {
        errln("file %s,  line %d: locale counts differ. They are (%d, %d)", 
            __FILE__, __LINE__, localeCount, localeCount2);
    }

    // Instantiate plural rules for each available locale.
    localesEnum->reset(status);
    for (;;) {
        status = U_ZERO_ERROR;
        const char *localeName = localesEnum->next(NULL, status);
        if (U_FAILURE(status)) {
            errln("file %s,  line %d: Error status = %s, locale = %s",
                __FILE__, __LINE__, u_errorName(status), localeName);
            return;
        }
        if (localeName == NULL) {
            break;
        }
        Locale locale = Locale::createFromName(localeName);
        PluralRules *pr = PluralRules::forLocale(locale, status);
        if (U_FAILURE(status)) {
            errln("file %s,  line %d: Error %s creating plural rules for locale %s", 
                __FILE__, __LINE__, u_errorName(status), localeName);
            continue;
        }
        if (pr == NULL) {
            errln("file %s, line %d: Null plural rules for locale %s", __FILE__, __LINE__, localeName);
            continue;
        }

        // Pump some numbers through the plural rules.  Can't check for correct results, 
        // mostly this to tickle any asserts or crashes that may be lurking.
        for (double n=0; n<120.0; n+=0.5) {
            UnicodeString keyword = pr->select(n);
            if (keyword.length() == 0) {
                errln("file %s, line %d, empty keyword for n = %g, locale %s",
                    __FILE__, __LINE__, n, localeName);
            }
        }
        delete pr;
    }

    uhash_close(localeSet);
    delete localesEnum;

}
Example #17
0
void
TZGNCore::initialize(const Locale& locale, UErrorCode& status) {
    if (U_FAILURE(status)) {
        return;
    }

    // TimeZoneNames
    fTimeZoneNames = TimeZoneNames::createInstance(locale, status);
    if (U_FAILURE(status)) {
        return;
    }

    // Initialize format patterns
    UnicodeString rpat(TRUE, gDefRegionPattern, -1);
    UnicodeString fpat(TRUE, gDefFallbackPattern, -1);

    UErrorCode tmpsts = U_ZERO_ERROR;   // OK with fallback warning..
    UResourceBundle *zoneStrings = ures_open(U_ICUDATA_ZONE, locale.getName(), &tmpsts);
    zoneStrings = ures_getByKeyWithFallback(zoneStrings, gZoneStrings, zoneStrings, &tmpsts);

    if (U_SUCCESS(tmpsts)) {
        const UChar *regionPattern = ures_getStringByKeyWithFallback(zoneStrings, gRegionFormatTag, NULL, &tmpsts);
        if (U_SUCCESS(tmpsts) && u_strlen(regionPattern) > 0) {
            rpat.setTo(regionPattern, -1);
        }
        tmpsts = U_ZERO_ERROR;
        const UChar *fallbackPattern = ures_getStringByKeyWithFallback(zoneStrings, gFallbackFormatTag, NULL, &tmpsts);
        if (U_SUCCESS(tmpsts) && u_strlen(fallbackPattern) > 0) {
            fpat.setTo(fallbackPattern, -1);
        }
    }
    ures_close(zoneStrings);

    fRegionFormat.applyPatternMinMaxArguments(rpat, 1, 1, status);
    fFallbackFormat.applyPatternMinMaxArguments(fpat, 2, 2, status);
    if (U_FAILURE(status)) {
        cleanup();
        return;
    }

    // locale display names
    fLocaleDisplayNames = LocaleDisplayNames::createInstance(locale);

    // hash table for names - no key/value deleters
    fLocationNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
    if (U_FAILURE(status)) {
        cleanup();
        return;
    }

    fPartialLocationNamesMap = uhash_open(hashPartialLocationKey, comparePartialLocationKey, NULL, &status);
    if (U_FAILURE(status)) {
        cleanup();
        return;
    }
    uhash_setKeyDeleter(fPartialLocationNamesMap, uprv_free);
    // no value deleter

    // target region
    const char* region = fLocale.getCountry();
    int32_t regionLen = uprv_strlen(region);
    if (regionLen == 0) {
        char loc[ULOC_FULLNAME_CAPACITY];
        uloc_addLikelySubtags(fLocale.getName(), loc, sizeof(loc), &status);

        regionLen = uloc_getCountry(loc, fTargetRegion, sizeof(fTargetRegion), &status);
        if (U_SUCCESS(status)) {
            fTargetRegion[regionLen] = 0;
        } else {
            cleanup();
            return;
        }
    } else if (regionLen < (int32_t)sizeof(fTargetRegion)) {
        uprv_strcpy(fTargetRegion, region);
    } else {
        fTargetRegion[0] = 0;
    }

    // preload generic names for the default zone
    TimeZone *tz = TimeZone::createDefault();
    const UChar *tzID = ZoneMeta::getCanonicalCLDRID(*tz);
    if (tzID != NULL) {
        loadStrings(UnicodeString(TRUE, tzID, -1));
    }
    delete tz;
}
const Normalizer2 *
Normalizer2::getInstance(const char *packageName,
                         const char *name,
                         UNormalization2Mode mode,
                         UErrorCode &errorCode) {
    if(U_FAILURE(errorCode)) {
        return NULL;
    }
    if(name==NULL || *name==0) {
        errorCode=U_ILLEGAL_ARGUMENT_ERROR;
        return NULL;
    }
    const Norm2AllModes *allModes=NULL;
    if(packageName==NULL) {
        if(0==uprv_strcmp(name, "nfc")) {
            allModes=Norm2AllModes::getNFCInstance(errorCode);
        } else if(0==uprv_strcmp(name, "nfkc")) {
            allModes=Norm2AllModes::getNFKCInstance(errorCode);
        } else if(0==uprv_strcmp(name, "nfkc_cf")) {
            allModes=Norm2AllModes::getNFKC_CFInstance(errorCode);
        }
    }
    if(allModes==NULL && U_SUCCESS(errorCode)) {
        {
            Mutex lock;
            if(cache!=NULL) {
                allModes=(Norm2AllModes *)uhash_get(cache, name);
            }
        }
        if(allModes==NULL) {
            LocalPointer<Norm2AllModes> localAllModes(
                Norm2AllModes::createInstance(packageName, name, errorCode));
            if(U_SUCCESS(errorCode)) {
                Mutex lock;
                if(cache==NULL) {
                    cache=uhash_open(uhash_hashChars, uhash_compareChars, NULL, &errorCode);
                    if(U_FAILURE(errorCode)) {
                        return NULL;
                    }
                    uhash_setKeyDeleter(cache, uprv_free);
                    uhash_setValueDeleter(cache, deleteNorm2AllModes);
                }
                void *temp=uhash_get(cache, name);
                if(temp==NULL) {
                    int32_t keyLength=uprv_strlen(name)+1;
                    char *nameCopy=(char *)uprv_malloc(keyLength);
                    if(nameCopy==NULL) {
                        errorCode=U_MEMORY_ALLOCATION_ERROR;
                        return NULL;
                    }
                    uprv_memcpy(nameCopy, name, keyLength);
                    allModes=localAllModes.getAlias();
                    uhash_put(cache, nameCopy, localAllModes.orphan(), &errorCode);
                } else {
                    // race condition
                    allModes=(Norm2AllModes *)temp;
                }
            }
        }
    }
    if(allModes!=NULL && U_SUCCESS(errorCode)) {
        switch(mode) {
        case UNORM2_COMPOSE:
            return &allModes->comp;
        case UNORM2_DECOMPOSE:
            return &allModes->decomp;
        case UNORM2_FCD:
            return &allModes->fcd;
        case UNORM2_COMPOSE_CONTIGUOUS:
            return &allModes->fcc;
        default:
            break;  // do nothing
        }
    }
    return NULL;
}
/*
 * Creating Olson tzid to metazone mappings from resource (3.8.1 and beyond)
 */
UHashtable*
ZoneMeta::createOlsonToMetaMap(void) {
    UErrorCode status = U_ZERO_ERROR;

    UHashtable *olsonToMeta = NULL;
    UResourceBundle *metazoneMappings = NULL;
    UResourceBundle *zoneItem = NULL;
    UResourceBundle *mz = NULL;
    StringEnumeration *tzids = NULL;

    olsonToMeta = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
    if (U_FAILURE(status)) {
        return NULL;
    }
    uhash_setKeyDeleter(olsonToMeta, deleteUCharString);
    uhash_setValueDeleter(olsonToMeta, deleteUVector);

    // Read metazone mappings from metazoneInfo bundle
    metazoneMappings = ures_openDirect(NULL, gMetazoneInfo, &status);
    metazoneMappings = ures_getByKey(metazoneMappings, gMetazoneMappings, metazoneMappings, &status);
    if (U_FAILURE(status)) {
        goto error_cleanup;
    }

    // Walk through all canonical tzids
    char zidkey[ZID_KEY_MAX];

    tzids = TimeZone::createEnumeration();
    const UnicodeString *tzid;
    while ((tzid = tzids->snext(status))) {
        if (U_FAILURE(status)) {
            goto error_cleanup;
        }
        // We may skip aliases, because the bundle
        // contains only canonical IDs.  For now, try
        // all of them.
        tzid->extract(0, tzid->length(), zidkey, sizeof(zidkey), US_INV);
        zidkey[sizeof(zidkey)-1] = 0; // NULL terminate just in case.

        // Replace '/' with ':'
        UBool foundSep = FALSE;
        char *p = zidkey;
        while (*p) {
            if (*p == '/') {
                *p = ':';
                foundSep = TRUE;
            }
            p++;
        }
        if (!foundSep) {
            // A valid time zone key has at least one separator
            continue;
        }

        zoneItem = ures_getByKey(metazoneMappings, zidkey, zoneItem, &status);
        if (U_FAILURE(status)) {
            status = U_ZERO_ERROR;
            continue;
        }

        UVector *mzMappings = NULL;
        while (ures_hasNext(zoneItem)) {
            mz = ures_getNextResource(zoneItem, mz, &status);
            const UChar *mz_name = ures_getStringByIndex(mz, 0, NULL, &status);
            const UChar *mz_from = ures_getStringByIndex(mz, 1, NULL, &status);
            const UChar *mz_to   = ures_getStringByIndex(mz, 2, NULL, &status);

            if(U_FAILURE(status)){
                status = U_ZERO_ERROR;
                continue;
            }
            // We do not want to use SimpleDateformat to parse boundary dates,
            // because this code could be triggered by the initialization code
            // used by SimpleDateFormat.
            UDate from = parseDate(mz_from, status);
            UDate to = parseDate(mz_to, status);
            if (U_FAILURE(status)) {
                status = U_ZERO_ERROR;
                continue;
            }

            OlsonToMetaMappingEntry *entry = (OlsonToMetaMappingEntry*)uprv_malloc(sizeof(OlsonToMetaMappingEntry));
            if (entry == NULL) {
                status = U_MEMORY_ALLOCATION_ERROR;
                break;
            }
            entry->mzid = mz_name;
            entry->from = from;
            entry->to = to;

            if (mzMappings == NULL) {
                mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status);
                if (U_FAILURE(status)) {
                    delete mzMappings;
                    deleteOlsonToMetaMappingEntry(entry);
                    uprv_free(entry);
                    break;
                }
            }

            mzMappings->addElement(entry, status);
            if (U_FAILURE(status)) {
                break;
            }
        }

        if (U_FAILURE(status)) {
            if (mzMappings != NULL) {
                delete mzMappings;
            }
            goto error_cleanup;
        }
        if (mzMappings != NULL) {
            // Add to hashtable
            int32_t tzidLen = tzid->length() + 1; // Add one for NUL terminator
            UChar *key = (UChar*)uprv_malloc(tzidLen * sizeof(UChar));
            if (key == NULL) {
                status = U_MEMORY_ALLOCATION_ERROR;
                delete mzMappings;
                goto error_cleanup;
            }
            tzid->extract(key, tzidLen, status);
            uhash_put(olsonToMeta, key, mzMappings, &status);
            if (U_FAILURE(status)) {
                goto error_cleanup;
            }
        }
    }

normal_cleanup:
    if (tzids != NULL) {
        delete tzids;
    }
    ures_close(zoneItem);
    ures_close(mz);
    ures_close(metazoneMappings);
    return olsonToMeta;

error_cleanup:
    if (olsonToMeta != NULL) {
        uhash_close(olsonToMeta);
        olsonToMeta = NULL;
    }
    goto normal_cleanup;
}
UHashtable*
ZoneMeta::createMetaToOlsonMap(void) {
    UErrorCode status = U_ZERO_ERROR;

    UHashtable *metaToOlson = NULL;
    UResourceBundle *metazones = NULL;
    UResourceBundle *mz = NULL;

    metaToOlson = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
    if (U_FAILURE(status)) {
        return NULL;
    }
    uhash_setKeyDeleter(metaToOlson, deleteUCharString);
    uhash_setValueDeleter(metaToOlson, deleteUVector);

    metazones = ures_openDirect(NULL, gSupplementalData, &status);
    metazones = ures_getByKey(metazones, gMapTimezonesTag, metazones, &status);
    metazones = ures_getByKey(metazones, gMetazonesTag, metazones, &status);
    if (U_FAILURE(status)) {
        goto error_cleanup;
    }

    while (ures_hasNext(metazones)) {
        mz = ures_getNextResource(metazones, mz, &status);
        if (U_FAILURE(status)) {
            status = U_ZERO_ERROR;
            continue;
        }
        const char *mzkey = ures_getKey(mz);
        if (uprv_strncmp(mzkey, gMetazoneIdPrefix, MZID_PREFIX_LEN) == 0) {
            const char *mzid = mzkey + MZID_PREFIX_LEN;
            const char *territory = uprv_strrchr(mzid, '_');
            int32_t mzidLen = 0;
            int32_t territoryLen = 0;
            if (territory) {
                mzidLen = territory - mzid;
                territory++;
                territoryLen = uprv_strlen(territory);
            }
            if (mzidLen > 0 && territoryLen > 0) {
                int32_t tzidLen;
                const UChar *tzid = ures_getStringByIndex(mz, 0, &tzidLen, &status);
                if (U_SUCCESS(status)) {
                    // Create MetaToOlsonMappingEntry
                    MetaToOlsonMappingEntry *entry = (MetaToOlsonMappingEntry*)uprv_malloc(sizeof(MetaToOlsonMappingEntry));
                    if (entry == NULL) {
                        status = U_MEMORY_ALLOCATION_ERROR;
                        goto error_cleanup;
                    }
                    entry->id = tzid;
                    entry->territory = (UChar*)uprv_malloc((territoryLen + 1) * sizeof(UChar));
                    if (entry->territory == NULL) {
                        status = U_MEMORY_ALLOCATION_ERROR;
                        uprv_free(entry);
                        goto error_cleanup;
                    }
                    u_charsToUChars(territory, entry->territory, territoryLen + 1);

                    // Check if mapping entries for metazone is already available
                    if (mzidLen < ZID_KEY_MAX) {
                        UChar mzidUChars[ZID_KEY_MAX];
                        u_charsToUChars(mzid, mzidUChars, mzidLen);
                        mzidUChars[mzidLen++] = 0; // Add NUL terminator
                        UVector *tzMappings = (UVector*)uhash_get(metaToOlson, mzidUChars);
                        if (tzMappings == NULL) {
                            // Create new UVector and put it into the hashtable
                            tzMappings = new UVector(deleteMetaToOlsonMappingEntry, NULL, status);
                            if (U_FAILURE(status)) {
                                deleteMetaToOlsonMappingEntry(entry);
                                goto error_cleanup;
                            }
                            UChar *key = (UChar*)uprv_malloc(mzidLen * sizeof(UChar));
                            if (key == NULL) {
                                status = U_MEMORY_ALLOCATION_ERROR;
                                delete tzMappings;
                                deleteMetaToOlsonMappingEntry(entry);
                                goto error_cleanup;
                            }
                            u_strncpy(key, mzidUChars, mzidLen);
                            uhash_put(metaToOlson, key, tzMappings, &status);
                            if (U_FAILURE(status)) {
                                goto error_cleanup;
                            }
                        }
                        tzMappings->addElement(entry, status);
                        if (U_FAILURE(status)) {
                            goto error_cleanup;
                        }
                    } else {
                        deleteMetaToOlsonMappingEntry(entry);
                    }
                } else {
                    status = U_ZERO_ERROR;
                }
            }
        }
    }

normal_cleanup:
    ures_close(mz);
    ures_close(metazones);
    return metaToOlson;

error_cleanup:
    if (metaToOlson != NULL) {
        uhash_close(metaToOlson);
        metaToOlson = NULL;
    }
    goto normal_cleanup;
}
Example #21
0
const UVector* U_EXPORT2
ZoneMeta::getMetazoneMappings(const UnicodeString &tzid) {
    UErrorCode status = U_ZERO_ERROR;
    UChar tzidUChars[ZID_KEY_MAX];
    tzid.extract(tzidUChars, ZID_KEY_MAX, status);
    if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
        return NULL;
    }

    UBool initialized;
    UMTX_CHECK(&gZoneMetaLock, gOlsonToMetaInitialized, initialized);
    if (!initialized) {
        UHashtable *tmpOlsonToMeta = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
        if (U_FAILURE(status)) {
            return NULL;
        }
        uhash_setKeyDeleter(tmpOlsonToMeta, deleteUCharString);
        uhash_setValueDeleter(tmpOlsonToMeta, deleteUVector);

        umtx_lock(&gZoneMetaLock);
        {
            if (!gOlsonToMetaInitialized) {
                gOlsonToMeta = tmpOlsonToMeta;
                tmpOlsonToMeta = NULL;
                gOlsonToMetaInitialized = TRUE;
            }
        }
        umtx_unlock(&gZoneMetaLock);

        // OK to call the following multiple times with the same function
        ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
        if (tmpOlsonToMeta != NULL) {
            uhash_close(tmpOlsonToMeta);
        }
    }

    // get the mapping from cache
    const UVector *result = NULL;

    umtx_lock(&gZoneMetaLock);
    {
        result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
    }
    umtx_unlock(&gZoneMetaLock);

    if (result != NULL) {
        return result;
    }

    // miss the cache - create new one
    UVector *tmpResult = createMetazoneMappings(tzid);
    if (tmpResult == NULL) {
        // not available
        return NULL;
    }

    // put the new one into the cache
    umtx_lock(&gZoneMetaLock);
    {
        // make sure it's already created
        result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
        if (result == NULL) {
            // add the one just created
            int32_t tzidLen = tzid.length() + 1;
            UChar *key = (UChar*)uprv_malloc(tzidLen * sizeof(UChar));
            if (key == NULL) {
                // memory allocation error..  just return NULL
                result = NULL;
                delete tmpResult;
            } else {
                tzid.extract(key, tzidLen, status);
                uhash_put(gOlsonToMeta, key, tmpResult, &status);
                if (U_FAILURE(status)) {
                    // delete the mapping
                    result = NULL;
                    delete tmpResult;
                } else {
                    result = tmpResult;
                }
            }
        } else {
            // another thread already put the one
            delete tmpResult;
        }
    }
    umtx_unlock(&gZoneMetaLock);

    return result;
}
Example #22
0
/*
 * Initializes the region data from the ICU resource bundles.  The region data
 * contains the basic relationships such as which regions are known, what the numeric
 * codes are, any known aliases, and the territory containment data.
 *
 * If the region data has already loaded, then this method simply returns without doing
 * anything meaningful.
 */
void Region::loadRegionData(UErrorCode &status) {

    // Construct service objs first
    LocalUHashtablePointer newRegionIDMap(uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status));
    LocalUHashtablePointer newNumericCodeMap(uhash_open(uhash_hashLong,uhash_compareLong,NULL,&status));
    LocalUHashtablePointer newRegionAliases(uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status));
    LocalPointer<DecimalFormat> df(new DecimalFormat(status), status);

    LocalPointer<UVector> continents(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
    LocalPointer<UVector> groupings(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
    allRegions = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);

    LocalUResourceBundlePointer metadata(ures_openDirect(NULL,"metadata",&status));
    LocalUResourceBundlePointer metadataAlias(ures_getByKey(metadata.getAlias(),"alias",NULL,&status));
    LocalUResourceBundlePointer territoryAlias(ures_getByKey(metadataAlias.getAlias(),"territory",NULL,&status));

    LocalUResourceBundlePointer supplementalData(ures_openDirect(NULL,"supplementalData",&status));
    LocalUResourceBundlePointer codeMappings(ures_getByKey(supplementalData.getAlias(),"codeMappings",NULL,&status));

    LocalUResourceBundlePointer idValidity(ures_getByKey(supplementalData.getAlias(),"idValidity",NULL,&status));
    LocalUResourceBundlePointer regionList(ures_getByKey(idValidity.getAlias(),"region",NULL,&status));
    LocalUResourceBundlePointer regionRegular(ures_getByKey(regionList.getAlias(),"regular",NULL,&status));
    LocalUResourceBundlePointer regionMacro(ures_getByKey(regionList.getAlias(),"macroregion",NULL,&status));
    LocalUResourceBundlePointer regionUnknown(ures_getByKey(regionList.getAlias(),"unknown",NULL,&status));

    LocalUResourceBundlePointer territoryContainment(ures_getByKey(supplementalData.getAlias(),"territoryContainment",NULL,&status));
    LocalUResourceBundlePointer worldContainment(ures_getByKey(territoryContainment.getAlias(),"001",NULL,&status));
    LocalUResourceBundlePointer groupingContainment(ures_getByKey(territoryContainment.getAlias(),"grouping",NULL,&status));

    if (U_FAILURE(status)) {
        return;
    }

    // now, initialize
    df->setParseIntegerOnly(TRUE);
    uhash_setValueDeleter(newRegionIDMap.getAlias(), deleteRegion);  // regionIDMap owns objs
    uhash_setKeyDeleter(newRegionAliases.getAlias(), uprv_deleteUObject); // regionAliases owns the string keys


    while ( ures_hasNext(regionRegular.getAlias()) ) {
        UnicodeString regionName = ures_getNextUnicodeString(regionRegular.getAlias(),NULL,&status);
        int32_t rangeMarkerLocation = regionName.indexOf(RANGE_MARKER);
        UChar buf[6];
        regionName.extract(buf,6,status);
        if ( rangeMarkerLocation > 0 ) {
            UChar endRange = regionName.charAt(rangeMarkerLocation+1);
            buf[rangeMarkerLocation] = 0;
            while ( buf[rangeMarkerLocation-1] <= endRange ) {
                LocalPointer<UnicodeString> newRegion(new UnicodeString(buf), status);
                allRegions->addElement(newRegion.orphan(),status);
                buf[rangeMarkerLocation-1]++;
            }
        } else {
            LocalPointer<UnicodeString> newRegion(new UnicodeString(regionName), status);
            allRegions->addElement(newRegion.orphan(),status);
        }
    }

    while ( ures_hasNext(regionMacro.getAlias()) ) {
        UnicodeString regionName = ures_getNextUnicodeString(regionMacro.getAlias(),NULL,&status);
        int32_t rangeMarkerLocation = regionName.indexOf(RANGE_MARKER);
        UChar buf[6];
        regionName.extract(buf,6,status);
        if ( rangeMarkerLocation > 0 ) {
            UChar endRange = regionName.charAt(rangeMarkerLocation+1);
            buf[rangeMarkerLocation] = 0;
            while ( buf[rangeMarkerLocation-1] <= endRange ) {
                LocalPointer<UnicodeString> newRegion(new UnicodeString(buf), status);
                allRegions->addElement(newRegion.orphan(),status);
                buf[rangeMarkerLocation-1]++;
            }
        } else {
            LocalPointer<UnicodeString> newRegion(new UnicodeString(regionName), status);
            allRegions->addElement(newRegion.orphan(),status);
        }
    }

    while ( ures_hasNext(regionUnknown.getAlias()) ) {
        LocalPointer<UnicodeString> regionName (new UnicodeString(ures_getNextUnicodeString(regionUnknown.getAlias(),NULL,&status),status));
        allRegions->addElement(regionName.orphan(),status);
    }

    while ( ures_hasNext(worldContainment.getAlias()) ) {
        UnicodeString *continentName = new UnicodeString(ures_getNextUnicodeString(worldContainment.getAlias(),NULL,&status));
        continents->addElement(continentName,status);
    }

    while ( ures_hasNext(groupingContainment.getAlias()) ) {
        UnicodeString *groupingName = new UnicodeString(ures_getNextUnicodeString(groupingContainment.getAlias(),NULL,&status));
        groupings->addElement(groupingName,status);
    }

    for ( int32_t i = 0 ; i < allRegions->size() ; i++ ) {
        LocalPointer<Region> r(new Region(), status);
        if ( U_FAILURE(status) ) {
           return;
        }
        UnicodeString *regionName = (UnicodeString *)allRegions->elementAt(i);
        r->idStr = *regionName;

        r->idStr.extract(0,r->idStr.length(),r->id,sizeof(r->id),US_INV);
        r->type = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known.

        Formattable result;
        UErrorCode ps = U_ZERO_ERROR;
        df->parse(r->idStr,result,ps);
        if ( U_SUCCESS(ps) ) {
            r->code = result.getLong(); // Convert string to number
            uhash_iput(newNumericCodeMap.getAlias(),r->code,(void *)(r.getAlias()),&status);
            r->type = URGN_SUBCONTINENT;
        } else {
            r->code = -1;
        }
        void* idStrAlias = (void*)&(r->idStr); // about to orphan 'r'. Save this off.
        uhash_put(newRegionIDMap.getAlias(),idStrAlias,(void *)(r.orphan()),&status); // regionIDMap takes ownership
    }

    // Process the territory aliases
    while ( ures_hasNext(territoryAlias.getAlias()) ) {
        LocalUResourceBundlePointer res(ures_getNextResource(territoryAlias.getAlias(),NULL,&status));
        const char *aliasFrom = ures_getKey(res.getAlias());
        LocalPointer<UnicodeString> aliasFromStr(new UnicodeString(aliasFrom, -1, US_INV), status);
        UnicodeString aliasTo = ures_getUnicodeStringByKey(res.getAlias(),"replacement",&status);
        res.adoptInstead(NULL);

        const Region *aliasToRegion = (Region *) uhash_get(newRegionIDMap.getAlias(),&aliasTo);
        Region *aliasFromRegion = (Region *)uhash_get(newRegionIDMap.getAlias(),aliasFromStr.getAlias());

        if ( aliasToRegion != NULL && aliasFromRegion == NULL ) { // This is just an alias from some string to a region
            uhash_put(newRegionAliases.getAlias(),(void *)aliasFromStr.orphan(), (void *)aliasToRegion,&status);
        } else {
            if ( aliasFromRegion == NULL ) { // Deprecated region code not in the master codes list - so need to create a deprecated region for it.
                LocalPointer<Region> newRgn(new Region, status); 
                if ( U_SUCCESS(status) ) {
                    aliasFromRegion = newRgn.orphan();
                } else {
                    return; // error out
                }
                aliasFromRegion->idStr.setTo(*aliasFromStr);
                aliasFromRegion->idStr.extract(0,aliasFromRegion->idStr.length(),aliasFromRegion->id,sizeof(aliasFromRegion->id),US_INV);
                uhash_put(newRegionIDMap.getAlias(),(void *)&(aliasFromRegion->idStr),(void *)aliasFromRegion,&status);
                Formattable result;
                UErrorCode ps = U_ZERO_ERROR;
                df->parse(aliasFromRegion->idStr,result,ps);
                if ( U_SUCCESS(ps) ) {
                    aliasFromRegion->code = result.getLong(); // Convert string to number
                    uhash_iput(newNumericCodeMap.getAlias(),aliasFromRegion->code,(void *)aliasFromRegion,&status);
                } else {
                    aliasFromRegion->code = -1;
                }
                aliasFromRegion->type = URGN_DEPRECATED;
            } else {
                aliasFromRegion->type = URGN_DEPRECATED;
            }

            {
                LocalPointer<UVector> newPreferredValues(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
                aliasFromRegion->preferredValues = newPreferredValues.orphan();
            }
            if( U_FAILURE(status)) {
                return;
            }
            UnicodeString currentRegion;
            //currentRegion.remove();   TODO: was already 0 length?
            for (int32_t i = 0 ; i < aliasTo.length() ; i++ ) {
                if ( aliasTo.charAt(i) != 0x0020 ) {
                    currentRegion.append(aliasTo.charAt(i));
                }
                if ( aliasTo.charAt(i) == 0x0020 || i+1 == aliasTo.length() ) {
                    Region *target = (Region *)uhash_get(newRegionIDMap.getAlias(),(void *)&currentRegion);
                    if (target) {
                        LocalPointer<UnicodeString> preferredValue(new UnicodeString(target->idStr), status);
                        aliasFromRegion->preferredValues->addElement((void *)preferredValue.orphan(),status);  // may add null if err
                    }
                    currentRegion.remove();
                }
            }
        }
    }

    // Process the code mappings - This will allow us to assign numeric codes to most of the territories.
    while ( ures_hasNext(codeMappings.getAlias()) ) {
        UResourceBundle *mapping = ures_getNextResource(codeMappings.getAlias(),NULL,&status);
        if ( ures_getType(mapping) == URES_ARRAY && ures_getSize(mapping) == 3) {
            UnicodeString codeMappingID = ures_getUnicodeStringByIndex(mapping,0,&status);
            UnicodeString codeMappingNumber = ures_getUnicodeStringByIndex(mapping,1,&status);
            UnicodeString codeMapping3Letter = ures_getUnicodeStringByIndex(mapping,2,&status);

            Region *r = (Region *)uhash_get(newRegionIDMap.getAlias(),(void *)&codeMappingID);
            if ( r ) {
                Formattable result;
                UErrorCode ps = U_ZERO_ERROR;
                df->parse(codeMappingNumber,result,ps);
                if ( U_SUCCESS(ps) ) {
                    r->code = result.getLong(); // Convert string to number
                    uhash_iput(newNumericCodeMap.getAlias(),r->code,(void *)r,&status);
                }
                LocalPointer<UnicodeString> code3(new UnicodeString(codeMapping3Letter), status);
                uhash_put(newRegionAliases.getAlias(),(void *)code3.orphan(), (void *)r,&status);
            }
        }
        ures_close(mapping);
    }

    // Now fill in the special cases for WORLD, UNKNOWN, CONTINENTS, and GROUPINGS
    Region *r;
    UnicodeString WORLD_ID_STRING(WORLD_ID);
    r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&WORLD_ID_STRING);
    if ( r ) {
        r->type = URGN_WORLD;
    }

    UnicodeString UNKNOWN_REGION_ID_STRING(UNKNOWN_REGION_ID);
    r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&UNKNOWN_REGION_ID_STRING);
    if ( r ) {
        r->type = URGN_UNKNOWN;
    }

    for ( int32_t i = 0 ; i < continents->size() ; i++ ) {
        r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)continents->elementAt(i));
        if ( r ) {
            r->type = URGN_CONTINENT;
        }
    }

    for ( int32_t i = 0 ; i < groupings->size() ; i++ ) {
        r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)groupings->elementAt(i));
        if ( r ) {
            r->type = URGN_GROUPING;
        }
    }

    // Special case: The region code "QO" (Outlying Oceania) is a subcontinent code added by CLDR
    // even though it looks like a territory code.  Need to handle it here.

    UnicodeString OUTLYING_OCEANIA_REGION_ID_STRING(OUTLYING_OCEANIA_REGION_ID);
    r = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&OUTLYING_OCEANIA_REGION_ID_STRING);
    if ( r ) {
        r->type = URGN_SUBCONTINENT;
    }

    // Load territory containment info from the supplemental data.
    while ( ures_hasNext(territoryContainment.getAlias()) ) {
        LocalUResourceBundlePointer mapping(ures_getNextResource(territoryContainment.getAlias(),NULL,&status));
        if( U_FAILURE(status) ) {
            return;  // error out
        }
        const char *parent = ures_getKey(mapping.getAlias());
        if (uprv_strcmp(parent, "containedGroupings") == 0 || uprv_strcmp(parent, "deprecated") == 0) {
            continue; // handle new pseudo-parent types added in ICU data per cldrbug 7808; for now just skip.
            // #11232 is to do something useful with these.
        }
        UnicodeString parentStr = UnicodeString(parent, -1 , US_INV);
        Region *parentRegion = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&parentStr);

        for ( int j = 0 ; j < ures_getSize(mapping.getAlias()); j++ ) {
            UnicodeString child = ures_getUnicodeStringByIndex(mapping.getAlias(),j,&status);
            Region *childRegion = (Region *) uhash_get(newRegionIDMap.getAlias(),(void *)&child);
            if ( parentRegion != NULL && childRegion != NULL ) {

                // Add the child region to the set of regions contained by the parent
                if (parentRegion->containedRegions == NULL) {
                    parentRegion->containedRegions = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
                }

                LocalPointer<UnicodeString> childStr(new UnicodeString(), status);
                if( U_FAILURE(status) ) {
                    return;  // error out
                }
                childStr->fastCopyFrom(childRegion->idStr);
                parentRegion->containedRegions->addElement((void *)childStr.orphan(),status);

                // Set the parent region to be the containing region of the child.
                // Regions of type GROUPING can't be set as the parent, since another region
                // such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent.
                if ( parentRegion->type != URGN_GROUPING) {
                    childRegion->containingRegion = parentRegion;
                }
            }
        }
    }

    // Create the availableRegions lists
    int32_t pos = UHASH_FIRST;
    while ( const UHashElement* element = uhash_nextElement(newRegionIDMap.getAlias(),&pos)) {
        Region *ar = (Region *)element->value.pointer;
        if ( availableRegions[ar->type] == NULL ) {
            LocalPointer<UVector> newAr(new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status), status);
            availableRegions[ar->type] = newAr.orphan();
        }
        LocalPointer<UnicodeString> arString(new UnicodeString(ar->idStr), status);
        if( U_FAILURE(status) ) {
            return;  // error out
        }
        availableRegions[ar->type]->addElement((void *)arString.orphan(),status);
    }
    
    ucln_i18n_registerCleanup(UCLN_I18N_REGION, region_cleanup);
    // copy hashtables
    numericCodeMap = newNumericCodeMap.orphan();
    regionIDMap = newRegionIDMap.orphan();
    regionAliases = newRegionAliases.orphan();
}
Example #23
0
TimeZoneGenericNames*
TimeZoneGenericNames::createInstance(const Locale& locale, UErrorCode& status) {
    if (U_FAILURE(status)) {
        return NULL;
    }
    TimeZoneGenericNames* instance = new TimeZoneGenericNames();
    if (instance == NULL) {
        status = U_MEMORY_ALLOCATION_ERROR;
        return NULL;
    }

    TZGNCoreRef *cacheEntry = NULL;
    {
        Mutex lock(&gTZGNLock);

        if (!gTZGNCoreCacheInitialized) {
            // Create empty hashtable
            gTZGNCoreCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
            if (U_SUCCESS(status)) {
                uhash_setKeyDeleter(gTZGNCoreCache, uprv_free);
                uhash_setValueDeleter(gTZGNCoreCache, deleteTZGNCoreRef);
                gTZGNCoreCacheInitialized = TRUE;
                ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEGENERICNAMES, tzgnCore_cleanup);
            }
        }
        if (U_FAILURE(status)) {
            return NULL;
        }

        // Check the cache, if not available, create new one and cache
        const char *key = locale.getName();
        cacheEntry = (TZGNCoreRef *)uhash_get(gTZGNCoreCache, key);
        if (cacheEntry == NULL) {
            TZGNCore *tzgnCore = NULL;
            char *newKey = NULL;

            tzgnCore = new TZGNCore(locale, status);
            if (tzgnCore == NULL) {
                status = U_MEMORY_ALLOCATION_ERROR;
            }
            if (U_SUCCESS(status)) {
                newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
                if (newKey == NULL) {
                    status = U_MEMORY_ALLOCATION_ERROR;
                } else {
                    uprv_strcpy(newKey, key);
                }
            }
            if (U_SUCCESS(status)) {
                cacheEntry = (TZGNCoreRef *)uprv_malloc(sizeof(TZGNCoreRef));
                if (cacheEntry == NULL) {
                    status = U_MEMORY_ALLOCATION_ERROR;
                } else {
                    cacheEntry->obj = tzgnCore;
                    cacheEntry->refCount = 1;
                    cacheEntry->lastAccess = (double)uprv_getUTCtime();

                    uhash_put(gTZGNCoreCache, newKey, cacheEntry, &status);
                }
            }
            if (U_FAILURE(status)) {
                if (tzgnCore != NULL) {
                    delete tzgnCore;
                }
                if (newKey != NULL) {
                    uprv_free(newKey);
                }
                if (cacheEntry != NULL) {
                    uprv_free(cacheEntry);
                }
                cacheEntry = NULL;
            }
        } else {
            // Update the reference count
            cacheEntry->refCount++;
            cacheEntry->lastAccess = (double)uprv_getUTCtime();
        }
        gAccessCount++;
        if (gAccessCount >= SWEEP_INTERVAL) {
            // sweep
            sweepCache();
            gAccessCount = 0;
        }
    }  // End of mutex locked block

    if (cacheEntry == NULL) {
        delete instance;
        return NULL;
    }

    instance->fRef = cacheEntry;
    return instance;
}
Example #24
0
TimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status) {
    Mutex lock(&gTimeZoneNamesLock);
    if (!gTimeZoneNamesCacheInitialized) {
        // Create empty hashtable if it is not already initialized.
        gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
        if (U_SUCCESS(status)) {
            uhash_setKeyDeleter(gTimeZoneNamesCache, uprv_free);
            uhash_setValueDeleter(gTimeZoneNamesCache, deleteTimeZoneNamesCacheEntry);
            gTimeZoneNamesCacheInitialized = TRUE;
            ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONENAMES, timeZoneNames_cleanup);
        }
    }

    if (U_FAILURE(status)) {
        return;
    }

    // Check the cache, if not available, create new one and cache
    TimeZoneNamesCacheEntry *cacheEntry = NULL;

    const char *key = locale.getName();
    cacheEntry = (TimeZoneNamesCacheEntry *)uhash_get(gTimeZoneNamesCache, key);
    if (cacheEntry == NULL) {
        TimeZoneNames *tznames = NULL;
        char *newKey = NULL;

        tznames = new TimeZoneNamesImpl(locale, status);
        if (tznames == NULL) {
            status = U_MEMORY_ALLOCATION_ERROR;
        }
        if (U_SUCCESS(status)) {
            newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
            if (newKey == NULL) {
                status = U_MEMORY_ALLOCATION_ERROR;
            } else {
                uprv_strcpy(newKey, key);
            }
        }
        if (U_SUCCESS(status)) {
            cacheEntry = (TimeZoneNamesCacheEntry *)uprv_malloc(sizeof(TimeZoneNamesCacheEntry));
            if (cacheEntry == NULL) {
                status = U_MEMORY_ALLOCATION_ERROR;
            } else {
                cacheEntry->names = tznames;
                cacheEntry->refCount = 1;
                cacheEntry->lastAccess = (double)uprv_getUTCtime();

                uhash_put(gTimeZoneNamesCache, newKey, cacheEntry, &status);
            }
        }
        if (U_FAILURE(status)) {
            if (tznames != NULL) {
                delete tznames;
            }
            if (newKey != NULL) {
                uprv_free(newKey);
            }
            if (cacheEntry != NULL) {
                uprv_free(cacheEntry);
            }
            cacheEntry = NULL;
        }
    } else {
        // Update the reference count
        cacheEntry->refCount++;
        cacheEntry->lastAccess = (double)uprv_getUTCtime();
    }
    gAccessCount++;
    if (gAccessCount >= SWEEP_INTERVAL) {
        // sweep
        sweepCache();
        gAccessCount = 0;
    }
    fTZnamesCacheEntry = cacheEntry;
}
Example #25
0
/*
 * Initializes the region data from the ICU resource bundles.  The region data
 * contains the basic relationships such as which regions are known, what the numeric
 * codes are, any known aliases, and the territory containment data.
 * 
 * If the region data has already loaded, then this method simply returns without doing
 * anything meaningful.
 */
void Region::loadRegionData() {

    if (regionDataIsLoaded) {
        return;
    }

    umtx_lock(&gRegionDataLock);

    if (regionDataIsLoaded) { // In case another thread gets to it before we do...
        umtx_unlock(&gRegionDataLock);
        return;
    }

   
    UErrorCode status = U_ZERO_ERROR;

    UResourceBundle* regionCodes = NULL;
    UResourceBundle* territoryAlias = NULL;
    UResourceBundle* codeMappings = NULL;
    UResourceBundle* worldContainment = NULL;
    UResourceBundle* territoryContainment = NULL;
    UResourceBundle* groupingContainment = NULL;

    DecimalFormat *df = new DecimalFormat(status);
    df->setParseIntegerOnly(TRUE);

    regionIDMap = uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status);
    uhash_setValueDeleter(regionIDMap, deleteRegion);

    numericCodeMap = uhash_open(uhash_hashLong,uhash_compareLong,NULL,&status);

    regionAliases = uhash_open(uhash_hashUnicodeString,uhash_compareUnicodeString,NULL,&status);
    uhash_setKeyDeleter(regionAliases,uprv_deleteUObject);

    UResourceBundle *rb = ures_openDirect(NULL,"metadata",&status);
    regionCodes = ures_getByKey(rb,"regionCodes",NULL,&status);
    territoryAlias = ures_getByKey(rb,"territoryAlias",NULL,&status);
    
    UResourceBundle *rb2 = ures_openDirect(NULL,"supplementalData",&status);
    codeMappings = ures_getByKey(rb2,"codeMappings",NULL,&status);

    territoryContainment = ures_getByKey(rb2,"territoryContainment",NULL,&status);
    worldContainment = ures_getByKey(territoryContainment,"001",NULL,&status);
    groupingContainment = ures_getByKey(territoryContainment,"grouping",NULL,&status);

    UVector *continents = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);

    while ( ures_hasNext(worldContainment) ) {
        UnicodeString *continentName = new UnicodeString(ures_getNextUnicodeString(worldContainment,NULL,&status));
        continents->addElement(continentName,status);
    }

    UVector *groupings = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
    while ( ures_hasNext(groupingContainment) ) {
        UnicodeString *groupingName = new UnicodeString(ures_getNextUnicodeString(groupingContainment,NULL,&status));
        groupings->addElement(groupingName,status);
    }

    while ( ures_hasNext(regionCodes) ) {
        UnicodeString regionID = ures_getNextUnicodeString(regionCodes,NULL,&status);
        Region *r = new Region();
        r->idStr = regionID;
        r->idStr.extract(0,r->idStr.length(),r->id,sizeof(r->id),US_INV);
        r->type = URGN_TERRITORY; // Only temporary - figure out the real type later once the aliases are known.

        uhash_put(regionIDMap,(void *)&(r->idStr),(void *)r,&status);
        Formattable result;
        UErrorCode ps = U_ZERO_ERROR;
        df->parse(r->idStr,result,ps);
        if ( U_SUCCESS(ps) ) {
            r->code = result.getLong(); // Convert string to number
            uhash_iput(numericCodeMap,r->code,(void *)r,&status);
            r->type = URGN_SUBCONTINENT;
        } else {
            r->code = Region::UNDEFINED_NUMERIC_CODE;
        }
    }


    // Process the territory aliases
    while ( ures_hasNext(territoryAlias) ) {
        UResourceBundle *res = ures_getNextResource(territoryAlias,NULL,&status);
        const char *aliasFrom = ures_getKey(res);
        UnicodeString* aliasFromStr = new UnicodeString(aliasFrom);
        UnicodeString aliasTo = ures_getUnicodeString(res,&status);
        ures_close(res);

        Region *aliasToRegion = (Region *) uhash_get(regionIDMap,&aliasTo);
        Region *aliasFromRegion = (Region *)uhash_get(regionIDMap,aliasFromStr);

        if ( aliasToRegion != NULL && aliasFromRegion == NULL ) { // This is just an alias from some string to a region
            uhash_put(regionAliases,(void *)aliasFromStr, (void *)aliasToRegion,&status);
        } else {
            if ( aliasFromRegion == NULL ) { // Deprecated region code not in the master codes list - so need to create a deprecated region for it.
                aliasFromRegion = new Region();
                aliasFromRegion->idStr.setTo(*aliasFromStr);
                aliasFromRegion->idStr.extract(0,aliasFromRegion->idStr.length(),aliasFromRegion->id,sizeof(aliasFromRegion->id),US_INV);
                uhash_put(regionIDMap,(void *)&(aliasFromRegion->idStr),(void *)aliasFromRegion,&status);
                Formattable result;
                UErrorCode ps = U_ZERO_ERROR;
                df->parse(aliasFromRegion->idStr,result,ps);
                if ( U_SUCCESS(ps) ) {
                    aliasFromRegion->code = result.getLong(); // Convert string to number
                    uhash_iput(numericCodeMap,aliasFromRegion->code,(void *)aliasFromRegion,&status);
                } else {
                    aliasFromRegion->code = Region::UNDEFINED_NUMERIC_CODE;
                }
                aliasFromRegion->type = URGN_DEPRECATED;
            } else {
                aliasFromRegion->type = URGN_DEPRECATED;
            }
            delete aliasFromStr;

            aliasFromRegion->preferredValues = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
            UnicodeString currentRegion;
            currentRegion.remove();
            for (int32_t i = 0 ; i < aliasTo.length() ; i++ ) {
                if ( aliasTo.charAt(i) != 0x0020 ) {
                    currentRegion.append(aliasTo.charAt(i));
                }
                if ( aliasTo.charAt(i) == 0x0020 || i+1 == aliasTo.length() ) {
                    Region *target = (Region *)uhash_get(regionIDMap,(void *)&currentRegion);
                    if (target) {
                        UnicodeString *preferredValue = new UnicodeString(target->idStr);
                        aliasFromRegion->preferredValues->addElement((void *)preferredValue,status);
                    }
                    currentRegion.remove();
                }
            }
        }
    }

    // Process the code mappings - This will allow us to assign numeric codes to most of the territories.
    while ( ures_hasNext(codeMappings) ) {
        UResourceBundle *mapping = ures_getNextResource(codeMappings,NULL,&status);
        if ( ures_getType(mapping) == URES_ARRAY && ures_getSize(mapping) == 3) {
            UnicodeString codeMappingID = ures_getUnicodeStringByIndex(mapping,0,&status);
            UnicodeString codeMappingNumber = ures_getUnicodeStringByIndex(mapping,1,&status);
            UnicodeString codeMapping3Letter = ures_getUnicodeStringByIndex(mapping,2,&status);

            Region *r = (Region *)uhash_get(regionIDMap,(void *)&codeMappingID);
            if ( r ) {
                Formattable result;
                UErrorCode ps = U_ZERO_ERROR;
                df->parse(codeMappingNumber,result,ps);
                if ( U_SUCCESS(ps) ) {
                    r->code = result.getLong(); // Convert string to number
                    uhash_iput(numericCodeMap,r->code,(void *)r,&status);
                }
                UnicodeString *code3 = new UnicodeString(codeMapping3Letter);
                uhash_put(regionAliases,(void *)code3, (void *)r,&status);
            }                    
        }
        ures_close(mapping);
    }

    // Now fill in the special cases for WORLD, UNKNOWN, CONTINENTS, and GROUPINGS
    Region *r;
    r = (Region *) uhash_get(regionIDMap,(void *)&WORLD_ID);
    if ( r ) {
        r->type = URGN_WORLD;
    }

    r = (Region *) uhash_get(regionIDMap,(void *)&UNKNOWN_REGION_ID);
    if ( r ) {
        r->type = URGN_UNKNOWN;
    }

    for ( int32_t i = 0 ; i < continents->size() ; i++ ) {
        r = (Region *) uhash_get(regionIDMap,(void *)continents->elementAt(i));
        if ( r ) {
            r->type = URGN_CONTINENT;
        }
    }
    delete continents;

    for ( int32_t i = 0 ; i < groupings->size() ; i++ ) {
        r = (Region *) uhash_get(regionIDMap,(void *)groupings->elementAt(i));
        if ( r ) {
            r->type = URGN_GROUPING;
        }
    }
    delete groupings;

    // Special case: The region code "QO" (Outlying Oceania) is a subcontinent code added by CLDR
    // even though it looks like a territory code.  Need to handle it here.

    r = (Region *) uhash_get(regionIDMap,(void *)&OUTLYING_OCEANIA_REGION_ID);
    if ( r ) {
        r->type = URGN_SUBCONTINENT;
    }

    // Load territory containment info from the supplemental data.
    while ( ures_hasNext(territoryContainment) ) {
        UResourceBundle *mapping = ures_getNextResource(territoryContainment,NULL,&status);
        const char *parent = ures_getKey(mapping);
        UnicodeString parentStr = UnicodeString(parent);
        Region *parentRegion = (Region *) uhash_get(regionIDMap,(void *)&parentStr);

        for ( int j = 0 ; j < ures_getSize(mapping); j++ ) {
            UnicodeString child = ures_getUnicodeStringByIndex(mapping,j,&status);
            Region *childRegion = (Region *) uhash_get(regionIDMap,(void *)&child);
            if ( parentRegion != NULL && childRegion != NULL ) {                    

                // Add the child region to the set of regions contained by the parent
                if (parentRegion->containedRegions == NULL) {
                    parentRegion->containedRegions = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
                }

                UnicodeString *childStr = new UnicodeString(status);
                childStr->fastCopyFrom(childRegion->idStr);
                parentRegion->containedRegions->addElement((void *)childStr,status);

                // Set the parent region to be the containing region of the child.
                // Regions of type GROUPING can't be set as the parent, since another region
                // such as a SUBCONTINENT, CONTINENT, or WORLD must always be the parent.
                if ( parentRegion->type != URGN_GROUPING) {
                    childRegion->containingRegion = parentRegion;
                }
            }
        }
        ures_close(mapping);
    }     

    // Create the availableRegions lists
    int32_t pos = -1;
    while ( const UHashElement* element = uhash_nextElement(regionIDMap,&pos)) {
        Region *ar = (Region *)element->value.pointer;
        if ( availableRegions[ar->type] == NULL ) {
            availableRegions[ar->type] = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
        }
        UnicodeString *arString = new UnicodeString(ar->idStr);
        availableRegions[ar->type]->addElement((void *)arString,status);
    }

    ures_close(territoryContainment);
    ures_close(worldContainment);
    ures_close(groupingContainment);

    ures_close(codeMappings);
    ures_close(rb2);
    ures_close(territoryAlias);
    ures_close(regionCodes);
    ures_close(rb);

    delete df;

    ucln_i18n_registerCleanup(UCLN_I18N_REGION, region_cleanup);

    regionDataIsLoaded = true;
    umtx_unlock(&gRegionDataLock);

}
Example #26
0
void
ZoneMeta::initAvailableMetaZoneIDs () {
    UBool initialized;
    UMTX_CHECK(&gZoneMetaLock, gMetaZoneIDsInitialized, initialized);
    if (!initialized) {
        umtx_lock(&gZoneMetaLock);
        {
            if (!gMetaZoneIDsInitialized) {
                UErrorCode status = U_ZERO_ERROR;
                UHashtable *metaZoneIDTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status);
                uhash_setKeyDeleter(metaZoneIDTable, uprv_deleteUObject);
                // No valueDeleter, because the vector maintain the value objects
                UVector *metaZoneIDs = NULL;
                if (U_SUCCESS(status)) {
                    metaZoneIDs = new UVector(NULL, uhash_compareUChars, status);
                    if (metaZoneIDs == NULL) {
                        status = U_MEMORY_ALLOCATION_ERROR;
                    }
                } else {
                    uhash_close(metaZoneIDTable);
                }
                if (U_SUCCESS(status)) {
                    U_ASSERT(metaZoneIDs != NULL);
                    metaZoneIDs->setDeleter(uprv_free);

                    UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status);
                    UResourceBundle *bundle = ures_getByKey(rb, gMapTimezonesTag, NULL, &status);
                    UResourceBundle res;
                    ures_initStackObject(&res);
                    while (U_SUCCESS(status) && ures_hasNext(bundle)) {
                        ures_getNextResource(bundle, &res, &status);
                        if (U_FAILURE(status)) {
                            break;
                        }
                        const char *mzID = ures_getKey(&res);
                        int32_t len = uprv_strlen(mzID);
                        UChar *uMzID = (UChar*)uprv_malloc(sizeof(UChar) * (len + 1));
                        if (uMzID == NULL) {
                            status = U_MEMORY_ALLOCATION_ERROR;
                            break;
                        }
                        u_charsToUChars(mzID, uMzID, len);
                        uMzID[len] = 0;
                        UnicodeString *usMzID = new UnicodeString(uMzID);
                        if (uhash_get(metaZoneIDTable, usMzID) == NULL) {
                            metaZoneIDs->addElement((void *)uMzID, status);
                            uhash_put(metaZoneIDTable, (void *)usMzID, (void *)uMzID, &status);
                        } else {
                            uprv_free(uMzID);
                            delete usMzID;
                        }
                    }
                    if (U_SUCCESS(status)) {
                        gMetaZoneIDs = metaZoneIDs;
                        gMetaZoneIDTable = metaZoneIDTable;
                        gMetaZoneIDsInitialized = TRUE;
                    } else {
                        uhash_close(metaZoneIDTable);
                        delete metaZoneIDs;
                    }
                    ures_close(&res);
                    ures_close(bundle);
                    ures_close(rb);
                }
            }
        }
        umtx_unlock(&gZoneMetaLock);
    }
}