1 /* 2 ******************************************************************************* 3 * Copyright (C) 2010-2015, 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 ) { 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 // TODO(ticket #11908): Init-once static cache, with u_cleanup() callback. 248 static StringEnumeration* availableNames = NULL; 249 250 if (U_FAILURE(status)) { 251 return NULL; 252 } 253 254 if ( availableNames == NULL ) { 255 // TODO: Simple array of UnicodeString objects, based on length of table resource? 256 LocalPointer<UVector> numsysNames(new UVector(uprv_deleteUObject, NULL, status), status); 257 if (U_FAILURE(status)) { 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 numsysNames->addElement(new UnicodeString(nsName, -1, US_INV),status); 274 ures_close(nsCurrent); 275 } 276 277 ures_close(numberingSystemsInfo); 278 if (U_FAILURE(status)) { 279 return NULL; 280 } 281 availableNames = new NumsysNameEnumeration(numsysNames.getAlias(), status); 282 if (availableNames == NULL) { 283 status = U_MEMORY_ALLOCATION_ERROR; 284 return NULL; 285 } 286 numsysNames.orphan(); // The names got adopted. 287 } 288 289 return availableNames; 290 } 291 292 NumsysNameEnumeration::NumsysNameEnumeration(UVector *numsysNames, UErrorCode& /*status*/) { 293 pos=0; 294 fNumsysNames = numsysNames; 295 } 296 297 const UnicodeString* 298 NumsysNameEnumeration::snext(UErrorCode& status) { 299 if (U_SUCCESS(status) && pos < fNumsysNames->size()) { 300 return (const UnicodeString*)fNumsysNames->elementAt(pos++); 301 } 302 return NULL; 303 } 304 305 void 306 NumsysNameEnumeration::reset(UErrorCode& /*status*/) { 307 pos=0; 308 } 309 310 int32_t 311 NumsysNameEnumeration::count(UErrorCode& /*status*/) const { 312 return (fNumsysNames==NULL) ? 0 : fNumsysNames->size(); 313 } 314 315 NumsysNameEnumeration::~NumsysNameEnumeration() { 316 delete fNumsysNames; 317 } 318 U_NAMESPACE_END 319 320 #endif /* #if !UCONFIG_NO_FORMATTING */ 321 322 //eof 323