Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/intl/icu/source/i18n/numsys.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) 2010-2015, International Business Machines Corporation and
6
* others. All Rights Reserved.
7
*******************************************************************************
8
*
9
*
10
* File NUMSYS.CPP
11
*
12
* Modification History:*
13
*   Date        Name        Description
14
*
15
********************************************************************************
16
*/
17
18
#include "unicode/utypes.h"
19
#include "unicode/localpointer.h"
20
#include "unicode/uchar.h"
21
#include "unicode/unistr.h"
22
#include "unicode/ures.h"
23
#include "unicode/ustring.h"
24
#include "unicode/uloc.h"
25
#include "unicode/schriter.h"
26
#include "unicode/numsys.h"
27
#include "cstring.h"
28
#include "uassert.h"
29
#include "uresimp.h"
30
#include "numsys_impl.h"
31
32
#if !UCONFIG_NO_FORMATTING
33
34
U_NAMESPACE_BEGIN
35
36
// Useful constants
37
38
0
#define DEFAULT_DIGITS UNICODE_STRING_SIMPLE("0123456789");
39
static const char gNumberingSystems[] = "numberingSystems";
40
static const char gNumberElements[] = "NumberElements";
41
static const char gDefault[] = "default";
42
static const char gNative[] = "native";
43
static const char gTraditional[] = "traditional";
44
static const char gFinance[] = "finance";
45
static const char gDesc[] = "desc";
46
static const char gRadix[] = "radix";
47
static const char gAlgorithmic[] = "algorithmic";
48
static const char gLatn[] = "latn";
49
50
51
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumberingSystem)
52
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumsysNameEnumeration)
53
54
    /**
55
     * Default Constructor.
56
     *
57
     * @draft ICU 4.2
58
     */
59
60
0
NumberingSystem::NumberingSystem() {
61
0
     radix = 10;
62
0
     algorithmic = FALSE;
63
0
     UnicodeString defaultDigits = DEFAULT_DIGITS;
64
0
     desc.setTo(defaultDigits);
65
0
     uprv_strcpy(name,gLatn);
66
0
}
67
68
    /**
69
     * Copy constructor.
70
     * @draft ICU 4.2
71
     */
72
73
NumberingSystem::NumberingSystem(const NumberingSystem& other) 
74
0
:  UObject(other) {
75
0
    *this=other;
76
0
}
77
78
NumberingSystem* U_EXPORT2
79
0
NumberingSystem::createInstance(int32_t radix_in, UBool isAlgorithmic_in, const UnicodeString & desc_in, UErrorCode &status) {
80
0
81
0
    if (U_FAILURE(status)) {
82
0
        return NULL;
83
0
    }
84
0
85
0
    if ( radix_in < 2 ) {
86
0
        status = U_ILLEGAL_ARGUMENT_ERROR;
87
0
        return NULL;
88
0
    }
89
0
90
0
    if ( !isAlgorithmic_in ) {
91
0
       if ( desc_in.countChar32() != radix_in ) {
92
0
           status = U_ILLEGAL_ARGUMENT_ERROR;
93
0
           return NULL;
94
0
       }
95
0
    }
96
0
97
0
    NumberingSystem *ns = new NumberingSystem();
98
0
99
0
    ns->setRadix(radix_in);
100
0
    ns->setDesc(desc_in);
101
0
    ns->setAlgorithmic(isAlgorithmic_in);
102
0
    ns->setName(NULL);
103
0
    return ns;
104
0
    
105
0
}
106
107
108
NumberingSystem* U_EXPORT2
109
0
NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) {
110
0
111
0
    if (U_FAILURE(status)) {
112
0
        return NULL;
113
0
    }
114
0
115
0
    UBool nsResolved = TRUE;
116
0
    UBool usingFallback = FALSE;
117
0
    char buffer[ULOC_KEYWORDS_CAPACITY];
118
0
    int32_t count = inLocale.getKeywordValue("numbers",buffer, sizeof(buffer),status);
119
0
    if (U_FAILURE(status) || status == U_STRING_NOT_TERMINATED_WARNING) {
120
0
        // the "numbers" keyword exceeds ULOC_KEYWORDS_CAPACITY; ignore and use default.
121
0
        count = 0;
122
0
        status = U_ZERO_ERROR;
123
0
    }
124
0
    if ( count > 0 ) { // @numbers keyword was specified in the locale
125
0
        U_ASSERT(count < ULOC_KEYWORDS_CAPACITY);
126
0
        buffer[count] = '\0'; // Make sure it is null terminated.
127
0
        if ( !uprv_strcmp(buffer,gDefault) || !uprv_strcmp(buffer,gNative) || 
128
0
             !uprv_strcmp(buffer,gTraditional) || !uprv_strcmp(buffer,gFinance)) {
129
0
            nsResolved = FALSE;
130
0
        }
131
0
    } else {
132
0
        uprv_strcpy(buffer,gDefault);
133
0
        nsResolved = FALSE;
134
0
    }
135
0
136
0
    if (!nsResolved) { // Resolve the numbering system ( default, native, traditional or finance ) into a "real" numbering system
137
0
        UErrorCode localStatus = U_ZERO_ERROR;
138
0
        UResourceBundle *resource = ures_open(NULL, inLocale.getName(), &localStatus);
139
0
        UResourceBundle *numberElementsRes = ures_getByKey(resource,gNumberElements,NULL,&localStatus);
140
0
        while (!nsResolved) {
141
0
            localStatus = U_ZERO_ERROR;
142
0
            count = 0;
143
0
            const UChar *nsName = ures_getStringByKeyWithFallback(numberElementsRes, buffer, &count, &localStatus);
144
0
            if ( count > 0 && count < ULOC_KEYWORDS_CAPACITY ) { // numbering system found
145
0
                u_UCharsToChars(nsName,buffer,count); 
146
0
                buffer[count] = '\0'; // Make sure it is null terminated.
147
0
                nsResolved = TRUE;
148
0
            } 
149
0
150
0
            if (!nsResolved) { // Fallback behavior per TR35 - traditional falls back to native, finance and native fall back to default
151
0
                if (!uprv_strcmp(buffer,gNative) || !uprv_strcmp(buffer,gFinance)) { 
152
0
                    uprv_strcpy(buffer,gDefault);
153
0
                } else if (!uprv_strcmp(buffer,gTraditional)) {
154
0
                    uprv_strcpy(buffer,gNative);
155
0
                } else { // If we get here we couldn't find even the default numbering system
156
0
                    usingFallback = TRUE;
157
0
                    nsResolved = TRUE;
158
0
                }
159
0
            }
160
0
        }
161
0
        ures_close(numberElementsRes);
162
0
        ures_close(resource);
163
0
    }
164
0
165
0
    if (usingFallback) {
166
0
        status = U_USING_FALLBACK_WARNING;
167
0
        NumberingSystem *ns = new NumberingSystem();
168
0
        return ns;
169
0
    } else {
170
0
        return NumberingSystem::createInstanceByName(buffer,status);
171
0
    }
172
0
 }
