2 *******************************************************************************
3 * Copyright (C) 2009-2014, 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"
22 #include "unicode/numsys.h"
31 static const UChar gNumberPatternSeparator
= 0x3B; // ;
38 static UBool U_CALLCONV
ValueComparator(UHashTok val1
, UHashTok val2
);
41 U_CALLCONV
ValueComparator(UHashTok val1
, UHashTok val2
) {
42 const UnicodeString
* affix_1
= (UnicodeString
*)val1
.pointer
;
43 const UnicodeString
* affix_2
= (UnicodeString
*)val2
.pointer
;
44 return *affix_1
== *affix_2
;
50 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo
)
52 static const UChar gDefaultCurrencyPluralPattern
[] = {'0', '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4, 0};
53 static const UChar gTripleCurrencySign
[] = {0xA4, 0xA4, 0xA4, 0};
54 static const UChar gPluralCountOther
[] = {0x6F, 0x74, 0x68, 0x65, 0x72, 0};
55 static const UChar gPart0
[] = {0x7B, 0x30, 0x7D, 0};
56 static const UChar gPart1
[] = {0x7B, 0x31, 0x7D, 0};
58 static const char gNumberElementsTag
[]="NumberElements";
59 static const char gLatnTag
[]="latn";
60 static const char gPatternsTag
[]="patterns";
61 static const char gDecimalFormatTag
[]="decimalFormat";
62 static const char gCurrUnitPtnTag
[]="CurrencyUnitPatterns";
64 CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode
& status
)
65 : fPluralCountToCurrencyUnitPattern(NULL
),
68 initialize(Locale::getDefault(), status
);
71 CurrencyPluralInfo::CurrencyPluralInfo(const Locale
& locale
, UErrorCode
& status
)
72 : fPluralCountToCurrencyUnitPattern(NULL
),
75 initialize(locale
, status
);
78 CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo
& info
)
80 fPluralCountToCurrencyUnitPattern(NULL
),
88 CurrencyPluralInfo::operator=(const CurrencyPluralInfo
& info
) {
93 deleteHash(fPluralCountToCurrencyUnitPattern
);
94 UErrorCode status
= U_ZERO_ERROR
;
95 fPluralCountToCurrencyUnitPattern
= initHash(status
);
96 copyHash(info
.fPluralCountToCurrencyUnitPattern
,
97 fPluralCountToCurrencyUnitPattern
, status
);
98 if ( U_FAILURE(status
) ) {
104 if (info
.fPluralRules
) {
105 fPluralRules
= info
.fPluralRules
->clone();
110 fLocale
= info
.fLocale
->clone();
118 CurrencyPluralInfo::~CurrencyPluralInfo() {
119 deleteHash(fPluralCountToCurrencyUnitPattern
);
120 fPluralCountToCurrencyUnitPattern
= NULL
;
128 CurrencyPluralInfo::operator==(const CurrencyPluralInfo
& info
) const {
129 #ifdef CURRENCY_PLURAL_INFO_DEBUG
130 if (*fPluralRules
== *info
.fPluralRules
) {
131 std::cout
<< "same plural rules\n";
133 if (*fLocale
== *info
.fLocale
) {
134 std::cout
<< "same locale\n";
136 if (fPluralCountToCurrencyUnitPattern
->equals(*info
.fPluralCountToCurrencyUnitPattern
)) {
137 std::cout
<< "same pattern\n";
140 return *fPluralRules
== *info
.fPluralRules
&&
141 *fLocale
== *info
.fLocale
&&
142 fPluralCountToCurrencyUnitPattern
->equals(*info
.fPluralCountToCurrencyUnitPattern
);
147 CurrencyPluralInfo::clone() const {
148 return new CurrencyPluralInfo(*this);
152 CurrencyPluralInfo::getPluralRules() const {
157 CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString
& pluralCount
,
158 UnicodeString
& result
) const {
159 const UnicodeString
* currencyPluralPattern
=
160 (UnicodeString
*)fPluralCountToCurrencyUnitPattern
->get(pluralCount
);
161 if (currencyPluralPattern
== NULL
) {
162 // fall back to "other"
163 if (pluralCount
.compare(gPluralCountOther
, 5)) {
164 currencyPluralPattern
=
165 (UnicodeString
*)fPluralCountToCurrencyUnitPattern
->get(UnicodeString(TRUE
, gPluralCountOther
, 5));
167 if (currencyPluralPattern
== NULL
) {
168 // no currencyUnitPatterns defined,
169 // fallback to predefined defult.
170 // This should never happen when ICU resource files are
171 // available, since currencyUnitPattern of "other" is always
173 result
= UnicodeString(gDefaultCurrencyPluralPattern
);
177 result
= *currencyPluralPattern
;
182 CurrencyPluralInfo::getLocale() const {
187 CurrencyPluralInfo::setPluralRules(const UnicodeString
& ruleDescription
,
188 UErrorCode
& status
) {
189 if (U_SUCCESS(status
)) {
193 fPluralRules
= PluralRules::createRules(ruleDescription
, status
);
199 CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString
& pluralCount
,
200 const UnicodeString
& pattern
,
201 UErrorCode
& status
) {
202 if (U_SUCCESS(status
)) {
203 fPluralCountToCurrencyUnitPattern
->put(pluralCount
, new UnicodeString(pattern
), status
);
209 CurrencyPluralInfo::setLocale(const Locale
& loc
, UErrorCode
& status
) {
210 initialize(loc
, status
);
215 CurrencyPluralInfo::initialize(const Locale
& loc
, UErrorCode
& status
) {
216 if (U_FAILURE(status
)) {
220 fLocale
= loc
.clone();
224 fPluralRules
= PluralRules::forLocale(loc
, status
);
225 setupCurrencyPluralPattern(loc
, status
);
230 CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale
& loc
, UErrorCode
& status
) {
231 if (U_FAILURE(status
)) {
235 if (fPluralCountToCurrencyUnitPattern
) {
236 deleteHash(fPluralCountToCurrencyUnitPattern
);
238 fPluralCountToCurrencyUnitPattern
= initHash(status
);
239 if (U_FAILURE(status
)) {
243 NumberingSystem
*ns
= NumberingSystem::createInstance(loc
,status
);
244 UErrorCode ec
= U_ZERO_ERROR
;
245 UResourceBundle
*rb
= ures_open(NULL
, loc
.getName(), &ec
);
246 UResourceBundle
*numElements
= ures_getByKeyWithFallback(rb
, gNumberElementsTag
, NULL
, &ec
);
247 rb
= ures_getByKeyWithFallback(numElements
, ns
->getName(), rb
, &ec
);
248 rb
= ures_getByKeyWithFallback(rb
, gPatternsTag
, rb
, &ec
);
250 const UChar
* numberStylePattern
= ures_getStringByKeyWithFallback(rb
, gDecimalFormatTag
, &ptnLen
, &ec
);
251 // Fall back to "latn" if num sys specific pattern isn't there.
252 if ( ec
== U_MISSING_RESOURCE_ERROR
&& uprv_strcmp(ns
->getName(),gLatnTag
)) {
254 rb
= ures_getByKeyWithFallback(numElements
, gLatnTag
, rb
, &ec
);
255 rb
= ures_getByKeyWithFallback(rb
, gPatternsTag
, rb
, &ec
);
256 numberStylePattern
= ures_getStringByKeyWithFallback(rb
, gDecimalFormatTag
, &ptnLen
, &ec
);
258 int32_t numberStylePatternLen
= ptnLen
;
259 const UChar
* negNumberStylePattern
= NULL
;
260 int32_t negNumberStylePatternLen
= 0;
262 // parse to check whether there is ";" separator in the numberStylePattern
263 UBool hasSeparator
= false;
265 for (int32_t styleCharIndex
= 0; styleCharIndex
< ptnLen
; ++styleCharIndex
) {
266 if (numberStylePattern
[styleCharIndex
] == gNumberPatternSeparator
) {
268 // split the number style pattern into positive and negative
269 negNumberStylePattern
= numberStylePattern
+ styleCharIndex
+ 1;
270 negNumberStylePatternLen
= ptnLen
- styleCharIndex
- 1;
271 numberStylePatternLen
= styleCharIndex
;
276 ures_close(numElements
);
284 UResourceBundle
*currRb
= ures_open(U_ICUDATA_CURR
, loc
.getName(), &ec
);
285 UResourceBundle
*currencyRes
= ures_getByKeyWithFallback(currRb
, gCurrUnitPtnTag
, NULL
, &ec
);
287 #ifdef CURRENCY_PLURAL_INFO_DEBUG
288 std::cout
<< "in set up\n";
290 StringEnumeration
* keywords
= fPluralRules
->getKeywords(ec
);
292 const char* pluralCount
;
293 while ((pluralCount
= keywords
->next(NULL
, ec
)) != NULL
) {
294 if ( U_SUCCESS(ec
) ) {
296 UErrorCode err
= U_ZERO_ERROR
;
297 const UChar
* patternChars
= ures_getStringByKeyWithFallback(
298 currencyRes
, pluralCount
, &ptnLen
, &err
);
299 if (U_SUCCESS(err
) && ptnLen
> 0) {
300 UnicodeString
* pattern
= new UnicodeString(patternChars
, ptnLen
);
301 #ifdef CURRENCY_PLURAL_INFO_DEBUG
303 pattern
->extract(0, pattern
->length(), result_1
, "UTF-8");
304 std::cout
<< "pluralCount: " << pluralCount
<< "; pattern: " << result_1
<< "\n";
306 pattern
->findAndReplace(UnicodeString(TRUE
, gPart0
, 3),
307 UnicodeString(numberStylePattern
, numberStylePatternLen
));
308 pattern
->findAndReplace(UnicodeString(TRUE
, gPart1
, 3), UnicodeString(TRUE
, gTripleCurrencySign
, 3));
311 UnicodeString
negPattern(patternChars
, ptnLen
);
312 negPattern
.findAndReplace(UnicodeString(TRUE
, gPart0
, 3),
313 UnicodeString(negNumberStylePattern
, negNumberStylePatternLen
));
314 negPattern
.findAndReplace(UnicodeString(TRUE
, gPart1
, 3), UnicodeString(TRUE
, gTripleCurrencySign
, 3));
315 pattern
->append(gNumberPatternSeparator
);
316 pattern
->append(negPattern
);
318 #ifdef CURRENCY_PLURAL_INFO_DEBUG
319 pattern
->extract(0, pattern
->length(), result_1
, "UTF-8");
320 std::cout
<< "pluralCount: " << pluralCount
<< "; pattern: " << result_1
<< "\n";
323 fPluralCountToCurrencyUnitPattern
->put(UnicodeString(pluralCount
, -1, US_INV
), pattern
, status
);
329 ures_close(currencyRes
);
336 CurrencyPluralInfo::deleteHash(Hashtable
* hTable
)
338 if ( hTable
== NULL
) {
341 int32_t pos
= UHASH_FIRST
;
342 const UHashElement
* element
= NULL
;
343 while ( (element
= hTable
->nextElement(pos
)) != NULL
) {
344 const UHashTok valueTok
= element
->value
;
345 const UnicodeString
* value
= (UnicodeString
*)valueTok
.pointer
;
354 CurrencyPluralInfo::initHash(UErrorCode
& status
) {
355 if ( U_FAILURE(status
) ) {
359 if ( (hTable
= new Hashtable(TRUE
, status
)) == NULL
) {
360 status
= U_MEMORY_ALLOCATION_ERROR
;
363 if ( U_FAILURE(status
) ) {
367 hTable
->setValueComparator(ValueComparator
);
373 CurrencyPluralInfo::copyHash(const Hashtable
* source
,
375 UErrorCode
& status
) {
376 if ( U_FAILURE(status
) ) {
379 int32_t pos
= UHASH_FIRST
;
380 const UHashElement
* element
= NULL
;
382 while ( (element
= source
->nextElement(pos
)) != NULL
) {
383 const UHashTok keyTok
= element
->key
;
384 const UnicodeString
* key
= (UnicodeString
*)keyTok
.pointer
;
385 const UHashTok valueTok
= element
->value
;
386 const UnicodeString
* value
= (UnicodeString
*)valueTok
.pointer
;
387 UnicodeString
* copy
= new UnicodeString(*value
);
388 target
->put(UnicodeString(*key
), copy
, status
);
389 if ( U_FAILURE(status
) ) {