tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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