1 /* 2 ******************************************************************************* 3 * Copyright (C) 2009, 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 26 U_NAMESPACE_BEGIN 27 28 29 static const UChar gNumberPatternSeparator = 0x3B; // ; 30 31 U_CDECL_BEGIN 32 33 /** 34 * @internal ICU 4.2 35 */ 36 static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2); 37 38 U_CDECL_END 39 40 UBool 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; 45 } 46 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 fPluralRules = PluralRules::createRules(ruleDescription, status); 187 } 188 } 189 190 191 void 192 CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount, 193 const UnicodeString& pattern, 194 UErrorCode& status) { 195 if (U_SUCCESS(status)) { 196 fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status); 197 } 198 } 199 200 201 void 202 CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) { 203 initialize(loc, status); 204 } 205 206 207 void 208 CurrencyPluralInfo::initialize(const Locale& loc, UErrorCode& status) { 209 if (U_FAILURE(status)) { 210 return; 211 } 212 delete fLocale; 213 fLocale = loc.clone(); 214 fPluralRules = PluralRules::forLocale(loc, status); 215 setupCurrencyPluralPattern(loc, status); 216 } 217 218 219 void 220 CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) { 221 if (U_FAILURE(status)) { 222 return; 223 } 224 225 fPluralCountToCurrencyUnitPattern = initHash(status); 226 if (U_FAILURE(status)) { 227 return; 228 } 229 230 UErrorCode ec = U_ZERO_ERROR; 231 UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec); 232 UResourceBundle *numberPatterns = ures_getByKey(rb, gNumberPatternsTag, NULL, &ec); 233 int32_t ptnLen; 234 // TODO: 0 to be NumberFormat::fNumberStyle 235 const UChar* numberStylePattern = ures_getStringByIndex(numberPatterns, 0, 236 &ptnLen, &ec); 237 int32_t numberStylePatternLen = ptnLen; 238 const UChar* negNumberStylePattern = NULL; 239 int32_t negNumberStylePatternLen = 0; 240 // TODO: Java 241 // parse to check whether there is ";" separator in the numberStylePattern 242 UBool hasSeparator = false; 243 if (U_SUCCESS(ec)) { 244 for (int32_t styleCharIndex = 0; styleCharIndex < ptnLen; ++styleCharIndex) { 245 if (numberStylePattern[styleCharIndex] == gNumberPatternSeparator) { 246 hasSeparator = true; 247 // split the number style pattern into positive and negative 248 negNumberStylePattern = numberStylePattern + styleCharIndex + 1; 249 negNumberStylePatternLen = ptnLen - styleCharIndex - 1; 250 numberStylePatternLen = styleCharIndex; 251 } 252 } 253 } 254 ures_close(numberPatterns); 255 256 if (U_FAILURE(ec)) { 257 ures_close(rb); 258 return; 259 } 260 261 UResourceBundle *currencyRes = ures_getByKeyWithFallback(rb, gCurrUnitPtnTag, NULL, &ec); 262 263 #ifdef CURRENCY_PLURAL_INFO_DEBUG 264 std::cout << "in set up\n"; 265 #endif 266 StringEnumeration* keywords = fPluralRules->getKeywords(ec); 267 if (U_SUCCESS(ec)) { 268 const char* pluralCount; 269 while ((pluralCount = keywords->next(NULL, ec)) != NULL) { 270 if ( U_SUCCESS(ec) ) { 271 int32_t ptnLen; 272 UErrorCode err = U_ZERO_ERROR; 273 const UChar* patternChars = ures_getStringByKeyWithFallback( 274 currencyRes, pluralCount, &ptnLen, &err); 275 if (U_SUCCESS(err) && ptnLen > 0) { 276 UnicodeString* pattern = new UnicodeString(patternChars, ptnLen); 277 #ifdef CURRENCY_PLURAL_INFO_DEBUG 278 char result_1[1000]; 279 pattern->extract(0, pattern->length(), result_1, "UTF-8"); 280 std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n"; 281 #endif 282 pattern->findAndReplace(gPart0, 283 UnicodeString(numberStylePattern, numberStylePatternLen)); 284 pattern->findAndReplace(gPart1, gTripleCurrencySign); 285 286 if (hasSeparator) { 287 UnicodeString negPattern(patternChars, ptnLen); 288 negPattern.findAndReplace(gPart0, 289 UnicodeString(negNumberStylePattern, negNumberStylePatternLen)); 290 negPattern.findAndReplace(gPart1, gTripleCurrencySign); 291 pattern->append(gNumberPatternSeparator); 292 pattern->append(negPattern); 293 } 294 #ifdef CURRENCY_PLURAL_INFO_DEBUG 295 pattern->extract(0, pattern->length(), result_1, "UTF-8"); 296 std::cout << "pluralCount: " << pluralCount << "; pattern: " << result_1 << "\n"; 297 #endif 298 299 fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount), pattern, status); 300 } 301 } 302 } 303 } 304 delete keywords; 305 ures_close(currencyRes); 306 ures_close(rb); 307 } 308 309 310 311 void 312 CurrencyPluralInfo::deleteHash(Hashtable* hTable) 313 { 314 if ( hTable == NULL ) { 315 return; 316 } 317 int32_t pos = -1; 318 const UHashElement* element = NULL; 319 while ( (element = hTable->nextElement(pos)) != NULL ) { 320 const UHashTok keyTok = element->key; 321 const UHashTok valueTok = element->value; 322 const UnicodeString* value = (UnicodeString*)valueTok.pointer; 323 delete value; 324 } 325 delete hTable; 326 hTable = NULL; 327 } 328 329 330 Hashtable* 331 CurrencyPluralInfo::initHash(UErrorCode& status) { 332 if ( U_FAILURE(status) ) { 333 return NULL; 334 } 335 Hashtable* hTable; 336 if ( (hTable = new Hashtable(TRUE, status)) == NULL ) { 337 status = U_MEMORY_ALLOCATION_ERROR; 338 return NULL; 339 } 340 hTable->setValueCompartor(ValueComparator); 341 return hTable; 342 } 343 344 345 void 346 CurrencyPluralInfo::copyHash(const Hashtable* source, 347 Hashtable* target, 348 UErrorCode& status) { 349 if ( U_FAILURE(status) ) { 350 return; 351 } 352 int32_t pos = -1; 353 const UHashElement* element = NULL; 354 if ( source ) { 355 while ( (element = source->nextElement(pos)) != NULL ) { 356 const UHashTok keyTok = element->key; 357 const UnicodeString* key = (UnicodeString*)keyTok.pointer; 358 const UHashTok valueTok = element->value; 359 const UnicodeString* value = (UnicodeString*)valueTok.pointer; 360 UnicodeString* copy = new UnicodeString(*value); 361 target->put(UnicodeString(*key), copy, status); 362 if ( U_FAILURE(status) ) { 363 return; 364 } 365 } 366 } 367 } 368 369 370 U_NAMESPACE_END 371 372 #endif 373