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