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