~ubuntu-branches/ubuntu/vivid/mozjs24/vivid

« back to all changes in this revision

Viewing changes to intl/icu/source/i18n/currpinf.cpp

  • Committer: Package Import Robot
  • Author(s): Tim Lunn
  • Date: 2014-02-11 21:55:34 UTC
  • Revision ID: package-import@ubuntu.com-20140211215534-m1zyq5aj59md3y07
Tags: upstream-24.2.0
ImportĀ upstreamĀ versionĀ 24.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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