]>
Commit | Line | Data |
---|---|---|
b75a7d8f A |
1 | /* |
2 | ******************************************************************************* | |
73c04bcf | 3 | * Copyright (C) 1997-2006, International Business Machines Corporation and * |
b75a7d8f A |
4 | * others. All Rights Reserved. * |
5 | ******************************************************************************* | |
6 | * | |
7 | * File DCFMTSYM.CPP | |
8 | * | |
9 | * Modification History: | |
10 | * | |
11 | * Date Name Description | |
12 | * 02/19/97 aliu Converted from java. | |
13 | * 03/18/97 clhuang Implemented with C++ APIs. | |
14 | * 03/27/97 helena Updated to pass the simple test after code review. | |
15 | * 08/26/97 aliu Added currency/intl currency symbol support. | |
374ca955 | 16 | * 07/20/98 stephen Slightly modified initialization of monetarySeparator |
b75a7d8f A |
17 | ******************************************************************************** |
18 | */ | |
19 | ||
20 | #include "unicode/utypes.h" | |
21 | ||
22 | #if !UCONFIG_NO_FORMATTING | |
23 | ||
24 | #include "unicode/dcfmtsym.h" | |
374ca955 | 25 | #include "unicode/ures.h" |
b75a7d8f A |
26 | #include "unicode/decimfmt.h" |
27 | #include "unicode/ucurr.h" | |
28 | #include "unicode/choicfmt.h" | |
374ca955 A |
29 | #include "ucurrimp.h" |
30 | #include "cstring.h" | |
31 | #include "locbased.h" | |
73c04bcf | 32 | #include "uresimp.h" |
b75a7d8f A |
33 | // ***************************************************************************** |
34 | // class DecimalFormatSymbols | |
35 | // ***************************************************************************** | |
36 | ||
37 | U_NAMESPACE_BEGIN | |
38 | ||
374ca955 | 39 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormatSymbols) |
b75a7d8f | 40 | |
374ca955 | 41 | static const char gNumberElements[] = "NumberElements"; |
b75a7d8f A |
42 | |
43 | static const UChar INTL_CURRENCY_SYMBOL_STR[] = {0xa4, 0xa4, 0}; | |
44 | ||
45 | // ------------------------------------- | |
46 | // Initializes this with the decimal format symbols in the default locale. | |
47 | ||
48 | DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode& status) | |
374ca955 A |
49 | : UObject(), |
50 | locale() | |
b75a7d8f | 51 | { |
374ca955 | 52 | initialize(locale, status, TRUE); |
b75a7d8f A |
53 | } |
54 | ||
55 | // ------------------------------------- | |
56 | // Initializes this with the decimal format symbols in the desired locale. | |
57 | ||
58 | DecimalFormatSymbols::DecimalFormatSymbols(const Locale& loc, UErrorCode& status) | |
374ca955 A |
59 | : UObject(), |
60 | locale(loc) | |
b75a7d8f | 61 | { |
374ca955 | 62 | initialize(locale, status); |
b75a7d8f A |
63 | } |
64 | ||
65 | // ------------------------------------- | |
66 | ||
67 | DecimalFormatSymbols::~DecimalFormatSymbols() | |
68 | { | |
69 | } | |
70 | ||
71 | // ------------------------------------- | |
72 | // copy constructor | |
73 | ||
74 | DecimalFormatSymbols::DecimalFormatSymbols(const DecimalFormatSymbols &source) | |
75 | : UObject(source) | |
76 | { | |
374ca955 | 77 | *this = source; |
b75a7d8f A |
78 | } |
79 | ||
80 | // ------------------------------------- | |
81 | // assignment operator | |
82 | ||
83 | DecimalFormatSymbols& | |
84 | DecimalFormatSymbols::operator=(const DecimalFormatSymbols& rhs) | |
85 | { | |
374ca955 A |
86 | if (this != &rhs) { |
87 | for(int32_t i = 0; i < (int32_t)kFormatSymbolCount; ++i) { | |
b75a7d8f A |
88 | // fastCopyFrom is safe, see docs on fSymbols |
89 | fSymbols[(ENumberFormatSymbol)i].fastCopyFrom(rhs.fSymbols[(ENumberFormatSymbol)i]); | |
90 | } | |
374ca955 A |
91 | locale = rhs.locale; |
92 | uprv_strcpy(validLocale, rhs.validLocale); | |
93 | uprv_strcpy(actualLocale, rhs.actualLocale); | |
b75a7d8f A |
94 | } |
95 | return *this; | |
96 | } | |
97 | ||
98 | // ------------------------------------- | |
99 | ||
100 | UBool | |
101 | DecimalFormatSymbols::operator==(const DecimalFormatSymbols& that) const | |
102 | { | |
103 | if (this == &that) { | |
104 | return TRUE; | |
105 | } | |
374ca955 | 106 | for(int32_t i = 0; i < (int32_t)kFormatSymbolCount; ++i) { |
b75a7d8f A |
107 | if(fSymbols[(ENumberFormatSymbol)i] != that.fSymbols[(ENumberFormatSymbol)i]) { |
108 | return FALSE; | |
109 | } | |
110 | } | |
374ca955 A |
111 | return locale == that.locale && |
112 | uprv_strcmp(validLocale, that.validLocale) == 0 && | |
113 | uprv_strcmp(actualLocale, that.actualLocale) == 0; | |
b75a7d8f A |
114 | } |
115 | ||
116 | // ------------------------------------- | |
117 | ||
118 | void | |
119 | DecimalFormatSymbols::initialize(const Locale& loc, UErrorCode& status, | |
120 | UBool useLastResortData) | |
121 | { | |
374ca955 | 122 | *validLocale = *actualLocale = 0; |
73c04bcf | 123 | currPattern = NULL; |
374ca955 A |
124 | if (U_FAILURE(status)) |
125 | return; | |
73c04bcf | 126 | |
374ca955 A |
127 | const char* locStr = loc.getName(); |
128 | UResourceBundle *resource = ures_open((char *)0, locStr, &status); | |
73c04bcf | 129 | UResourceBundle *numberElementsRes = ures_getByKey(resource, gNumberElements, NULL, &status); |
b75a7d8f A |
130 | if (U_FAILURE(status)) |
131 | { | |
132 | // Initializes with last resort data if necessary. | |
133 | if (useLastResortData) | |
134 | { | |
135 | status = U_USING_FALLBACK_WARNING; | |
136 | initialize(); | |
137 | } | |
b75a7d8f | 138 | } |
374ca955 A |
139 | else { |
140 | // Gets the number element array. | |
141 | int32_t numberElementsLength = ures_getSize(numberElementsRes); | |
b75a7d8f | 142 | |
374ca955 A |
143 | if (numberElementsLength > (int32_t)kFormatSymbolCount) { |
144 | /* Warning: Invalid format. Array too large. */ | |
145 | numberElementsLength = (int32_t)kFormatSymbolCount; | |
146 | } | |
147 | // If the array size is too small, something is wrong with the resource | |
148 | // bundle, returns the failure error code. | |
149 | if (numberElementsLength != 12 || U_FAILURE(status)) { | |
150 | status = U_INVALID_FORMAT_ERROR; | |
151 | } | |
152 | else { | |
153 | const UChar *numberElements[kFormatSymbolCount]; | |
154 | int32_t numberElementsStrLen[kFormatSymbolCount]; | |
155 | int32_t i = 0; | |
156 | for(i = 0; i<numberElementsLength; i++) { | |
157 | numberElements[i] = ures_getStringByIndex(numberElementsRes, i, &numberElementsStrLen[i], &status); | |
158 | } | |
b75a7d8f | 159 | |
374ca955 A |
160 | if (U_SUCCESS(status)) { |
161 | initialize(numberElements, numberElementsStrLen, numberElementsLength); | |
162 | ||
163 | // Obtain currency data from the currency API. This is strictly | |
164 | // for backward compatibility; we don't use DecimalFormatSymbols | |
165 | // for currency data anymore. | |
166 | UErrorCode internalStatus = U_ZERO_ERROR; // don't propagate failures out | |
167 | UChar curriso[4]; | |
168 | UnicodeString tempStr; | |
169 | ucurr_forLocale(locStr, curriso, 4, &internalStatus); | |
170 | ||
171 | // Reuse numberElements[0] as a temporary buffer | |
172 | uprv_getStaticCurrencyName(curriso, locStr, tempStr, internalStatus); | |
173 | if (U_SUCCESS(internalStatus)) { | |
174 | fSymbols[kIntlCurrencySymbol] = curriso; | |
175 | fSymbols[kCurrencySymbol] = tempStr; | |
176 | } | |
177 | /* else use the default values. */ | |
b75a7d8f | 178 | } |
374ca955 A |
179 | |
180 | U_LOCALE_BASED(locBased, *this); | |
181 | locBased.setLocaleIDs(ures_getLocaleByType(numberElementsRes, | |
182 | ULOC_VALID_LOCALE, &status), | |
183 | ures_getLocaleByType(numberElementsRes, | |
184 | ULOC_ACTUAL_LOCALE, &status)); | |
b75a7d8f | 185 | } |
73c04bcf A |
186 | //load the currency data |
187 | UChar ucc[4]={0}; //Currency Codes are always 3 chars long | |
188 | int32_t uccLen = 4; | |
189 | const char* locName = loc.getName(); | |
190 | uccLen = ucurr_forLocale(locName, ucc, uccLen, &status); | |
191 | if(U_SUCCESS(status) && uccLen > 0) { | |
192 | char cc[4]={0}; | |
193 | u_UCharsToChars(ucc, cc, uccLen); | |
194 | /* An explicit currency was requested */ | |
195 | UErrorCode localStatus = U_ZERO_ERROR; | |
196 | UResourceBundle *currency = ures_getByKeyWithFallback(resource, "Currencies", NULL, &localStatus); | |
197 | currency = ures_getByKeyWithFallback(currency, cc, currency, &localStatus); | |
198 | if(U_SUCCESS(localStatus) && ures_getSize(currency)>2) { // the length is 3 if more data is present | |
199 | currency = ures_getByIndex(currency, 2, currency, &localStatus); | |
200 | int32_t currPatternLen = 0; | |
201 | currPattern = ures_getStringByIndex(currency, (int32_t)0, &currPatternLen, &localStatus); | |
202 | UnicodeString decimalSep = ures_getStringByIndex(currency, (int32_t)1, NULL, &localStatus); | |
203 | UnicodeString groupingSep = ures_getStringByIndex(currency, (int32_t)2, NULL, &localStatus); | |
204 | if(U_SUCCESS(localStatus)){ | |
205 | fSymbols[kMonetaryGroupingSeparatorSymbol] = groupingSep; | |
206 | fSymbols[kMonetarySeparatorSymbol] = decimalSep; | |
207 | //pattern.setTo(TRUE, currPattern, currPatternLen); | |
208 | status = localStatus; | |
209 | } | |
210 | } | |
211 | ures_close(currency); | |
212 | /* else An explicit currency was requested and is unknown or locale data is malformed. */ | |
213 | /* ucurr_* API will get the correct value later on. */ | |
214 | }else{ | |
215 | // ignore the error if no currency | |
216 | status = U_ZERO_ERROR; | |
217 | } | |
b75a7d8f | 218 | } |
73c04bcf | 219 | ures_close(resource); |
374ca955 | 220 | ures_close(numberElementsRes); |
b75a7d8f A |
221 | } |
222 | ||
223 | // Initializes the DecimalFormatSymbol instance with the data obtained | |
224 | // from ResourceBundle in the desired locale. | |
225 | ||
226 | void | |
374ca955 | 227 | DecimalFormatSymbols::initialize(const UChar** numberElements, int32_t *numberElementsStrLen, int32_t numberElementsLength) |
b75a7d8f | 228 | { |
374ca955 A |
229 | static const int32_t TYPE_MAPPING[][2] = { |
230 | {kDecimalSeparatorSymbol, 0}, | |
231 | {kGroupingSeparatorSymbol, 1}, | |
232 | {kPatternSeparatorSymbol, 2}, | |
233 | {kPercentSymbol, 3}, | |
234 | {kZeroDigitSymbol, 4}, | |
235 | {kDigitSymbol, 5}, | |
236 | {kMinusSignSymbol, 6}, | |
237 | {kExponentialSymbol, 7}, | |
238 | {kPerMillSymbol, 8}, | |
239 | {kInfinitySymbol, 9}, | |
240 | {kNaNSymbol, 10}, | |
241 | {kPlusSignSymbol, 11}, | |
242 | {kMonetarySeparatorSymbol, 0} | |
243 | }; | |
244 | int32_t idx; | |
245 | ||
246 | for (idx = 0; idx < (int32_t)(sizeof(TYPE_MAPPING)/sizeof(TYPE_MAPPING[0])); idx++) { | |
247 | if (TYPE_MAPPING[idx][1] < numberElementsLength) { | |
248 | fSymbols[TYPE_MAPPING[idx][0]].setTo(TRUE, numberElements[TYPE_MAPPING[idx][1]], numberElementsStrLen[TYPE_MAPPING[idx][1]]); | |
249 | } | |
250 | } | |
b75a7d8f A |
251 | |
252 | // Default values until it's set later on. | |
253 | fSymbols[kCurrencySymbol] = (UChar)0xa4; // 'OX' currency symbol | |
254 | fSymbols[kIntlCurrencySymbol] = INTL_CURRENCY_SYMBOL_STR; | |
374ca955 A |
255 | // TODO: read from locale data, if this makes it into CLDR |
256 | fSymbols[kSignificantDigitSymbol] = (UChar)0x0040; // '@' significant digit | |
257 | fSymbols[kPadEscapeSymbol] = (UChar)0x002a; // TODO: '*' Hard coded for now; get from resource later | |
73c04bcf | 258 | fSymbols[kMonetaryGroupingSeparatorSymbol] = fSymbols[kGroupingSeparatorSymbol]; |
b75a7d8f A |
259 | } |
260 | ||
261 | // initialize with default values | |
262 | void | |
263 | DecimalFormatSymbols::initialize() { | |
264 | /* | |
265 | * These strings used to be in static arrays, but the HP/UX aCC compiler | |
266 | * cannot initialize a static array with class constructors. | |
267 | * markus 2000may25 | |
268 | */ | |
269 | fSymbols[kDecimalSeparatorSymbol] = (UChar)0x2e; // '.' decimal separator | |
270 | fSymbols[kGroupingSeparatorSymbol].remove(); // group (thousands) separator | |
271 | fSymbols[kPatternSeparatorSymbol] = (UChar)0x3b; // ';' pattern separator | |
272 | fSymbols[kPercentSymbol] = (UChar)0x25; // '%' percent sign | |
273 | fSymbols[kZeroDigitSymbol] = (UChar)0x30; // '0' native 0 digit | |
274 | fSymbols[kDigitSymbol] = (UChar)0x23; // '#' pattern digit | |
b75a7d8f | 275 | fSymbols[kPlusSignSymbol] = (UChar)0x002b; // '+' plus sign |
374ca955 | 276 | fSymbols[kMinusSignSymbol] = (UChar)0x2d; // '-' minus sign |
b75a7d8f A |
277 | fSymbols[kCurrencySymbol] = (UChar)0xa4; // 'OX' currency symbol |
278 | fSymbols[kIntlCurrencySymbol] = INTL_CURRENCY_SYMBOL_STR; | |
279 | fSymbols[kMonetarySeparatorSymbol] = (UChar)0x2e; // '.' monetary decimal separator | |
280 | fSymbols[kExponentialSymbol] = (UChar)0x45; // 'E' exponential | |
281 | fSymbols[kPerMillSymbol] = (UChar)0x2030; // '%o' per mill | |
282 | fSymbols[kPadEscapeSymbol] = (UChar)0x2a; // '*' pad escape symbol | |
283 | fSymbols[kInfinitySymbol] = (UChar)0x221e; // 'oo' infinite | |
284 | fSymbols[kNaNSymbol] = (UChar)0xfffd; // SUB NaN | |
374ca955 A |
285 | fSymbols[kSignificantDigitSymbol] = (UChar)0x0040; // '@' significant digit |
286 | } | |
287 | ||
288 | Locale | |
289 | DecimalFormatSymbols::getLocale(ULocDataLocaleType type, UErrorCode& status) const { | |
290 | U_LOCALE_BASED(locBased, *this); | |
291 | return locBased.getLocale(type, status); | |
b75a7d8f A |
292 | } |
293 | ||
294 | U_NAMESPACE_END | |
295 | ||
296 | #endif /* #if !UCONFIG_NO_FORMATTING */ | |
297 | ||
298 | //eof |