]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/currpinf.cpp
ICU-57166.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / currpinf.cpp
CommitLineData
729e4ab9
A
1/*
2 *******************************************************************************
b331163b 3 * Copyright (C) 2009-2014, International Business Machines Corporation and
729e4ab9
A
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"
4388f060 22#include "unicode/numsys.h"
729e4ab9
A
23#include "cstring.h"
24#include "hash.h"
25#include "uresimp.h"
26#include "ureslocs.h"
27
28U_NAMESPACE_BEGIN
29
30
31static const UChar gNumberPatternSeparator = 0x3B; // ;
32
33U_CDECL_BEGIN
34
35/**
36 * @internal ICU 4.2
37 */
38static UBool U_CALLCONV ValueComparator(UHashTok val1, UHashTok val2);
39
40UBool
41U_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
47U_CDECL_END
48
49
50UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CurrencyPluralInfo)
51
52static const UChar gDefaultCurrencyPluralPattern[] = {'0', '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4, 0};
53static const UChar gTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
54static const UChar gPluralCountOther[] = {0x6F, 0x74, 0x68, 0x65, 0x72, 0};
55static const UChar gPart0[] = {0x7B, 0x30, 0x7D, 0};
56static const UChar gPart1[] = {0x7B, 0x31, 0x7D, 0};
57
58static const char gNumberElementsTag[]="NumberElements";
59static const char gLatnTag[]="latn";
60static const char gPatternsTag[]="patterns";
61static const char gDecimalFormatTag[]="decimalFormat";
62static const char gCurrUnitPtnTag[]="CurrencyUnitPatterns";
63
64CurrencyPluralInfo::CurrencyPluralInfo(UErrorCode& status)
65: fPluralCountToCurrencyUnitPattern(NULL),
66 fPluralRules(NULL),
67 fLocale(NULL) {
68 initialize(Locale::getDefault(), status);
69}
70
71CurrencyPluralInfo::CurrencyPluralInfo(const Locale& locale, UErrorCode& status)
72: fPluralCountToCurrencyUnitPattern(NULL),
73 fPluralRules(NULL),
74 fLocale(NULL) {
75 initialize(locale, status);
76}
77
78CurrencyPluralInfo::CurrencyPluralInfo(const CurrencyPluralInfo& info)
79: UObject(info),
80 fPluralCountToCurrencyUnitPattern(NULL),
81 fPluralRules(NULL),
82 fLocale(NULL) {
83 *this = info;
84}
85
86
87CurrencyPluralInfo&
88CurrencyPluralInfo::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
118CurrencyPluralInfo::~CurrencyPluralInfo() {
119 deleteHash(fPluralCountToCurrencyUnitPattern);
120 fPluralCountToCurrencyUnitPattern = NULL;
121 delete fPluralRules;
122 delete fLocale;
123 fPluralRules = NULL;
124 fLocale = NULL;
125}
126
127UBool
128CurrencyPluralInfo::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
146CurrencyPluralInfo*
147CurrencyPluralInfo::clone() const {
148 return new CurrencyPluralInfo(*this);
149}
150
151const PluralRules*
152CurrencyPluralInfo::getPluralRules() const {
153 return fPluralRules;
154}
155
156UnicodeString&
157CurrencyPluralInfo::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"
4388f060 163 if (pluralCount.compare(gPluralCountOther, 5)) {
729e4ab9 164 currencyPluralPattern =
4388f060 165 (UnicodeString*)fPluralCountToCurrencyUnitPattern->get(UnicodeString(TRUE, gPluralCountOther, 5));
729e4ab9
A
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
181const Locale&
182CurrencyPluralInfo::getLocale() const {
183 return *fLocale;
184}
185
186void
187CurrencyPluralInfo::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
198void
199CurrencyPluralInfo::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
208void
209CurrencyPluralInfo::setLocale(const Locale& loc, UErrorCode& status) {
210 initialize(loc, status);
211}
212
213
214void
215CurrencyPluralInfo::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
229void
230CurrencyPluralInfo::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
4388f060 243 NumberingSystem *ns = NumberingSystem::createInstance(loc,status);
729e4ab9
A
244 UErrorCode ec = U_ZERO_ERROR;
245 UResourceBundle *rb = ures_open(NULL, loc.getName(), &ec);
4388f060
A
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);
729e4ab9
A
249 int32_t ptnLen;
250 const UChar* numberStylePattern = ures_getStringByKeyWithFallback(rb, gDecimalFormatTag, &ptnLen, &ec);
4388f060
A
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 }
729e4ab9
A
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 }
4388f060
A
275
276 ures_close(numElements);
729e4ab9 277 ures_close(rb);
4388f060 278 delete ns;
729e4ab9
A
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
4388f060 306 pattern->findAndReplace(UnicodeString(TRUE, gPart0, 3),
729e4ab9 307 UnicodeString(numberStylePattern, numberStylePatternLen));
4388f060 308 pattern->findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
729e4ab9
A
309
310 if (hasSeparator) {
311 UnicodeString negPattern(patternChars, ptnLen);
4388f060 312 negPattern.findAndReplace(UnicodeString(TRUE, gPart0, 3),
729e4ab9 313 UnicodeString(negNumberStylePattern, negNumberStylePatternLen));
4388f060 314 negPattern.findAndReplace(UnicodeString(TRUE, gPart1, 3), UnicodeString(TRUE, gTripleCurrencySign, 3));
729e4ab9
A
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
4388f060 323 fPluralCountToCurrencyUnitPattern->put(UnicodeString(pluralCount, -1, US_INV), pattern, status);
729e4ab9
A
324 }
325 }
326 }
327 }
328 delete keywords;
329 ures_close(currencyRes);
330 ures_close(currRb);
331}
332
333
334
335void
336CurrencyPluralInfo::deleteHash(Hashtable* hTable)
337{
338 if ( hTable == NULL ) {
339 return;
340 }
b331163b 341 int32_t pos = UHASH_FIRST;
729e4ab9
A
342 const UHashElement* element = NULL;
343 while ( (element = hTable->nextElement(pos)) != NULL ) {
729e4ab9
A
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
353Hashtable*
354CurrencyPluralInfo::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
372void
373CurrencyPluralInfo::copyHash(const Hashtable* source,
374 Hashtable* target,
375 UErrorCode& status) {
376 if ( U_FAILURE(status) ) {
377 return;
378 }
b331163b 379 int32_t pos = UHASH_FIRST;
729e4ab9
A
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
397U_NAMESPACE_END
398
399#endif