DictionaryMatcher * ICULanguageBreakFactory::loadDictionaryMatcherFor(UScriptCode script, int32_t /* brkType */) { UErrorCode status = U_ZERO_ERROR; // open root from brkitr tree. UResourceBundle *b = ures_open(U_ICUDATA_BRKITR, "", &status); b = ures_getByKeyWithFallback(b, "dictionaries", b, &status); int32_t dictnlength = 0; const UChar *dictfname = ures_getStringByKeyWithFallback(b, uscript_getShortName(script), &dictnlength, &status); if (U_FAILURE(status)) { ures_close(b); return NULL; } CharString dictnbuf; CharString ext; const UChar *extStart = u_memrchr(dictfname, 0x002e, dictnlength); // last dot if (extStart != NULL) { int32_t len = (int32_t)(extStart - dictfname); ext.appendInvariantChars(UnicodeString(FALSE, extStart + 1, dictnlength - len - 1), status); dictnlength = len; } dictnbuf.appendInvariantChars(UnicodeString(FALSE, dictfname, dictnlength), status); ures_close(b); UDataMemory *file = udata_open(U_ICUDATA_BRKITR, ext.data(), dictnbuf.data(), &status); if (U_SUCCESS(status)) { // build trie const uint8_t *data = (const uint8_t *)udata_getMemory(file); const int32_t *indexes = (const int32_t *)data; const int32_t offset = indexes[DictionaryData::IX_STRING_TRIE_OFFSET]; const int32_t trieType = indexes[DictionaryData::IX_TRIE_TYPE] & DictionaryData::TRIE_TYPE_MASK; DictionaryMatcher *m = NULL; if (trieType == DictionaryData::TRIE_TYPE_BYTES) { const int32_t transform = indexes[DictionaryData::IX_TRANSFORM]; const char *characters = (const char *)(data + offset); m = new BytesDictionaryMatcher(characters, transform, file); } else if (trieType == DictionaryData::TRIE_TYPE_UCHARS) { const UChar *characters = (const UChar *)(data + offset); m = new UCharsDictionaryMatcher(characters, file); } if (m == NULL) { // no matcher exists to take ownership - either we are an invalid // type or memory allocation failed udata_close(file); } return m; } else if (dictfname != NULL) { // we don't have a dictionary matcher. // returning NULL here will cause us to fail to find a dictionary break engine, as expected status = U_ZERO_ERROR; return NULL; } return NULL; }
PluralMapBase::Category PluralMapBase::toCategory(const UnicodeString &pluralForm) { CharString cCategory; UErrorCode status = U_ZERO_ERROR; cCategory.appendInvariantChars(pluralForm, status); return U_FAILURE(status) ? NONE : toCategory(cCategory.data()); }
const Hashtable* LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID) { // LocaleUtility_cache is a hash-of-hashes. The top-level keys // are path strings ('bundleID') passed to // ures_openAvailableLocales. The top-level values are // second-level hashes. The second-level keys are result strings // from ures_openAvailableLocales. The second-level values are // garbage ((void*)1 or other random pointer). UErrorCode status = U_ZERO_ERROR; umtx_initOnce(LocaleUtilityInitOnce, locale_utility_init, status); Hashtable *cache = LocaleUtility_cache; if (cache == NULL) { // Catastrophic failure. return NULL; } Hashtable* htp; umtx_lock(NULL); htp = (Hashtable*) cache->get(bundleID); umtx_unlock(NULL); if (htp == NULL) { htp = new Hashtable(status); if (htp && U_SUCCESS(status)) { CharString cbundleID; cbundleID.appendInvariantChars(bundleID, status); const char* path = cbundleID.isEmpty() ? NULL : cbundleID.data(); UEnumeration *uenum = ures_openAvailableLocales(path, &status); for (;;) { const UChar* id = uenum_unext(uenum, NULL, &status); if (id == NULL) { break; } htp->put(UnicodeString(id), (void*)htp, status); } uenum_close(uenum); if (U_FAILURE(status)) { delete htp; return NULL; } umtx_lock(NULL); Hashtable *t = static_cast<Hashtable *>(cache->get(bundleID)); if (t != NULL) { // Another thread raced through this code, creating the cache entry first. // Discard ours and return theirs. umtx_unlock(NULL); delete htp; htp = t; } else { cache->put(bundleID, (void*)htp, status); umtx_unlock(NULL); } } } return htp; }
void TimeUnitFormat::checkConsistency(UTimeUnitFormatStyle style, const char* key, UErrorCode& err) { if (U_FAILURE(err)) { return; } // there should be patterns for each plural rule in each time unit. // For each time unit, // for each plural rule, following is unit pattern fall-back rule: // ( for example: "one" hour ) // look for its unit pattern in its locale tree. // if pattern is not found in its own locale, such as de_DE, // look for the pattern in its parent, such as de, // keep looking till found or till root. // if the pattern is not found in root either, // fallback to plural count "other", // look for the pattern of "other" in the locale tree: // "de_DE" to "de" to "root". // If not found, fall back to value of // static variable DEFAULT_PATTERN_FOR_xxx, such as "{0} h". // // Following is consistency check to create pattern for each // plural rule in each time unit using above fall-back rule. // StringEnumeration* keywords = getPluralRules().getKeywords(err); if (U_SUCCESS(err)) { const UnicodeString* pluralCount; while ((pluralCount = keywords->snext(err)) != NULL) { if ( U_SUCCESS(err) ) { for (int32_t i = 0; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; ++i) { // for each time unit, // get all the patterns for each plural rule in this locale. Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i]; if ( countToPatterns == NULL ) { countToPatterns = initHash(err); if (U_FAILURE(err)) { delete countToPatterns; return; } fTimeUnitToCountToPatterns[i] = countToPatterns; } MessageFormat** formatters = (MessageFormat**)countToPatterns->get(*pluralCount); if( formatters == NULL || formatters[style] == NULL ) { // look through parents const char* localeName = getLocaleID(err); CharString pluralCountChars; pluralCountChars.appendInvariantChars(*pluralCount, err); searchInLocaleChain(style, key, localeName, (TimeUnit::UTimeUnitFields)i, *pluralCount, pluralCountChars.data(), countToPatterns, err); } } } } } delete keywords; }
static void strToLocale( const UnicodeString &str, void *localePtr, UErrorCode &status) { if (U_FAILURE(status)) { return; } CharString localeStr; localeStr.appendInvariantChars(str, status); *static_cast<Locale *>(localePtr) = Locale(localeStr.data()); }
static void strToDouble( const UnicodeString &str, void *doublePtr, UErrorCode &status) { if (U_FAILURE(status)) { return; } CharString buffer; buffer.appendInvariantChars(str, status); if (U_FAILURE(status)) { return; } *static_cast<double *>(doublePtr) = atof(buffer.data()); }
// getCDFUnitFallback returns a pointer to the prefix-suffix pair for a given // variant and log10 value within table. If the given variant doesn't exist, it // falls back to the OTHER variant. Therefore, this method will always return // some non-NULL value. static const CDFUnit* getCDFUnitFallback(const UHashtable* table, const UnicodeString& variant, int32_t log10Value) { CharString cvariant; UErrorCode status = U_ZERO_ERROR; const CDFUnit *cdfUnit = NULL; cvariant.appendInvariantChars(variant, status); if (!U_FAILURE(status)) { cdfUnit = (const CDFUnit*) uhash_get(table, cvariant.data()); } if (cdfUnit == NULL) { cdfUnit = (const CDFUnit*) uhash_get(table, gOther); } return &cdfUnit[log10Value]; }
void CurrencyAffixInfo::set( const char *locale, const PluralRules *rules, const UChar *currency, UErrorCode &status) { if (U_FAILURE(status)) { return; } fIsDefault = FALSE; if (currency == NULL) { fSymbol.setTo(gDefaultSymbols, 1); fISO.setTo(gDefaultSymbols, 2); fLong.remove(); fLong.append(gDefaultSymbols, 3); fIsDefault = TRUE; return; } int32_t len; UBool unusedIsChoice; const UChar *symbol = ucurr_getName( currency, locale, UCURR_SYMBOL_NAME, &unusedIsChoice, &len, &status); if (U_FAILURE(status)) { return; } fSymbol.setTo(symbol, len); fISO.setTo(currency, u_strlen(currency)); fLong.remove(); StringEnumeration* keywords = rules->getKeywords(status); if (U_FAILURE(status)) { return; } const UnicodeString* pluralCount; while ((pluralCount = keywords->snext(status)) != NULL) { CharString pCount; pCount.appendInvariantChars(*pluralCount, status); const UChar *pluralName = ucurr_getPluralName( currency, locale, &unusedIsChoice, pCount.data(), &len, &status); fLong.setVariant(pCount.data(), UnicodeString(pluralName, len), status); } delete keywords; }
static int32_t toEnum( const Numberformattesttuple_EnumConversion *table, int32_t tableLength, const UnicodeString &str, UErrorCode &status) { if (U_FAILURE(status)) { return 0; } CharString cstr; cstr.appendInvariantChars(str, status); if (U_FAILURE(status)) { return 0; } for (int32_t i = 0; i < tableLength; ++i) { if (uprv_strcmp(cstr.data(), table[i].str) == 0) { return table[i].value; } } status = U_ILLEGAL_ARGUMENT_ERROR; return 0; }
ENumberFormatTestTupleField NumberFormatTestTuple::getFieldByName( const UnicodeString &name) { CharString buffer; UErrorCode status = U_ZERO_ERROR; buffer.appendInvariantChars(name, status); if (U_FAILURE(status)) { return kNumberFormatTestTupleFieldCount; } int32_t result = -1; for (int32_t i = 0; i < UPRV_LENGTHOF(gFieldData); ++i) { if (uprv_strcmp(gFieldData[i].name, buffer.data()) == 0) { result = i; break; } } if (result == -1) { return kNumberFormatTestTupleFieldCount; } return (ENumberFormatTestTupleField) result; }
// Helpers. static int32_t parseSetNum(const UnicodeString &setNumStr, UErrorCode &errorCode) { CharString cs; cs.appendInvariantChars(setNumStr, errorCode); return parseSetNum(cs.data(), errorCode); }
NumberFormat* NumberFormat::makeInstance(const Locale& desiredLocale, UNumberFormatStyle style, UBool mustBeDecimalFormat, UErrorCode& status) { if (U_FAILURE(status)) return NULL; if (style < 0 || style >= UNUM_FORMAT_STYLE_COUNT) { status = U_ILLEGAL_ARGUMENT_ERROR; return NULL; } // Some styles are not supported. This is a result of merging // the @draft ICU 4.2 NumberFormat::EStyles into the long-existing UNumberFormatStyle. // Ticket #8503 is for reviewing/fixing/merging the two relevant implementations: // this one and unum_open(). // The UNUM_PATTERN_ styles are not supported here // because this method does not take a pattern string. if (!isStyleSupported(style)) { status = U_UNSUPPORTED_ERROR; return NULL; } #if U_PLATFORM_USES_ONLY_WIN32_API if (!mustBeDecimalFormat) { 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 (U_SUCCESS(status) && count > 0 && uprv_strcmp(buffer, "host") == 0) { Win32NumberFormat *f = NULL; UBool curr = TRUE; switch (style) { case UNUM_DECIMAL: curr = FALSE; // fall-through case UNUM_CURRENCY: case UNUM_CURRENCY_ISO: // do not support plural formatting here case UNUM_CURRENCY_PLURAL: f = new Win32NumberFormat(desiredLocale, curr, status); if (U_SUCCESS(status)) { return f; } delete f; break; default: break; } } } #endif // Use numbering system cache hashtable umtx_initOnce(gNSCacheInitOnce, &nscacheInit); // Get cached numbering system LocalPointer<NumberingSystem> ownedNs; NumberingSystem *ns = NULL; if (NumberingSystem_cache != NULL) { // TODO: Bad hash key usage, see ticket #8504. int32_t hashKey = desiredLocale.hashCode(); Mutex lock(&nscacheMutex); ns = (NumberingSystem *)uhash_iget(NumberingSystem_cache, hashKey); if (ns == NULL) { ns = NumberingSystem::createInstance(desiredLocale,status); uhash_iput(NumberingSystem_cache, hashKey, (void*)ns, &status); } } else { ownedNs.adoptInstead(NumberingSystem::createInstance(desiredLocale,status)); ns = ownedNs.getAlias(); } // check results of getting a numbering system if (U_FAILURE(status)) { return NULL; } if (mustBeDecimalFormat && ns->isAlgorithmic()) { status = U_UNSUPPORTED_ERROR; return NULL; } LocalPointer<DecimalFormatSymbols> symbolsToAdopt; UnicodeString pattern; LocalUResourceBundlePointer ownedResource(ures_open(NULL, desiredLocale.getName(), &status)); 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.adoptInstead(new DecimalFormatSymbols(status)); if (symbolsToAdopt.isNull()) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } // Creates a DecimalFormat instance with the last resort number patterns. pattern.setTo(TRUE, gLastResortNumberPatterns[style], -1); } else { // Loads the decimal symbols of the desired locale. symbolsToAdopt.adoptInstead(new DecimalFormatSymbols(desiredLocale, status)); if (symbolsToAdopt.isNull()) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } UResourceBundle *resource = ownedResource.orphan(); UResourceBundle *numElements = ures_getByKeyWithFallback(resource, gNumberElements, NULL, &status); resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &status); resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); ownedResource.adoptInstead(resource); int32_t patLen = 0; const UChar *patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); // Didn't find a pattern specific to the numbering system, so fall back to "latn" if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(gLatn,ns->getName())) { status = U_ZERO_ERROR; resource = ures_getByKeyWithFallback(numElements, gLatn, resource, &status); resource = ures_getByKeyWithFallback(resource, gPatterns, resource, &status); patResStr = ures_getStringByKeyWithFallback(resource, gFormatKeys[style], &patLen, &status); } ures_close(numElements); // Creates the specified decimal format style of the desired locale. pattern.setTo(TRUE, patResStr, patLen); } if (U_FAILURE(status)) { return NULL; } if(style==UNUM_CURRENCY || style == UNUM_CURRENCY_ISO){ const UChar* currPattern = symbolsToAdopt->getCurrencyPattern(); if(currPattern!=NULL){ pattern.setTo(currPattern, u_strlen(currPattern)); } } NumberFormat *f; 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 ) { CharString nsLocID; nsLocID.appendInvariantChars(nsDesc.tempSubString(0, firstSlash), status); nsRuleSetGroup.setTo(nsDesc,firstSlash+1,lastSlash-firstSlash-1); nsRuleSetName.setTo(nsDesc,lastSlash+1); nsLoc = Locale::createFromName(nsLocID.data()); 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 (r == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } r->setDefaultRuleSet(nsRuleSetName,status); f = r; } else { // replace single currency sign in the pattern with double currency sign // if the style is UNUM_CURRENCY_ISO if (style == UNUM_CURRENCY_ISO) { pattern.findAndReplace(UnicodeString(TRUE, gSingleCurrencySign, 1), UnicodeString(TRUE, gDoubleCurrencySign, 2)); } // "new DecimalFormat()" does not adopt the symbols if its memory allocation fails. DecimalFormatSymbols *syms = symbolsToAdopt.orphan(); f = new DecimalFormat(pattern, syms, style, status); if (f == NULL) { delete syms; status = U_MEMORY_ALLOCATION_ERROR; return NULL; } } f->setLocaleIDs(ures_getLocaleByType(ownedResource.getAlias(), ULOC_VALID_LOCALE, &status), ures_getLocaleByType(ownedResource.getAlias(), ULOC_ACTUAL_LOCALE, &status)); if (U_FAILURE(status)) { delete f; return NULL; } return f; }
UnicodeString &QuantityFormatter::format( const Formattable& quantity, const NumberFormat &fmt, const PluralRules &rules, UnicodeString &appendTo, FieldPosition &pos, UErrorCode &status) const { if (U_FAILURE(status)) { return appendTo; } UnicodeString count; const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt); if (decFmt != NULL) { FixedDecimal fd = decFmt->getFixedDecimal(quantity, status); if (U_FAILURE(status)) { return appendTo; } count = rules.select(fd); } else { if (quantity.getType() == Formattable::kDouble) { count = rules.select(quantity.getDouble()); } else if (quantity.getType() == Formattable::kLong) { count = rules.select(quantity.getLong()); } else if (quantity.getType() == Formattable::kInt64) { count = rules.select((double) quantity.getInt64()); } else { status = U_ILLEGAL_ARGUMENT_ERROR; return appendTo; } } CharString buffer; buffer.appendInvariantChars(count, status); if (U_FAILURE(status)) { return appendTo; } int32_t pluralIndex = getPluralIndex(buffer.data()); if (pluralIndex == -1) { pluralIndex = 0; } const SimplePatternFormatter *pattern = formatters[pluralIndex]; if (pattern == NULL) { pattern = formatters[0]; } if (pattern == NULL) { status = U_INVALID_STATE_ERROR; return appendTo; } UnicodeString formattedNumber; FieldPosition fpos(pos.getField()); fmt.format(quantity, formattedNumber, fpos, status); const UnicodeString *params[1] = {&formattedNumber}; int32_t offsets[1]; pattern->format(params, LENGTHOF(params), appendTo, offsets, LENGTHOF(offsets), status); if (offsets[0] != -1) { if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { pos.setBeginIndex(fpos.getBeginIndex() + offsets[0]); pos.setEndIndex(fpos.getEndIndex() + offsets[0]); } } return appendTo; }
const Hashtable * LocaleUtility::getAvailableLocaleNames(const UnicodeString & bundleID) { // LocaleUtility_cache is a hash-of-hashes. The top-level keys // are path strings ('bundleID') passed to // ures_openAvailableLocales. The top-level values are // second-level hashes. The second-level keys are result strings // from ures_openAvailableLocales. The second-level values are // garbage ((void*)1 or other random pointer). UErrorCode status = U_ZERO_ERROR; Hashtable * cache; umtx_lock(NULL); cache = LocaleUtility_cache; umtx_unlock(NULL); if (cache == NULL) { cache = new Hashtable(status); if (cache == NULL || U_FAILURE(status)) { return NULL; // catastrophic failure; e.g. out of memory } cache->setValueDeleter(uhash_deleteHashtable); Hashtable * h; // set this to final LocaleUtility_cache value umtx_lock(NULL); h = LocaleUtility_cache; if (h == NULL) { LocaleUtility_cache = h = cache; cache = NULL; ucln_common_registerCleanup(UCLN_COMMON_SERVICE, service_cleanup); } umtx_unlock(NULL); if (cache != NULL) { delete cache; } cache = h; } U_ASSERT(cache != NULL); Hashtable * htp; umtx_lock(NULL); htp = (Hashtable *) cache->get(bundleID); umtx_unlock(NULL); if (htp == NULL) { htp = new Hashtable(status); if (htp && U_SUCCESS(status)) { CharString cbundleID; cbundleID.appendInvariantChars(bundleID, status); const char * path = cbundleID.isEmpty() ? NULL : cbundleID.data(); UEnumeration * uenum = ures_openAvailableLocales(path, &status); for (;;) { const UChar * id = uenum_unext(uenum, NULL, &status); if (id == NULL) { break; } htp->put(UnicodeString(id), (void *)htp, status); } uenum_close(uenum); if (U_FAILURE(status)) { delete htp; return NULL; } umtx_lock(NULL); cache->put(bundleID, (void *)htp, status); umtx_unlock(NULL); } } return htp; }