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', '.', '#', '#', ' ', 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}; 56 57 static const char gNumberPatternsTag[]="NumberPatterns"; 58 static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns"; 59 60 CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status) 61 : fPluralCountToCurrencyUnitPattern(NULL), 62 fPluralRules(NULL), 63 fLocale(NULL) { 64 initialize(Locale::getDefault(), status); 65 } 66 67 CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status) 68 : fPluralCountToCurrencyUnitPattern(NULL), 69 fPluralRules(NULL), 70 fLocale(NULL) { 71 initialize(locale, status); 72 } 73 74 CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info) 75 : UObject(info), 76 fPluralCountToCurrencyUnitPattern(NULL), 77 fPluralRules(NULL), 78 fLocale(NULL) { 79 *this = info; 80 } 81 82 83 CurrencyPluralInfo& 84 CurrencyPluralInfo::operator=(const CurrencyPluralInfo& info) { 85 if (this == &info) { 86 return *this; 87 } 88 89 deleteHash(fPluralCountToCurrencyUnitPattern); 90 UErrorCode status = U_ZERO_ERROR; 91 fPluralCountToCurrencyUnitPattern = initHash(status); 92 copyHash(info.fPluralCountToCurrencyUnitPattern, 93 fPluralCountToCurrencyUnitPattern, status); 94 if ( U_FAILURE(status) ) { 95 return *this; 96 } 97 98 delete fPluralRules; 99 delete fLocale; 100 if (info.fPluralRules) { 101 fPluralRules = info.fPluralRules->clone(); 102 } else { 103 fPluralRules = NULL; 104 } 105 if (info.fLocale) { 106 fLocale = info.fLocale->clone(); 107 } else { 108 fLocale = NULL; 109 } 110 return *this; 111 } 112 113 114 CurrencyPluralInfo::~CurrencyPluralInfo() { 115 deleteHash(fPluralCountToCurrencyUnitPattern); 116 fPluralCountToCurrencyUnitPattern = NULL; 117 delete fPluralRules; 118 delete fLocale; 119 fPluralRules = NULL; 120 fLocale = NULL; 121 } 122 123 UBool 124 CurrencyPluralInfo::operator==(const CurrencyPluralInfo& info) const { 125 #ifdef CURRENCY_PLURAL_INFO_DEBUG 126 if (*fPluralRules == *info.fPluralRules) { 127 std::cout << "same plural rules\n"; 128 } 129 if (*fLocale == *info.fLocale) { 130 std::cout << "same locale\n"; 131 } 132 if (fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern)) { 133 std::cout << "same pattern\n"; 134 } 135 #endif 136 return *fPluralRules == *info.fPluralRules && 137 *fLocale == *info.fLocale && 138 fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern); 139 } 140 141 142 CurrencyPluralInfo* 143 CurrencyPluralInfo::clone() const { 144 return new CurrencyPluralInfo(*this); 145 } 146 147 const PluralRules* 148 CurrencyPluralInfo::getPluralRules() const { 149 return fPluralRules; 150 } 151 152 UnicodeString& 153 CurrencyPluralInfo::getCurrencyPluralPattern(const UnicodeString& pluralCount, 154 UnicodeString& result) const { 155 const UnicodeString* currencyPluralPattern = 156 (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(pluralCount); 157 if (currencyPluralPattern == NULL) { 158 // fall back to "other" 159 if (pluralCount.compare(gPluralCountOther)) { 160 currencyPluralPattern = 161 (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(gPluralCountOther); 162 } 163 if (currencyPluralPattern == NULL) { 164 // no currencyUnitPatterns defined, 165 // fallback to predefined defult. 166 // This should never happen when ICU resource files are 167 // available, since currencyUnitPattern of "other" is always 168 // defined in root. 169 result = UnicodeString(gDefaultCurrencyPluralPattern); 170 return result; 171 } 172 } 173 result = *currencyPluralPattern; 174 return result; 175 } 176 177 const Locale& 178 CurrencyPluralInfo::getLocale() const { 179 return *fLocale; 180 } 181 182 void 183 CurrencyPluralInfo::setPluralRules(const UnicodeString& ruleDescription, 184 UErrorCode& status) { 185 if (U_SUCCESS(status)) { 186 if (fPluralRules) { 187 delete fPluralRules; 188 } 189 fPluralRules = PluralRules::createRules(ruleDescription, status); 190 } 191 } 192 193 194 void 195 CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount, 196 const UnicodeString& pattern, 197 UErrorCode& status) { 198 if (U_SUCCESS(status)) { 199 fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status); 200 } 201 } 202 203 204 void 205 CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) { 206 initialize(loc, status); 207 } 208 209 210 void 211 CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) { 212 if (U_FAILURE(status)) { 213 return; 214 } 215 delete fLocale; 216 fLocale = loc.clone(); 217 if (fPluralRules) { 218 delete fPluralRules; 219 } 220 fPluralRules = PluralRules::forLocale(loc, status); 221 setupCurrencyPluralPattern(loc, status); 222 } 223 224 225 void 226 CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) { 227 if (U_FAILURE(status)) { 228 return; 229 } 230 231 if (fPluralCountToCurrencyUnitPattern) { 232 deleteHash(fPluralCountToCurrencyUnitPattern); 233 } 234 fPluralCountToCurrencyUnitPattern = initHash(status); 235 if (U_FAILURE(status)) { 236 return; 237 } 238 239 UErrorCode ec = U_ZERO_ERROR; 240 UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec); 241 UResourceBundle *numberPatterns = ures_getByKey(rb, gNumberPatternsTag, NULL, &ec); 242 int32_t ptnLen; 243 // TODO: 0 to be NumberFormat::fNumberStyle 244 const UChar* numberStylePattern = ures_getStringByIndex(numberPatterns, 0, 245 &ptnLen, &ec); 246 int32_t numberStylePatternLen = ptnLen; 247 const UChar* negNumberStylePattern = NULL; 248 int32_t negNumberStylePatternLen = 0; 249 // TODO: Java 250 // parse to check whether there is ";" separator in the numberStylePattern 251 UBool hasSeparator = false; 252 if (U_SUCCESS(ec)) { 253 for (int32_t styleCharIndex = 0; styleCharIndex < ptnLen; ++styleCharIndex) { 254 if (numberStylePattern[styleCharIndex] == gNumberPatternSeparator) { 255 hasSeparator = true; 256 // split the number style pattern into positive and negative 257 negNumberStylePattern = numberStylePattern + styleCharIndex + 1; 258 negNumberStylePatternLen = ptnLen - styleCharIndex - 1; 259 numberStylePatternLen = styleCharIndex; 260 } 261 } 262 } 263 ures_close(numberPatterns); 264 ures_close(rb); 265 266 if (U_FAILURE(ec)) { 267 return; 268 } 269 270 UResourceBundle *currRb = ures_open(U_ICUDATA_CURR, loc.getName(), &ec); 271 UResourceBundle *currencyRes = ures_getByKeyWithFallback(currRb, gCurrUnitPtnTag, NULL, &ec); 272 273 #ifdef CURRENCY_PLURAL_INFO_DEBUG 274 std::cout << "in set up\n"; 275 #endif 276 StringEnumeration* keywords = fPluralRules->getKeywords(ec); 277 if (U_SUCCESS(ec)) { 278 const char* pluralCount; 279 while ((pluralCount = keywords->next(NULL, ec)) != NULL) { 280 if ( U_SUCCESS(ec) ) { 281 int32_t ptnLen; 282 UErrorCode err = U_ZERO_ERROR; 283 const UChar* patternChars = ures_getStringByKeyWithFallback( 284 currencyRes, pluralCount, &ptnLen, &err); 285 if (U_SUCCESS(err) && ptnLen > 0) { 286 UnicodeString* pattern = new UnicodeString(patternChars, ptnLen); 287 #ifdef CURRENCY_PLURAL_INFO_DEBUG 288 char result_1[1000]; 289 pattern->extract(0, pattern->length(), result_1, "UTF-8"); 290 std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n"; 291 #endif 292 pattern->findAndReplace(gPart0, 293 UnicodeString(numberStylePattern, numberStylePatternLen)); 294 pattern->findAndReplace(gPart1, gTripleCurrencySign); 295 296 if (hasSeparator) { 297 UnicodeString negPattern(patternChars, ptnLen); 298 negPattern.findAndReplace(gPart0, 299 UnicodeString(negNumberStylePattern, negNumberStylePatternLen)); 300 negPattern.findAndReplace(gPart1, gTripleCurrencySign); 301 pattern->append(gNumberPatternSeparator); 302 pattern->append(negPattern); 303 } 304 #ifdef CURRENCY_PLURAL_INFO_DEBUG 305 pattern->extract(0, pattern->length(), result_1, "UTF-8"); 306 std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n"; 307 #endif 308 309 fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount), pattern, status); 310 } 311 } 312 } 313 } 314 delete keywords; 315 ures_close(currencyRes); 316 ures_close(currRb); 317 } 318 319 320 321 void 322 CurrencyPluralInfo::deleteHash(Hashtable* hTable) 323 { 324 if ( hTable == NULL ) { 325 return; 326 } 327 int32_t pos = -1; 328 const UHashElement* element = NULL; 329 while ( (element = hTable->nextElement(pos)) != NULL ) { 330 const UHashTok keyTok = element->key; 331 const UHashTok valueTok = element->value; 332 const UnicodeString* value = (UnicodeString*)valueTok.pointer; 333 delete value; 334 } 335 delete hTable; 336 hTable = NULL; 337 } 338 339 340 Hashtable* 341 CurrencyPluralInfo::initHash(UErrorCode& status) { 342 if ( U_FAILURE(status) ) { 343 return NULL; 344 } 345 Hashtable* hTable; 346 if ( (hTable = new Hashtable(TRUE, status)) == NULL ) { 347 status = U_MEMORY_ALLOCATION_ERROR; 348 return NULL; 349 } 350 hTable->setValueComparator(ValueComparator); 351 return hTable; 352 } 353 354 355 void 356 CurrencyPluralInfo::copyHash(const Hashtable* source, 357 Hashtable* target, 358 UErrorCode& status) { 359 if ( U_FAILURE(status) ) { 360 return; 361 } 362 int32_t pos = -1; 363 const UHashElement* element = NULL; 364 if ( source ) { 365 while ( (element = source->nextElement(pos)) != NULL ) { 366 const UHashTok keyTok = element->key; 367 const UnicodeString* key = (UnicodeString*)keyTok.pointer; 368 const UHashTok valueTok = element->value; 369 const UnicodeString* value = (UnicodeString*)valueTok.pointer; 370 UnicodeString* copy = new UnicodeString(*value); 371 target->put(UnicodeString(*key), copy, status); 372 if ( U_FAILURE(status) ) { 373 return; 374 } 375 } 376 } 377 } 378 379 380 U_NAMESPACE_END 381 382 #endif 383