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