173
174
NumberingSystem* U_EXPORT2
175
0
NumberingSystem::createInstance(UErrorCode& status) {
176
0
    return NumberingSystem::createInstance(Locale::getDefault(), status);
177
0
}
178
179
NumberingSystem* U_EXPORT2
180
0
NumberingSystem::createInstanceByName(const char *name, UErrorCode& status) {
181
0
    UResourceBundle *numberingSystemsInfo = NULL;
182
0
    UResourceBundle *nsTop, *nsCurrent;
183
0
    int32_t radix = 10;
184
0
    int32_t algorithmic = 0;
185
0
186
0
    numberingSystemsInfo = ures_openDirect(NULL,gNumberingSystems, &status);
187
0
    nsCurrent = ures_getByKey(numberingSystemsInfo,gNumberingSystems,NULL,&status);
188
0
    nsTop = ures_getByKey(nsCurrent,name,NULL,&status);
189
0
    UnicodeString nsd = ures_getUnicodeStringByKey(nsTop,gDesc,&status);
190
0
191
0
    ures_getByKey(nsTop,gRadix,nsCurrent,&status);
192
0
    radix = ures_getInt(nsCurrent,&status);
193
0
194
0
    ures_getByKey(nsTop,gAlgorithmic,nsCurrent,&status);
195
0
    algorithmic = ures_getInt(nsCurrent,&status);
196
0
197
0
    UBool isAlgorithmic = ( algorithmic == 1 );
198
0
199
0
    ures_close(nsCurrent);
200
0
    ures_close(nsTop);
201
0
    ures_close(numberingSystemsInfo);
202
0
203
0
    if (U_FAILURE(status)) {
204
0
        status = U_UNSUPPORTED_ERROR;
205
0
        return NULL;
206
0
    }
207
0
208
0
    NumberingSystem* ns = NumberingSystem::createInstance(radix,isAlgorithmic,nsd,status);
209
0
    ns->setName(name);
210
0
    return ns;
211
0
}
212
213
    /**
214
     * Destructor.
215
     * @draft ICU 4.2
216
     */
