Home | History | Annotate | Download | only in i18n
      1 /*
      2 *******************************************************************************
      3 * Copyright (C) 2010-2012, 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 || !isValidDigitString(desc_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() {
    212     return radix;
    213 }
    214 
    215 UnicodeString NumberingSystem::getDescription() {
    216     return desc;
    217 }
    218 
    219 const char * NumberingSystem::getName() {
    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 
    248     static StringEnumeration* availableNames = NULL;
    249 
    250     if (U_FAILURE(status)) {
    251         return NULL;
    252     }
    253 
    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         }
    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             fNumsysNames->addElement(new UnicodeString(nsName, -1, US_INV),status);
    274             ures_close(nsCurrent);
    275         }
    276 
    277         ures_close(numberingSystemsInfo);
    278         availableNames = new NumsysNameEnumeration(fNumsysNames,status);
    279 
    280     }
    281 
    282     return availableNames;
    283 }
    284 
    285 UBool NumberingSystem::isValidDigitString(const UnicodeString& str) {
    286 
    287     StringCharacterIterator it(str);
    288     UChar32 c;
    289     int32_t i = 0;
    290 
    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 }
    300 
    301 NumsysNameEnumeration::NumsysNameEnumeration(UVector *fNameList, UErrorCode& /*status*/) {
    302     pos=0;
    303     fNumsysNames = fNameList;
    304 }
    305 
    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 }
    313 
    314 void
    315 NumsysNameEnumeration::reset(UErrorCode& /*status*/) {
    316     pos=0;
    317 }
    318 
    319 int32_t
    320 NumsysNameEnumeration::count(UErrorCode& /*status*/) const {
    321     return (fNumsysNames==NULL) ? 0 : fNumsysNames->size();
    322 }
    323 
    324 NumsysNameEnumeration::~NumsysNameEnumeration() {
    325     delete fNumsysNames;
    326 }
    327 U_NAMESPACE_END
    328 
    329 #endif /* #if !UCONFIG_NO_FORMATTING */
    330 
    331 //eof
    332