/* udata_getCacheHashTable() * Get the hash table used to store the data cache entries. * Lazy create it if it doesn't yet exist. */ static UHashtable *udata_getHashTable() { UErrorCode err = U_ZERO_ERROR; UBool cacheIsInitialized; UHashtable *tHT = NULL; UMTX_CHECK(NULL, (gCommonDataCache != NULL), cacheIsInitialized); if (cacheIsInitialized) { return gCommonDataCache; } tHT = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &err); /* Check for null pointer. */ if (tHT == NULL) { return NULL; /* TODO: Handle this error better. */ } uhash_setValueDeleter(tHT, DataCacheElement_deleter); umtx_lock(NULL); if (gCommonDataCache == NULL) { gCommonDataCache = tHT; tHT = NULL; ucln_common_registerCleanup(UCLN_COMMON_UDATA, udata_cleanup); } umtx_unlock(NULL); if (tHT != NULL) { uhash_close(tHT); } if (U_FAILURE(err)) { return NULL; /* TODO: handle this error better. */ } return gCommonDataCache; }
U_CDECL_END U_NAMESPACE_BEGIN Locale *locale_set_default_internal(const char *id, UErrorCode& status) { // Synchronize this entire function. Mutex lock(&gDefaultLocaleMutex); UBool canonicalize = FALSE; // If given a NULL string for the locale id, grab the default // name from the system. // (Different from most other locale APIs, where a null name means use // the current ICU default locale.) if (id == NULL) { id = uprv_getDefaultLocaleID(); // This function not thread safe? TODO: verify. canonicalize = TRUE; // always canonicalize host ID } char localeNameBuf[512]; if (canonicalize) { uloc_canonicalize(id, localeNameBuf, sizeof(localeNameBuf)-1, &status); } else { uloc_getName(id, localeNameBuf, sizeof(localeNameBuf)-1, &status); } localeNameBuf[sizeof(localeNameBuf)-1] = 0; // Force null termination in event of // a long name filling the buffer. // (long names are truncated.) // if (U_FAILURE(status)) { return gDefaultLocale; } if (gDefaultLocalesHashT == NULL) { gDefaultLocalesHashT = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); if (U_FAILURE(status)) { return gDefaultLocale; } uhash_setValueDeleter(gDefaultLocalesHashT, deleteLocale); ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup); } Locale *newDefault = (Locale *)uhash_get(gDefaultLocalesHashT, localeNameBuf); if (newDefault == NULL) { newDefault = new Locale(Locale::eBOGUS); if (newDefault == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return gDefaultLocale; } newDefault->init(localeNameBuf, FALSE); uhash_put(gDefaultLocalesHashT, (char*) newDefault->getName(), newDefault, &status); if (U_FAILURE(status)) { return gDefaultLocale; } } gDefaultLocale = newDefault; return gDefaultLocale; }
/** * Copy constructor. */ AnyTransliterator::AnyTransliterator(const AnyTransliterator& o) : Transliterator(o), target(o.target), targetScript(o.targetScript) { // Don't copy the cache contents UErrorCode ec = U_ZERO_ERROR; cache = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &ec); uhash_setValueDeleter(cache, _deleteTransliterator); }
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. }
/** * Copy constructor. */ AnyTransliterator::AnyTransliterator(const AnyTransliterator& o) : Transliterator(o), target(o.target), targetScript(o.targetScript) { // Don't copy the cache contents UErrorCode ec = U_ZERO_ERROR; cache = uhash_openSize(uhash_hashLong, uhash_compareLong, NULL, ANY_TRANS_CACHE_INIT_SIZE, &ec); if (U_FAILURE(ec)) { return; } uhash_setValueDeleter(cache, _deleteTransliterator); }
void TimeZoneNamesImpl::initialize(const Locale& locale, UErrorCode& status) { if (U_FAILURE(status)) { return; } // Load zoneStrings bundle UErrorCode tmpsts = U_ZERO_ERROR; // OK with fallback warning.. fZoneStrings = ures_open(U_ICUDATA_ZONE, locale.getName(), &tmpsts); fZoneStrings = ures_getByKeyWithFallback(fZoneStrings, gZoneStrings, fZoneStrings, &tmpsts); if (U_FAILURE(tmpsts)) { status = tmpsts; cleanup(); return; } // Initialize hashtables holding time zone/meta zone names fMZNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status); fTZNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status); if (U_FAILURE(status)) { cleanup(); return; } uhash_setValueDeleter(fMZNamesMap, deleteZNames); uhash_setValueDeleter(fTZNamesMap, deleteTZNames); // no key deleters for name maps // preload zone strings for the default zone TimeZone *tz = TimeZone::createDefault(); const UChar *tzID = ZoneMeta::getCanonicalCLDRID(*tz); if (tzID != NULL) { loadStrings(UnicodeString(tzID)); } delete tz; return; }
static void U_CALLCONV nscacheInit() { U_ASSERT(NumberingSystem_cache == NULL); ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); UErrorCode status = U_ZERO_ERROR; NumberingSystem_cache = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &status); if (U_FAILURE(status)) { // Number Format code will run with no cache if creation fails. NumberingSystem_cache = NULL; return; } uhash_setValueDeleter(NumberingSystem_cache, deleteNumberingSystem); }
AnyTransliterator::AnyTransliterator(const UnicodeString& id, const UnicodeString& theTarget, const UnicodeString& theVariant, UScriptCode theTargetScript, UErrorCode& ec) : Transliterator(id, NULL), targetScript(theTargetScript) { cache = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &ec); uhash_setValueDeleter(cache, _deleteTransliterator); target = theTarget; if (theVariant.length() > 0) { target.append(VARIANT_SEP).append(theVariant); } }
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); }
CEToStringsMap::CEToStringsMap(UErrorCode &status) : map(NULL) { if (U_FAILURE(status)) { return; } map = uhash_open(uhash_hashLong, uhash_compareLong, uhash_compareCaselessUnicodeString, &status); if (U_FAILURE(status)) { return; } uhash_setValueDeleter(map, deleteStringList); }
// 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); }
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); }
AnyTransliterator::AnyTransliterator(const UnicodeString& id, const UnicodeString& theTarget, const UnicodeString& theVariant, UScriptCode theTargetScript, UErrorCode& ec) : Transliterator(id, NULL), targetScript(theTargetScript) { cache = uhash_openSize(uhash_hashLong, uhash_compareLong, NULL, ANY_TRANS_CACHE_INIT_SIZE, &ec); if (U_FAILURE(ec)) { return; } uhash_setValueDeleter(cache, _deleteTransliterator); target = theTarget; if (theVariant.length() > 0) { target.append(VARIANT_SEP).append(theVariant); } }
U_CDECL_END U_NAMESPACE_BEGIN RBBISymbolTable::RBBISymbolTable(RBBIRuleScanner *rs, const UnicodeString &rules, UErrorCode &status) :fRules(rules), fRuleScanner(rs), ffffString(UChar(0xffff)) { fHashTable = NULL; fCachedSetLookup = NULL; fHashTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status); // uhash_open checks status if (U_FAILURE(status)) { return; } uhash_setValueDeleter(fHashTable, RBBISymbolTableEntry_deleter); }
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; }
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; }
extern void storeMapping(uint32_t codepoint, uint32_t* mapping,int32_t length, UStringPrepType type, UErrorCode* status){ UChar* map = NULL; int16_t adjustedLen=0, i; uint16_t trieWord = 0; ValueStruct *value = NULL; uint32_t savedTrieWord = 0; /* initialize the hashtable */ if(hashTable==NULL){ hashTable = uhash_open(hashEntry, compareEntries, NULL, status); uhash_setValueDeleter(hashTable, valueDeleter); } /* figure out if the code point has type already stored */ savedTrieWord= utrie_get32(sprepTrie,codepoint,NULL); if(savedTrieWord!=0){ if((savedTrieWord- _SPREP_TYPE_THRESHOLD) == USPREP_PROHIBITED){ /* turn on the first bit in trie word */ trieWord += 0x01; }else{ /* * the codepoint has value something other than prohibited * and a mapping .. error! */ fprintf(stderr,"Type for codepoint \\U%08X already set!.\n", (int)codepoint); exit(U_ILLEGAL_ARGUMENT_ERROR); } } /* figure out the real length */ for(i=0; i<length; i++){ if(mapping[i] > 0xFFFF){ adjustedLen +=2; }else{ adjustedLen++; } } if(adjustedLen == 0){ trieWord = (uint16_t)(_SPREP_MAX_INDEX_VALUE << 2); /* make sure that the value of trieWord is less than the threshold */ if(trieWord < _SPREP_TYPE_THRESHOLD){ /* now set the value in the trie */ if(!utrie_set32(sprepTrie,codepoint,trieWord)){ fprintf(stderr,"Could not set the value for code point.\n"); exit(U_ILLEGAL_ARGUMENT_ERROR); } /* value is set so just return */ return; }else{ fprintf(stderr,"trieWord cannot contain value greater than threshold 0x%04X.\n",_SPREP_TYPE_THRESHOLD); exit(U_ILLEGAL_CHAR_FOUND); } } if(adjustedLen == 1){ /* calculate the delta */ int16_t delta = (int16_t)((int32_t)codepoint - (int16_t) mapping[0]); if(delta >= SPREP_DELTA_RANGE_NEGATIVE_LIMIT && delta <= SPREP_DELTA_RANGE_POSITIVE_LIMIT){ trieWord = delta << 2; /* make sure that the second bit is OFF */ if((trieWord & 0x02) != 0 ){ fprintf(stderr,"The second bit in the trie word is not zero while storing a delta.\n"); exit(U_INTERNAL_PROGRAM_ERROR); } /* make sure that the value of trieWord is less than the threshold */ if(trieWord < _SPREP_TYPE_THRESHOLD){ /* now set the value in the trie */ if(!utrie_set32(sprepTrie,codepoint,trieWord)){ fprintf(stderr,"Could not set the value for code point.\n"); exit(U_ILLEGAL_ARGUMENT_ERROR); } /* value is set so just return */ return; } } /* * if the delta is not in the given range or if the trieWord is larger than the threshold * just fall through for storing the mapping in the mapping table */ } map = (UChar*) uprv_calloc(adjustedLen + 1, U_SIZEOF_UCHAR); i=0; while(i<length){ if(mapping[i] <= 0xFFFF){ map[i] = (uint16_t)mapping[i]; }else{ map[i] = U16_LEAD(mapping[i]); map[i+1] = U16_TRAIL(mapping[i]); } i++; } value = (ValueStruct*) uprv_malloc(sizeof(ValueStruct)); value->mapping = map; value->type = type; value->length = adjustedLen; if(value->length > _SPREP_MAX_INDEX_TOP_LENGTH){ mappingDataCapacity++; } if(maxLength < value->length){ maxLength = value->length; } uhash_iput(hashTable,codepoint,value,status); mappingDataCapacity += adjustedLen; if(U_FAILURE(*status)){ fprintf(stderr, "Failed to put entries into the hastable. Error: %s\n", u_errorName(*status)); exit(*status); } }
UHashtable* ZoneMeta::createCanonicalMap(void) { UErrorCode status = U_ZERO_ERROR; UHashtable *canonicalMap = NULL; UResourceBundle *zoneFormatting = NULL; UResourceBundle *tzitem = NULL; UResourceBundle *aliases = NULL; StringEnumeration* tzenum = NULL; int32_t numZones; canonicalMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status); if (U_FAILURE(status)) { return NULL; } // no key deleter uhash_setValueDeleter(canonicalMap, deleteCanonicalMapEntry); zoneFormatting = ures_openDirect(NULL, gSupplementalData, &status); zoneFormatting = ures_getByKey(zoneFormatting, gZoneFormattingTag, zoneFormatting, &status); if (U_FAILURE(status)) { goto error_cleanup; } while (ures_hasNext(zoneFormatting)) { tzitem = ures_getNextResource(zoneFormatting, tzitem, &status); if (U_FAILURE(status)) { status = U_ZERO_ERROR; continue; } if (ures_getType(tzitem) != URES_TABLE) { continue; } int32_t canonicalLen; const UChar *canonical = ures_getStringByKey(tzitem, gCanonicalTag, &canonicalLen, &status); if (U_FAILURE(status)) { status = U_ZERO_ERROR; continue; } int32_t territoryLen; const UChar *territory = ures_getStringByKey(tzitem, gTerritoryTag, &territoryLen, &status); if (U_FAILURE(status)) { territory = NULL; status = U_ZERO_ERROR; } // Create canonical map entry CanonicalMapEntry *entry = (CanonicalMapEntry*)uprv_malloc(sizeof(CanonicalMapEntry)); if (entry == NULL) { status = U_MEMORY_ALLOCATION_ERROR; goto error_cleanup; } entry->id = canonical; if (territory == NULL || u_strcmp(territory, gWorld) == 0) { entry->country = NULL; } else { entry->country = territory; } // Put this entry in the hashtable. Since this hashtable has no key deleter, // key is treated as const, but must be passed as non-const. uhash_put(canonicalMap, (UChar*)canonical, entry, &status); if (U_FAILURE(status)) { goto error_cleanup; } // Get aliases aliases = ures_getByKey(tzitem, gAliasesTag, aliases, &status); if (U_FAILURE(status)) { // No aliases status = U_ZERO_ERROR; continue; } while (ures_hasNext(aliases)) { const UChar* alias = ures_getNextString(aliases, NULL, NULL, &status); if (U_FAILURE(status)) { status = U_ZERO_ERROR; continue; } // Create canonical map entry for this alias entry = (CanonicalMapEntry*)uprv_malloc(sizeof(CanonicalMapEntry)); if (entry == NULL) { status = U_MEMORY_ALLOCATION_ERROR; goto error_cleanup; } entry->id = canonical; if (territory == NULL || u_strcmp(territory, gWorld) == 0) { entry->country = NULL; } else { entry->country = territory; } // Put this entry in the hashtable. Since this hashtable has no key deleter, // key is treated as const, but must be passed as non-const. uhash_put(canonicalMap, (UChar*)alias, entry, &status); if (U_FAILURE(status)) { goto error_cleanup; } } } // Some available Olson zones are not included in CLDR data (such as Asia/Riyadh87). // Also, when we update Olson tzdata, new zones may be added. // This code scans all available zones in zoneinfo.res, and if any of them are // missing, add them to the map. tzenum = TimeZone::createEnumeration(); numZones = tzenum->count(status); if (U_SUCCESS(status)) { int32_t i; for (i = 0; i < numZones; i++) { const UnicodeString *zone = tzenum->snext(status); if (U_FAILURE(status)) { // We should not get here. status = U_ZERO_ERROR; continue; } UChar zoneUChars[ZID_KEY_MAX]; int32_t zoneUCharsLen = zone->extract(zoneUChars, ZID_KEY_MAX, status) + 1; // Add one for NUL termination if (U_FAILURE(status) || status==U_STRING_NOT_TERMINATED_WARNING) { status = U_ZERO_ERROR; continue; // zone id is too long to extract } CanonicalMapEntry *entry = (CanonicalMapEntry*)uhash_get(canonicalMap, zoneUChars); if (entry) { // Already included in CLDR data continue; } // Not in CLDR data, but it could be new one whose alias is available // in CLDR. int32_t nTzdataEquivalent = TimeZone::countEquivalentIDs(*zone); int32_t j; for (j = 0; j < nTzdataEquivalent; j++) { UnicodeString alias = TimeZone::getEquivalentID(*zone, j); if (alias == *zone) { continue; } UChar aliasUChars[ZID_KEY_MAX]; alias.extract(aliasUChars, ZID_KEY_MAX, status); if (U_FAILURE(status) || status==U_STRING_NOT_TERMINATED_WARNING) { status = U_ZERO_ERROR; continue; // zone id is too long to extract } entry = (CanonicalMapEntry*)uhash_get(canonicalMap, aliasUChars); if (entry != NULL) { break; } } // Create a new map entry CanonicalMapEntry* newEntry = (CanonicalMapEntry*)uprv_malloc(sizeof(CanonicalMapEntry)); int32_t idLen; if (newEntry == NULL) { status = U_MEMORY_ALLOCATION_ERROR; goto error_cleanup; } if (entry == NULL) { // Set dereferenced zone ID as the canonical ID UnicodeString derefZone; TimeZone::dereferOlsonLink(*zone, derefZone); if (derefZone.length() == 0) { // It should never happen.. but just in case derefZone = *zone; } idLen = derefZone.length() + 1; newEntry->id = allocUStringInTable(idLen); if (newEntry->id == NULL) { status = U_MEMORY_ALLOCATION_ERROR; uprv_free(newEntry); goto error_cleanup; } // Copy NULL terminated string derefZone.extract((UChar*)(newEntry->id), idLen, status); if (U_FAILURE(status)) { removeLastUStringFromTable(); uprv_free(newEntry); goto error_cleanup; } // No territory information available newEntry->country = NULL; } else { // Duplicate the entry newEntry->id = entry->id; newEntry->country = entry->country; } // Put this entry in the hashtable UChar *key = allocUStringInTable(zoneUCharsLen); if (key == NULL) { status = U_MEMORY_ALLOCATION_ERROR; deleteCanonicalMapEntry(newEntry); goto error_cleanup; } u_strncpy(key, zoneUChars, zoneUCharsLen); uhash_put(canonicalMap, key, newEntry, &status); if (U_FAILURE(status)) { goto error_cleanup; } } } normal_cleanup: ures_close(aliases); ures_close(tzitem); ures_close(zoneFormatting); delete tzenum; return canonicalMap; error_cleanup: if (canonicalMap != NULL) { uhash_close(canonicalMap); canonicalMap = NULL; } goto normal_cleanup; }
NumberFormat* NumberFormat::makeInstance(const Locale& desiredLocale, EStyles style, UErrorCode& status) { if (U_FAILURE(status)) return NULL; if (style < 0 || style >= kStyleCount) { status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } #ifdef U_WINDOWS char buffer[8]; int32_t count = desiredLocale.getKeywordValue("compat", buffer, sizeof(buffer), status); // if the locale has "@compat=host", create a host-specific NumberFormat if (count > 0 && uprv_strcmp(buffer, "host") == 0) { Win32NumberFormat *f = NULL; UBool curr = TRUE; switch (style) { case kNumberStyle: curr = FALSE; // fall-through case kCurrencyStyle: case kIsoCurrencyStyle: // do not support plural formatting here case kPluralCurrencyStyle: f = new Win32NumberFormat(desiredLocale, curr, status); if (U_SUCCESS(status)) { return f; } delete f; break; default: break; } } #endif NumberFormat* f = NULL; DecimalFormatSymbols* symbolsToAdopt = NULL; UnicodeString pattern; UResourceBundle *resource = ures_open((char *)0, desiredLocale.getName(), &status); UResourceBundle *numberPatterns = ures_getByKey(resource, DecimalFormat::fgNumberPatterns, NULL, &status); NumberingSystem *ns = NULL; UBool deleteSymbols = TRUE; UHashtable * cache = NULL; int32_t hashKey; UBool getCache = FALSE; UBool deleteNS = FALSE; if (U_FAILURE(status)) { // We don't appear to have resource data available -- use the last-resort data status = U_USING_FALLBACK_WARNING; // When the data is unavailable, and locale isn't passed in, last resort data is used. symbolsToAdopt = new DecimalFormatSymbols(status); // Creates a DecimalFormat instance with the last resort number patterns. pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1); } else { // If not all the styled patterns exists for the NumberFormat in this locale, // sets the status code to failure and returns nil. if (ures_getSize(numberPatterns) < (int32_t)(sizeof(gLastResortNumberPatterns)/sizeof(gLastResortNumberPatterns[0])) -2 ) { //minus 2: ISO and plural status = U_INVALID_FORMAT_ERROR; goto cleanup; } // Loads the decimal symbols of the desired locale. symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status); int32_t patLen = 0; /* for ISOCURRENCYSTYLE and PLURALCURRENCYSTYLE, * the pattern is the same as the pattern of CURRENCYSTYLE * but by replacing the single currency sign with * double currency sign or triple currency sign. */ int styleInNumberPattern = ((style == kIsoCurrencyStyle || style == kPluralCurrencyStyle) ? kCurrencyStyle : style); const UChar *patResStr = ures_getStringByIndex(numberPatterns, (int32_t)styleInNumberPattern, &patLen, &status); // Creates the specified decimal format style of the desired locale. pattern.setTo(TRUE, patResStr, patLen); } if (U_FAILURE(status) || symbolsToAdopt == NULL) { goto cleanup; } if(style==kCurrencyStyle || style == kIsoCurrencyStyle){ const UChar* currPattern = symbolsToAdopt->getCurrencyPattern(); if(currPattern!=NULL){ pattern.setTo(currPattern, u_strlen(currPattern)); } } // Use numbering system cache hashtable UMTX_CHECK(&nscacheMutex, (UBool)(cache != NumberingSystem_cache), getCache); if (getCache) { umtx_lock(&nscacheMutex); cache = NumberingSystem_cache; umtx_unlock(&nscacheMutex); } // Check cache we got, create if non-existant status = U_ZERO_ERROR; if (cache == NULL) { cache = uhash_open(uhash_hashLong, uhash_compareLong, NULL, &status); if (cache == NULL || U_FAILURE(status)) { // cache not created - out of memory cache = NULL; } else { // cache created uhash_setValueDeleter(cache, deleteNumberingSystem); // set final NumberingSystem_cache value UHashtable* h = NULL; UMTX_CHECK(&nscacheMutex, (UBool)(h != NumberingSystem_cache), getCache); if (getCache) { umtx_lock(&nscacheMutex); h = NumberingSystem_cache; umtx_unlock(&nscacheMutex); } if (h == NULL) { umtx_lock(&nscacheMutex); NumberingSystem_cache = h = cache; cache = NULL; ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); umtx_unlock(&nscacheMutex); } if(cache != NULL) { uhash_close(cache); } cache = h; } } // Get cached numbering system if (cache != NULL) { hashKey = desiredLocale.hashCode(); umtx_lock(&nscacheMutex); ns = (NumberingSystem *)uhash_iget(cache, hashKey); if (ns == NULL) { ns = NumberingSystem::createInstance(desiredLocale,status); uhash_iput(cache, hashKey, (void*)ns, &status); } umtx_unlock(&nscacheMutex); } else { ns = NumberingSystem::createInstance(desiredLocale,status); deleteNS = TRUE; } // check results of getting a numbering system if ((ns == NULL) || (U_FAILURE(status))) { goto cleanup; } if (ns->isAlgorithmic()) { UnicodeString nsDesc; UnicodeString nsRuleSetGroup; UnicodeString nsRuleSetName; Locale nsLoc; URBNFRuleSetTag desiredRulesType = URBNF_NUMBERING_SYSTEM; nsDesc.setTo(ns->getDescription()); int32_t firstSlash = nsDesc.indexOf(gSlash); int32_t lastSlash = nsDesc.lastIndexOf(gSlash); if ( lastSlash > firstSlash ) { char nsLocID[ULOC_FULLNAME_CAPACITY]; nsDesc.extract(0,firstSlash,nsLocID,ULOC_FULLNAME_CAPACITY,US_INV); nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1); nsRuleSetName.setTo(nsDesc,lastSlash+1); nsLoc = Locale::createFromName(nsLocID); UnicodeString SpelloutRules = UNICODE_STRING_SIMPLE("SpelloutRules"); if ( nsRuleSetGroup.compare(SpelloutRules) == 0 ) { desiredRulesType = URBNF_SPELLOUT; } } else { nsLoc = desiredLocale; nsRuleSetName.setTo(nsDesc); } RuleBasedNumberFormat *r = new RuleBasedNumberFormat(desiredRulesType,nsLoc,status); if (U_FAILURE(status) || r == NULL) { goto cleanup; } r->setDefaultRuleSet(nsRuleSetName,status); f = (NumberFormat *) r; } else { // replace single currency sign in the pattern with double currency sign // if the style is kIsoCurrencyStyle if (style == kIsoCurrencyStyle) { pattern.findAndReplace(gSingleCurrencySign, gDoubleCurrencySign); } f = new DecimalFormat(pattern, symbolsToAdopt, style, status); if (U_FAILURE(status) || f == NULL) { goto cleanup; } deleteSymbols = FALSE; } f->setLocaleIDs(ures_getLocaleByType(numberPatterns, ULOC_VALID_LOCALE, &status), ures_getLocaleByType(numberPatterns, ULOC_ACTUAL_LOCALE, &status)); cleanup: ures_close(numberPatterns); ures_close(resource); if (deleteNS && ns) { delete ns; } if (U_FAILURE(status)) { /* If f exists, then it will delete the symbols */ if (f==NULL) { delete symbolsToAdopt; } else { delete f; } return NULL; } if (f == NULL || symbolsToAdopt == NULL) { status = U_MEMORY_ALLOCATION_ERROR; f = NULL; } if (deleteSymbols && symbolsToAdopt != NULL) { delete symbolsToAdopt; } return f; }
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; }
/* * 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; }
U_CDECL_END U_NAMESPACE_BEGIN //---------------------------------------------------------------------------------------- // // Constructor. // //---------------------------------------------------------------------------------------- RBBIRuleScanner::RBBIRuleScanner(RBBIRuleBuilder *rb) { fRB = rb; fStackPtr = 0; fStack[fStackPtr] = 0; fNodeStackPtr = 0; fRuleNum = 0; fNodeStack[0] = NULL; fRuleSets[kRuleSet_rule_char-128] = NULL; fRuleSets[kRuleSet_white_space-128] = NULL; fRuleSets[kRuleSet_name_char-128] = NULL; fRuleSets[kRuleSet_name_start_char-128] = NULL; fRuleSets[kRuleSet_digit_char-128] = NULL; fSymbolTable = NULL; fSetTable = NULL; fScanIndex = 0; fNextIndex = 0; fReverseRule = FALSE; fLookAheadRule = FALSE; fLineNum = 1; fCharNum = 0; fQuoteMode = FALSE; // Do not check status until after all critical fields are sufficiently initialized // that the destructor can run cleanly. if (U_FAILURE(*rb->fStatus)) { return; } // // Set up the constant Unicode Sets. // Note: These could be made static, lazily initialized, and shared among // all instances of RBBIRuleScanners. BUT this is quite a bit simpler, // and the time to build these few sets should be small compared to a // full break iterator build. fRuleSets[kRuleSet_rule_char-128] = new UnicodeSet(gRuleSet_rule_char_pattern, *rb->fStatus); fRuleSets[kRuleSet_white_space-128] = (UnicodeSet*) uprv_openRuleWhiteSpaceSet(rb->fStatus); fRuleSets[kRuleSet_name_char-128] = new UnicodeSet(gRuleSet_name_char_pattern, *rb->fStatus); fRuleSets[kRuleSet_name_start_char-128] = new UnicodeSet(gRuleSet_name_start_char_pattern, *rb->fStatus); fRuleSets[kRuleSet_digit_char-128] = new UnicodeSet(gRuleSet_digit_char_pattern, *rb->fStatus); if (*rb->fStatus == U_ILLEGAL_ARGUMENT_ERROR) { // This case happens if ICU's data is missing. UnicodeSet tries to look up property // names from the init string, can't find them, and claims an illegal arguement. // Change the error so that the actual problem will be clearer to users. *rb->fStatus = U_BRK_INIT_ERROR; } if (U_FAILURE(*rb->fStatus)) { return; } fSymbolTable = new RBBISymbolTable(this, rb->fRules, *rb->fStatus); fSetTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, rb->fStatus); uhash_setValueDeleter(fSetTable, RBBISetTable_deleter); }
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; }
/* * 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 *)¤tRegion); 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); }
/* * 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 *)¤tRegion); 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(); }