Coverage Report

Created: 2018-09-25 14:53

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