dcfmtsym.cpp (24476B)
1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /* 4 ******************************************************************************* 5 * Copyright (C) 1997-2016, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ******************************************************************************* 8 * 9 * File DCFMTSYM.CPP 10 * 11 * Modification History: 12 * 13 * Date Name Description 14 * 02/19/97 aliu Converted from java. 15 * 03/18/97 clhuang Implemented with C++ APIs. 16 * 03/27/97 helena Updated to pass the simple test after code review. 17 * 08/26/97 aliu Added currency/intl currency symbol support. 18 * 07/20/98 stephen Slightly modified initialization of monetarySeparator 19 ******************************************************************************** 20 */ 21 22 #include "unicode/utypes.h" 23 24 #if !UCONFIG_NO_FORMATTING 25 26 #include "unicode/dcfmtsym.h" 27 #include "unicode/ures.h" 28 #include "unicode/decimfmt.h" 29 #include "unicode/ucurr.h" 30 #include "unicode/choicfmt.h" 31 #include "unicode/unistr.h" 32 #include "unicode/numsys.h" 33 #include "unicode/unum.h" 34 #include "unicode/utf16.h" 35 #include "ucurrimp.h" 36 #include "cstring.h" 37 #include "locbased.h" 38 #include "uresimp.h" 39 #include "ureslocs.h" 40 #include "charstr.h" 41 #include "uassert.h" 42 43 // ***************************************************************************** 44 // class DecimalFormatSymbols 45 // ***************************************************************************** 46 47 U_NAMESPACE_BEGIN 48 49 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormatSymbols) 50 51 static const char gNumberElements[] = "NumberElements"; 52 static const char gCurrencySpacingTag[] = "currencySpacing"; 53 static const char gBeforeCurrencyTag[] = "beforeCurrency"; 54 static const char gAfterCurrencyTag[] = "afterCurrency"; 55 static const char gCurrencyMatchTag[] = "currencyMatch"; 56 static const char gCurrencySudMatchTag[] = "surroundingMatch"; 57 static const char gCurrencyInsertBtnTag[] = "insertBetween"; 58 static const char gLatn[] = "latn"; 59 static const char gSymbols[] = "symbols"; 60 static const char gNumberElementsLatnSymbols[] = "NumberElements/latn/symbols"; 61 62 static const char16_t INTL_CURRENCY_SYMBOL_STR[] = {0xa4, 0xa4, 0}; 63 64 // List of field names to be loaded from the data files. 65 // These are parallel with the enum ENumberFormatSymbol in unicode/dcfmtsym.h. 66 static const char *gNumberElementKeys[DecimalFormatSymbols::kFormatSymbolCount] = { 67 "decimal", 68 "group", 69 nullptr, /* #11897: the <list> symbol is NOT the pattern separator symbol */ 70 "percentSign", 71 nullptr, /* Native zero digit is deprecated from CLDR - get it from the numbering system */ 72 nullptr, /* Pattern digit character is deprecated from CLDR - use # by default always */ 73 "minusSign", 74 "plusSign", 75 nullptr, /* currency symbol - Wait until we know the currency before loading from CLDR */ 76 nullptr, /* intl currency symbol - Wait until we know the currency before loading from CLDR */ 77 "currencyDecimal", 78 "exponential", 79 "perMille", 80 nullptr, /* Escape padding character - not in CLDR */ 81 "infinity", 82 "nan", 83 nullptr, /* Significant digit symbol - not in CLDR */ 84 "currencyGroup", 85 nullptr, /* one digit - get it from the numbering system */ 86 nullptr, /* two digit - get it from the numbering system */ 87 nullptr, /* three digit - get it from the numbering system */ 88 nullptr, /* four digit - get it from the numbering system */ 89 nullptr, /* five digit - get it from the numbering system */ 90 nullptr, /* six digit - get it from the numbering system */ 91 nullptr, /* seven digit - get it from the numbering system */ 92 nullptr, /* eight digit - get it from the numbering system */ 93 nullptr, /* nine digit - get it from the numbering system */ 94 "superscriptingExponent", /* Multiplication (x) symbol for exponents */ 95 "approximatelySign" /* Approximately sign symbol */ 96 }; 97 98 // ------------------------------------- 99 // Initializes this with the decimal format symbols in the default locale. 100 101 DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status) 102 : UObject(), locale() { 103 initialize(locale, status, true); 104 } 105 106 // ------------------------------------- 107 // Initializes this with the decimal format symbols in the desired locale. 108 109 DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, UErrorCode& status) 110 : UObject(), locale(loc) { 111 initialize(locale, status); 112 } 113 114 DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, const NumberingSystem& ns, UErrorCode& status) 115 : UObject(), locale(loc) { 116 initialize(locale, status, false, &ns); 117 } 118 119 DecimalFormatSymbols::DecimalFormatSymbols() 120 : UObject(), 121 locale(Locale::getRoot()), 122 actualLocale(Locale::getRoot()), 123 validLocale(Locale::getRoot()) { 124 initialize(); 125 } 126 127 DecimalFormatSymbols* 128 DecimalFormatSymbols::createWithLastResortData(UErrorCode& status) { 129 if (U_FAILURE(status)) { return nullptr; } 130 DecimalFormatSymbols* sym = new DecimalFormatSymbols(); 131 if (sym == nullptr) { 132 status = U_MEMORY_ALLOCATION_ERROR; 133 } 134 return sym; 135 } 136 137 // ------------------------------------- 138 139 DecimalFormatSymbols::~DecimalFormatSymbols() 140 { 141 } 142 143 // ------------------------------------- 144 // copy constructor 145 146 DecimalFormatSymbols::DecimalFormatSymbols(const DecimalFormatSymbols &source) 147 : UObject(source) 148 { 149 *this = source; 150 } 151 152 // ------------------------------------- 153 // assignment operator 154 155 DecimalFormatSymbols& 156 DecimalFormatSymbols::operator=(const DecimalFormatSymbols& rhs) 157 { 158 if (this != &rhs) { 159 for (int32_t i = 0; i < static_cast<int32_t>(kFormatSymbolCount); ++i) { 160 // fastCopyFrom is safe, see docs on fSymbols 161 fSymbols[static_cast<ENumberFormatSymbol>(i)].fastCopyFrom(rhs.fSymbols[static_cast<ENumberFormatSymbol>(i)]); 162 } 163 for (int32_t i = 0; i < static_cast<int32_t>(UNUM_CURRENCY_SPACING_COUNT); ++i) { 164 currencySpcBeforeSym[i].fastCopyFrom(rhs.currencySpcBeforeSym[i]); 165 currencySpcAfterSym[i].fastCopyFrom(rhs.currencySpcAfterSym[i]); 166 } 167 locale = rhs.locale; 168 actualLocale = rhs.actualLocale; 169 validLocale = rhs.validLocale; 170 fIsCustomCurrencySymbol = rhs.fIsCustomCurrencySymbol; 171 fIsCustomIntlCurrencySymbol = rhs.fIsCustomIntlCurrencySymbol; 172 fCodePointZero = rhs.fCodePointZero; 173 currPattern = rhs.currPattern; 174 uprv_strcpy(nsName, rhs.nsName); 175 } 176 return *this; 177 } 178 179 // ------------------------------------- 180 181 bool 182 DecimalFormatSymbols::operator==(const DecimalFormatSymbols& that) const 183 { 184 if (this == &that) { 185 return true; 186 } 187 if (fIsCustomCurrencySymbol != that.fIsCustomCurrencySymbol) { 188 return false; 189 } 190 if (fIsCustomIntlCurrencySymbol != that.fIsCustomIntlCurrencySymbol) { 191 return false; 192 } 193 for (int32_t i = 0; i < static_cast<int32_t>(kFormatSymbolCount); ++i) { 194 if (fSymbols[static_cast<ENumberFormatSymbol>(i)] != that.fSymbols[static_cast<ENumberFormatSymbol>(i)]) { 195 return false; 196 } 197 } 198 for (int32_t i = 0; i < static_cast<int32_t>(UNUM_CURRENCY_SPACING_COUNT); ++i) { 199 if(currencySpcBeforeSym[i] != that.currencySpcBeforeSym[i]) { 200 return false; 201 } 202 if(currencySpcAfterSym[i] != that.currencySpcAfterSym[i]) { 203 return false; 204 } 205 } 206 // No need to check fCodePointZero since it is based on fSymbols 207 return locale == that.locale && 208 actualLocale == that.actualLocale && 209 validLocale == that.validLocale; 210 } 211 212 // ------------------------------------- 213 214 namespace { 215 216 /** 217 * Sink for enumerating all of the decimal format symbols (more specifically, anything 218 * under the "NumberElements.symbols" tree). 219 * 220 * More specific bundles (en_GB) are enumerated before their parents (en_001, en, root): 221 * Only store a value if it is still missing, that is, it has not been overridden. 222 */ 223 struct DecFmtSymDataSink : public ResourceSink { 224 225 // Destination for data, modified via setters. 226 DecimalFormatSymbols& dfs; 227 // Boolean array of whether or not we have seen a particular symbol yet. 228 // Can't simply check fSymbols because it is pre-populated with defaults. 229 UBool seenSymbol[DecimalFormatSymbols::kFormatSymbolCount]; 230 231 // Constructor/Destructor 232 DecFmtSymDataSink(DecimalFormatSymbols& _dfs) : dfs(_dfs) { 233 uprv_memset(seenSymbol, false, sizeof(seenSymbol)); 234 } 235 virtual ~DecFmtSymDataSink(); 236 237 virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/, 238 UErrorCode &errorCode) override { 239 ResourceTable symbolsTable = value.getTable(errorCode); 240 if (U_FAILURE(errorCode)) { return; } 241 for (int32_t j = 0; symbolsTable.getKeyAndValue(j, key, value); ++j) { 242 for (int32_t i=0; i<DecimalFormatSymbols::kFormatSymbolCount; i++) { 243 if (gNumberElementKeys[i] != nullptr && uprv_strcmp(key, gNumberElementKeys[i]) == 0) { 244 if (!seenSymbol[i]) { 245 seenSymbol[i] = true; 246 dfs.setSymbol( 247 static_cast<DecimalFormatSymbols::ENumberFormatSymbol>(i), 248 value.getUnicodeString(errorCode)); 249 if (U_FAILURE(errorCode)) { return; } 250 } 251 break; 252 } 253 } 254 } 255 } 256 257 // Returns true if all the symbols have been seen. 258 UBool seenAll() { 259 for (int32_t i=0; i<DecimalFormatSymbols::kFormatSymbolCount; i++) { 260 if (!seenSymbol[i]) { 261 return false; 262 } 263 } 264 return true; 265 } 266 267 // If monetary decimal or grouping were not explicitly set, then set them to be the 268 // same as their non-monetary counterparts. 269 void resolveMissingMonetarySeparators(const UnicodeString* fSymbols) { 270 if (!seenSymbol[DecimalFormatSymbols::kMonetarySeparatorSymbol]) { 271 dfs.setSymbol( 272 DecimalFormatSymbols::kMonetarySeparatorSymbol, 273 fSymbols[DecimalFormatSymbols::kDecimalSeparatorSymbol]); 274 } 275 if (!seenSymbol[DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol]) { 276 dfs.setSymbol( 277 DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, 278 fSymbols[DecimalFormatSymbols::kGroupingSeparatorSymbol]); 279 } 280 } 281 }; 282 283 struct CurrencySpacingSink : public ResourceSink { 284 DecimalFormatSymbols& dfs; 285 UBool hasBeforeCurrency; 286 UBool hasAfterCurrency; 287 288 CurrencySpacingSink(DecimalFormatSymbols& _dfs) 289 : dfs(_dfs), hasBeforeCurrency(false), hasAfterCurrency(false) {} 290 virtual ~CurrencySpacingSink(); 291 292 virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/, 293 UErrorCode &errorCode) override { 294 ResourceTable spacingTypesTable = value.getTable(errorCode); 295 for (int32_t i = 0; spacingTypesTable.getKeyAndValue(i, key, value); ++i) { 296 UBool beforeCurrency; 297 if (uprv_strcmp(key, gBeforeCurrencyTag) == 0) { 298 beforeCurrency = true; 299 hasBeforeCurrency = true; 300 } else if (uprv_strcmp(key, gAfterCurrencyTag) == 0) { 301 beforeCurrency = false; 302 hasAfterCurrency = true; 303 } else { 304 continue; 305 } 306 307 ResourceTable patternsTable = value.getTable(errorCode); 308 for (int32_t j = 0; patternsTable.getKeyAndValue(j, key, value); ++j) { 309 UCurrencySpacing pattern; 310 if (uprv_strcmp(key, gCurrencyMatchTag) == 0) { 311 pattern = UNUM_CURRENCY_MATCH; 312 } else if (uprv_strcmp(key, gCurrencySudMatchTag) == 0) { 313 pattern = UNUM_CURRENCY_SURROUNDING_MATCH; 314 } else if (uprv_strcmp(key, gCurrencyInsertBtnTag) == 0) { 315 pattern = UNUM_CURRENCY_INSERT; 316 } else { 317 continue; 318 } 319 320 const UnicodeString& current = dfs.getPatternForCurrencySpacing( 321 pattern, beforeCurrency, errorCode); 322 if (current.isEmpty()) { 323 dfs.setPatternForCurrencySpacing( 324 pattern, beforeCurrency, value.getUnicodeString(errorCode)); 325 } 326 } 327 } 328 } 329 330 void resolveMissing() { 331 // For consistency with Java, this method overwrites everything with the defaults unless 332 // both beforeCurrency and afterCurrency were found in CLDR. 333 static const char* defaults[] = { "[:letter:]", "[:digit:]", " " }; 334 if (!hasBeforeCurrency || !hasAfterCurrency) { 335 for (int32_t pattern = 0; pattern < UNUM_CURRENCY_SPACING_COUNT; pattern++) { 336 dfs.setPatternForCurrencySpacing(static_cast<UCurrencySpacing>(pattern), 337 false, UnicodeString(defaults[pattern], -1, US_INV)); 338 } 339 for (int32_t pattern = 0; pattern < UNUM_CURRENCY_SPACING_COUNT; pattern++) { 340 dfs.setPatternForCurrencySpacing(static_cast<UCurrencySpacing>(pattern), 341 true, UnicodeString(defaults[pattern], -1, US_INV)); 342 } 343 } 344 } 345 }; 346 347 // Virtual destructors must be defined out of line. 348 DecFmtSymDataSink::~DecFmtSymDataSink() {} 349 CurrencySpacingSink::~CurrencySpacingSink() {} 350 351 } // namespace 352 353 void 354 DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status, 355 UBool useLastResortData, const NumberingSystem* ns) 356 { 357 if (U_FAILURE(status)) { return; } 358 359 // First initialize all the symbols to the fallbacks for anything we can't find 360 initialize(); 361 362 // 363 // Next get the numbering system for this locale and set zero digit 364 // and the digit string based on the numbering system for the locale 365 // 366 LocalPointer<NumberingSystem> nsLocal; 367 if (ns == nullptr) { 368 // Use the numbering system according to the locale. 369 // Save it into a LocalPointer so it gets cleaned up. 370 nsLocal.adoptInstead(NumberingSystem::createInstance(loc, status)); 371 ns = nsLocal.getAlias(); 372 } 373 const char *nsName; 374 if (U_SUCCESS(status) && ns->getRadix() == 10 && !ns->isAlgorithmic()) { 375 nsName = ns->getName(); 376 UnicodeString digitString(ns->getDescription()); 377 int32_t digitIndex = 0; 378 UChar32 digit = digitString.char32At(0); 379 fSymbols[kZeroDigitSymbol].setTo(digit); 380 for (int32_t i = kOneDigitSymbol; i <= kNineDigitSymbol; ++i) { 381 digitIndex += U16_LENGTH(digit); 382 digit = digitString.char32At(digitIndex); 383 fSymbols[i].setTo(digit); 384 } 385 } else { 386 nsName = gLatn; 387 } 388 uprv_strcpy(this->nsName, nsName); 389 390 // Open resource bundles 391 const char* locStr = loc.getName(); 392 LocalUResourceBundlePointer resource(ures_open(nullptr, locStr, &status)); 393 LocalUResourceBundlePointer numberElementsRes( 394 ures_getByKeyWithFallback(resource.getAlias(), gNumberElements, nullptr, &status)); 395 396 if (U_FAILURE(status)) { 397 if ( useLastResortData ) { 398 status = U_USING_DEFAULT_WARNING; 399 initialize(); 400 } 401 return; 402 } 403 404 // Set locale IDs 405 // TODO: Is there a way to do this without depending on the resource bundle instance? 406 actualLocale = Locale( 407 ures_getLocaleByType(numberElementsRes.getAlias(), ULOC_ACTUAL_LOCALE, &status)); 408 validLocale = Locale( 409 ures_getLocaleByType(numberElementsRes.getAlias(), ULOC_VALID_LOCALE, &status)); 410 411 // Now load the rest of the data from the data sink. 412 // Start with loading this nsName if it is not Latin. 413 DecFmtSymDataSink sink(*this); 414 if (uprv_strcmp(nsName, gLatn) != 0) { 415 CharString path; 416 path.append(gNumberElements, status) 417 .append('/', status) 418 .append(nsName, status) 419 .append('/', status) 420 .append(gSymbols, status); 421 ures_getAllItemsWithFallback(resource.getAlias(), path.data(), sink, status); 422 423 // If no symbols exist for the given nsName and resource bundle, silently ignore 424 // and fall back to Latin. 425 if (status == U_MISSING_RESOURCE_ERROR) { 426 status = U_ZERO_ERROR; 427 } else if (U_FAILURE(status)) { 428 return; 429 } 430 } 431 432 // Continue with Latin if necessary. 433 if (!sink.seenAll()) { 434 ures_getAllItemsWithFallback(resource.getAlias(), gNumberElementsLatnSymbols, sink, status); 435 if (U_FAILURE(status)) { return; } 436 } 437 438 // Let the monetary number separators equal the default number separators if necessary. 439 sink.resolveMissingMonetarySeparators(fSymbols); 440 441 // Resolve codePointZero 442 UChar32 tempCodePointZero = -1; 443 for (int32_t i=0; i<=9; i++) { 444 const UnicodeString& stringDigit = getConstDigitSymbol(i); 445 if (stringDigit.countChar32() != 1) { 446 tempCodePointZero = -1; 447 break; 448 } 449 UChar32 cp = stringDigit.char32At(0); 450 if (i == 0) { 451 tempCodePointZero = cp; 452 } else if (cp != tempCodePointZero + i) { 453 tempCodePointZero = -1; 454 break; 455 } 456 } 457 fCodePointZero = tempCodePointZero; 458 459 // Get the default currency from the currency API. 460 UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out 461 char16_t curriso[4]; 462 UnicodeString tempStr; 463 int32_t currisoLength = ucurr_forLocale(locStr, curriso, UPRV_LENGTHOF(curriso), &internalStatus); 464 if (U_SUCCESS(internalStatus) && currisoLength == 3) { 465 setCurrency(curriso, status); 466 } else { 467 setCurrency(nullptr, status); 468 } 469 470 // Currency Spacing. 471 LocalUResourceBundlePointer currencyResource(ures_open(U_ICUDATA_CURR, locStr, &status)); 472 CurrencySpacingSink currencySink(*this); 473 ures_getAllItemsWithFallback(currencyResource.getAlias(), gCurrencySpacingTag, currencySink, status); 474 currencySink.resolveMissing(); 475 if (U_FAILURE(status)) { return; } 476 } 477 478 void 479 DecimalFormatSymbols::initialize() { 480 /* 481 * These strings used to be in static arrays, but the HP/UX aCC compiler 482 * cannot initialize a static array with class constructors. 483 * markus 2000may25 484 */ 485 fSymbols[kDecimalSeparatorSymbol] = static_cast<char16_t>(0x2e); // '.' decimal separator 486 fSymbols[kGroupingSeparatorSymbol].remove(); // group (thousands) separator 487 fSymbols[kPatternSeparatorSymbol] = static_cast<char16_t>(0x3b); // ';' pattern separator 488 fSymbols[kPercentSymbol] = static_cast<char16_t>(0x25); // '%' percent sign 489 fSymbols[kZeroDigitSymbol] = static_cast<char16_t>(0x30); // '0' native 0 digit 490 fSymbols[kOneDigitSymbol] = static_cast<char16_t>(0x31); // '1' native 1 digit 491 fSymbols[kTwoDigitSymbol] = static_cast<char16_t>(0x32); // '2' native 2 digit 492 fSymbols[kThreeDigitSymbol] = static_cast<char16_t>(0x33); // '3' native 3 digit 493 fSymbols[kFourDigitSymbol] = static_cast<char16_t>(0x34); // '4' native 4 digit 494 fSymbols[kFiveDigitSymbol] = static_cast<char16_t>(0x35); // '5' native 5 digit 495 fSymbols[kSixDigitSymbol] = static_cast<char16_t>(0x36); // '6' native 6 digit 496 fSymbols[kSevenDigitSymbol] = static_cast<char16_t>(0x37); // '7' native 7 digit 497 fSymbols[kEightDigitSymbol] = static_cast<char16_t>(0x38); // '8' native 8 digit 498 fSymbols[kNineDigitSymbol] = static_cast<char16_t>(0x39); // '9' native 9 digit 499 fSymbols[kDigitSymbol] = static_cast<char16_t>(0x23); // '#' pattern digit 500 fSymbols[kPlusSignSymbol] = static_cast<char16_t>(0x002b); // '+' plus sign 501 fSymbols[kMinusSignSymbol] = static_cast<char16_t>(0x2d); // '-' minus sign 502 fSymbols[kCurrencySymbol] = static_cast<char16_t>(0xa4); // 'OX' currency symbol 503 fSymbols[kIntlCurrencySymbol].setTo(true, INTL_CURRENCY_SYMBOL_STR, 2); 504 fSymbols[kMonetarySeparatorSymbol] = static_cast<char16_t>(0x2e); // '.' monetary decimal separator 505 fSymbols[kExponentialSymbol] = static_cast<char16_t>(0x45); // 'E' exponential 506 fSymbols[kPerMillSymbol] = static_cast<char16_t>(0x2030); // '%o' per mill 507 fSymbols[kPadEscapeSymbol] = static_cast<char16_t>(0x2a); // '*' pad escape symbol 508 fSymbols[kInfinitySymbol] = static_cast<char16_t>(0x221e); // 'oo' infinite 509 fSymbols[kNaNSymbol] = static_cast<char16_t>(0xfffd); // SUB NaN 510 fSymbols[kSignificantDigitSymbol] = static_cast<char16_t>(0x0040); // '@' significant digit 511 fSymbols[kMonetaryGroupingSeparatorSymbol].remove(); // 512 fSymbols[kExponentMultiplicationSymbol] = static_cast<char16_t>(0xd7); // 'x' multiplication symbol for exponents 513 fSymbols[kApproximatelySignSymbol] = u'~'; // '~' approximately sign 514 fIsCustomCurrencySymbol = false; 515 fIsCustomIntlCurrencySymbol = false; 516 fCodePointZero = 0x30; 517 U_ASSERT(fCodePointZero == fSymbols[kZeroDigitSymbol].char32At(0)); 518 currPattern = nullptr; 519 nsName[0] = 0; 520 } 521 522 void DecimalFormatSymbols::setCurrency(const char16_t* currency, UErrorCode& status) { 523 // TODO: If this method is made public: 524 // - Adopt ICU4J behavior of not allowing currency to be null. 525 // - Also verify that the length of currency is 3. 526 if (!currency) { 527 return; 528 } 529 530 UnicodeString tempStr; 531 uprv_getStaticCurrencyName(currency, locale.getName(), tempStr, status); 532 if (U_SUCCESS(status)) { 533 fSymbols[kIntlCurrencySymbol].setTo(currency, 3); 534 fSymbols[kCurrencySymbol] = tempStr; 535 } 536 537 char cc[4]={0}; 538 u_UCharsToChars(currency, cc, 3); 539 540 /* An explicit currency was requested */ 541 // TODO(ICU-13297): Move this data loading logic into a centralized place 542 UErrorCode localStatus = U_ZERO_ERROR; 543 LocalUResourceBundlePointer rbTop(ures_open(U_ICUDATA_CURR, locale.getName(), &localStatus)); 544 LocalUResourceBundlePointer rb( 545 ures_getByKeyWithFallback(rbTop.getAlias(), "Currencies", nullptr, &localStatus)); 546 ures_getByKeyWithFallback(rb.getAlias(), cc, rb.getAlias(), &localStatus); 547 if(U_SUCCESS(localStatus) && ures_getSize(rb.getAlias())>2) { // the length is 3 if more data is present 548 ures_getByIndex(rb.getAlias(), 2, rb.getAlias(), &localStatus); 549 int32_t currPatternLen = 0; 550 currPattern = 551 ures_getStringByIndex(rb.getAlias(), static_cast<int32_t>(0), &currPatternLen, &localStatus); 552 UnicodeString decimalSep = 553 ures_getUnicodeStringByIndex(rb.getAlias(), static_cast<int32_t>(1), &localStatus); 554 UnicodeString groupingSep = 555 ures_getUnicodeStringByIndex(rb.getAlias(), static_cast<int32_t>(2), &localStatus); 556 if(U_SUCCESS(localStatus)){ 557 fSymbols[kMonetaryGroupingSeparatorSymbol] = groupingSep; 558 fSymbols[kMonetarySeparatorSymbol] = decimalSep; 559 //pattern.setTo(true, currPattern, currPatternLen); 560 } 561 } 562 /* else An explicit currency was requested and is unknown or locale data is malformed. */ 563 /* ucurr_* API will get the correct value later on. */ 564 } 565 566 Locale 567 DecimalFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const { 568 return LocaleBased::getLocale(validLocale, actualLocale, type, status); 569 } 570 571 const UnicodeString& 572 DecimalFormatSymbols::getPatternForCurrencySpacing(UCurrencySpacing type, 573 UBool beforeCurrency, 574 UErrorCode& status) const { 575 if (U_FAILURE(status)) { 576 return fNoSymbol; // always empty. 577 } 578 if (beforeCurrency) { 579 return currencySpcBeforeSym[static_cast<int32_t>(type)]; 580 } else { 581 return currencySpcAfterSym[static_cast<int32_t>(type)]; 582 } 583 } 584 585 void 586 DecimalFormatSymbols::setPatternForCurrencySpacing(UCurrencySpacing type, 587 UBool beforeCurrency, 588 const UnicodeString& pattern) { 589 if (beforeCurrency) { 590 currencySpcBeforeSym[static_cast<int32_t>(type)] = pattern; 591 } else { 592 currencySpcAfterSym[static_cast<int32_t>(type)] = pattern; 593 } 594 } 595 U_NAMESPACE_END 596 597 #endif /* #if !UCONFIG_NO_FORMATTING */ 598 599 //eof