2 *******************************************************************************
3 * Copyright (C) 2009-2011, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
8 #include "unicode/currpinf.h"
10 #if !UCONFIG_NO_FORMATTING
12 //#define CURRENCY_PLURAL_INFO_DEBUG 1
14 #ifdef CURRENCY_PLURAL_INFO_DEBUG
19 #include "unicode/locid.h"
20 #include "unicode/plurrule.h"
21 #include "unicode/ures.h"
30 static const UChar gNumberPatternSeparator
= 0x3B; // ;
37 static UBool U_CALLCONV
ValueComparator(UHashTok val1
, UHashTok val2
);
40 U_CALLCONV
ValueComparator(UHashTok val1
, UHashTok val2
) {
41 const UnicodeString
* affix_1
= (UnicodeString
*)val1
.pointer
;
42 const UnicodeString
* affix_2
= (UnicodeString
*)val2
.pointer
;
43 return *affix_1
== *affix_2
;
49 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo
)
51 static const UChar gDefaultCurrencyPluralPattern
[] = {'0', '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4, 0};
52 static const UChar gTripleCurrencySign
[] = {0xA4, 0xA4, 0xA4, 0};
53 static const UChar gPluralCountOther
[] = {0x6F, 0x74, 0x68, 0x65, 0x72, 0};
54 static const UChar gPart0
[] = {0x7B, 0x30, 0x7D, 0};
55 static const UChar gPart1
[] = {0x7B, 0x31, 0x7D, 0};
57 static const char gNumberElementsTag
[]="NumberElements";
58 static const char gLatnTag
[]="latn";
59 static const char gPatternsTag
[]="patterns";
60 static const char gDecimalFormatTag
[]="decimalFormat";
61 static const char gCurrUnitPtnTag
[]="CurrencyUnitPatterns";
63 CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode
& status
)
64 : fPluralCountToCurrencyUnitPattern(NULL
),
67 initialize(Locale::getDefault(), status
);
70 CurrencyPluralInfo::CurrencyPluralInfo(const Locale
& locale
, UErrorCode
& status
)
71 : fPluralCountToCurrencyUnitPattern(NULL
),
74 initialize(locale
, status
);
77 CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo
& info
)
79 fPluralCountToCurrencyUnitPattern(NULL
),
87 CurrencyPluralInfo::operator=(const CurrencyPluralInfo
& info
) {
92 deleteHash(fPluralCountToCurrencyUnitPattern
);
93 UErrorCode status
= U_ZERO_ERROR
;
94 fPluralCountToCurrencyUnitPattern
= initHash(status
);
95 copyHash(info
.fPluralCountToCurrencyUnitPattern
,
96 fPluralCountToCurrencyUnitPattern
, status
);
97 if ( U_FAILURE(status
) ) {
103 if (info
.fPluralRules
) {
104 fPluralRules
= info
.fPluralRules
->clone();
109 fLocale
= info
.fLocale
->clone();
117 CurrencyPluralInfo::~CurrencyPluralInfo() {
118 deleteHash(fPluralCountToCurrencyUnitPattern
);
119 fPluralCountToCurrencyUnitPattern
= NULL
;
127 CurrencyPluralInfo::operator==(const CurrencyPluralInfo
& info
) const {
128 #ifdef CURRENCY_PLURAL_INFO_DEBUG
129 if (*fPluralRules
== *info
.fPluralRules
) {
130 std::cout
<< "same plural rules\n";
132 if (*fLocale
== *info
.fLocale
) {
133 std::cout
<< "same locale\n";
135 if (fPluralCountToCurrencyUnitPattern
->equals(*info
.fPluralCountToCurrencyUnitPattern
)) {
136 std::cout
<< "same pattern\n";
139 return *fPluralRules
== *info
.fPluralRules
&&
140 *fLocale
== *info
.fLocale
&&
141 fPluralCountToCurrencyUnitPattern
->equals(*info
.fPluralCountToCurrencyUnitPattern
);
146 CurrencyPluralInfo::clone() const {
147 return new CurrencyPluralInfo(*this);
151 CurrencyPluralInfo::getPluralRules() const {
156 CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString
& pluralCount
,
157 UnicodeString
& result
) const {
158 const UnicodeString
* currencyPluralPattern
=
159 (UnicodeString
*)fPluralCountToCurrencyUnitPattern
->get(pluralCount
);
160 if (currencyPluralPattern
== NULL
) {
161 // fall back to "other"
162 if (pluralCount
.compare(gPluralCountOther
)) {
163 currencyPluralPattern
=
164 (UnicodeString
*)fPluralCountToCurrencyUnitPattern
->get(gPluralCountOther
);
166 if (currencyPluralPattern
== NULL
) {
167 // no currencyUnitPatterns defined,
168 // fallback to predefined defult.
169 // This should never happen when ICU resource files are
170 // available, since currencyUnitPattern of "other" is always
172 result
= UnicodeString(gDefaultCurrencyPluralPattern
);
176 result
= *currencyPluralPattern
;
181 CurrencyPluralInfo::getLocale() const {
186 CurrencyPluralInfo::setPluralRules(const UnicodeString
& ruleDescription
,
187 UErrorCode
& status
) {
188 if (U_SUCCESS(status
)) {
192 fPluralRules
= PluralRules::createRules(ruleDescription
, status
);
198 CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString
& pluralCount
,
199 const UnicodeString
& pattern
,
200 UErrorCode
& status
) {
201 if (U_SUCCESS(status
)) {
202 fPluralCountToCurrencyUnitPattern
->put(pluralCount
, new UnicodeString(pattern
), status
);
208 CurrencyPluralInfo::setLocale(const Locale
& loc
, UErrorCode
& status
) {
209 initialize(loc
, status
);
214 CurrencyPluralInfo::initialize(const Locale
& loc
, UErrorCode
& status
) {
215 if (U_FAILURE(status
)) {
219 fLocale
= loc
.clone();
223 fPluralRules
= PluralRules::forLocale(loc
, status
);
224 setupCurrencyPluralPattern(loc
, status
);
229 CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale
& loc
, UErrorCode
& status
) {
230 if (U_FAILURE(status
)) {
234 if (fPluralCountToCurrencyUnitPattern
) {
235 deleteHash(fPluralCountToCurrencyUnitPattern
);
237 fPluralCountToCurrencyUnitPattern
= initHash(status
);
238 if (U_FAILURE(status
)) {
242 UErrorCode ec
= U_ZERO_ERROR
;
243 UResourceBundle
*rb
= ures_open(NULL
, loc
.getName(), &ec
);
244 rb
= ures_getByKey(rb
, gNumberElementsTag
, rb
, &ec
);
245 rb
= ures_getByKey(rb
, gLatnTag
, rb
, &ec
);
246 rb
= ures_getByKey(rb
, gPatternsTag
, rb
, &ec
);
248 const UChar
* numberStylePattern
= ures_getStringByKeyWithFallback(rb
, gDecimalFormatTag
, &ptnLen
, &ec
);
249 int32_t numberStylePatternLen
= ptnLen
;
250 const UChar
* negNumberStylePattern
= NULL
;
251 int32_t negNumberStylePatternLen
= 0;
253 // parse to check whether there is ";" separator in the numberStylePattern
254 UBool hasSeparator
= false;
256 for (int32_t styleCharIndex
= 0; styleCharIndex
< ptnLen
; ++styleCharIndex
) {
257 if (numberStylePattern
[styleCharIndex
] == gNumberPatternSeparator
) {
259 // split the number style pattern into positive and negative
260 negNumberStylePattern
= numberStylePattern
+ styleCharIndex
+ 1;
261 negNumberStylePatternLen
= ptnLen
- styleCharIndex
- 1;
262 numberStylePatternLen
= styleCharIndex
;
272 UResourceBundle
*currRb
= ures_open(U_ICUDATA_CURR
, loc
.getName(), &ec
);
273 UResourceBundle
*currencyRes
= ures_getByKeyWithFallback(currRb
, gCurrUnitPtnTag
, NULL
, &ec
);
275 #ifdef CURRENCY_PLURAL_INFO_DEBUG
276 std::cout
<< "in set up\n";
278 StringEnumeration
* keywords
= fPluralRules
->getKeywords(ec
);
280 const char* pluralCount
;
281 while ((pluralCount
= keywords
->next(NULL
, ec
)) != NULL
) {
282 if ( U_SUCCESS(ec
) ) {
284 UErrorCode err
= U_ZERO_ERROR
;
285 const UChar
* patternChars
= ures_getStringByKeyWithFallback(
286 currencyRes
, pluralCount
, &ptnLen
, &err
);
287 if (U_SUCCESS(err
) && ptnLen
> 0) {
288 UnicodeString
* pattern
= new UnicodeString(patternChars
, ptnLen
);
289 #ifdef CURRENCY_PLURAL_INFO_DEBUG
291 pattern
->extract(0, pattern
->length(), result_1
, "UTF-8");
292 std::cout
<< "pluralCount: " << pluralCount
<< "; pattern: " << result_1
<< "\n";
294 pattern
->findAndReplace(gPart0
,
295 UnicodeString(numberStylePattern
, numberStylePatternLen
));
296 pattern
->findAndReplace(gPart1
, gTripleCurrencySign
);
299 UnicodeString
negPattern(patternChars
, ptnLen
);
300 negPattern
.findAndReplace(gPart0
,
301 UnicodeString(negNumberStylePattern
, negNumberStylePatternLen
));
302 negPattern
.findAndReplace(gPart1
, gTripleCurrencySign
);
303 pattern
->append(gNumberPatternSeparator
);
304 pattern
->append(negPattern
);
306 #ifdef CURRENCY_PLURAL_INFO_DEBUG
307 pattern
->extract(0, pattern
->length(), result_1
, "UTF-8");
308 std::cout
<< "pluralCount: " << pluralCount
<< "; pattern: " << result_1
<< "\n";
311 fPluralCountToCurrencyUnitPattern
->put(UnicodeString(pluralCount
), pattern
, status
);
317 ures_close(currencyRes
);
324 CurrencyPluralInfo::deleteHash(Hashtable
* hTable
)
326 if ( hTable
== NULL
) {
330 const UHashElement
* element
= NULL
;
331 while ( (element
= hTable
->nextElement(pos
)) != NULL
) {
332 const UHashTok keyTok
= element
->key
;
333 const UHashTok valueTok
= element
->value
;
334 const UnicodeString
* value
= (UnicodeString
*)valueTok
.pointer
;
343 CurrencyPluralInfo::initHash(UErrorCode
& status
) {
344 if ( U_FAILURE(status
) ) {
348 if ( (hTable
= new Hashtable(TRUE
, status
)) == NULL
) {
349 status
= U_MEMORY_ALLOCATION_ERROR
;
352 if ( U_FAILURE(status
) ) {
356 hTable
->setValueComparator(ValueComparator
);
362 CurrencyPluralInfo::copyHash(const Hashtable
* source
,
364 UErrorCode
& status
) {
365 if ( U_FAILURE(status
) ) {
369 const UHashElement
* element
= NULL
;
371 while ( (element
= source
->nextElement(pos
)) != NULL
) {
372 const UHashTok keyTok
= element
->key
;
373 const UnicodeString
* key
= (UnicodeString
*)keyTok
.pointer
;
374 const UHashTok valueTok
= element
->value
;
375 const UnicodeString
* value
= (UnicodeString
*)valueTok
.pointer
;
376 UnicodeString
* copy
= new UnicodeString(*value
);
377 target
->put(UnicodeString(*key
), copy
, status
);
378 if ( U_FAILURE(status
) ) {