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