tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

numsys.cpp (11412B)


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