1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #include "unicode/utypes.h"
5 
6 #if !UCONFIG_NO_FORMATTING
7 
8 // Allow implicit conversion from char16_t* to UnicodeString for this file:
9 // Helpful in toString methods and elsewhere.
10 #define UNISTR_FROM_STRING_EXPLICIT
11 
12 #include "numparse_types.h"
13 #include "number_currencysymbols.h"
14 
15 using namespace icu;
16 using namespace icu::number;
17 using namespace icu::number::impl;
18 
19 
CurrencySymbols(CurrencyUnit currency,const Locale & locale,UErrorCode & status)20 CurrencySymbols::CurrencySymbols(CurrencyUnit currency, const Locale& locale, UErrorCode& status)
21         : fCurrency(currency), fLocaleName(locale.getName(), status) {
22     fCurrencySymbol.setToBogus();
23     fIntlCurrencySymbol.setToBogus();
24 }
25 
CurrencySymbols(CurrencyUnit currency,const Locale & locale,const DecimalFormatSymbols & symbols,UErrorCode & status)26 CurrencySymbols::CurrencySymbols(CurrencyUnit currency, const Locale& locale,
27                                  const DecimalFormatSymbols& symbols, UErrorCode& status)
28         : CurrencySymbols(currency, locale, status) {
29     // If either of the overrides is present, save it in the local UnicodeString.
30     if (symbols.isCustomCurrencySymbol()) {
31         fCurrencySymbol = symbols.getConstSymbol(DecimalFormatSymbols::kCurrencySymbol);
32     }
33     if (symbols.isCustomIntlCurrencySymbol()) {
34         fIntlCurrencySymbol = symbols.getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
35     }
36 }
37 
getIsoCode() const38 const char16_t* CurrencySymbols::getIsoCode() const {
39     return fCurrency.getISOCurrency();
40 }
41 
getNarrowCurrencySymbol(UErrorCode & status) const42 UnicodeString CurrencySymbols::getNarrowCurrencySymbol(UErrorCode& status) const {
43     // Note: currently no override is available for narrow currency symbol
44     return loadSymbol(UCURR_NARROW_SYMBOL_NAME, status);
45 }
46 
getCurrencySymbol(UErrorCode & status) const47 UnicodeString CurrencySymbols::getCurrencySymbol(UErrorCode& status) const {
48     if (!fCurrencySymbol.isBogus()) {
49         return fCurrencySymbol;
50     }
51     return loadSymbol(UCURR_SYMBOL_NAME, status);
52 }
53 
loadSymbol(UCurrNameStyle selector,UErrorCode & status) const54 UnicodeString CurrencySymbols::loadSymbol(UCurrNameStyle selector, UErrorCode& status) const {
55     const char16_t* isoCode = fCurrency.getISOCurrency();
56     int32_t symbolLen = 0;
57     const char16_t* symbol = ucurr_getName(
58             isoCode,
59             fLocaleName.data(),
60             selector,
61             nullptr /* isChoiceFormat */,
62             &symbolLen,
63             &status);
64     // If given an unknown currency, ucurr_getName returns the input string, which we can't alias safely!
65     // Otherwise, symbol points to a resource bundle, and we can use readonly-aliasing constructor.
66     if (symbol == isoCode) {
67         return UnicodeString(isoCode, 3);
68     } else {
69         return UnicodeString(TRUE, symbol, symbolLen);
70     }
71 }
72 
getIntlCurrencySymbol(UErrorCode &) const73 UnicodeString CurrencySymbols::getIntlCurrencySymbol(UErrorCode&) const {
74     if (!fIntlCurrencySymbol.isBogus()) {
75         return fIntlCurrencySymbol;
76     }
77     // Note: Not safe to use readonly-aliasing constructor here because the buffer belongs to this object,
78     // which could be destructed or moved during the lifetime of the return value.
79     return UnicodeString(fCurrency.getISOCurrency(), 3);
80 }
81 
getPluralName(StandardPlural::Form plural,UErrorCode & status) const82 UnicodeString CurrencySymbols::getPluralName(StandardPlural::Form plural, UErrorCode& status) const {
83     const char16_t* isoCode = fCurrency.getISOCurrency();
84     int32_t symbolLen = 0;
85     const char16_t* symbol = ucurr_getPluralName(
86             isoCode,
87             fLocaleName.data(),
88             nullptr /* isChoiceFormat */,
89             StandardPlural::getKeyword(plural),
90             &symbolLen,
91             &status);
92     // If given an unknown currency, ucurr_getName returns the input string, which we can't alias safely!
93     // Otherwise, symbol points to a resource bundle, and we can use readonly-aliasing constructor.
94     if (symbol == isoCode) {
95         return UnicodeString(isoCode, 3);
96     } else {
97         return UnicodeString(TRUE, symbol, symbolLen);
98     }
99 }
100 
101 
102 CurrencyUnit
resolveCurrency(const DecimalFormatProperties & properties,const Locale & locale,UErrorCode & status)103 icu::number::impl::resolveCurrency(const DecimalFormatProperties& properties, const Locale& locale,
104                                    UErrorCode& status) {
105     if (!properties.currency.isNull()) {
106         return properties.currency.getNoError();
107     } else {
108         UErrorCode localStatus = U_ZERO_ERROR;
109         char16_t buf[4] = {};
110         ucurr_forLocale(locale.getName(), buf, 4, &localStatus);
111         if (U_SUCCESS(localStatus)) {
112             return CurrencyUnit(buf, status);
113         } else {
114             // Default currency (XXX)
115             return CurrencyUnit();
116         }
117     }
118 }
119 
120 
121 #endif /* #if !UCONFIG_NO_FORMATTING */
122