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