OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ******************************************************************************* |
| 3 * Copyright (C) 2009-2010, International Business Machines Corporation and |
| 4 * others. All Rights Reserved. |
| 5 ******************************************************************************* |
| 6 */ |
| 7 |
| 8 #include "unicode/currpinf.h" |
| 9 |
| 10 #if !UCONFIG_NO_FORMATTING |
| 11 |
| 12 //#define CURRENCY_PLURAL_INFO_DEBUG 1 |
| 13 |
| 14 #ifdef CURRENCY_PLURAL_INFO_DEBUG |
| 15 #include <iostream> |
| 16 #endif |
| 17 |
| 18 |
| 19 #include "unicode/locid.h" |
| 20 #include "unicode/plurrule.h" |
| 21 #include "unicode/ures.h" |
| 22 #include "cstring.h" |
| 23 #include "hash.h" |
| 24 #include "uresimp.h" |
| 25 #include "ureslocs.h" |
| 26 |
| 27 U_NAMESPACE_BEGIN |
| 28 |
| 29 |
| 30 static const UChar gNumberPatternSeparator = 0x3B; // ; |
| 31 |
| 32 U_CDECL_BEGIN |
| 33 |
| 34 /** |
| 35 * @internal ICU 4.2 |
| 36 */ |
| 37 static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2); |
| 38 |
| 39 UBool |
| 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; |
| 44 } |
| 45 |
| 46 U_CDECL_END |
| 47 |
| 48 |
| 49 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo) |
| 50 |
| 51 static const UChar gDefaultCurrencyPluralPattern[] = {'0', '.', '#', '#', ' ', 0
xA4, 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}; |
| 56 |
| 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"; |
| 62 |
| 63 CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status) |
| 64 : fPluralCountToCurrencyUnitPattern(NULL), |
| 65 fPluralRules(NULL), |
| 66 fLocale(NULL) { |
| 67 initialize(Locale::getDefault(), status); |
| 68 } |
| 69 |
| 70 CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status) |
| 71 : fPluralCountToCurrencyUnitPattern(NULL), |
| 72 fPluralRules(NULL), |
| 73 fLocale(NULL) { |
| 74 initialize(locale, status); |
| 75 } |
| 76 |
| 77 CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info) |
| 78 : UObject(info), |
| 79 fPluralCountToCurrencyUnitPattern(NULL), |
| 80 fPluralRules(NULL), |
| 81 fLocale(NULL) { |
| 82 *this = info; |
| 83 } |
| 84 |
| 85 |
| 86 CurrencyPluralInfo& |
| 87 CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) { |
| 88 if (this == &info) { |
| 89 return *this; |
| 90 } |
| 91 |
| 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) ) { |
| 98 return *this; |
| 99 } |
| 100 |
| 101 delete fPluralRules; |
| 102 delete fLocale; |
| 103 if (info.fPluralRules) { |
| 104 fPluralRules = info.fPluralRules->clone(); |
| 105 } else { |
| 106 fPluralRules = NULL; |
| 107 } |
| 108 if (info.fLocale) { |
| 109 fLocale = info.fLocale->clone(); |
| 110 } else { |
| 111 fLocale = NULL; |
| 112 } |
| 113 return *this; |
| 114 } |
| 115 |
| 116 |
| 117 CurrencyPluralInfo::~CurrencyPluralInfo() { |
| 118 deleteHash(fPluralCountToCurrencyUnitPattern); |
| 119 fPluralCountToCurrencyUnitPattern = NULL; |
| 120 delete fPluralRules; |
| 121 delete fLocale; |
| 122 fPluralRules = NULL; |
| 123 fLocale = NULL; |
| 124 } |
| 125 |
| 126 UBool |
| 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"; |
| 131 } |
| 132 if (*fLocale == *info.fLocale) { |
| 133 std::cout << "same locale\n"; |
| 134 } |
| 135 if (fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUn
itPattern)) { |
| 136 std::cout << "same pattern\n"; |
| 137 } |
| 138 #endif |
| 139 return *fPluralRules == *info.fPluralRules && |
| 140 *fLocale == *info.fLocale && |
| 141 fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrenc
yUnitPattern); |
| 142 } |
| 143 |
| 144 |
| 145 CurrencyPluralInfo* |
| 146 CurrencyPluralInfo::clone() const { |
| 147 return new CurrencyPluralInfo(*this); |
| 148 } |
| 149 |
| 150 const PluralRules* |
| 151 CurrencyPluralInfo::getPluralRules() const { |
| 152 return fPluralRules; |
| 153 } |
| 154 |
| 155 UnicodeString& |
| 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(gPluralCo
untOther); |
| 165 } |
| 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 |
| 171 // defined in root. |
| 172 result = UnicodeString(gDefaultCurrencyPluralPattern); |
| 173 return result; |
| 174 } |
| 175 } |
| 176 result = *currencyPluralPattern; |
| 177 return result; |
| 178 } |
| 179 |
| 180 const Locale& |
| 181 CurrencyPluralInfo::getLocale() const { |
| 182 return *fLocale; |
| 183 } |
| 184 |
| 185 void |
| 186 CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription, |
| 187 UErrorCode& status) { |
| 188 if (U_SUCCESS(status)) { |
| 189 if (fPluralRules) { |
| 190 delete fPluralRules; |
| 191 } |
| 192 fPluralRules = PluralRules::createRules(ruleDescription, status); |
| 193 } |
| 194 } |
| 195 |
| 196 |
| 197 void |
| 198 CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount, |
| 199 const UnicodeString& pattern, |
| 200 UErrorCode& status) { |
| 201 if (U_SUCCESS(status)) { |
| 202 fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pa
ttern), status); |
| 203 } |
| 204 } |
| 205 |
| 206 |
| 207 void |
| 208 CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) { |
| 209 initialize(loc, status); |
| 210 } |
| 211 |
| 212 |
| 213 void |
| 214 CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) { |
| 215 if (U_FAILURE(status)) { |
| 216 return; |
| 217 } |
| 218 delete fLocale; |
| 219 fLocale = loc.clone(); |
| 220 if (fPluralRules) { |
| 221 delete fPluralRules; |
| 222 } |
| 223 fPluralRules = PluralRules::forLocale(loc, status); |
| 224 setupCurrencyPluralPattern(loc, status); |
| 225 } |
| 226 |
| 227 |
| 228 void |
| 229 CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& st
atus) { |
| 230 if (U_FAILURE(status)) { |
| 231 return; |
| 232 } |
| 233 |
| 234 if (fPluralCountToCurrencyUnitPattern) { |
| 235 deleteHash(fPluralCountToCurrencyUnitPattern); |
| 236 } |
| 237 fPluralCountToCurrencyUnitPattern = initHash(status); |
| 238 if (U_FAILURE(status)) { |
| 239 return; |
| 240 } |
| 241 |
| 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); |
| 247 int32_t ptnLen; |
| 248 const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecim
alFormatTag, &ptnLen, &ec); |
| 249 int32_t numberStylePatternLen = ptnLen; |
| 250 const UChar* negNumberStylePattern = NULL; |
| 251 int32_t negNumberStylePatternLen = 0; |
| 252 // TODO: Java |
| 253 // parse to check whether there is ";" separator in the numberStylePattern |
| 254 UBool hasSeparator = false; |
| 255 if (U_SUCCESS(ec)) { |
| 256 for (int32_t styleCharIndex = 0; styleCharIndex < ptnLen; ++styleCharInd
ex) { |
| 257 if (numberStylePattern[styleCharIndex] == gNumberPatternSeparator) { |
| 258 hasSeparator = true; |
| 259 // split the number style pattern into positive and negative |
| 260 negNumberStylePattern = numberStylePattern + styleCharIndex + 1; |
| 261 negNumberStylePatternLen = ptnLen - styleCharIndex - 1; |
| 262 numberStylePatternLen = styleCharIndex; |
| 263 } |
| 264 } |
| 265 } |
| 266 ures_close(rb); |
| 267 |
| 268 if (U_FAILURE(ec)) { |
| 269 return; |
| 270 } |
| 271 |
| 272 UResourceBundle *currRb = ures_open(U_ICUDATA_CURR, loc.getName(), &ec); |
| 273 UResourceBundle *currencyRes = ures_getByKeyWithFallback(currRb, gCurrUnitPt
nTag, NULL, &ec); |
| 274 |
| 275 #ifdef CURRENCY_PLURAL_INFO_DEBUG |
| 276 std::cout << "in set up\n"; |
| 277 #endif |
| 278 StringEnumeration* keywords = fPluralRules->getKeywords(ec); |
| 279 if (U_SUCCESS(ec)) { |
| 280 const char* pluralCount; |
| 281 while ((pluralCount = keywords->next(NULL, ec)) != NULL) { |
| 282 if ( U_SUCCESS(ec) ) { |
| 283 int32_t ptnLen; |
| 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, ptn
Len); |
| 289 #ifdef CURRENCY_PLURAL_INFO_DEBUG |
| 290 char result_1[1000]; |
| 291 pattern->extract(0, pattern->length(), result_1, "UTF-8"); |
| 292 std::cout << "pluralCount: " << pluralCount << "; pattern: "
<< result_1 << "\n"; |
| 293 #endif |
| 294 pattern->findAndReplace(gPart0, |
| 295 UnicodeString(numberStylePattern, numberStylePatternLen)); |
| 296 pattern->findAndReplace(gPart1, gTripleCurrencySign); |
| 297 |
| 298 if (hasSeparator) { |
| 299 UnicodeString negPattern(patternChars, ptnLen); |
| 300 negPattern.findAndReplace(gPart0, |
| 301 UnicodeString(negNumberStylePattern, negNumberStylePat
ternLen)); |
| 302 negPattern.findAndReplace(gPart1, gTripleCurrencySign); |
| 303 pattern->append(gNumberPatternSeparator); |
| 304 pattern->append(negPattern); |
| 305 } |
| 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"; |
| 309 #endif |
| 310 |
| 311 fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralC
ount), pattern, status); |
| 312 } |
| 313 } |
| 314 } |
| 315 } |
| 316 delete keywords; |
| 317 ures_close(currencyRes); |
| 318 ures_close(currRb); |
| 319 } |
| 320 |
| 321 |
| 322 |
| 323 void |
| 324 CurrencyPluralInfo::deleteHash(Hashtable* hTable) |
| 325 { |
| 326 if ( hTable == NULL ) { |
| 327 return; |
| 328 } |
| 329 int32_t pos = -1; |
| 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; |
| 335 delete value; |
| 336 } |
| 337 delete hTable; |
| 338 hTable = NULL; |
| 339 } |
| 340 |
| 341 |
| 342 Hashtable* |
| 343 CurrencyPluralInfo::initHash(UErrorCode& status) { |
| 344 if ( U_FAILURE(status) ) { |
| 345 return NULL; |
| 346 } |
| 347 Hashtable* hTable; |
| 348 if ( (hTable = new Hashtable(TRUE, status)) == NULL ) { |
| 349 status = U_MEMORY_ALLOCATION_ERROR; |
| 350 return NULL; |
| 351 } |
| 352 hTable->setValueComparator(ValueComparator); |
| 353 return hTable; |
| 354 } |
| 355 |
| 356 |
| 357 void |
| 358 CurrencyPluralInfo::copyHash(const Hashtable* source, |
| 359 Hashtable* target, |
| 360 UErrorCode& status) { |
| 361 if ( U_FAILURE(status) ) { |
| 362 return; |
| 363 } |
| 364 int32_t pos = -1; |
| 365 const UHashElement* element = NULL; |
| 366 if ( source ) { |
| 367 while ( (element = source->nextElement(pos)) != NULL ) { |
| 368 const UHashTok keyTok = element->key; |
| 369 const UnicodeString* key = (UnicodeString*)keyTok.pointer; |
| 370 const UHashTok valueTok = element->value; |
| 371 const UnicodeString* value = (UnicodeString*)valueTok.pointer; |
| 372 UnicodeString* copy = new UnicodeString(*value); |
| 373 target->put(UnicodeString(*key), copy, status); |
| 374 if ( U_FAILURE(status) ) { |
| 375 return; |
| 376 } |
| 377 } |
| 378 } |
| 379 } |
| 380 |
| 381 |
| 382 U_NAMESPACE_END |
| 383 |
| 384 #endif |
OLD | NEW |