• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *******************************************************************************
3  * Copyright (C) 2009-2011, 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
ValueComparator(UHashTok val1,UHashTok val2)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 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 
CurrencyPluralInfo(UErrorCode & status)63 CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status)
64 :   fPluralCountToCurrencyUnitPattern(NULL),
65     fPluralRules(NULL),
66     fLocale(NULL) {
67     initialize(Locale::getDefault(), status);
68 }
69 
CurrencyPluralInfo(const Locale & locale,UErrorCode & status)70 CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status)
71 :   fPluralCountToCurrencyUnitPattern(NULL),
72     fPluralRules(NULL),
73     fLocale(NULL) {
74     initialize(locale, status);
75 }
76 
CurrencyPluralInfo(const CurrencyPluralInfo & info)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&
operator =(const CurrencyPluralInfo & info)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 
~CurrencyPluralInfo()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
operator ==(const CurrencyPluralInfo & info) const127 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.fPluralCountToCurrencyUnitPattern)) {
136         std::cout << "same pattern\n";
137     }
138 #endif
139     return *fPluralRules == *info.fPluralRules &&
140            *fLocale == *info.fLocale &&
141            fPluralCountToCurrencyUnitPattern->equals(*info.fPluralCountToCurrencyUnitPattern);
142 }
143 
144 
145 CurrencyPluralInfo*
clone() const146 CurrencyPluralInfo::clone() const {
147     return new CurrencyPluralInfo(*this);
148 }
149 
150 const PluralRules*
getPluralRules() const151 CurrencyPluralInfo::getPluralRules() const {
152     return fPluralRules;
153 }
154 
155 UnicodeString&
getCurrencyPluralPattern(const UnicodeString & pluralCount,UnicodeString & result) const156 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, 5)) {
163             currencyPluralPattern =
164                 (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(UnicodeString(TRUE, gPluralCountOther, 5));
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&
getLocale() const181 CurrencyPluralInfo::getLocale() const {
182     return *fLocale;
183 }
184 
185 void
setPluralRules(const UnicodeString & ruleDescription,UErrorCode & status)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
setCurrencyPluralPattern(const UnicodeString & pluralCount,const UnicodeString & pattern,UErrorCode & status)198 CurrencyPluralInfo::setCurrencyPluralPattern(const UnicodeString& pluralCount,
199                                              const UnicodeString& pattern,
200                                              UErrorCode& status) {
201     if (U_SUCCESS(status)) {
202         fPluralCountToCurrencyUnitPattern->put(pluralCount, new UnicodeString(pattern), status);
203     }
204 }
205 
206 
207 void
setLocale(const Locale & loc,UErrorCode & status)208 CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) {
209     initialize(loc, status);
210 }
211 
212 
213 void
initialize(const Locale & loc,UErrorCode & status)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
setupCurrencyPluralPattern(const Locale & loc,UErrorCode & status)229 CurrencyPluralInfo::setupCurrencyPluralPattern(const Locale& loc, UErrorCode& status) {
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_getByKeyWithFallback(rb, gNumberElementsTag, rb, &ec);
245     rb = ures_getByKeyWithFallback(rb, gLatnTag, rb, &ec);
246     rb = ures_getByKeyWithFallback(rb, gPatternsTag, rb, &ec);
247     int32_t ptnLen;
248     const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &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; ++styleCharIndex) {
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, gCurrUnitPtnTag, 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, ptnLen);
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(UnicodeString(TRUE, gPart0, 3),
295                       UnicodeString(numberStylePattern, numberStylePatternLen));
296                     pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
297 
298                     if (hasSeparator) {
299                         UnicodeString negPattern(patternChars, ptnLen);
300                         negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3),
301                           UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
302                         negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
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(pluralCount, -1, US_INV), pattern, status);
312                 }
313             }
314         }
315     }
316     delete keywords;
317     ures_close(currencyRes);
318     ures_close(currRb);
319 }
320 
321 
322 
323 void
deleteHash(Hashtable * hTable)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*
initHash(UErrorCode & status)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     if ( U_FAILURE(status) ) {
353         delete hTable;
354         return NULL;
355     }
356     hTable->setValueComparator(ValueComparator);
357     return hTable;
358 }
359 
360 
361 void
copyHash(const Hashtable * source,Hashtable * target,UErrorCode & status)362 CurrencyPluralInfo::copyHash(const Hashtable* source,
363                            Hashtable* target,
364                            UErrorCode& status) {
365     if ( U_FAILURE(status) ) {
366         return;
367     }
368     int32_t pos = -1;
369     const UHashElement* element = NULL;
370     if ( source ) {
371         while ( (element = source->nextElement(pos)) != NULL ) {
372             const UHashTok keyTok = element->key;
373             const UnicodeString* key = (UnicodeString*)keyTok.pointer;
374             const UHashTok valueTok = element->value;
375             const UnicodeString* value = (UnicodeString*)valueTok.pointer;
376             UnicodeString* copy = new UnicodeString(*value);
377             target->put(UnicodeString(*key), copy, status);
378             if ( U_FAILURE(status) ) {
379                 return;
380             }
381         }
382     }
383 }
384 
385 
386 U_NAMESPACE_END
387 
388 #endif
389