intl/icu/source/i18n/numsys.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial