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