123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- // Copyright (C) 2016 and later: Unicode, Inc. and others.
- // License & terms of use: http://www.unicode.org/copyright.html
- /*
- *******************************************************************************
- * Copyright (C) 2009-2014, International Business Machines Corporation and
- * others. All Rights Reserved.
- *******************************************************************************
- */
- #include "unicode/currpinf.h"
- #if !UCONFIG_NO_FORMATTING
- //#define CURRENCY_PLURAL_INFO_DEBUG 1
- #ifdef CURRENCY_PLURAL_INFO_DEBUG
- #include <iostream>
- #endif
- #include "unicode/locid.h"
- #include "unicode/plurrule.h"
- #include "unicode/ures.h"
- #include "unicode/numsys.h"
- #include "cstring.h"
- #include "hash.h"
- #include "uresimp.h"
- #include "ureslocs.h"
- U_NAMESPACE_BEGIN
- static const UChar gNumberPatternSeparator = 0x3B; // ;
- U_CDECL_BEGIN
- /**
- * @internal ICU 4.2
- */
- static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2);
- UBool
- U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2) {
- const UnicodeString* affix_1 = (UnicodeString*)val1.pointer;
- const UnicodeString* affix_2 = (UnicodeString*)val2.pointer;
- return *affix_1 == *affix_2;
- }
- U_CDECL_END
- UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo)
- static const UChar gDefaultCurrencyPluralPattern[] = {'0', '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4, 0};
- static const UChar gTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
- static const UChar gPluralCountOther[] = {0x6F, 0x74, 0x68, 0x65, 0x72, 0};
- static const UChar gPart0[] = {0x7B, 0x30, 0x7D, 0};
- static const UChar gPart1[] = {0x7B, 0x31, 0x7D, 0};
- static const char gNumberElementsTag[]="NumberElements";
- static const char gLatnTag[]="latn";
- static const char gPatternsTag[]="patterns";
- static const char gDecimalFormatTag[]="decimalFormat";
- static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns";
- CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status)
- : fPluralCountToCurrencyUnitPattern(NULL),
- fPluralRules(NULL),
- fLocale(NULL) {
- initialize(Locale::getDefault(), status);
- }
- CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status)
- : fPluralCountToCurrencyUnitPattern(NULL),
- fPluralRules(NULL),
- fLocale(NULL) {
- initialize(locale, status);
- }
- CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info)
- : UObject(info),
- fPluralCountToCurrencyUnitPattern(NULL),
- fPluralRules(NULL),
- fLocale(NULL) {
- *this = info;
- }
- CurrencyPluralInfo&
- CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) {
- if (this == &info) {
- return *this;
- }
- deleteHash(fPluralCountToCurrencyUnitPattern);
- UErrorCode status = U_ZERO_ERROR;
- fPluralCountToCurrencyUnitPattern = initHash(status);
- copyHash(info.fPluralCountToCurrencyUnitPattern,
- fPluralCountToCurrencyUnitPattern, status);
- if ( U_FAILURE(status) ) {
- return *this;
- }
- delete fPluralRules;
- delete fLocale;
- if (info.fPluralRules) {
- fPluralRules = info.fPluralRules->clone();
- } else {
- fPluralRules = NULL;
- }
- if (info.fLocale) {
- fLocale = info.fLocale->clone();
- } else {
- fLocale = NULL;
- }
- return *this;
- }
- CurrencyPluralInfo::~CurrencyPluralInfo() {
- deleteHash(fPluralCountToCurrencyUnitPattern);
- fPluralCountToCurrencyUnitPattern = NULL;
- delete fPluralRules;
- delete fLocale;
- fPluralRules = NULL;
- fLocale = NULL;
- }
- UBool
- CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const {
- #ifdef CURRENCY_PLURAL_INFO_DEBUG
- if (*fPluralRules == *info.fPluralRules) {
- std::cout << "same plural rules\n";
- }
- if (*fLocale == *info.fLocale) {
- std::cout << "same locale\n";
- }
- if (fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern)) {
- std::cout << "same pattern\n";
- }
- #endif
- return *fPluralRules == *info.fPluralRules &&
- *fLocale == *info.fLocale &&
- fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern);
- }
- CurrencyPluralInfo*
- CurrencyPluralInfo::clone() const {
- return new CurrencyPluralInfo(*this);
- }
- const PluralRules*
- CurrencyPluralInfo::getPluralRules() const {
- return fPluralRules;
- }
- UnicodeString&
- CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString& pluralCount,
- UnicodeString& result) const {
- const UnicodeString* currencyPluralPattern =
- (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount);
- if (currencyPluralPattern == NULL) {
- // fall back to "other"
- if (pluralCount.compare(gPluralCountOther, 5)) {
- currencyPluralPattern =
- (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(UnicodeString(TRUE, gPluralCountOther, 5));
- }
- if (currencyPluralPattern == NULL) {
- // no currencyUnitPatterns defined,
- // fallback to predefined defult.
- // This should never happen when ICU resource files are
- // available, since currencyUnitPattern of "other" is always
- // defined in root.
- result = UnicodeString(gDefaultCurrencyPluralPattern);
- return result;
- }
- }
- result = *currencyPluralPattern;
- return result;
- }
- const Locale&
- CurrencyPluralInfo::getLocale() const {
- return *fLocale;
- }
- void
- CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription,
- UErrorCode& status) {
- if (U_SUCCESS(status)) {
- if (fPluralRules) {
- delete fPluralRules;
- }
- fPluralRules = PluralRules::createRules(ruleDescription, status);
- }
- }
- void
- CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount,
- const UnicodeString& pattern,
- UErrorCode& status) {
- if (U_SUCCESS(status)) {
- fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status);
- }
- }
- void
- CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) {
- initialize(loc, status);
- }
- void
- CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
- delete fLocale;
- fLocale = loc.clone();
- if (fPluralRules) {
- delete fPluralRules;
- }
- fPluralRules = PluralRules::forLocale(loc, status);
- setupCurrencyPluralPattern(loc, status);
- }
-
- void
- CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
- if (fPluralCountToCurrencyUnitPattern) {
- deleteHash(fPluralCountToCurrencyUnitPattern);
- }
- fPluralCountToCurrencyUnitPattern = initHash(status);
- if (U_FAILURE(status)) {
- return;
- }
- NumberingSystem *ns = NumberingSystem::createInstance(loc,status);
- UErrorCode ec = U_ZERO_ERROR;
- UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec);
- UResourceBundle *numElements = ures_getByKeyWithFallback(rb, gNumberElementsTag, NULL, &ec);
- rb = ures_getByKeyWithFallback(numElements, ns->getName(), rb, &ec);
- rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec);
- int32_t ptnLen;
- const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec);
- // Fall back to "latn" if num sys specific pattern isn't there.
- if ( ec == U_MISSING_RESOURCE_ERROR && uprv_strcmp(ns->getName(),gLatnTag)) {
- ec = U_ZERO_ERROR;
- rb = ures_getByKeyWithFallback(numElements, gLatnTag, rb, &ec);
- rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec);
- numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec);
- }
- int32_t numberStylePatternLen = ptnLen;
- const UChar* negNumberStylePattern = NULL;
- int32_t negNumberStylePatternLen = 0;
- // TODO: Java
- // parse to check whether there is ";" separator in the numberStylePattern
- UBool hasSeparator = false;
- if (U_SUCCESS(ec)) {
- for (int32_t styleCharIndex = 0; styleCharIndex < ptnLen; ++styleCharIndex) {
- if (numberStylePattern[styleCharIndex] == gNumberPatternSeparator) {
- hasSeparator = true;
- // split the number style pattern into positive and negative
- negNumberStylePattern = numberStylePattern + styleCharIndex + 1;
- negNumberStylePatternLen = ptnLen - styleCharIndex - 1;
- numberStylePatternLen = styleCharIndex;
- }
- }
- }
- ures_close(numElements);
- ures_close(rb);
- delete ns;
- if (U_FAILURE(ec)) {
- return;
- }
- UResourceBundle *currRb = ures_open(U_ICUDATA_CURR, loc.getName(), &ec);
- UResourceBundle *currencyRes = ures_getByKeyWithFallback(currRb, gCurrUnitPtnTag, NULL, &ec);
-
- #ifdef CURRENCY_PLURAL_INFO_DEBUG
- std::cout << "in set up\n";
- #endif
- StringEnumeration* keywords = fPluralRules->getKeywords(ec);
- if (U_SUCCESS(ec)) {
- const char* pluralCount;
- while ((pluralCount = keywords->next(NULL, ec)) != NULL) {
- if ( U_SUCCESS(ec) ) {
- int32_t ptnLen;
- UErrorCode err = U_ZERO_ERROR;
- const UChar* patternChars = ures_getStringByKeyWithFallback(
- currencyRes, pluralCount, &ptnLen, &err);
- if (U_SUCCESS(err) && ptnLen > 0) {
- UnicodeString* pattern = new UnicodeString(patternChars, ptnLen);
- #ifdef CURRENCY_PLURAL_INFO_DEBUG
- char result_1[1000];
- pattern->extract(0, pattern->length(), result_1, "UTF-8");
- std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
- #endif
- pattern->findAndReplace(UnicodeString(TRUE, gPart0, 3),
- UnicodeString(numberStylePattern, numberStylePatternLen));
- pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
- if (hasSeparator) {
- UnicodeString negPattern(patternChars, ptnLen);
- negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3),
- UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
- negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
- pattern->append(gNumberPatternSeparator);
- pattern->append(negPattern);
- }
- #ifdef CURRENCY_PLURAL_INFO_DEBUG
- pattern->extract(0, pattern->length(), result_1, "UTF-8");
- std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
- #endif
- fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount, -1, US_INV), pattern, status);
- }
- }
- }
- }
- delete keywords;
- ures_close(currencyRes);
- ures_close(currRb);
- }
- void
- CurrencyPluralInfo::deleteHash(Hashtable* hTable)
- {
- if ( hTable == NULL ) {
- return;
- }
- int32_t pos = UHASH_FIRST;
- const UHashElement* element = NULL;
- while ( (element = hTable->nextElement(pos)) != NULL ) {
- const UHashTok valueTok = element->value;
- const UnicodeString* value = (UnicodeString*)valueTok.pointer;
- delete value;
- }
- delete hTable;
- hTable = NULL;
- }
- Hashtable*
- CurrencyPluralInfo::initHash(UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return NULL;
- }
- Hashtable* hTable;
- if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
- if ( U_FAILURE(status) ) {
- delete hTable;
- return NULL;
- }
- hTable->setValueComparator(ValueComparator);
- return hTable;
- }
- void
- CurrencyPluralInfo::copyHash(const Hashtable* source,
- Hashtable* target,
- UErrorCode& status) {
- if ( U_FAILURE(status) ) {
- return;
- }
- int32_t pos = UHASH_FIRST;
- const UHashElement* element = NULL;
- if ( source ) {
- while ( (element = source->nextElement(pos)) != NULL ) {
- const UHashTok keyTok = element->key;
- const UnicodeString* key = (UnicodeString*)keyTok.pointer;
- const UHashTok valueTok = element->value;
- const UnicodeString* value = (UnicodeString*)valueTok.pointer;
- UnicodeString* copy = new UnicodeString(*value);
- target->put(UnicodeString(*key), copy, status);
- if ( U_FAILURE(status) ) {
- return;
- }
- }
- }
- }
- U_NAMESPACE_END
- #endif
|