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