1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/currpinf.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,399 @@ 1.4 +/* 1.5 + ******************************************************************************* 1.6 + * Copyright (C) 2009-2011, International Business Machines Corporation and 1.7 + * others. All Rights Reserved. 1.8 + ******************************************************************************* 1.9 + */ 1.10 + 1.11 +#include "unicode/currpinf.h" 1.12 + 1.13 +#if !UCONFIG_NO_FORMATTING 1.14 + 1.15 +//#define CURRENCY_PLURAL_INFO_DEBUG 1 1.16 + 1.17 +#ifdef CURRENCY_PLURAL_INFO_DEBUG 1.18 +#include <iostream> 1.19 +#endif 1.20 + 1.21 + 1.22 +#include "unicode/locid.h" 1.23 +#include "unicode/plurrule.h" 1.24 +#include "unicode/ures.h" 1.25 +#include "unicode/numsys.h" 1.26 +#include "cstring.h" 1.27 +#include "hash.h" 1.28 +#include "uresimp.h" 1.29 +#include "ureslocs.h" 1.30 + 1.31 +U_NAMESPACE_BEGIN 1.32 + 1.33 + 1.34 +static const UChar gNumberPatternSeparator = 0x3B; // ; 1.35 + 1.36 +U_CDECL_BEGIN 1.37 + 1.38 +/** 1.39 + * @internal ICU 4.2 1.40 + */ 1.41 +static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2); 1.42 + 1.43 +UBool 1.44 +U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2) { 1.45 + const UnicodeString* affix_1 = (UnicodeString*)val1.pointer; 1.46 + const UnicodeString* affix_2 = (UnicodeString*)val2.pointer; 1.47 + return *affix_1 == *affix_2; 1.48 +} 1.49 + 1.50 +U_CDECL_END 1.51 + 1.52 + 1.53 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo) 1.54 + 1.55 +static const UChar gDefaultCurrencyPluralPattern[] = {'0', '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4, 0}; 1.56 +static const UChar gTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0}; 1.57 +static const UChar gPluralCountOther[] = {0x6F, 0x74, 0x68, 0x65, 0x72, 0}; 1.58 +static const UChar gPart0[] = {0x7B, 0x30, 0x7D, 0}; 1.59 +static const UChar gPart1[] = {0x7B, 0x31, 0x7D, 0}; 1.60 + 1.61 +static const char gNumberElementsTag[]="NumberElements"; 1.62 +static const char gLatnTag[]="latn"; 1.63 +static const char gPatternsTag[]="patterns"; 1.64 +static const char gDecimalFormatTag[]="decimalFormat"; 1.65 +static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns"; 1.66 + 1.67 +CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status) 1.68 +: fPluralCountToCurrencyUnitPattern(NULL), 1.69 + fPluralRules(NULL), 1.70 + fLocale(NULL) { 1.71 + initialize(Locale::getDefault(), status); 1.72 +} 1.73 + 1.74 +CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status) 1.75 +: fPluralCountToCurrencyUnitPattern(NULL), 1.76 + fPluralRules(NULL), 1.77 + fLocale(NULL) { 1.78 + initialize(locale, status); 1.79 +} 1.80 + 1.81 +CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info) 1.82 +: UObject(info), 1.83 + fPluralCountToCurrencyUnitPattern(NULL), 1.84 + fPluralRules(NULL), 1.85 + fLocale(NULL) { 1.86 + *this = info; 1.87 +} 1.88 + 1.89 + 1.90 +CurrencyPluralInfo& 1.91 +CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) { 1.92 + if (this == &info) { 1.93 + return *this; 1.94 + } 1.95 + 1.96 + deleteHash(fPluralCountToCurrencyUnitPattern); 1.97 + UErrorCode status = U_ZERO_ERROR; 1.98 + fPluralCountToCurrencyUnitPattern = initHash(status); 1.99 + copyHash(info.fPluralCountToCurrencyUnitPattern, 1.100 + fPluralCountToCurrencyUnitPattern, status); 1.101 + if ( U_FAILURE(status) ) { 1.102 + return *this; 1.103 + } 1.104 + 1.105 + delete fPluralRules; 1.106 + delete fLocale; 1.107 + if (info.fPluralRules) { 1.108 + fPluralRules = info.fPluralRules->clone(); 1.109 + } else { 1.110 + fPluralRules = NULL; 1.111 + } 1.112 + if (info.fLocale) { 1.113 + fLocale = info.fLocale->clone(); 1.114 + } else { 1.115 + fLocale = NULL; 1.116 + } 1.117 + return *this; 1.118 +} 1.119 + 1.120 + 1.121 +CurrencyPluralInfo::~CurrencyPluralInfo() { 1.122 + deleteHash(fPluralCountToCurrencyUnitPattern); 1.123 + fPluralCountToCurrencyUnitPattern = NULL; 1.124 + delete fPluralRules; 1.125 + delete fLocale; 1.126 + fPluralRules = NULL; 1.127 + fLocale = NULL; 1.128 +} 1.129 + 1.130 +UBool 1.131 +CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const { 1.132 +#ifdef CURRENCY_PLURAL_INFO_DEBUG 1.133 + if (*fPluralRules == *info.fPluralRules) { 1.134 + std::cout << "same plural rules\n"; 1.135 + } 1.136 + if (*fLocale == *info.fLocale) { 1.137 + std::cout << "same locale\n"; 1.138 + } 1.139 + if (fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern)) { 1.140 + std::cout << "same pattern\n"; 1.141 + } 1.142 +#endif 1.143 + return *fPluralRules == *info.fPluralRules && 1.144 + *fLocale == *info.fLocale && 1.145 + fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern); 1.146 +} 1.147 + 1.148 + 1.149 +CurrencyPluralInfo* 1.150 +CurrencyPluralInfo::clone() const { 1.151 + return new CurrencyPluralInfo(*this); 1.152 +} 1.153 + 1.154 +const PluralRules* 1.155 +CurrencyPluralInfo::getPluralRules() const { 1.156 + return fPluralRules; 1.157 +} 1.158 + 1.159 +UnicodeString& 1.160 +CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString& pluralCount, 1.161 + UnicodeString& result) const { 1.162 + const UnicodeString* currencyPluralPattern = 1.163 + (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount); 1.164 + if (currencyPluralPattern == NULL) { 1.165 + // fall back to "other" 1.166 + if (pluralCount.compare(gPluralCountOther, 5)) { 1.167 + currencyPluralPattern = 1.168 + (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(UnicodeString(TRUE, gPluralCountOther, 5)); 1.169 + } 1.170 + if (currencyPluralPattern == NULL) { 1.171 + // no currencyUnitPatterns defined, 1.172 + // fallback to predefined defult. 1.173 + // This should never happen when ICU resource files are 1.174 + // available, since currencyUnitPattern of "other" is always 1.175 + // defined in root. 1.176 + result = UnicodeString(gDefaultCurrencyPluralPattern); 1.177 + return result; 1.178 + } 1.179 + } 1.180 + result = *currencyPluralPattern; 1.181 + return result; 1.182 +} 1.183 + 1.184 +const Locale& 1.185 +CurrencyPluralInfo::getLocale() const { 1.186 + return *fLocale; 1.187 +} 1.188 + 1.189 +void 1.190 +CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription, 1.191 + UErrorCode& status) { 1.192 + if (U_SUCCESS(status)) { 1.193 + if (fPluralRules) { 1.194 + delete fPluralRules; 1.195 + } 1.196 + fPluralRules = PluralRules::createRules(ruleDescription, status); 1.197 + } 1.198 +} 1.199 + 1.200 + 1.201 +void 1.202 +CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount, 1.203 + const UnicodeString& pattern, 1.204 + UErrorCode& status) { 1.205 + if (U_SUCCESS(status)) { 1.206 + fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status); 1.207 + } 1.208 +} 1.209 + 1.210 + 1.211 +void 1.212 +CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) { 1.213 + initialize(loc, status); 1.214 +} 1.215 + 1.216 + 1.217 +void 1.218 +CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) { 1.219 + if (U_FAILURE(status)) { 1.220 + return; 1.221 + } 1.222 + delete fLocale; 1.223 + fLocale = loc.clone(); 1.224 + if (fPluralRules) { 1.225 + delete fPluralRules; 1.226 + } 1.227 + fPluralRules = PluralRules::forLocale(loc, status); 1.228 + setupCurrencyPluralPattern(loc, status); 1.229 +} 1.230 + 1.231 + 1.232 +void 1.233 +CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) { 1.234 + if (U_FAILURE(status)) { 1.235 + return; 1.236 + } 1.237 + 1.238 + if (fPluralCountToCurrencyUnitPattern) { 1.239 + deleteHash(fPluralCountToCurrencyUnitPattern); 1.240 + } 1.241 + fPluralCountToCurrencyUnitPattern = initHash(status); 1.242 + if (U_FAILURE(status)) { 1.243 + return; 1.244 + } 1.245 + 1.246 + NumberingSystem *ns = NumberingSystem::createInstance(loc,status); 1.247 + UErrorCode ec = U_ZERO_ERROR; 1.248 + UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec); 1.249 + UResourceBundle *numElements = ures_getByKeyWithFallback(rb, gNumberElementsTag, NULL, &ec); 1.250 + rb = ures_getByKeyWithFallback(numElements, ns->getName(), rb, &ec); 1.251 + rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec); 1.252 + int32_t ptnLen; 1.253 + const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec); 1.254 + // Fall back to "latn" if num sys specific pattern isn't there. 1.255 + if ( ec == U_MISSING_RESOURCE_ERROR && uprv_strcmp(ns->getName(),gLatnTag)) { 1.256 + ec = U_ZERO_ERROR; 1.257 + rb = ures_getByKeyWithFallback(numElements, gLatnTag, rb, &ec); 1.258 + rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec); 1.259 + numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec); 1.260 + } 1.261 + int32_t numberStylePatternLen = ptnLen; 1.262 + const UChar* negNumberStylePattern = NULL; 1.263 + int32_t negNumberStylePatternLen = 0; 1.264 + // TODO: Java 1.265 + // parse to check whether there is ";" separator in the numberStylePattern 1.266 + UBool hasSeparator = false; 1.267 + if (U_SUCCESS(ec)) { 1.268 + for (int32_t styleCharIndex = 0; styleCharIndex < ptnLen; ++styleCharIndex) { 1.269 + if (numberStylePattern[styleCharIndex] == gNumberPatternSeparator) { 1.270 + hasSeparator = true; 1.271 + // split the number style pattern into positive and negative 1.272 + negNumberStylePattern = numberStylePattern + styleCharIndex + 1; 1.273 + negNumberStylePatternLen = ptnLen - styleCharIndex - 1; 1.274 + numberStylePatternLen = styleCharIndex; 1.275 + } 1.276 + } 1.277 + } 1.278 + 1.279 + ures_close(numElements); 1.280 + ures_close(rb); 1.281 + delete ns; 1.282 + 1.283 + if (U_FAILURE(ec)) { 1.284 + return; 1.285 + } 1.286 + 1.287 + UResourceBundle *currRb = ures_open(U_ICUDATA_CURR, loc.getName(), &ec); 1.288 + UResourceBundle *currencyRes = ures_getByKeyWithFallback(currRb, gCurrUnitPtnTag, NULL, &ec); 1.289 + 1.290 +#ifdef CURRENCY_PLURAL_INFO_DEBUG 1.291 + std::cout << "in set up\n"; 1.292 +#endif 1.293 + StringEnumeration* keywords = fPluralRules->getKeywords(ec); 1.294 + if (U_SUCCESS(ec)) { 1.295 + const char* pluralCount; 1.296 + while ((pluralCount = keywords->next(NULL, ec)) != NULL) { 1.297 + if ( U_SUCCESS(ec) ) { 1.298 + int32_t ptnLen; 1.299 + UErrorCode err = U_ZERO_ERROR; 1.300 + const UChar* patternChars = ures_getStringByKeyWithFallback( 1.301 + currencyRes, pluralCount, &ptnLen, &err); 1.302 + if (U_SUCCESS(err) && ptnLen > 0) { 1.303 + UnicodeString* pattern = new UnicodeString(patternChars, ptnLen); 1.304 +#ifdef CURRENCY_PLURAL_INFO_DEBUG 1.305 + char result_1[1000]; 1.306 + pattern->extract(0, pattern->length(), result_1, "UTF-8"); 1.307 + std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n"; 1.308 +#endif 1.309 + pattern->findAndReplace(UnicodeString(TRUE, gPart0, 3), 1.310 + UnicodeString(numberStylePattern, numberStylePatternLen)); 1.311 + pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3)); 1.312 + 1.313 + if (hasSeparator) { 1.314 + UnicodeString negPattern(patternChars, ptnLen); 1.315 + negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3), 1.316 + UnicodeString(negNumberStylePattern, negNumberStylePatternLen)); 1.317 + negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3)); 1.318 + pattern->append(gNumberPatternSeparator); 1.319 + pattern->append(negPattern); 1.320 + } 1.321 +#ifdef CURRENCY_PLURAL_INFO_DEBUG 1.322 + pattern->extract(0, pattern->length(), result_1, "UTF-8"); 1.323 + std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n"; 1.324 +#endif 1.325 + 1.326 + fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount, -1, US_INV), pattern, status); 1.327 + } 1.328 + } 1.329 + } 1.330 + } 1.331 + delete keywords; 1.332 + ures_close(currencyRes); 1.333 + ures_close(currRb); 1.334 +} 1.335 + 1.336 + 1.337 + 1.338 +void 1.339 +CurrencyPluralInfo::deleteHash(Hashtable* hTable) 1.340 +{ 1.341 + if ( hTable == NULL ) { 1.342 + return; 1.343 + } 1.344 + int32_t pos = -1; 1.345 + const UHashElement* element = NULL; 1.346 + while ( (element = hTable->nextElement(pos)) != NULL ) { 1.347 + const UHashTok valueTok = element->value; 1.348 + const UnicodeString* value = (UnicodeString*)valueTok.pointer; 1.349 + delete value; 1.350 + } 1.351 + delete hTable; 1.352 + hTable = NULL; 1.353 +} 1.354 + 1.355 + 1.356 +Hashtable* 1.357 +CurrencyPluralInfo::initHash(UErrorCode& status) { 1.358 + if ( U_FAILURE(status) ) { 1.359 + return NULL; 1.360 + } 1.361 + Hashtable* hTable; 1.362 + if ( (hTable = new Hashtable(TRUE, status)) == NULL ) { 1.363 + status = U_MEMORY_ALLOCATION_ERROR; 1.364 + return NULL; 1.365 + } 1.366 + if ( U_FAILURE(status) ) { 1.367 + delete hTable; 1.368 + return NULL; 1.369 + } 1.370 + hTable->setValueComparator(ValueComparator); 1.371 + return hTable; 1.372 +} 1.373 + 1.374 + 1.375 +void 1.376 +CurrencyPluralInfo::copyHash(const Hashtable* source, 1.377 + Hashtable* target, 1.378 + UErrorCode& status) { 1.379 + if ( U_FAILURE(status) ) { 1.380 + return; 1.381 + } 1.382 + int32_t pos = -1; 1.383 + const UHashElement* element = NULL; 1.384 + if ( source ) { 1.385 + while ( (element = source->nextElement(pos)) != NULL ) { 1.386 + const UHashTok keyTok = element->key; 1.387 + const UnicodeString* key = (UnicodeString*)keyTok.pointer; 1.388 + const UHashTok valueTok = element->value; 1.389 + const UnicodeString* value = (UnicodeString*)valueTok.pointer; 1.390 + UnicodeString* copy = new UnicodeString(*value); 1.391 + target->put(UnicodeString(*key), copy, status); 1.392 + if ( U_FAILURE(status) ) { 1.393 + return; 1.394 + } 1.395 + } 1.396 + } 1.397 +} 1.398 + 1.399 + 1.400 +U_NAMESPACE_END 1.401 + 1.402 +#endif