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