217
0
NumberingSystem::~NumberingSystem() {
218
0
}
219
220
0
int32_t NumberingSystem::getRadix() const {
221
0
    return radix;
222
0
}
223
224
0
UnicodeString NumberingSystem::getDescription() const {
225
0
    return desc;
226
0
}
227
228
0
const char * NumberingSystem::getName() const {
229
0
    return name;
230
0
}
231
232
0
void NumberingSystem::setRadix(int32_t r) {
233
0
    radix = r;
234
0
}
235
236
0
void NumberingSystem::setAlgorithmic(UBool c) {
237
0
    algorithmic = c;
238
0
}
239
240
0
void NumberingSystem::setDesc(const UnicodeString &d) {
241
0
    desc.setTo(d);
242
0
}
243
0
void NumberingSystem::setName(const char *n) {
244
0
    if ( n == NULL ) {
245
0
        name[0] = (char) 0;
246
0
    } else {
247
0
        uprv_strncpy(name,n,NUMSYS_NAME_CAPACITY);
248
0
        name[NUMSYS_NAME_CAPACITY] = (char)0; // Make sure it is null terminated.
249
0
    }
250
0
}
251
0
UBool NumberingSystem::isAlgorithmic() const {
252
0
    return ( algorithmic );
253
0
}
254
255
0
StringEnumeration* NumberingSystem::getAvailableNames(UErrorCode &status) {
256
0
    // TODO(ticket #11908): Init-once static cache, with u_cleanup() callback.
257
0
    static StringEnumeration* availableNames = NULL;
258
0
259
0
    if (U_FAILURE(status)) {
260
0
        return NULL;
261
0
    }
262
0
263
0
    if ( availableNames == NULL ) {
264
0
        // TODO: Simple array of UnicodeString objects, based on length of table resource?
265
0
        LocalPointer<UVector> numsysNames(new UVector(uprv_deleteUObject, NULL, status), status);
266
0
        if (U_FAILURE(status)) {
267
0
            return NULL;
268
0
        }
269
0
        
270
0
        UErrorCode rbstatus = U_ZERO_ERROR;
271
0
        UResourceBundle *numberingSystemsInfo = ures_openDirect(NULL, "numberingSystems", &rbstatus);
272
0
        numberingSystemsInfo = ures_getByKey(numberingSystemsInfo,"numberingSystems",numberingSystemsInfo,&rbstatus);
273
0
        if(U_FAILURE(rbstatus)) {
274
0
            status = U_MISSING_RESOURCE_ERROR;
275
0
            ures_close(numberingSystemsInfo);
276
0
            return NULL;
277
0
        }
278
0
279
0
        while ( ures_hasNext(numberingSystemsInfo) ) {
280
0
            UResourceBundle *nsCurrent = ures_getNextResource(numberingSystemsInfo,NULL,&rbstatus);
281
0
            const char *nsName = ures_getKey(nsCurrent);
282
0
            numsysNames->addElement(new UnicodeString(nsName, -1, US_INV),status);
283
0
            ures_close(nsCurrent);
284
0
        }
285
0
286
0
        ures_close(numberingSystemsInfo);
287
0
        if (U_FAILURE(status)) {
288
0
            return NULL;
289
0
        }
290
0
        availableNames = new NumsysNameEnumeration(numsysNames.getAlias(), status);
291
0
        if (availableNames == NULL) {
292
0
            status = U_MEMORY_ALLOCATION_ERROR;
293
0
            return NULL;
294
0
        }
295
0
        numsysNames.orphan();  // The names got adopted.
296
0
    }
297
0
298
0
    return availableNames;
299
0
}
300
301
0
NumsysNameEnumeration::NumsysNameEnumeration(UVector *numsysNames, UErrorCode& /*status*/) {
302
0
    pos=0;
303
0
    fNumsysNames = numsysNames;
304
0
}
305
306
const UnicodeString*
307
0
NumsysNameEnumeration::snext(UErrorCode& status) {
308
0
    if (U_SUCCESS(status) && pos < fNumsysNames->size()) {
309
0
        return (const UnicodeString*)fNumsysNames->elementAt(pos++);
310
0
    }
311
0
    return NULL;
312
0
}
313
314
void
315
0
NumsysNameEnumeration::reset(UErrorCode& /*status*/) {
316
0
    pos=0;
317
0
}
318
319
int32_t
320
0
NumsysNameEnumeration::count(UErrorCode& /*status*/) const {
321
0
    return (fNumsysNames==NULL) ? 0 : fNumsysNames->size();
322
0
}
323
324
0
NumsysNameEnumeration::~NumsysNameEnumeration() {
325
0
    delete fNumsysNames;
326
0
}
327
U_NAMESPACE_END
328
329
#endif /* #if !UCONFIG_NO_FORMATTING */
330
331
//eof