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"
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 ) {
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) ) {
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) ) {