]>
Commit | Line | Data |
---|---|---|
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 |