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

     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 */
    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"
    29 #if !UCONFIG_NO_FORMATTING
    31 U_NAMESPACE_BEGIN
    33 // Useful constants
    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";
    48 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumberingSystem)
    49 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumsysNameEnumeration)
    51     /**
    52      * Default Constructor.
    53      *
    54      * @draft ICU 4.2
    55      */
    57 NumberingSystem::NumberingSystem() {
    58      radix = 10;
    59      algorithmic = FALSE;
    60      UnicodeString defaultDigits = DEFAULT_DIGITS;
    61      desc.setTo(defaultDigits);
    62      uprv_strcpy(name,gLatn);
    63 }
    65     /**
    66      * Copy constructor.
    67      * @draft ICU 4.2
    68      */
    70 NumberingSystem::NumberingSystem(const NumberingSystem& other) 
    71 :  UObject(other) {
    72     *this=other;
    73 }
    75 NumberingSystem* U_EXPORT2
    76 NumberingSystem::createInstance(int32_t radix_in, UBool isAlgorithmic_in, const UnicodeString & desc_in, UErrorCode &status) {
    78     if (U_FAILURE(status)) {
    79         return NULL;
    80     }
    82     if ( radix_in < 2 ) {
    83         status = U_ILLEGAL_ARGUMENT_ERROR;
    84         return NULL;
    85     }
    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     }
    94     NumberingSystem *ns = new NumberingSystem();
    96     ns->setRadix(radix_in);
    97     ns->setDesc(desc_in);
    98     ns->setAlgorithmic(isAlgorithmic_in);
    99     ns->setName(NULL);
   100     return ns;
   102 }
   105 NumberingSystem* U_EXPORT2
   106 NumberingSystem::createInstance(const Locale & inLocale, UErrorCode& status) {
   108     if (U_FAILURE(status)) {
   109         return NULL;
   110     }
   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     }
   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             } 
   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     }
   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  }
   165 NumberingSystem* U_EXPORT2
   166 NumberingSystem::createInstance(UErrorCode& status) {
   167     return NumberingSystem::createInstance(Locale::getDefault(), status);
   168 }
   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;
   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);
   182     ures_getByKey(nsTop,gRadix,nsCurrent,&status);
   183     radix = ures_getInt(nsCurrent,&status);
   185     ures_getByKey(nsTop,gAlgorithmic,nsCurrent,&status);
   186     algorithmic = ures_getInt(nsCurrent,&status);
   188     UBool isAlgorithmic = ( algorithmic == 1 );
   190     ures_close(nsCurrent);
   191     ures_close(nsTop);
   192     ures_close(numberingSystemsInfo);
   194     if (U_FAILURE(status)) {
   195         status = U_UNSUPPORTED_ERROR;
   196         return NULL;
   197     }
   199     NumberingSystem* ns = NumberingSystem::createInstance(radix,isAlgorithmic,nsd,status);
   200     ns->setName(name);
   201     return ns;
   202 }
   204     /**
   205      * Destructor.
   206      * @draft ICU 4.2
   207      */
   208 NumberingSystem::~NumberingSystem() {
   209 }
   211 int32_t NumberingSystem::getRadix() const {
   212     return radix;
   213 }
   215 UnicodeString NumberingSystem::getDescription() const {
   216     return desc;
   217 }
   219 const char * NumberingSystem::getName() const {
   220     return name;
   221 }
   223 void NumberingSystem::setRadix(int32_t r) {
   224     radix = r;
   225 }
   227 void NumberingSystem::setAlgorithmic(UBool c) {
   228     algorithmic = c;
   229 }
   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 }
   246 StringEnumeration* NumberingSystem::getAvailableNames(UErrorCode &status) {
   248     static StringEnumeration* availableNames = NULL;
   250     if (U_FAILURE(status)) {
   251         return NULL;
   252     }
   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         }
   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         }
   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         }
   277         ures_close(numberingSystemsInfo);
   278         availableNames = new NumsysNameEnumeration(fNumsysNames,status);
   280     }
   282     return availableNames;
   283 }
   285 UBool NumberingSystem::isValidDigitString(const UnicodeString& str) {
   287     StringCharacterIterator it(str);
   288     UChar32 c;
   289     int32_t i = 0;
   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 }
   301 NumsysNameEnumeration::NumsysNameEnumeration(UVector *fNameList, UErrorCode& /*status*/) {
   302     pos=0;
   303     fNumsysNames = fNameList;
   304 }
   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 }
   314 void
   315 NumsysNameEnumeration::reset(UErrorCode& /*status*/) {
   316     pos=0;
   317 }
   319 int32_t
   320 NumsysNameEnumeration::count(UErrorCode& /*status*/) const {
   321     return (fNumsysNames==NULL) ? 0 : fNumsysNames->size();
   322 }
   324 NumsysNameEnumeration::~NumsysNameEnumeration() {
   325     delete fNumsysNames;
   326 }
   327 U_NAMESPACE_END
   329 #endif /* #if !UCONFIG_NO_FORMATTING */
   331 //eof

mercurial