intl/icu/source/i18n/currpinf.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

michael@0 1 /*
michael@0 2 *******************************************************************************
michael@0 3 * Copyright (C) 2009-2011, International Business Machines Corporation and
michael@0 4 * others. All Rights Reserved.
michael@0 5 *******************************************************************************
michael@0 6 */
michael@0 7
michael@0 8 #include "unicode/currpinf.h"
michael@0 9
michael@0 10 #if !UCONFIG_NO_FORMATTING
michael@0 11
michael@0 12 //#define CURRENCY_PLURAL_INFO_DEBUG 1
michael@0 13
michael@0 14 #ifdef CURRENCY_PLURAL_INFO_DEBUG
michael@0 15 #include <iostream>
michael@0 16 #endif
michael@0 17
michael@0 18
michael@0 19 #include "unicode/locid.h"
michael@0 20 #include "unicode/plurrule.h"
michael@0 21 #include "unicode/ures.h"
michael@0 22 #include "unicode/numsys.h"
michael@0 23 #include "cstring.h"
michael@0 24 #include "hash.h"
michael@0 25 #include "uresimp.h"
michael@0 26 #include "ureslocs.h"
michael@0 27
michael@0 28 U_NAMESPACE_BEGIN
michael@0 29
michael@0 30
michael@0 31 static const UChar gNumberPatternSeparator = 0x3B; // ;
michael@0 32
michael@0 33 U_CDECL_BEGIN
michael@0 34
michael@0 35 /**
michael@0 36 * @internal ICU 4.2
michael@0 37 */
michael@0 38 static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2);
michael@0 39
michael@0 40 UBool
michael@0 41 U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2) {
michael@0 42 const UnicodeString* affix_1 = (UnicodeString*)val1.pointer;
michael@0 43 const UnicodeString* affix_2 = (UnicodeString*)val2.pointer;
michael@0 44 return *affix_1 == *affix_2;
michael@0 45 }
michael@0 46
michael@0 47 U_CDECL_END
michael@0 48
michael@0 49
michael@0 50 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo)
michael@0 51
michael@0 52 static const UChar gDefaultCurrencyPluralPattern[] = {'0', '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4, 0};
michael@0 53 static const UChar gTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
michael@0 54 static const UChar gPluralCountOther[] = {0x6F, 0x74, 0x68, 0x65, 0x72, 0};
michael@0 55 static const UChar gPart0[] = {0x7B, 0x30, 0x7D, 0};
michael@0 56 static const UChar gPart1[] = {0x7B, 0x31, 0x7D, 0};
michael@0 57
michael@0 58 static const char gNumberElementsTag[]="NumberElements";
michael@0 59 static const char gLatnTag[]="latn";
michael@0 60 static const char gPatternsTag[]="patterns";
michael@0 61 static const char gDecimalFormatTag[]="decimalFormat";
michael@0 62 static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns";
michael@0 63
michael@0 64 CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status)
michael@0 65 : fPluralCountToCurrencyUnitPattern(NULL),
michael@0 66 fPluralRules(NULL),
michael@0 67 fLocale(NULL) {
michael@0 68 initialize(Locale::getDefault(), status);
michael@0 69 }
michael@0 70
michael@0 71 CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status)
michael@0 72 : fPluralCountToCurrencyUnitPattern(NULL),
michael@0 73 fPluralRules(NULL),
michael@0 74 fLocale(NULL) {
michael@0 75 initialize(locale, status);
michael@0 76 }
michael@0 77
michael@0 78 CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info)
michael@0 79 : UObject(info),
michael@0 80 fPluralCountToCurrencyUnitPattern(NULL),
michael@0 81 fPluralRules(NULL),
michael@0 82 fLocale(NULL) {
michael@0 83 *this = info;
michael@0 84 }
michael@0 85
michael@0 86
michael@0 87 CurrencyPluralInfo&
michael@0 88 CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) {
michael@0 89 if (this == &info) {
michael@0 90 return *this;
michael@0 91 }
michael@0 92
michael@0 93 deleteHash(fPluralCountToCurrencyUnitPattern);
michael@0 94 UErrorCode status = U_ZERO_ERROR;
michael@0 95 fPluralCountToCurrencyUnitPattern = initHash(status);
michael@0 96 copyHash(info.fPluralCountToCurrencyUnitPattern,
michael@0 97 fPluralCountToCurrencyUnitPattern, status);
michael@0 98 if ( U_FAILURE(status) ) {
michael@0 99 return *this;
michael@0 100 }
michael@0 101
michael@0 102 delete fPluralRules;
michael@0 103 delete fLocale;
michael@0 104 if (info.fPluralRules) {
michael@0 105 fPluralRules = info.fPluralRules->clone();
michael@0 106 } else {
michael@0 107 fPluralRules = NULL;
michael@0 108 }
michael@0 109 if (info.fLocale) {
michael@0 110 fLocale = info.fLocale->clone();
michael@0 111 } else {
michael@0 112 fLocale = NULL;
michael@0 113 }
michael@0 114 return *this;
michael@0 115 }
michael@0 116
michael@0 117
michael@0 118 CurrencyPluralInfo::~CurrencyPluralInfo() {
michael@0 119 deleteHash(fPluralCountToCurrencyUnitPattern);
michael@0 120 fPluralCountToCurrencyUnitPattern = NULL;
michael@0 121 delete fPluralRules;
michael@0 122 delete fLocale;
michael@0 123 fPluralRules = NULL;
michael@0 124 fLocale = NULL;
michael@0 125 }
michael@0 126
michael@0 127 UBool
michael@0 128 CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const {
michael@0 129 #ifdef CURRENCY_PLURAL_INFO_DEBUG
michael@0 130 if (*fPluralRules == *info.fPluralRules) {
michael@0 131 std::cout << "same plural rules\n";
michael@0 132 }
michael@0 133 if (*fLocale == *info.fLocale) {
michael@0 134 std::cout << "same locale\n";
michael@0 135 }
michael@0 136 if (fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern)) {
michael@0 137 std::cout << "same pattern\n";
michael@0 138 }
michael@0 139 #endif
michael@0 140 return *fPluralRules == *info.fPluralRules &&
michael@0 141 *fLocale == *info.fLocale &&
michael@0 142 fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern);
michael@0 143 }
michael@0 144
michael@0 145
michael@0 146 CurrencyPluralInfo*
michael@0 147 CurrencyPluralInfo::clone() const {
michael@0 148 return new CurrencyPluralInfo(*this);
michael@0 149 }
michael@0 150
michael@0 151 const PluralRules*
michael@0 152 CurrencyPluralInfo::getPluralRules() const {
michael@0 153 return fPluralRules;
michael@0 154 }
michael@0 155
michael@0 156 UnicodeString&
michael@0 157 CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString& pluralCount,
michael@0 158 UnicodeString& result) const {
michael@0 159 const UnicodeString* currencyPluralPattern =
michael@0 160 (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount);
michael@0 161 if (currencyPluralPattern == NULL) {
michael@0 162 // fall back to "other"
michael@0 163 if (pluralCount.compare(gPluralCountOther, 5)) {
michael@0 164 currencyPluralPattern =
michael@0 165 (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(UnicodeString(TRUE, gPluralCountOther, 5));
michael@0 166 }
michael@0 167 if (currencyPluralPattern == NULL) {
michael@0 168 // no currencyUnitPatterns defined,
michael@0 169 // fallback to predefined defult.
michael@0 170 // This should never happen when ICU resource files are
michael@0 171 // available, since currencyUnitPattern of "other" is always
michael@0 172 // defined in root.
michael@0 173 result = UnicodeString(gDefaultCurrencyPluralPattern);
michael@0 174 return result;
michael@0 175 }
michael@0 176 }
michael@0 177 result = *currencyPluralPattern;
michael@0 178 return result;
michael@0 179 }
michael@0 180
michael@0 181 const Locale&
michael@0 182 CurrencyPluralInfo::getLocale() const {
michael@0 183 return *fLocale;
michael@0 184 }
michael@0 185
michael@0 186 void
michael@0 187 CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription,
michael@0 188 UErrorCode& status) {
michael@0 189 if (U_SUCCESS(status)) {
michael@0 190 if (fPluralRules) {
michael@0 191 delete fPluralRules;
michael@0 192 }
michael@0 193 fPluralRules = PluralRules::createRules(ruleDescription, status);
michael@0 194 }
michael@0 195 }
michael@0 196
michael@0 197
michael@0 198 void
michael@0 199 CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount,
michael@0 200 const UnicodeString& pattern,
michael@0 201 UErrorCode& status) {
michael@0 202 if (U_SUCCESS(status)) {
michael@0 203 fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status);
michael@0 204 }
michael@0 205 }
michael@0 206
michael@0 207
michael@0 208 void
michael@0 209 CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) {
michael@0 210 initialize(loc, status);
michael@0 211 }
michael@0 212
michael@0 213
michael@0 214 void
michael@0 215 CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) {
michael@0 216 if (U_FAILURE(status)) {
michael@0 217 return;
michael@0 218 }
michael@0 219 delete fLocale;
michael@0 220 fLocale = loc.clone();
michael@0 221 if (fPluralRules) {
michael@0 222 delete fPluralRules;
michael@0 223 }
michael@0 224 fPluralRules = PluralRules::forLocale(loc, status);
michael@0 225 setupCurrencyPluralPattern(loc, status);
michael@0 226 }
michael@0 227
michael@0 228
michael@0 229 void
michael@0 230 CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) {
michael@0 231 if (U_FAILURE(status)) {
michael@0 232 return;
michael@0 233 }
michael@0 234
michael@0 235 if (fPluralCountToCurrencyUnitPattern) {
michael@0 236 deleteHash(fPluralCountToCurrencyUnitPattern);
michael@0 237 }
michael@0 238 fPluralCountToCurrencyUnitPattern = initHash(status);
michael@0 239 if (U_FAILURE(status)) {
michael@0 240 return;
michael@0 241 }
michael@0 242
michael@0 243 NumberingSystem *ns = NumberingSystem::createInstance(loc,status);
michael@0 244 UErrorCode ec = U_ZERO_ERROR;
michael@0 245 UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec);
michael@0 246 UResourceBundle *numElements = ures_getByKeyWithFallback(rb, gNumberElementsTag, NULL, &ec);
michael@0 247 rb = ures_getByKeyWithFallback(numElements, ns->getName(), rb, &ec);
michael@0 248 rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec);
michael@0 249 int32_t ptnLen;
michael@0 250 const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec);
michael@0 251 // Fall back to "latn" if num sys specific pattern isn't there.
michael@0 252 if ( ec == U_MISSING_RESOURCE_ERROR && uprv_strcmp(ns->getName(),gLatnTag)) {
michael@0 253 ec = U_ZERO_ERROR;
michael@0 254 rb = ures_getByKeyWithFallback(numElements, gLatnTag, rb, &ec);
michael@0 255 rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec);
michael@0 256 numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec);
michael@0 257 }
michael@0 258 int32_t numberStylePatternLen = ptnLen;
michael@0 259 const UChar* negNumberStylePattern = NULL;
michael@0 260 int32_t negNumberStylePatternLen = 0;
michael@0 261 // TODO: Java
michael@0 262 // parse to check whether there is ";" separator in the numberStylePattern
michael@0 263 UBool hasSeparator = false;
michael@0 264 if (U_SUCCESS(ec)) {
michael@0 265 for (int32_t styleCharIndex = 0; styleCharIndex < ptnLen; ++styleCharIndex) {
michael@0 266 if (numberStylePattern[styleCharIndex] == gNumberPatternSeparator) {
michael@0 267 hasSeparator = true;
michael@0 268 // split the number style pattern into positive and negative
michael@0 269 negNumberStylePattern = numberStylePattern + styleCharIndex + 1;
michael@0 270 negNumberStylePatternLen = ptnLen - styleCharIndex - 1;
michael@0 271 numberStylePatternLen = styleCharIndex;
michael@0 272 }
michael@0 273 }
michael@0 274 }
michael@0 275
michael@0 276 ures_close(numElements);
michael@0 277 ures_close(rb);
michael@0 278 delete ns;
michael@0 279
michael@0 280 if (U_FAILURE(ec)) {
michael@0 281 return;
michael@0 282 }
michael@0 283
michael@0 284 UResourceBundle *currRb = ures_open(U_ICUDATA_CURR, loc.getName(), &ec);
michael@0 285 UResourceBundle *currencyRes = ures_getByKeyWithFallback(currRb, gCurrUnitPtnTag, NULL, &ec);
michael@0 286
michael@0 287 #ifdef CURRENCY_PLURAL_INFO_DEBUG
michael@0 288 std::cout << "in set up\n";
michael@0 289 #endif
michael@0 290 StringEnumeration* keywords = fPluralRules->getKeywords(ec);
michael@0 291 if (U_SUCCESS(ec)) {
michael@0 292 const char* pluralCount;
michael@0 293 while ((pluralCount = keywords->next(NULL, ec)) != NULL) {
michael@0 294 if ( U_SUCCESS(ec) ) {
michael@0 295 int32_t ptnLen;
michael@0 296 UErrorCode err = U_ZERO_ERROR;
michael@0 297 const UChar* patternChars = ures_getStringByKeyWithFallback(
michael@0 298 currencyRes, pluralCount, &ptnLen, &err);
michael@0 299 if (U_SUCCESS(err) && ptnLen > 0) {
michael@0 300 UnicodeString* pattern = new UnicodeString(patternChars, ptnLen);
michael@0 301 #ifdef CURRENCY_PLURAL_INFO_DEBUG
michael@0 302 char result_1[1000];
michael@0 303 pattern->extract(0, pattern->length(), result_1, "UTF-8");
michael@0 304 std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
michael@0 305 #endif
michael@0 306 pattern->findAndReplace(UnicodeString(TRUE, gPart0, 3),
michael@0 307 UnicodeString(numberStylePattern, numberStylePatternLen));
michael@0 308 pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
michael@0 309
michael@0 310 if (hasSeparator) {
michael@0 311 UnicodeString negPattern(patternChars, ptnLen);
michael@0 312 negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3),
michael@0 313 UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
michael@0 314 negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
michael@0 315 pattern->append(gNumberPatternSeparator);
michael@0 316 pattern->append(negPattern);
michael@0 317 }
michael@0 318 #ifdef CURRENCY_PLURAL_INFO_DEBUG
michael@0 319 pattern->extract(0, pattern->length(), result_1, "UTF-8");
michael@0 320 std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n";
michael@0 321 #endif
michael@0 322
michael@0 323 fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount, -1, US_INV), pattern, status);
michael@0 324 }
michael@0 325 }
michael@0 326 }
michael@0 327 }
michael@0 328 delete keywords;
michael@0 329 ures_close(currencyRes);
michael@0 330 ures_close(currRb);
michael@0 331 }
michael@0 332
michael@0 333
michael@0 334
michael@0 335 void
michael@0 336 CurrencyPluralInfo::deleteHash(Hashtable* hTable)
michael@0 337 {
michael@0 338 if ( hTable == NULL ) {
michael@0 339 return;
michael@0 340 }
michael@0 341 int32_t pos = -1;
michael@0 342 const UHashElement* element = NULL;
michael@0 343 while ( (element = hTable->nextElement(pos)) != NULL ) {
michael@0 344 const UHashTok valueTok = element->value;
michael@0 345 const UnicodeString* value = (UnicodeString*)valueTok.pointer;
michael@0 346 delete value;
michael@0 347 }
michael@0 348 delete hTable;
michael@0 349 hTable = NULL;
michael@0 350 }
michael@0 351
michael@0 352
michael@0 353 Hashtable*
michael@0 354 CurrencyPluralInfo::initHash(UErrorCode& status) {
michael@0 355 if ( U_FAILURE(status) ) {
michael@0 356 return NULL;
michael@0 357 }
michael@0 358 Hashtable* hTable;
michael@0 359 if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
michael@0 360 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 361 return NULL;
michael@0 362 }
michael@0 363 if ( U_FAILURE(status) ) {
michael@0 364 delete hTable;
michael@0 365 return NULL;
michael@0 366 }
michael@0 367 hTable->setValueComparator(ValueComparator);
michael@0 368 return hTable;
michael@0 369 }
michael@0 370
michael@0 371
michael@0 372 void
michael@0 373 CurrencyPluralInfo::copyHash(const Hashtable* source,
michael@0 374 Hashtable* target,
michael@0 375 UErrorCode& status) {
michael@0 376 if ( U_FAILURE(status) ) {
michael@0 377 return;
michael@0 378 }
michael@0 379 int32_t pos = -1;
michael@0 380 const UHashElement* element = NULL;
michael@0 381 if ( source ) {
michael@0 382 while ( (element = source->nextElement(pos)) != NULL ) {
michael@0 383 const UHashTok keyTok = element->key;
michael@0 384 const UnicodeString* key = (UnicodeString*)keyTok.pointer;
michael@0 385 const UHashTok valueTok = element->value;
michael@0 386 const UnicodeString* value = (UnicodeString*)valueTok.pointer;
michael@0 387 UnicodeString* copy = new UnicodeString(*value);
michael@0 388 target->put(UnicodeString(*key), copy, status);
michael@0 389 if ( U_FAILURE(status) ) {
michael@0 390 return;
michael@0 391 }
michael@0 392 }
michael@0 393 }
michael@0 394 }
michael@0 395
michael@0 396
michael@0 397 U_NAMESPACE_END
michael@0 398
michael@0 399 #endif

mercurial