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