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