Home | History | Annotate | Download | only in i18n
      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