2 *******************************************************************************
3 * Copyright (C) 1997-2008, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
9 * Modification History:
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.
16 * 07/20/98 stephen Slightly modified initialization of monetarySeparator
17 ********************************************************************************
20 #include "unicode/utypes.h"
22 #if !UCONFIG_NO_FORMATTING
24 #include "unicode/dcfmtsym.h"
25 #include "unicode/ures.h"
26 #include "unicode/decimfmt.h"
27 #include "unicode/ucurr.h"
28 #include "unicode/choicfmt.h"
33 // *****************************************************************************
34 // class DecimalFormatSymbols
35 // *****************************************************************************
39 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormatSymbols
)
41 static const char gNumberElements
[] = "NumberElements";
43 static const UChar INTL_CURRENCY_SYMBOL_STR
[] = {0xa4, 0xa4, 0};
45 // -------------------------------------
46 // Initializes this with the decimal format symbols in the default locale.
48 DecimalFormatSymbols::DecimalFormatSymbols(UErrorCode
& status
)
52 initialize(locale
, status
, TRUE
);
55 // -------------------------------------
56 // Initializes this with the decimal format symbols in the desired locale.
58 DecimalFormatSymbols::DecimalFormatSymbols(const Locale
& loc
, UErrorCode
& status
)
62 initialize(locale
, status
);
65 // -------------------------------------
67 DecimalFormatSymbols::~DecimalFormatSymbols()
71 // -------------------------------------
74 DecimalFormatSymbols::DecimalFormatSymbols(const DecimalFormatSymbols
&source
)
80 // -------------------------------------
81 // assignment operator
84 DecimalFormatSymbols::operator=(const DecimalFormatSymbols
& rhs
)
87 for(int32_t i
= 0; i
< (int32_t)kFormatSymbolCount
; ++i
) {
88 // fastCopyFrom is safe, see docs on fSymbols
89 fSymbols
[(ENumberFormatSymbol
)i
].fastCopyFrom(rhs
.fSymbols
[(ENumberFormatSymbol
)i
]);
92 uprv_strcpy(validLocale
, rhs
.validLocale
);
93 uprv_strcpy(actualLocale
, rhs
.actualLocale
);
98 // -------------------------------------
101 DecimalFormatSymbols::operator==(const DecimalFormatSymbols
& that
) const
106 for(int32_t i
= 0; i
< (int32_t)kFormatSymbolCount
; ++i
) {
107 if(fSymbols
[(ENumberFormatSymbol
)i
] != that
.fSymbols
[(ENumberFormatSymbol
)i
]) {
111 return locale
== that
.locale
&&
112 uprv_strcmp(validLocale
, that
.validLocale
) == 0 &&
113 uprv_strcmp(actualLocale
, that
.actualLocale
) == 0;
116 // -------------------------------------
119 DecimalFormatSymbols::initialize(const Locale
& loc
, UErrorCode
& status
,
120 UBool useLastResortData
)
122 *validLocale
= *actualLocale
= 0;
124 if (U_FAILURE(status
))
127 const char* locStr
= loc
.getName();
128 UResourceBundle
*resource
= ures_open((char *)0, locStr
, &status
);
129 UResourceBundle
*numberElementsRes
= ures_getByKey(resource
, gNumberElements
, NULL
, &status
);
130 if (U_FAILURE(status
))
132 // Initializes with last resort data if necessary.
133 if (useLastResortData
)
135 status
= U_USING_FALLBACK_WARNING
;
140 // Gets the number element array.
141 int32_t numberElementsLength
= ures_getSize(numberElementsRes
);
143 if (numberElementsLength
> (int32_t)kFormatSymbolCount
) {
144 /* Warning: Invalid format. Array too large. */
145 numberElementsLength
= (int32_t)kFormatSymbolCount
;
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
;
153 const UChar
*numberElements
[kFormatSymbolCount
];
154 int32_t numberElementsStrLen
[kFormatSymbolCount
];
156 for(i
= 0; i
<numberElementsLength
; i
++) {
157 numberElements
[i
] = ures_getStringByIndex(numberElementsRes
, i
, &numberElementsStrLen
[i
], &status
);
160 if (U_SUCCESS(status
)) {
161 initialize(numberElements
, numberElementsStrLen
, numberElementsLength
);
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
168 UnicodeString tempStr
;
169 ucurr_forLocale(locStr
, curriso
, 4, &internalStatus
);
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
;
177 /* else use the default values. */
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
));
186 //load the currency data
187 UChar ucc
[4]={0}; //Currency Codes are always 3 chars long
189 const char* locName
= loc
.getName();
190 UErrorCode localStatus
= U_ZERO_ERROR
;
191 uccLen
= ucurr_forLocale(locName
, ucc
, uccLen
, &localStatus
);
192 if(U_SUCCESS(localStatus
) && uccLen
> 0) {
194 u_UCharsToChars(ucc
, cc
, uccLen
);
195 /* An explicit currency was requested */
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
;
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. */
215 // else ignore the error if no currency
217 ures_close(resource
);
218 ures_close(numberElementsRes
);
221 // Initializes the DecimalFormatSymbol instance with the data obtained
222 // from ResourceBundle in the desired locale.
225 DecimalFormatSymbols::initialize(const UChar
** numberElements
, int32_t *numberElementsStrLen
, int32_t numberElementsLength
)
227 static const int8_t TYPE_MAPPING
[][2] = {
228 {kDecimalSeparatorSymbol
, 0},
229 {kGroupingSeparatorSymbol
, 1},
230 {kPatternSeparatorSymbol
, 2},
232 {kZeroDigitSymbol
, 4},
234 {kMinusSignSymbol
, 6},
235 {kExponentialSymbol
, 7},
237 {kInfinitySymbol
, 9},
239 {kPlusSignSymbol
, 11},
240 {kMonetarySeparatorSymbol
, 0}
244 for (idx
= 0; idx
< (int32_t)(sizeof(TYPE_MAPPING
)/sizeof(TYPE_MAPPING
[0])); idx
++) {
245 if (TYPE_MAPPING
[idx
][1] < numberElementsLength
) {
246 fSymbols
[TYPE_MAPPING
[idx
][0]].setTo(TRUE
, numberElements
[TYPE_MAPPING
[idx
][1]], numberElementsStrLen
[TYPE_MAPPING
[idx
][1]]);
250 // Default values until it's set later on.
251 fSymbols
[kCurrencySymbol
] = (UChar
)0xa4; // 'OX' currency symbol
252 fSymbols
[kIntlCurrencySymbol
] = INTL_CURRENCY_SYMBOL_STR
;
253 // TODO: read from locale data, if this makes it into CLDR
254 fSymbols
[kSignificantDigitSymbol
] = (UChar
)0x0040; // '@' significant digit
255 fSymbols
[kPadEscapeSymbol
] = (UChar
)0x002a; // TODO: '*' Hard coded for now; get from resource later
256 fSymbols
[kMonetaryGroupingSeparatorSymbol
] = fSymbols
[kGroupingSeparatorSymbol
];
259 // initialize with default values
261 DecimalFormatSymbols::initialize() {
263 * These strings used to be in static arrays, but the HP/UX aCC compiler
264 * cannot initialize a static array with class constructors.
267 fSymbols
[kDecimalSeparatorSymbol
] = (UChar
)0x2e; // '.' decimal separator
268 fSymbols
[kGroupingSeparatorSymbol
].remove(); // group (thousands) separator
269 fSymbols
[kPatternSeparatorSymbol
] = (UChar
)0x3b; // ';' pattern separator
270 fSymbols
[kPercentSymbol
] = (UChar
)0x25; // '%' percent sign
271 fSymbols
[kZeroDigitSymbol
] = (UChar
)0x30; // '0' native 0 digit
272 fSymbols
[kDigitSymbol
] = (UChar
)0x23; // '#' pattern digit
273 fSymbols
[kPlusSignSymbol
] = (UChar
)0x002b; // '+' plus sign
274 fSymbols
[kMinusSignSymbol
] = (UChar
)0x2d; // '-' minus sign
275 fSymbols
[kCurrencySymbol
] = (UChar
)0xa4; // 'OX' currency symbol
276 fSymbols
[kIntlCurrencySymbol
] = INTL_CURRENCY_SYMBOL_STR
;
277 fSymbols
[kMonetarySeparatorSymbol
] = (UChar
)0x2e; // '.' monetary decimal separator
278 fSymbols
[kExponentialSymbol
] = (UChar
)0x45; // 'E' exponential
279 fSymbols
[kPerMillSymbol
] = (UChar
)0x2030; // '%o' per mill
280 fSymbols
[kPadEscapeSymbol
] = (UChar
)0x2a; // '*' pad escape symbol
281 fSymbols
[kInfinitySymbol
] = (UChar
)0x221e; // 'oo' infinite
282 fSymbols
[kNaNSymbol
] = (UChar
)0xfffd; // SUB NaN
283 fSymbols
[kSignificantDigitSymbol
] = (UChar
)0x0040; // '@' significant digit
287 DecimalFormatSymbols::getLocale(ULocDataLocaleType type
, UErrorCode
& status
) const {
288 U_LOCALE_BASED(locBased
, *this);
289 return locBased
.getLocale(type
, status
);
294 #endif /* #if !UCONFIG_NO_FORMATTING */