// // RBBISymbolTable::addEntry Add a new entry to the symbol table. // Indicate an error if the name already exists - // this will only occur in the case of duplicate // variable assignments. // void RBBISymbolTable::addEntry(const UnicodeString & key, RBBINode * val, UErrorCode & err) { RBBISymbolTableEntry * e; /* test for buffer overflows */ if (U_FAILURE(err)) { return; } e = (RBBISymbolTableEntry *)uhash_get(fHashTable, &key); if (e != NULL) { err = U_BRK_VARIABLE_REDFINITION; return; } e = new RBBISymbolTableEntry; if (e == NULL) { err = U_MEMORY_ALLOCATION_ERROR; return; } e->key = key; e->val = val; uhash_put(fHashTable, &e->key, e, &err); }
const UChar *ZNStringPool::get(const UChar *s, UErrorCode &status) { const UChar *pooledString; if (U_FAILURE(status)) { return &EmptyString; } pooledString = static_cast<UChar *>(uhash_get(fHash, s)); if (pooledString != NULL) { return pooledString; } int32_t length = u_strlen(s); int32_t remainingLength = POOL_CHUNK_SIZE - fChunks->fLimit; if (remainingLength <= length) { U_ASSERT(length < POOL_CHUNK_SIZE); if (length >= POOL_CHUNK_SIZE) { status = U_INTERNAL_PROGRAM_ERROR; return &EmptyString; } ZNStringPoolChunk *oldChunk = fChunks; fChunks = new ZNStringPoolChunk; if (fChunks == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return &EmptyString; } fChunks->fNext = oldChunk; } UChar *destString = &fChunks->fStrings[fChunks->fLimit]; u_strcpy(destString, s); fChunks->fLimit += (length + 1); uhash_put(fHash, destString, destString, &status); return destString; }
//---------------------------------------------------------------------------------------- // // findSetFor given a UnicodeString, // - find the corresponding Unicode Set (uset node) // (create one if necessary) // - Set fLeftChild of the caller's node (should be a setRef node) // to the uset node // Maintain a hash table of uset nodes, so the same one is always used // for the same string. // If a "to adopt" set is provided and we haven't seen this key before, // add the provided set to the hash table. // If the string is one (32 bit) char in length, the set contains // just one element which is the char in question. // If the string is "any", return a set containing all chars. // //---------------------------------------------------------------------------------------- void RBBIRuleScanner::findSetFor(const UnicodeString &s, RBBINode *node, UnicodeSet *setToAdopt) { RBBISetTableEl *el; // First check whether we've already cached a set for this string. // If so, just use the cached set in the new node. // delete any set provided by the caller, since we own it. el = (RBBISetTableEl *)uhash_get(fSetTable, &s); if (el != NULL) { delete setToAdopt; node->fLeftChild = el->val; U_ASSERT(node->fLeftChild->fType == RBBINode::uset); return; } // Haven't seen this set before. // If the caller didn't provide us with a prebuilt set, // create a new UnicodeSet now. if (setToAdopt == NULL) { if (s.compare(kAny, -1) == 0) { setToAdopt = new UnicodeSet(0x000000, 0x10ffff); } else { UChar32 c; c = s.char32At(0); setToAdopt = new UnicodeSet(c, c); } } // // Make a new uset node to refer to this UnicodeSet // This new uset node becomes the child of the caller's setReference node. // RBBINode *usetNode = new RBBINode(RBBINode::uset); usetNode->fInputSet = setToAdopt; usetNode->fParent = node; node->fLeftChild = usetNode; usetNode->fText = s; // // Add the new uset node to the list of all uset nodes. // fRB->fUSetNodes->addElement(usetNode, *fRB->fStatus); // // Add the new set to the set hash table. // el = (RBBISetTableEl *)uprv_malloc(sizeof(RBBISetTableEl)); UnicodeString *tkey = new UnicodeString(s); if (tkey == NULL || el == NULL || setToAdopt == NULL) { error(U_MEMORY_ALLOCATION_ERROR); return; } el->key = tkey; el->val = usetNode; uhash_put(fSetTable, el->key, el, fRB->fStatus); return; }
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; } }
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; }
CollData *CollDataCache::get(UCollator *collator, UErrorCode &status) { char keyBuffer[KEY_BUFFER_SIZE]; int32_t keyLength = KEY_BUFFER_SIZE; char *key = getKey(collator, keyBuffer, &keyLength); CollData *result = NULL, *newData = NULL; CollDataCacheEntry *entry = NULL, *newEntry = NULL; umtx_lock(&lock); entry = (CollDataCacheEntry *) uhash_get(cache, key); if (entry == NULL) { umtx_unlock(&lock); newData = new CollData(collator, key, keyLength, status); newEntry = new CollDataCacheEntry(newData); if (U_FAILURE(status) || newData == NULL || newEntry == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } umtx_lock(&lock); entry = (CollDataCacheEntry *) uhash_get(cache, key); if (entry == NULL) { uhash_put(cache, newData->key, newEntry, &status); umtx_unlock(&lock); if (U_FAILURE(status)) { delete newEntry; delete newData; return NULL; } return newData; } } result = entry->data; entry->refCount += 1; umtx_unlock(&lock); if (key != keyBuffer) { deleteKey(key); } if (newEntry != NULL) { delete newEntry; delete newData; } return result; }
SPUString *SPUStringPool::addString(UnicodeString *src, UErrorCode &status) { SPUString *hashedString = static_cast<SPUString *>(uhash_get(fHash, src)); if (hashedString != NULL) { delete src; } else { hashedString = new SPUString(src); uhash_put(fHash, src, hashedString, &status); fVec->addElement(hashedString, status); } return hashedString; }
// // ZNStringPool::adopt() Put a string into the hash, but do not copy the string data // into the pool's storage. Used for strings from resource bundles, // which will perisist for the life of the zone string formatter, and // therefore can be used directly without copying. const UChar *ZNStringPool::adopt(const UChar * s, UErrorCode &status) { const UChar *pooledString; if (U_FAILURE(status)) { return &EmptyString; } if (s != NULL) { pooledString = static_cast<UChar *>(uhash_get(fHash, s)); if (pooledString == NULL) { UChar *ncs = const_cast<UChar *>(s); uhash_put(fHash, ncs, ncs, &status); } } return s; }
// 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); }
// createCDFUnit returns a pointer to the prefix-suffix pair for a given // variant and log10 value within table. If no such prefix-suffix pair is // stored in table, one is created within table before returning pointer. static CDFUnit* createCDFUnit(const char* variant, int32_t log10Value, UHashtable* table, UErrorCode& status) { if (U_FAILURE(status)) { return NULL; } CDFUnit *cdfUnit = (CDFUnit*) uhash_get(table, variant); if (cdfUnit == NULL) { cdfUnit = new CDFUnit[MAX_DIGITS]; if (cdfUnit == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } uhash_put(table, uprv_strdup(variant), cdfUnit, &status); if (U_FAILURE(status)) { return NULL; } } CDFUnit* result = &cdfUnit[log10Value]; return result; }
// Places a new value and creationStatus in the cache for the given key. // On entry, gCacheMutex must be held. key must not exist in the cache. // On exit, value and creation status placed under key. Soft reference added // to value on successful add. On error sets status. void UnifiedCache::_putNew( const CacheKeyBase &key, const SharedObject *value, const UErrorCode creationStatus, UErrorCode &status) const { if (U_FAILURE(status)) { return; } CacheKeyBase *keyToAdopt = key.clone(); if (keyToAdopt == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return; } keyToAdopt->creationStatus = creationStatus; uhash_put(fHashtable, keyToAdopt, (void *) value, &status); if (U_SUCCESS(status)) { value->addSoftRef(); } }
const GenderInfo* GenderInfo::getInstance(const Locale& locale, UErrorCode& status) { // Make sure our cache exists. umtx_initOnce(gGenderInitOnce, &GenderInfo_initCache, status); if (U_FAILURE(status)) { return NULL; } const GenderInfo* result = NULL; const char* key = locale.getName(); { Mutex lock(&gGenderMetaLock); result = (const GenderInfo*) uhash_get(gGenderInfoCache, key); } if (result) { return result; } // On cache miss, try to create GenderInfo from CLDR data result = loadInstance(locale, status); if (U_FAILURE(status)) { return NULL; } // Try to put our GenderInfo object in cache. If there is a race condition, // favor the GenderInfo object that is already in the cache. { Mutex lock(&gGenderMetaLock); GenderInfo* temp = (GenderInfo*) uhash_get(gGenderInfoCache, key); if (temp) { result = temp; } else { uhash_put(gGenderInfoCache, uprv_strdup(key), (void*) result, &status); if (U_FAILURE(status)) { return NULL; } } } return result; }
/* Stores the shared data in the SHARED_DATA_HASHTABLE * @param data The shared data */ static void ucnv_shareConverterData(UConverterSharedData * data) { UErrorCode err = U_ZERO_ERROR; /*Lazy evaluates the Hashtable itself */ /*void *sanity = NULL;*/ if (SHARED_DATA_HASHTABLE == NULL) { SHARED_DATA_HASHTABLE = uhash_openSize(uhash_hashChars, uhash_compareChars, ucnv_io_countAvailableAliases(&err), &err); if (U_FAILURE(err)) return; } /* ### check to see if the element is not already there! */ /* sanity = ucnv_getSharedConverterData (data->staticData->name); if(sanity != NULL) { UCNV_DEBUG_LOG("put:overwrite!",data->staticData->name,sanity); } UCNV_DEBUG_LOG("put:chk",data->staticData->name,sanity); */ /* Mark it shared */ data->sharedDataCached = TRUE; uhash_put(SHARED_DATA_HASHTABLE, (void*) data->staticData->name, /* Okay to cast away const as long as keyDeleter == NULL */ data, &err); UCNV_DEBUG_LOG("put", data->staticData->name,data); }
void UnifiedCache::_putNew( const CacheKeyBase &key, const SharedObject *value, const UErrorCode creationStatus, UErrorCode &status) const { if (U_FAILURE(status)) { return; } CacheKeyBase *keyToAdopt = key.clone(); if (keyToAdopt == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return; } keyToAdopt->fCreationStatus = creationStatus; if (value->softRefCount == 0) { _registerMaster(keyToAdopt, value); } void *oldValue = uhash_put(fHashtable, keyToAdopt, (void *) value, &status); U_ASSERT(oldValue == nullptr); (void)oldValue; if (U_SUCCESS(status)) { value->softRefCount++; } }
/* * 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(); }
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; }
U_CDECL_END static void U_CALLCONV initFromResourceBundle(UErrorCode& sts) { U_NAMESPACE_USE ucln_common_registerCleanup(UCLN_COMMON_LOCALE_KEY_TYPE, uloc_key_type_cleanup); gLocExtKeyMap = uhash_open(uhash_hashIChars, uhash_compareIChars, NULL, &sts); LocalUResourceBundlePointer keyTypeDataRes(ures_openDirect(NULL, "keyTypeData", &sts)); LocalUResourceBundlePointer keyMapRes(ures_getByKey(keyTypeDataRes.getAlias(), "keyMap", NULL, &sts)); LocalUResourceBundlePointer typeMapRes(ures_getByKey(keyTypeDataRes.getAlias(), "typeMap", NULL, &sts)); if (U_FAILURE(sts)) { return; } UErrorCode tmpSts = U_ZERO_ERROR; LocalUResourceBundlePointer typeAliasRes(ures_getByKey(keyTypeDataRes.getAlias(), "typeAlias", NULL, &tmpSts)); tmpSts = U_ZERO_ERROR; LocalUResourceBundlePointer bcpTypeAliasRes(ures_getByKey(keyTypeDataRes.getAlias(), "bcpTypeAlias", NULL, &tmpSts)); // initialize vectors storing dynamically allocated objects gKeyTypeStringPool = new UVector(uloc_deleteKeyTypeStringPoolEntry, NULL, sts); if (gKeyTypeStringPool == NULL) { if (U_SUCCESS(sts)) { sts = U_MEMORY_ALLOCATION_ERROR; } } if (U_FAILURE(sts)) { return; } gLocExtKeyDataEntries = new UVector(uloc_deleteKeyDataEntry, NULL, sts); if (gLocExtKeyDataEntries == NULL) { if (U_SUCCESS(sts)) { sts = U_MEMORY_ALLOCATION_ERROR; } } if (U_FAILURE(sts)) { return; } gLocExtTypeEntries = new UVector(uloc_deleteTypeEntry, NULL, sts); if (gLocExtTypeEntries == NULL) { if (U_SUCCESS(sts)) { sts = U_MEMORY_ALLOCATION_ERROR; } } if (U_FAILURE(sts)) { return; } // iterate through keyMap resource LocalUResourceBundlePointer keyMapEntry; while (ures_hasNext(keyMapRes.getAlias())) { keyMapEntry.adoptInstead(ures_getNextResource(keyMapRes.getAlias(), keyMapEntry.orphan(), &sts)); if (U_FAILURE(sts)) { break; } const char* legacyKeyId = ures_getKey(keyMapEntry.getAlias()); int32_t bcpKeyIdLen = 0; const UChar* uBcpKeyId = ures_getString(keyMapEntry.getAlias(), &bcpKeyIdLen, &sts); if (U_FAILURE(sts)) { break; } // empty value indicates that BCP key is same with the legacy key. const char* bcpKeyId = legacyKeyId; if (bcpKeyIdLen > 0) { char* bcpKeyIdBuf = (char*)uprv_malloc(bcpKeyIdLen + 1); if (bcpKeyIdBuf == NULL) { sts = U_MEMORY_ALLOCATION_ERROR; break; } u_UCharsToChars(uBcpKeyId, bcpKeyIdBuf, bcpKeyIdLen); bcpKeyIdBuf[bcpKeyIdLen] = 0; gKeyTypeStringPool->addElement(bcpKeyIdBuf, sts); if (U_FAILURE(sts)) { break; } bcpKeyId = bcpKeyIdBuf; } UBool isTZ = uprv_strcmp(legacyKeyId, "timezone") == 0; UHashtable* typeDataMap = uhash_open(uhash_hashIChars, uhash_compareIChars, NULL, &sts); if (U_FAILURE(sts)) { break; } uint32_t specialTypes = SPECIALTYPE_NONE; LocalUResourceBundlePointer typeAliasResByKey; LocalUResourceBundlePointer bcpTypeAliasResByKey; if (typeAliasRes.isValid()) { tmpSts = U_ZERO_ERROR; typeAliasResByKey.adoptInstead(ures_getByKey(typeAliasRes.getAlias(), legacyKeyId, NULL, &tmpSts)); if (U_FAILURE(tmpSts)) { typeAliasResByKey.orphan(); } } if (bcpTypeAliasRes.isValid()) { tmpSts = U_ZERO_ERROR; bcpTypeAliasResByKey.adoptInstead(ures_getByKey(bcpTypeAliasRes.getAlias(), bcpKeyId, NULL, &tmpSts)); if (U_FAILURE(tmpSts)) { bcpTypeAliasResByKey.orphan(); } } // look up type map for the key, and walk through the mapping data tmpSts = U_ZERO_ERROR; LocalUResourceBundlePointer typeMapResByKey(ures_getByKey(typeMapRes.getAlias(), legacyKeyId, NULL, &tmpSts)); if (U_FAILURE(tmpSts)) { // type map for each key must exist U_ASSERT(FALSE); } else { LocalUResourceBundlePointer typeMapEntry; while (ures_hasNext(typeMapResByKey.getAlias())) { typeMapEntry.adoptInstead(ures_getNextResource(typeMapResByKey.getAlias(), typeMapEntry.orphan(), &sts)); if (U_FAILURE(sts)) { break; } const char* legacyTypeId = ures_getKey(typeMapEntry.getAlias()); // special types if (uprv_strcmp(legacyTypeId, "CODEPOINTS") == 0) { specialTypes |= SPECIALTYPE_CODEPOINTS; continue; } if (uprv_strcmp(legacyTypeId, "REORDER_CODE") == 0) { specialTypes |= SPECIALTYPE_REORDER_CODE; continue; } if (uprv_strcmp(legacyTypeId, "RG_KEY_VALUE") == 0) { specialTypes |= SPECIALTYPE_RG_KEY_VALUE; continue; } if (isTZ) { // a timezone key uses a colon instead of a slash in the resource. // e.g. America:Los_Angeles if (uprv_strchr(legacyTypeId, ':') != NULL) { int32_t legacyTypeIdLen = uprv_strlen(legacyTypeId); char* legacyTypeIdBuf = (char*)uprv_malloc(legacyTypeIdLen + 1); if (legacyTypeIdBuf == NULL) { sts = U_MEMORY_ALLOCATION_ERROR; break; } const char* p = legacyTypeId; char* q = legacyTypeIdBuf; while (*p) { if (*p == ':') { *q++ = '/'; } else { *q++ = *p; } p++; } *q = 0; gKeyTypeStringPool->addElement(legacyTypeIdBuf, sts); if (U_FAILURE(sts)) { break; } legacyTypeId = legacyTypeIdBuf; } } int32_t bcpTypeIdLen = 0; const UChar* uBcpTypeId = ures_getString(typeMapEntry.getAlias(), &bcpTypeIdLen, &sts); if (U_FAILURE(sts)) { break; } // empty value indicates that BCP type is same with the legacy type. const char* bcpTypeId = legacyTypeId; if (bcpTypeIdLen > 0) { char* bcpTypeIdBuf = (char*)uprv_malloc(bcpTypeIdLen + 1); if (bcpTypeIdBuf == NULL) { sts = U_MEMORY_ALLOCATION_ERROR; break; } u_UCharsToChars(uBcpTypeId, bcpTypeIdBuf, bcpTypeIdLen); bcpTypeIdBuf[bcpTypeIdLen] = 0; gKeyTypeStringPool->addElement(bcpTypeIdBuf, sts); if (U_FAILURE(sts)) { break; } bcpTypeId = bcpTypeIdBuf; } // Note: legacy type value should never be // equivalent to bcp type value of a different // type under the same key. So we use a single // map for lookup. LocExtType* t = (LocExtType*)uprv_malloc(sizeof(LocExtType)); if (t == NULL) { sts = U_MEMORY_ALLOCATION_ERROR; break; } t->bcpId = bcpTypeId; t->legacyId = legacyTypeId; gLocExtTypeEntries->addElement((void*)t, sts); if (U_FAILURE(sts)) { break; } uhash_put(typeDataMap, (void*)legacyTypeId, t, &sts); if (bcpTypeId != legacyTypeId) { // different type value uhash_put(typeDataMap, (void*)bcpTypeId, t, &sts); } if (U_FAILURE(sts)) { break; } // also put aliases in the map if (typeAliasResByKey.isValid()) { LocalUResourceBundlePointer typeAliasDataEntry; ures_resetIterator(typeAliasResByKey.getAlias()); while (ures_hasNext(typeAliasResByKey.getAlias()) && U_SUCCESS(sts)) { int32_t toLen; typeAliasDataEntry.adoptInstead(ures_getNextResource(typeAliasResByKey.getAlias(), typeAliasDataEntry.orphan(), &sts)); const UChar* to = ures_getString(typeAliasDataEntry.getAlias(), &toLen, &sts); if (U_FAILURE(sts)) { break; } // check if this is an alias of canoncal legacy type if (uprv_compareInvWithUChar(NULL, legacyTypeId, -1, to, toLen) == 0) { const char* from = ures_getKey(typeAliasDataEntry.getAlias()); if (isTZ) { // replace colon with slash if necessary if (uprv_strchr(from, ':') != NULL) { int32_t fromLen = uprv_strlen(from); char* fromBuf = (char*)uprv_malloc(fromLen + 1); if (fromBuf == NULL) { sts = U_MEMORY_ALLOCATION_ERROR; break; } const char* p = from; char* q = fromBuf; while (*p) { if (*p == ':') { *q++ = '/'; } else { *q++ = *p; } p++; } *q = 0; gKeyTypeStringPool->addElement(fromBuf, sts); if (U_FAILURE(sts)) { break; } from = fromBuf; } } uhash_put(typeDataMap, (void*)from, t, &sts); } } if (U_FAILURE(sts)) { break; } } if (bcpTypeAliasResByKey.isValid()) { LocalUResourceBundlePointer bcpTypeAliasDataEntry; ures_resetIterator(bcpTypeAliasResByKey.getAlias()); while (ures_hasNext(bcpTypeAliasResByKey.getAlias()) && U_SUCCESS(sts)) { int32_t toLen; bcpTypeAliasDataEntry.adoptInstead(ures_getNextResource(bcpTypeAliasResByKey.getAlias(), bcpTypeAliasDataEntry.orphan(), &sts)); const UChar* to = ures_getString(bcpTypeAliasDataEntry.getAlias(), &toLen, &sts); if (U_FAILURE(sts)) { break; } // check if this is an alias of bcp type if (uprv_compareInvWithUChar(NULL, bcpTypeId, -1, to, toLen) == 0) { const char* from = ures_getKey(bcpTypeAliasDataEntry.getAlias()); uhash_put(typeDataMap, (void*)from, t, &sts); } } if (U_FAILURE(sts)) { break; } } } } if (U_FAILURE(sts)) { break; } LocExtKeyData* keyData = (LocExtKeyData*)uprv_malloc(sizeof(LocExtKeyData)); if (keyData == NULL) { sts = U_MEMORY_ALLOCATION_ERROR; break; } keyData->bcpId = bcpKeyId; keyData->legacyId = legacyKeyId; keyData->specialTypes = specialTypes; keyData->typeMap = typeDataMap; gLocExtKeyDataEntries->addElement((void*)keyData, sts); if (U_FAILURE(sts)) { break; } uhash_put(gLocExtKeyMap, (void*)legacyKeyId, keyData, &sts); if (legacyKeyId != bcpKeyId) { // different key value uhash_put(gLocExtKeyMap, (void*)bcpKeyId, keyData, &sts); } if (U_FAILURE(sts)) { break; } } }
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; }
const UVector* U_EXPORT2 ZoneMeta::getMetazoneMappings(const UnicodeString &tzid) { UErrorCode status = U_ZERO_ERROR; UChar tzidUChars[ZID_KEY_MAX + 1]; tzid.extract(tzidUChars, ZID_KEY_MAX + 1, status); if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) { return NULL; } umtx_initOnce(gOlsonToMetaInitOnce, &olsonToMetaInit, status); if (U_FAILURE(status)) { return NULL; } // 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; }
static void TestOtherAPI(void){ UErrorCode status = U_ZERO_ERROR; UHashtable *hash; /* Use the correct type when cast to void * */ const UChar one[4] = {0x006F, 0x006E, 0x0065, 0}; /* L"one" */ const UChar one2[4] = {0x006F, 0x006E, 0x0065, 0}; /* Get around compiler optimizations */ const UChar two[4] = {0x0074, 0x0077, 0x006F, 0}; /* L"two" */ const UChar two2[4] = {0x0074, 0x0077, 0x006F, 0}; /* L"two" */ const UChar three[6] = {0x0074, 0x0068, 0x0072, 0x0065, 0x0065, 0}; /* L"three" */ const UChar four[6] = {0x0066, 0x006F, 0x0075, 0x0072, 0}; /* L"four" */ const UChar five[6] = {0x0066, 0x0069, 0x0076, 0x0065, 0}; /* L"five" */ const UChar five2[6] = {0x0066, 0x0069, 0x0076, 0x0065, 0}; /* L"five" */ hash = uhash_open(uhash_hashUChars, uhash_compareUChars, &status); if (U_FAILURE(status)) { log_err("FAIL: uhash_open failed with %s and returned 0x%08x\n", u_errorName(status), hash); return; } if (hash == NULL) { log_err("FAIL: uhash_open returned NULL\n"); return; } log_verbose("Ok: uhash_open returned 0x%08X\n", hash); uhash_puti(hash, (void*)one, 1, &status); if(uhash_count(hash) != 1){ log_err("FAIL: uhas_count() failed. Expected: 1, Got: %d\n", uhash_count(hash)); } uhash_puti(hash, (void*)two, 2, &status); uhash_puti(hash, (void*)three, 3, &status); uhash_puti(hash, (void*)four, 4, &status); uhash_puti(hash, (void*)five, 5, &status); if(uhash_count(hash) != 5){ log_err("FAIL: uhas_count() failed. Expected: 5, Got: %d\n", uhash_count(hash)); } if(uhash_geti(hash, (void*)two2) != 2){ log_err("FAIL: uhash_geti failed\n"); } if(uhash_removei(hash, (void*)five2) != 5){ log_err("FAIL: uhash_remove() failed\n"); } if(uhash_count(hash) != 4){ log_err("FAIL: uhas_count() failed. Expected: 4, Got: %d\n", uhash_count(hash)); } uhash_put(hash, (void*)one, NULL, &status); if(uhash_count(hash) != 3){ log_err("FAIL: uhash_put() with value=NULL didn't remove the key value pair\n"); } status=U_ILLEGAL_ARGUMENT_ERROR; uhash_puti(hash, (void*)one, 1, &status); if(uhash_count(hash) != 3){ log_err("FAIL: uhash_put() with value!=NULL should fail when status != U_ZERO_ERROR \n"); } status=U_ZERO_ERROR; uhash_puti(hash, (void*)one, 1, &status); if(uhash_count(hash) != 4){ log_err("FAIL: uhash_put() with value!=NULL didn't replace the key value pair\n"); } if(_compareUChars((void*)one, (void*)two) == TRUE || _compareUChars((void*)one, (void*)one) != TRUE || _compareUChars((void*)one, (void*)one2) != TRUE || _compareUChars((void*)one, NULL) == TRUE ) { log_err("FAIL: compareUChars failed\n"); } uhash_removeAll(hash); if(uhash_count(hash) != 0){ log_err("FAIL: uhas_count() failed. Expected: 0, Got: %d\n", uhash_count(hash)); } uhash_setKeyComparator(hash, uhash_compareLong); uhash_setKeyHasher(hash, uhash_hashLong); uhash_iputi(hash, 1001, 1, &status); uhash_iputi(hash, 1002, 2, &status); uhash_iputi(hash, 1003, 3, &status); if(_compareLong(1001, 1002) == TRUE || _compareLong(1001, 1001) != TRUE || _compareLong(1001, 0) == TRUE ) { log_err("FAIL: compareLong failed\n"); } /*set the resize policy to just GROW and SHRINK*/ /*how to test this??*/ uhash_setResizePolicy(hash, U_GROW_AND_SHRINK); uhash_iputi(hash, 1004, 4, &status); uhash_iputi(hash, 1005, 5, &status); uhash_iputi(hash, 1006, 6, &status); if(uhash_count(hash) != 6){ log_err("FAIL: uhash_count() failed. Expected: 6, Got: %d\n", uhash_count(hash)); } if(uhash_iremovei(hash, 1004) != 4){ log_err("FAIL: uhash_remove failed\n"); } if(uhash_iremovei(hash, 1004) != 0){ log_err("FAIL: uhash_remove failed\n"); } uhash_close(hash); }
void AlphabeticIndex::buildIndex(UErrorCode &status) { if (U_FAILURE(status)) { return; } if (!indexBuildRequired_) { return; } // Discard any already-built data. // This is important when the user builds and uses an index, then subsequently modifies it, // necessitating a rebuild. bucketList_->removeAllElements(); labels_->removeAllElements(); uhash_removeAll(alreadyIn_); noDistinctSorting_->clear(); notAlphabetic_->clear(); // first sort the incoming Labels, with a "best" ordering among items // that are the same according to the collator UVector preferenceSorting(status); // Vector of UnicodeStrings; owned by the vector. preferenceSorting.setDeleter(uprv_deleteUObject); appendUnicodeSetToUVector(preferenceSorting, *initialLabels_, status); preferenceSorting.sortWithUComparator(PreferenceComparator, &status, status); // We now make a set of Labels. // Some of the input may, however, be redundant. // That is, we might have c, ch, d, where "ch" sorts just like "c", "h" // So we make a pass through, filtering out those cases. // TODO: filtering these out would seem to be at odds with the eventual goal // of being able to split buckets that contain too many items. UnicodeSet labelSet; for (int32_t psIndex=0; psIndex<preferenceSorting.size(); psIndex++) { UnicodeString item = *static_cast<const UnicodeString *>(preferenceSorting.elementAt(psIndex)); // TODO: Since preferenceSorting was originally populated from the contents of a UnicodeSet, // is it even possible for duplicates to show up in this check? if (labelSet.contains(item)) { UnicodeSetIterator itemAlreadyInIter(labelSet); while (itemAlreadyInIter.next()) { const UnicodeString &itemAlreadyIn = itemAlreadyInIter.getString(); if (collatorPrimaryOnly_->compare(item, itemAlreadyIn) == 0) { UnicodeSet *targets = static_cast<UnicodeSet *>(uhash_get(alreadyIn_, &itemAlreadyIn)); if (targets == NULL) { // alreadyIn.put(itemAlreadyIn, targets = new LinkedHashSet<String>()); targets = new UnicodeSet(); uhash_put(alreadyIn_, itemAlreadyIn.clone(), targets, &status); } targets->add(item); break; } } } else if (item.moveIndex32(0, 1) < item.length() && // Label contains more than one code point. collatorPrimaryOnly_->compare(item, separated(item)) == 0) { noDistinctSorting_->add(item); } else if (!ALPHABETIC->containsSome(item)) { notAlphabetic_->add(item); } else { labelSet.add(item); } } // If we have no labels, hard-code a fallback default set of [A-Z] // This case can occur with locales that don't have exemplar character data, including root. // A no-labels situation will cause other problems; it needs to be avoided. if (labelSet.isEmpty()) { labelSet.add((UChar32)0x41, (UChar32)0x5A); } // Move the set of Labels from the set into a vector, and sort // according to the collator. appendUnicodeSetToUVector(*labels_, labelSet, status); labels_->sortWithUComparator(sortCollateComparator, collatorPrimaryOnly_, status); // if the result is still too large, cut down to maxLabelCount_ elements, by removing every nth element // Implemented by copying the elements to be retained to a new UVector. const int32_t size = labelSet.size() - 1; if (size > maxLabelCount_) { UVector *newLabels = new UVector(status); newLabels->setDeleter(uprv_deleteUObject); int32_t count = 0; int32_t old = -1; for (int32_t srcIndex=0; srcIndex<labels_->size(); srcIndex++) { const UnicodeString *str = static_cast<const UnicodeString *>(labels_->elementAt(srcIndex)); ++count; const int32_t bump = count * maxLabelCount_ / size; if (bump == old) { // it.remove(); } else { newLabels->addElement(str->clone(), status); old = bump; } } delete labels_; labels_ = newLabels; } // We now know the list of labels. // Create a corresponding list of buckets, one per label. buildBucketList(status); // Corresponds to Java BucketList constructor. // Bin the Records into the Buckets. bucketRecords(status); indexBuildRequired_ = FALSE; resetBucketIterator(status); }
/* * This method updates the cache and must be called with a lock */ const UChar* TZGNCore::getPartialLocationName(const UnicodeString& tzCanonicalID, const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName) { U_ASSERT(!tzCanonicalID.isEmpty()); U_ASSERT(!mzID.isEmpty()); U_ASSERT(!mzDisplayName.isEmpty()); PartialLocationKey key; key.tzID = ZoneMeta::findTimeZoneID(tzCanonicalID); key.mzID = ZoneMeta::findMetaZoneID(mzID); key.isLong = isLong; U_ASSERT(key.tzID != NULL && key.mzID != NULL); const UChar* uplname = (const UChar*)uhash_get(fPartialLocationNamesMap, (void *)&key); if (uplname != NULL) { return uplname; } UnicodeString location; UnicodeString usCountryCode; ZoneMeta::getCanonicalCountry(tzCanonicalID, usCountryCode); if (!usCountryCode.isEmpty()) { char countryCode[ULOC_COUNTRY_CAPACITY]; U_ASSERT(usCountryCode.length() < ULOC_COUNTRY_CAPACITY); int32_t ccLen = usCountryCode.extract(0, usCountryCode.length(), countryCode, sizeof(countryCode), US_INV); countryCode[ccLen] = 0; UnicodeString regionalGolden; fTimeZoneNames->getReferenceZoneID(mzID, countryCode, regionalGolden); if (tzCanonicalID == regionalGolden) { // Use country name fLocaleDisplayNames->regionDisplayName(countryCode, location); } else { // Otherwise, use exemplar city name fTimeZoneNames->getExemplarLocationName(tzCanonicalID, location); } } else { fTimeZoneNames->getExemplarLocationName(tzCanonicalID, location); if (location.isEmpty()) { // This could happen when the time zone is not associated with a country, // and its ID is not hierarchical, for example, CST6CDT. // We use the canonical ID itself as the location for this case. location.setTo(tzCanonicalID); } } UErrorCode status = U_ZERO_ERROR; UnicodeString name; fFallbackFormat.format(location, mzDisplayName, name, status); if (U_FAILURE(status)) { return NULL; } uplname = fStringPool.get(name, status); if (U_SUCCESS(status)) { // Add the name to cache PartialLocationKey* cacheKey = (PartialLocationKey *)uprv_malloc(sizeof(PartialLocationKey)); if (cacheKey != NULL) { cacheKey->tzID = key.tzID; cacheKey->mzID = key.mzID; cacheKey->isLong = key.isLong; uhash_put(fPartialLocationNamesMap, (void *)cacheKey, (void *)uplname, &status); if (U_FAILURE(status)) { uprv_free(cacheKey); } else { // put the name to the local trie as well GNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(GNameInfo)); if (nameinfo != NULL) { nameinfo->type = isLong ? UTZGNM_LONG : UTZGNM_SHORT; nameinfo->tzID = key.tzID; fGNamesTrie.put(uplname, nameinfo, status); } } } } return uplname; }
/* * This method updates the cache and must be called with a lock */ const UChar* TZGNCore::getGenericLocationName(const UnicodeString& tzCanonicalID) { U_ASSERT(!tzCanonicalID.isEmpty()); if (tzCanonicalID.length() > ZID_KEY_MAX) { return NULL; } UErrorCode status = U_ZERO_ERROR; UChar tzIDKey[ZID_KEY_MAX + 1]; int32_t tzIDKeyLen = tzCanonicalID.extract(tzIDKey, ZID_KEY_MAX + 1, status); U_ASSERT(status == U_ZERO_ERROR); // already checked length above tzIDKey[tzIDKeyLen] = 0; const UChar *locname = (const UChar *)uhash_get(fLocationNamesMap, tzIDKey); if (locname != NULL) { // gEmpty indicate the name is not available if (locname == gEmpty) { return NULL; } return locname; } // Construct location name UnicodeString name; UnicodeString usCountryCode; UBool isPrimary = FALSE; ZoneMeta::getCanonicalCountry(tzCanonicalID, usCountryCode, &isPrimary); if (!usCountryCode.isEmpty()) { if (isPrimary) { // If this is the primary zone in the country, use the country name. char countryCode[ULOC_COUNTRY_CAPACITY]; U_ASSERT(usCountryCode.length() < ULOC_COUNTRY_CAPACITY); int32_t ccLen = usCountryCode.extract(0, usCountryCode.length(), countryCode, sizeof(countryCode), US_INV); countryCode[ccLen] = 0; UnicodeString country; fLocaleDisplayNames->regionDisplayName(countryCode, country); fRegionFormat.format(country, name, status); } else { // If this is not the primary zone in the country, // use the exemplar city name. // getExemplarLocationName should retur non-empty string // if the time zone is associated with a region UnicodeString city; fTimeZoneNames->getExemplarLocationName(tzCanonicalID, city); fRegionFormat.format(city, name, status); } if (U_FAILURE(status)) { return NULL; } } locname = name.isEmpty() ? NULL : fStringPool.get(name, status); if (U_SUCCESS(status)) { // Cache the result const UChar* cacheID = ZoneMeta::findTimeZoneID(tzCanonicalID); U_ASSERT(cacheID != NULL); if (locname == NULL) { // gEmpty to indicate - no location name available uhash_put(fLocationNamesMap, (void *)cacheID, (void *)gEmpty, &status); } else { uhash_put(fLocationNamesMap, (void *)cacheID, (void *)locname, &status); if (U_FAILURE(status)) { locname = NULL; } else { // put the name info into the trie GNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(GNameInfo)); if (nameinfo != NULL) { nameinfo->type = UTZGNM_LOCATION; nameinfo->tzID = cacheID; fGNamesTrie.put(locname, nameinfo, status); } } } } return locname; }
void StringToCEsMap::put(const UnicodeString *string, const CEList *ces, UErrorCode &status) { uhash_put(map, (void *) string, (void *) ces, &status); }
static UStringPrepProfile* usprep_getProfile(const char* path, const char* name, UErrorCode *status){ UStringPrepProfile* profile = NULL; initCache(status); if(U_FAILURE(*status)){ return NULL; } UStringPrepKey stackKey; /* * const is cast way to save malloc, strcpy and free calls * we use the passed in pointers for fetching the data from the * hash table which is safe */ stackKey.name = (char*) name; stackKey.path = (char*) path; /* fetch the data from the cache */ umtx_lock(usprepMutex()); profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey)); if(profile != NULL) { profile->refCount++; } umtx_unlock(usprepMutex()); if(profile == NULL) { /* else load the data and put the data in the cache */ LocalMemory<UStringPrepProfile> newProfile; if(newProfile.allocateInsteadAndReset() == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; return NULL; } /* load the data */ if(!loadData(newProfile.getAlias(), path, name, _SPREP_DATA_TYPE, status) || U_FAILURE(*status) ){ return NULL; } /* get the options */ newProfile->doNFKC = (UBool)((newProfile->indexes[_SPREP_OPTIONS] & _SPREP_NORMALIZATION_ON) > 0); newProfile->checkBiDi = (UBool)((newProfile->indexes[_SPREP_OPTIONS] & _SPREP_CHECK_BIDI_ON) > 0); LocalMemory<UStringPrepKey> key; LocalMemory<char> keyName; LocalMemory<char> keyPath; if( key.allocateInsteadAndReset() == NULL || keyName.allocateInsteadAndCopy(static_cast<int32_t>(uprv_strlen(name)+1)) == NULL || (path != NULL && keyPath.allocateInsteadAndCopy(static_cast<int32_t>(uprv_strlen(path)+1)) == NULL) ) { *status = U_MEMORY_ALLOCATION_ERROR; usprep_unload(newProfile.getAlias()); return NULL; } umtx_lock(usprepMutex()); // If another thread already inserted the same key/value, refcount and cleanup our thread data profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey)); if(profile != NULL) { profile->refCount++; usprep_unload(newProfile.getAlias()); } else { /* initialize the key members */ key->name = keyName.orphan(); uprv_strcpy(key->name, name); if(path != NULL){ key->path = keyPath.orphan(); uprv_strcpy(key->path, path); } profile = newProfile.orphan(); /* add the data object to the cache */ profile->refCount = 1; uhash_put(SHARED_DATA_HASHTABLE, key.orphan(), profile, status); } umtx_unlock(usprepMutex()); } return profile; }
const UChar* U_EXPORT2 ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) { if (U_FAILURE(status)) { return NULL; } if (tzid.isBogus() || tzid.length() > ZID_KEY_MAX) { status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } // Checking the cached results umtx_initOnce(gCanonicalIDCacheInitOnce, &initCanonicalIDCache, status); if (U_FAILURE(status)) { return NULL; } const UChar *canonicalID = NULL; UErrorCode tmpStatus = U_ZERO_ERROR; UChar utzid[ZID_KEY_MAX + 1]; tzid.extract(utzid, ZID_KEY_MAX + 1, tmpStatus); U_ASSERT(tmpStatus == U_ZERO_ERROR); // we checked the length of tzid already if (!uprv_isInvariantUString(utzid, -1)) { // All of known tz IDs are only containing ASCII invariant characters. status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } // Check if it was already cached umtx_lock(gZoneMetaLock()); { canonicalID = (const UChar *)uhash_get(gCanonicalIDCache, utzid); } umtx_unlock(gZoneMetaLock()); if (canonicalID != NULL) { return canonicalID; } // If not, resolve CLDR canonical ID with resource data UBool isInputCanonical = FALSE; char id[ZID_KEY_MAX + 1]; tzid.extract(0, 0x7fffffff, id, UPRV_LENGTHOF(id), US_INV); // replace '/' with ':' char *p = id; while (*p++) { if (*p == '/') { *p = ':'; } } UResourceBundle *top = ures_openDirect(NULL, gKeyTypeData, &tmpStatus); UResourceBundle *rb = ures_getByKey(top, gTypeMapTag, NULL, &tmpStatus); ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus); ures_getByKey(rb, id, rb, &tmpStatus); if (U_SUCCESS(tmpStatus)) { // type entry (canonical) found // the input is the canonical ID. resolve to const UChar* canonicalID = TimeZone::findID(tzid); isInputCanonical = TRUE; } if (canonicalID == NULL) { // If a map element not found, then look for an alias tmpStatus = U_ZERO_ERROR; ures_getByKey(top, gTypeAliasTag, rb, &tmpStatus); ures_getByKey(rb, gTimezoneTag, rb, &tmpStatus); const UChar *canonical = ures_getStringByKey(rb,id,NULL,&tmpStatus); if (U_SUCCESS(tmpStatus)) { // canonical map found canonicalID = canonical; } if (canonicalID == NULL) { // Dereference the input ID using the tz data const UChar *derefer = TimeZone::dereferOlsonLink(tzid); if (derefer == NULL) { status = U_ILLEGAL_ARGUMENT_ERROR; } else { int32_t len = u_strlen(derefer); u_UCharsToChars(derefer,id,len); id[len] = (char) 0; // Make sure it is null terminated. // replace '/' with ':' char *q = id; while (*q++) { if (*q == '/') { *q = ':'; } } // If a dereference turned something up then look for an alias. // rb still points to the alias table, so we don't have to go looking // for it. tmpStatus = U_ZERO_ERROR; canonical = ures_getStringByKey(rb,id,NULL,&tmpStatus); if (U_SUCCESS(tmpStatus)) { // canonical map for the dereferenced ID found canonicalID = canonical; } else { canonicalID = derefer; isInputCanonical = TRUE; } } } } ures_close(rb); ures_close(top); if (U_SUCCESS(status)) { U_ASSERT(canonicalID != NULL); // canocanilD must be non-NULL here // Put the resolved canonical ID to the cache umtx_lock(gZoneMetaLock()); { const UChar* idInCache = (const UChar *)uhash_get(gCanonicalIDCache, utzid); if (idInCache == NULL) { const UChar* key = ZoneMeta::findTimeZoneID(tzid); U_ASSERT(key != NULL); if (key != NULL) { idInCache = (const UChar *)uhash_put(gCanonicalIDCache, (void *)key, (void *)canonicalID, &status); U_ASSERT(idInCache == NULL); } } if (U_SUCCESS(status) && isInputCanonical) { // Also put canonical ID itself into the cache if not exist const UChar *canonicalInCache = (const UChar*)uhash_get(gCanonicalIDCache, canonicalID); if (canonicalInCache == NULL) { canonicalInCache = (const UChar *)uhash_put(gCanonicalIDCache, (void *)canonicalID, (void *)canonicalID, &status); U_ASSERT(canonicalInCache == NULL); } } } umtx_unlock(gZoneMetaLock()); } return canonicalID; }
static UDataMemory *udata_cacheDataItem(const char *path, UDataMemory *item, UErrorCode *pErr) { DataCacheElement *newElement; const char *baseName; int32_t nameLen; UHashtable *htable; UDataMemory *oldValue = NULL; UErrorCode subErr = U_ZERO_ERROR; if (U_FAILURE(*pErr)) { return NULL; } /* Create a new DataCacheElement - the thingy we store in the hash table - * and copy the supplied path and UDataMemoryItems into it. */ newElement = uprv_malloc(sizeof(DataCacheElement)); if (newElement == NULL) { *pErr = U_MEMORY_ALLOCATION_ERROR; return NULL; } newElement->item = UDataMemory_createNewInstance(pErr); if (U_FAILURE(*pErr)) { uprv_free(newElement); return NULL; } UDatamemory_assign(newElement->item, item); baseName = findBasename(path); nameLen = (int32_t)uprv_strlen(baseName); newElement->name = uprv_malloc(nameLen+1); if (newElement->name == NULL) { *pErr = U_MEMORY_ALLOCATION_ERROR; uprv_free(newElement->item); uprv_free(newElement); return NULL; } uprv_strcpy(newElement->name, baseName); /* Stick the new DataCacheElement into the hash table. */ htable = udata_getHashTable(); umtx_lock(NULL); oldValue = uhash_get(htable, path); if (oldValue != NULL) { subErr = U_USING_DEFAULT_WARNING; } else { uhash_put( htable, newElement->name, /* Key */ newElement, /* Value */ &subErr); } umtx_unlock(NULL); #ifdef UDATA_DEBUG fprintf(stderr, "Cache: [%s] <<< %p : %s. vFunc=%p\n", newElement->name, newElement->item, u_errorName(subErr), newElement->item->vFuncs); #endif if (subErr == U_USING_DEFAULT_WARNING || U_FAILURE(subErr)) { *pErr = subErr; /* copy sub err unto fillin ONLY if something happens. */ uprv_free(newElement->name); uprv_free(newElement->item); uprv_free(newElement); return oldValue; } return newElement->item; }
/* * 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); }
static UStringPrepProfile* usprep_getProfile(const char* path, const char* name, UErrorCode *status){ UStringPrepProfile* profile = NULL; initCache(status); if(U_FAILURE(*status)){ return NULL; } UStringPrepKey stackKey; /* * const is cast way to save malloc, strcpy and free calls * we use the passed in pointers for fetching the data from the * hash table which is safe */ stackKey.name = (char*) name; stackKey.path = (char*) path; /* fetch the data from the cache */ profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey)); if(profile == NULL){ UStringPrepKey* key = (UStringPrepKey*) uprv_malloc(sizeof(UStringPrepKey)); if(key == NULL){ *status = U_MEMORY_ALLOCATION_ERROR; return NULL; } /* else load the data and put the data in the cache */ profile = (UStringPrepProfile*) uprv_malloc(sizeof(UStringPrepProfile)); if(profile == NULL){ *status = U_MEMORY_ALLOCATION_ERROR; uprv_free(key); return NULL; } /* initialize the data struct members */ uprv_memset(profile->indexes,0,sizeof(profile->indexes)); profile->mappingData = NULL; profile->sprepData = NULL; profile->refCount = 0; /* initialize the key memebers */ key->name = (char*) uprv_malloc(uprv_strlen(name)+1); if(key->name == NULL){ *status = U_MEMORY_ALLOCATION_ERROR; uprv_free(key); uprv_free(profile); return NULL; } uprv_strcpy(key->name, name); key->path=NULL; if(path != NULL){ key->path = (char*) uprv_malloc(uprv_strlen(path)+1); if(key->path == NULL){ *status = U_MEMORY_ALLOCATION_ERROR; uprv_free(key->path); uprv_free(key); uprv_free(profile); return NULL; } uprv_strcpy(key->path, path); } /* load the data */ if(!loadData(profile, path, name, _SPREP_DATA_TYPE, status) || U_FAILURE(*status) ){ return NULL; } /* get the options */ profile->doNFKC = (UBool)((profile->indexes[_SPREP_OPTIONS] & _SPREP_NORMALIZATION_ON) > 0); profile->checkBiDi = (UBool)((profile->indexes[_SPREP_OPTIONS] & _SPREP_CHECK_BIDI_ON) > 0); if(profile->checkBiDi) { profile->bdp = ubidi_getSingleton(status); if(U_FAILURE(*status)) { usprep_unload(profile); uprv_free(key->path); uprv_free(key); uprv_free(profile); return NULL; } } else { profile->bdp = NULL; } umtx_lock(&usprepMutex); /* add the data object to the cache */ uhash_put(SHARED_DATA_HASHTABLE, key, profile, status); umtx_unlock(&usprepMutex); } umtx_lock(&usprepMutex); /* increment the refcount */ profile->refCount++; umtx_unlock(&usprepMutex); return profile; }