tor-browser

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

unum.cpp (30317B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 *   Copyright (C) 1996-2015, International Business Machines
      6 *   Corporation and others.  All Rights Reserved.
      7 *******************************************************************************
      8 * Modification History:
      9 *
     10 *   Date        Name        Description
     11 *   06/24/99    helena      Integrated Alan's NF enhancements and Java2 bug fixes
     12 *******************************************************************************
     13 */
     14 
     15 #include "unicode/utypes.h"
     16 
     17 #if !UCONFIG_NO_FORMATTING
     18 
     19 #include "unicode/unum.h"
     20 
     21 #include "unicode/uloc.h"
     22 #include "unicode/numfmt.h"
     23 #include "unicode/decimfmt.h"
     24 #include "unicode/rbnf.h"
     25 #include "unicode/compactdecimalformat.h"
     26 #include "unicode/ustring.h"
     27 #include "unicode/fmtable.h"
     28 #include "unicode/dcfmtsym.h"
     29 #include "unicode/curramt.h"
     30 #include "unicode/localpointer.h"
     31 #include "unicode/measfmt.h"
     32 #include "unicode/udisplaycontext.h"
     33 #include "uassert.h"
     34 #include "cpputils.h"
     35 #include "cstring.h"
     36 #include "putilimp.h"
     37 
     38 
     39 U_NAMESPACE_USE
     40 
     41 
     42 U_CAPI UNumberFormat* U_EXPORT2
     43 unum_open(  UNumberFormatStyle    style,
     44            const    char16_t*    pattern,
     45            int32_t            patternLength,
     46            const    char*     locale,
     47            UParseError*       parseErr,
     48            UErrorCode*        status) {
     49    if(U_FAILURE(*status)) {
     50        return nullptr;
     51    }
     52 
     53    NumberFormat *retVal = nullptr;
     54 
     55    switch(style) {
     56    case UNUM_DECIMAL:
     57    case UNUM_CURRENCY:
     58    case UNUM_PERCENT:
     59    case UNUM_SCIENTIFIC:
     60    case UNUM_CURRENCY_ISO:
     61    case UNUM_CURRENCY_PLURAL:
     62    case UNUM_CURRENCY_ACCOUNTING:
     63    case UNUM_CASH_CURRENCY:
     64    case UNUM_CURRENCY_STANDARD:
     65        retVal = NumberFormat::createInstance(Locale(locale), style, *status);
     66        break;
     67 
     68    case UNUM_PATTERN_DECIMAL: {
     69        UParseError tErr;
     70        /* UnicodeString can handle the case when patternLength = -1. */
     71        const UnicodeString pat(pattern, patternLength);
     72 
     73        if(parseErr==nullptr){
     74            parseErr = &tErr;
     75        }
     76 
     77        DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale(locale), *status);
     78        if(syms == nullptr) {
     79            *status = U_MEMORY_ALLOCATION_ERROR;
     80            return nullptr;
     81        }
     82        if (U_FAILURE(*status)) {
     83            delete syms;
     84            return nullptr;
     85        }
     86 
     87        retVal = new DecimalFormat(pat, syms, *parseErr, *status);
     88        if(retVal == nullptr) {
     89            delete syms;
     90        }
     91    } break;
     92 
     93 #if U_HAVE_RBNF
     94    case UNUM_PATTERN_RULEBASED: {
     95        UParseError tErr;
     96        /* UnicodeString can handle the case when patternLength = -1. */
     97        const UnicodeString pat(pattern, patternLength);
     98        
     99        if(parseErr==nullptr){
    100            parseErr = &tErr;
    101        }
    102        
    103        retVal = new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
    104    } break;
    105 
    106    case UNUM_SPELLOUT:
    107        retVal = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
    108        break;
    109 
    110    case UNUM_ORDINAL:
    111        retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
    112        break;
    113 
    114    case UNUM_DURATION:
    115        retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
    116        break;
    117 
    118    case UNUM_NUMBERING_SYSTEM: {
    119        // if the locale ID specifies a numbering system, go through NumberFormat::createInstance()
    120        // to handle it properly (we have to specify UNUM_DEFAULT to get it to handle the numbering
    121        // system, but we'll always get a RuleBasedNumberFormat back); otherwise, just go ahead and
    122        // create a RuleBasedNumberFormat ourselves
    123        UErrorCode localErr = U_ZERO_ERROR;
    124        Locale localeObj(locale);
    125        int32_t keywordLength = localeObj.getKeywordValue("numbers", nullptr, 0, localErr);
    126        if (keywordLength > 0) {
    127            retVal = NumberFormat::createInstance(localeObj, UNUM_DEFAULT, *status);
    128        } else {
    129            retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, localeObj, *status);
    130        }
    131    } break;
    132 #endif
    133 
    134    case UNUM_DECIMAL_COMPACT_SHORT:
    135        retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_SHORT, *status);
    136        break;
    137 
    138    case UNUM_DECIMAL_COMPACT_LONG:
    139        retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_LONG, *status);
    140        break;
    141 
    142    default:
    143        *status = U_UNSUPPORTED_ERROR;
    144        return nullptr;
    145    }
    146 
    147    if(retVal == nullptr && U_SUCCESS(*status)) {
    148        *status = U_MEMORY_ALLOCATION_ERROR;
    149    }
    150 
    151    if (U_FAILURE(*status) && retVal != nullptr) {
    152        delete retVal;
    153        retVal = nullptr;
    154    }
    155 
    156    return reinterpret_cast<UNumberFormat *>(retVal);
    157 }
    158 
    159 U_CAPI void U_EXPORT2
    160 unum_close(UNumberFormat* fmt)
    161 {
    162    delete (NumberFormat*) fmt;
    163 }
    164 
    165 U_CAPI UNumberFormat* U_EXPORT2
    166 unum_clone(const UNumberFormat *fmt,
    167       UErrorCode *status)
    168 {
    169    if(U_FAILURE(*status))
    170        return nullptr;
    171 
    172    Format* res = nullptr;
    173    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    174    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    175    if (df != nullptr) {
    176        res = df->clone();
    177    } else {
    178        const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
    179        U_ASSERT(rbnf != nullptr);
    180        res = rbnf->clone();
    181    }
    182 
    183    if (res == nullptr) {
    184        *status = U_MEMORY_ALLOCATION_ERROR;
    185        return nullptr;
    186    }
    187    
    188    return (UNumberFormat*) res;
    189 }
    190 
    191 U_CAPI int32_t U_EXPORT2
    192 unum_format(    const    UNumberFormat*    fmt,
    193        int32_t           number,
    194        char16_t*            result,
    195        int32_t           resultLength,
    196        UFieldPosition    *pos,
    197        UErrorCode*       status)
    198 {
    199        return unum_formatInt64(fmt, number, result, resultLength, pos, status);
    200 }
    201 
    202 U_CAPI int32_t U_EXPORT2
    203 unum_formatInt64(const UNumberFormat* fmt,
    204        int64_t         number,
    205        char16_t*          result,
    206        int32_t         resultLength,
    207        UFieldPosition *pos,
    208        UErrorCode*     status)
    209 {
    210    if(U_FAILURE(*status))
    211        return -1;
    212    
    213    UnicodeString res;
    214    if(!(result==nullptr && resultLength==0)) {
    215        // nullptr destination for pure preflighting: empty dummy string
    216        // otherwise, alias the destination buffer
    217        res.setTo(result, 0, resultLength);
    218    }
    219    
    220    FieldPosition fp;
    221 
    222    if (pos != nullptr)
    223        fp.setField(pos->field);
    224    
    225    ((const NumberFormat*)fmt)->format(number, res, fp, *status);
    226 
    227    if (pos != nullptr) {
    228        pos->beginIndex = fp.getBeginIndex();
    229        pos->endIndex = fp.getEndIndex();
    230    }
    231    
    232    return res.extract(result, resultLength, *status);
    233 }
    234 
    235 U_CAPI int32_t U_EXPORT2
    236 unum_formatDouble(    const    UNumberFormat*  fmt,
    237            double          number,
    238            char16_t*          result,
    239            int32_t         resultLength,
    240            UFieldPosition  *pos, /* 0 if ignore */
    241            UErrorCode*     status)
    242 {
    243 
    244  if(U_FAILURE(*status)) return -1;
    245 
    246  UnicodeString res;
    247  if(!(result==nullptr && resultLength==0)) {
    248    // nullptr destination for pure preflighting: empty dummy string
    249    // otherwise, alias the destination buffer
    250    res.setTo(result, 0, resultLength);
    251  }
    252 
    253  FieldPosition fp;
    254 
    255  if (pos != nullptr)
    256    fp.setField(pos->field);
    257  
    258  ((const NumberFormat*)fmt)->format(number, res, fp, *status);
    259 
    260  if (pos != nullptr) {
    261    pos->beginIndex = fp.getBeginIndex();
    262    pos->endIndex = fp.getEndIndex();
    263  }
    264  
    265  return res.extract(result, resultLength, *status);
    266 }
    267 
    268 U_CAPI int32_t U_EXPORT2
    269 unum_formatDoubleForFields(const UNumberFormat* format,
    270                           double number,
    271                           char16_t* result,
    272                           int32_t resultLength,
    273                           UFieldPositionIterator* fpositer,
    274                           UErrorCode* status)
    275 {
    276    if (U_FAILURE(*status))
    277        return -1;
    278 
    279    if (result == nullptr ? resultLength != 0 : resultLength < 0) {
    280        *status = U_ILLEGAL_ARGUMENT_ERROR;
    281        return -1;
    282    }
    283 
    284    UnicodeString res;
    285    if (result != nullptr) {
    286        // nullptr destination for pure preflighting: empty dummy string
    287        // otherwise, alias the destination buffer
    288        res.setTo(result, 0, resultLength);
    289    }
    290 
    291    ((const NumberFormat*)format)->format(number, res, (FieldPositionIterator*)fpositer, *status);
    292 
    293    return res.extract(result, resultLength, *status);
    294 }
    295 
    296 U_CAPI int32_t U_EXPORT2 
    297 unum_formatDecimal(const    UNumberFormat*  fmt,
    298            const char *    number,
    299            int32_t         length,
    300            char16_t*          result,
    301            int32_t         resultLength,
    302            UFieldPosition  *pos, /* 0 if ignore */
    303            UErrorCode*     status) {
    304 
    305    if(U_FAILURE(*status)) {
    306        return -1;
    307    }
    308    if ((result == nullptr && resultLength != 0) || resultLength < 0) {
    309        *status = U_ILLEGAL_ARGUMENT_ERROR;
    310        return -1;
    311    }
    312 
    313    FieldPosition fp;
    314    if (pos != nullptr) {
    315        fp.setField(pos->field);
    316    }
    317 
    318    if (length < 0) {
    319        length = static_cast<int32_t>(uprv_strlen(number));
    320    }
    321    StringPiece numSP(number, length);
    322    Formattable numFmtbl(numSP, *status);
    323 
    324    UnicodeString resultStr;
    325    if (resultLength > 0) {
    326        // Alias the destination buffer.
    327        resultStr.setTo(result, 0, resultLength);
    328    }
    329    ((const NumberFormat*)fmt)->format(numFmtbl, resultStr, fp, *status);
    330    if (pos != nullptr) {
    331        pos->beginIndex = fp.getBeginIndex();
    332        pos->endIndex = fp.getEndIndex();
    333    }
    334    return resultStr.extract(result, resultLength, *status);
    335 }
    336 
    337 
    338 
    339 
    340 U_CAPI int32_t U_EXPORT2 
    341 unum_formatDoubleCurrency(const UNumberFormat* fmt,
    342                          double number,
    343                          char16_t* currency,
    344                          char16_t* result,
    345                          int32_t resultLength,
    346                          UFieldPosition* pos, /* ignored if 0 */
    347                          UErrorCode* status) {
    348    if (U_FAILURE(*status)) return -1;
    349 
    350    UnicodeString res;
    351    if (!(result==nullptr && resultLength==0)) {
    352        // nullptr destination for pure preflighting: empty dummy string
    353        // otherwise, alias the destination buffer
    354        res.setTo(result, 0, resultLength);
    355    }
    356    
    357    FieldPosition fp;
    358    if (pos != nullptr) {
    359        fp.setField(pos->field);
    360    }
    361    CurrencyAmount *tempCurrAmnt = new CurrencyAmount(number, currency, *status);
    362    // Check for null pointer.
    363    if (tempCurrAmnt == nullptr) {
    364        *status = U_MEMORY_ALLOCATION_ERROR;
    365        return -1;
    366    }
    367    Formattable n(tempCurrAmnt);
    368    ((const NumberFormat*)fmt)->format(n, res, fp, *status);
    369 
    370    if (pos != nullptr) {
    371        pos->beginIndex = fp.getBeginIndex();
    372        pos->endIndex = fp.getEndIndex();
    373    }
    374  
    375    return res.extract(result, resultLength, *status);
    376 }
    377 
    378 static void
    379 parseRes(Formattable& res,
    380         const   UNumberFormat*  fmt,
    381         const   char16_t*          text,
    382         int32_t         textLength,
    383         int32_t         *parsePos /* 0 = start */,
    384         UErrorCode      *status)
    385 {
    386    if(U_FAILURE(*status))
    387        return;
    388    
    389    const UnicodeString src(static_cast<UBool>(textLength == -1), text, textLength);
    390    ParsePosition pp;
    391 
    392    if (parsePos != nullptr)
    393        pp.setIndex(*parsePos);
    394    
    395    reinterpret_cast<const NumberFormat*>(fmt)->parse(src, res, pp);
    396    
    397    if(pp.getErrorIndex() != -1) {
    398        *status = U_PARSE_ERROR;
    399        if (parsePos != nullptr) {
    400            *parsePos = pp.getErrorIndex();
    401        }
    402    } else if (parsePos != nullptr) {
    403        *parsePos = pp.getIndex();
    404    }
    405 }
    406 
    407 U_CAPI int32_t U_EXPORT2
    408 unum_parse(    const   UNumberFormat*  fmt,
    409        const   char16_t*          text,
    410        int32_t         textLength,
    411        int32_t         *parsePos /* 0 = start */,
    412        UErrorCode      *status)
    413 {
    414    Formattable res;
    415    parseRes(res, fmt, text, textLength, parsePos, status);
    416    return res.getLong(*status);
    417 }
    418 
    419 U_CAPI int64_t U_EXPORT2
    420 unum_parseInt64(    const   UNumberFormat*  fmt,
    421        const   char16_t*          text,
    422        int32_t         textLength,
    423        int32_t         *parsePos /* 0 = start */,
    424        UErrorCode      *status)
    425 {
    426    Formattable res;
    427    parseRes(res, fmt, text, textLength, parsePos, status);
    428    return res.getInt64(*status);
    429 }
    430 
    431 U_CAPI double U_EXPORT2
    432 unum_parseDouble(    const   UNumberFormat*  fmt,
    433            const   char16_t*          text,
    434            int32_t         textLength,
    435            int32_t         *parsePos /* 0 = start */,
    436            UErrorCode      *status)
    437 {
    438    Formattable res;
    439    parseRes(res, fmt, text, textLength, parsePos, status);
    440    return res.getDouble(*status);
    441 }
    442 
    443 U_CAPI int32_t U_EXPORT2
    444 unum_parseDecimal(const UNumberFormat*  fmt,
    445            const char16_t*    text,
    446            int32_t         textLength,
    447            int32_t         *parsePos /* 0 = start */,
    448            char            *outBuf,
    449            int32_t         outBufLength,
    450            UErrorCode      *status)
    451 {
    452    if (U_FAILURE(*status)) {
    453        return -1;
    454    }
    455    if ((outBuf == nullptr && outBufLength != 0) || outBufLength < 0) {
    456        *status = U_ILLEGAL_ARGUMENT_ERROR;
    457        return -1;
    458    }
    459    Formattable res;
    460    parseRes(res, fmt, text, textLength, parsePos, status);
    461    StringPiece sp = res.getDecimalNumber(*status);
    462    if (U_FAILURE(*status)) {
    463       return -1;
    464    } else if (sp.size() > outBufLength) {
    465        *status = U_BUFFER_OVERFLOW_ERROR;
    466    } else if (sp.size() == outBufLength) {
    467        uprv_strncpy(outBuf, sp.data(), sp.size());
    468        *status = U_STRING_NOT_TERMINATED_WARNING;
    469    } else {
    470        U_ASSERT(outBufLength > 0);
    471        uprv_strcpy(outBuf, sp.data());
    472    }
    473    return sp.size();
    474 }
    475 
    476 U_CAPI double U_EXPORT2
    477 unum_parseDoubleCurrency(const UNumberFormat* fmt,
    478                         const char16_t* text,
    479                         int32_t textLength,
    480                         int32_t* parsePos, /* 0 = start */
    481                         char16_t* currency,
    482                         UErrorCode* status) {
    483    double doubleVal = 0.0;
    484    currency[0] = 0;
    485    if (U_FAILURE(*status)) {
    486        return doubleVal;
    487    }
    488    const UnicodeString src(textLength == -1, text, textLength);
    489    ParsePosition pp;
    490    if (parsePos != nullptr) {
    491        pp.setIndex(*parsePos);
    492    }
    493    *status = U_PARSE_ERROR; // assume failure, reset if succeed
    494    LocalPointer<CurrencyAmount> currAmt(((const NumberFormat*)fmt)->parseCurrency(src, pp));
    495    if (pp.getErrorIndex() != -1) {
    496        if (parsePos != nullptr) {
    497            *parsePos = pp.getErrorIndex();
    498        }
    499    } else {
    500        if (parsePos != nullptr) {
    501            *parsePos = pp.getIndex();
    502        }
    503        if (pp.getIndex() > 0) {
    504            *status = U_ZERO_ERROR;
    505            u_strcpy(currency, currAmt->getISOCurrency());
    506            doubleVal = currAmt->getNumber().getDouble(*status);
    507        }
    508    }
    509    return doubleVal;
    510 }
    511 
    512 U_CAPI const char* U_EXPORT2
    513 unum_getAvailable(int32_t index)
    514 {
    515    return uloc_getAvailable(index);
    516 }
    517 
    518 U_CAPI int32_t U_EXPORT2
    519 unum_countAvailable()
    520 {
    521    return uloc_countAvailable();
    522 }
    523 
    524 U_CAPI bool U_EXPORT2
    525 unum_hasAttribute(const UNumberFormat*          fmt,
    526          UNumberFormatAttribute  attr)
    527 {
    528    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    529    bool isDecimalFormat = dynamic_cast<const DecimalFormat*>(nf) != nullptr;
    530    
    531    switch (attr) {
    532        case UNUM_LENIENT_PARSE:
    533        case UNUM_MAX_INTEGER_DIGITS:
    534        case UNUM_MIN_INTEGER_DIGITS:
    535        case UNUM_INTEGER_DIGITS:
    536        case UNUM_MAX_FRACTION_DIGITS:
    537        case UNUM_MIN_FRACTION_DIGITS:
    538        case UNUM_FRACTION_DIGITS:
    539        case UNUM_ROUNDING_MODE:
    540            return true;
    541        default:
    542            return isDecimalFormat;
    543    }
    544 }
    545 
    546 U_CAPI int32_t U_EXPORT2
    547 unum_getAttribute(const UNumberFormat*          fmt,
    548          UNumberFormatAttribute  attr)
    549 {
    550    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    551    if (attr == UNUM_LENIENT_PARSE) {
    552        // Supported for all subclasses
    553        return nf->isLenient();
    554    }
    555    else if (attr == UNUM_MAX_INTEGER_DIGITS) {
    556        return nf->getMaximumIntegerDigits();
    557    }
    558    else if (attr == UNUM_MIN_INTEGER_DIGITS) {
    559        return nf->getMinimumIntegerDigits();
    560    }
    561    else if (attr == UNUM_INTEGER_DIGITS) {
    562        // TODO: what should this return?
    563        return nf->getMinimumIntegerDigits();
    564    }
    565    else if (attr == UNUM_MAX_FRACTION_DIGITS) {
    566        return nf->getMaximumFractionDigits();
    567    }
    568    else if (attr == UNUM_MIN_FRACTION_DIGITS) {
    569        return nf->getMinimumFractionDigits();
    570    }
    571    else if (attr == UNUM_FRACTION_DIGITS) {
    572        // TODO: what should this return?
    573        return nf->getMinimumFractionDigits();
    574    }
    575    else if (attr == UNUM_ROUNDING_MODE) {
    576        return nf->getRoundingMode();
    577    }
    578 
    579    // The remaining attributes are only supported for DecimalFormat
    580    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    581    if (df != nullptr) {
    582        UErrorCode ignoredStatus = U_ZERO_ERROR;
    583        return df->getAttribute(attr, ignoredStatus);
    584    }
    585 
    586    return -1;
    587 }
    588 
    589 U_CAPI void U_EXPORT2
    590 unum_setAttribute(    UNumberFormat*          fmt,
    591            UNumberFormatAttribute  attr,
    592            int32_t                 newValue)
    593 {
    594    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    595    if (attr == UNUM_LENIENT_PARSE) {
    596        // Supported for all subclasses
    597        // keep this here as the class may not be a DecimalFormat
    598        return nf->setLenient(newValue != 0);
    599    }
    600    else if (attr == UNUM_MAX_INTEGER_DIGITS) {
    601        return nf->setMaximumIntegerDigits(newValue);
    602    }
    603    else if (attr == UNUM_MIN_INTEGER_DIGITS) {
    604        return nf->setMinimumIntegerDigits(newValue);
    605    }
    606    else if (attr == UNUM_INTEGER_DIGITS) {
    607        nf->setMinimumIntegerDigits(newValue);
    608        return nf->setMaximumIntegerDigits(newValue);
    609    }
    610    else if (attr == UNUM_MAX_FRACTION_DIGITS) {
    611        return nf->setMaximumFractionDigits(newValue);
    612    }
    613    else if (attr == UNUM_MIN_FRACTION_DIGITS) {
    614        return nf->setMinimumFractionDigits(newValue);
    615    }
    616    else if (attr == UNUM_FRACTION_DIGITS) {
    617        nf->setMinimumFractionDigits(newValue);
    618        return nf->setMaximumFractionDigits(newValue);
    619    }
    620    else if (attr == UNUM_ROUNDING_MODE) {
    621        return nf->setRoundingMode((NumberFormat::ERoundingMode)newValue);
    622    }
    623 
    624    // The remaining attributes are only supported for DecimalFormat
    625    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    626    if (df != nullptr) {
    627        UErrorCode ignoredStatus = U_ZERO_ERROR;
    628        df->setAttribute(attr, newValue, ignoredStatus);
    629    }
    630 }
    631 
    632 U_CAPI double U_EXPORT2
    633 unum_getDoubleAttribute(const UNumberFormat*          fmt,
    634          UNumberFormatAttribute  attr)
    635 {
    636    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    637    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    638    if (df != nullptr &&  attr == UNUM_ROUNDING_INCREMENT) {
    639        return df->getRoundingIncrement();
    640    } else {
    641        return -1.0;
    642    }
    643 }
    644 
    645 U_CAPI void U_EXPORT2
    646 unum_setDoubleAttribute(    UNumberFormat*          fmt,
    647            UNumberFormatAttribute  attr,
    648            double                 newValue)
    649 {
    650    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    651    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    652    if (df != nullptr && attr == UNUM_ROUNDING_INCREMENT) {   
    653        df->setRoundingIncrement(newValue);
    654    }
    655 }
    656 
    657 U_CAPI int32_t U_EXPORT2
    658 unum_getTextAttribute(const UNumberFormat*  fmt,
    659            UNumberFormatTextAttribute      tag,
    660            char16_t*                          result,
    661            int32_t                         resultLength,
    662            UErrorCode*                     status)
    663 {
    664    if(U_FAILURE(*status))
    665        return -1;
    666 
    667    UnicodeString res;
    668    if(!(result==nullptr && resultLength==0)) {
    669        // nullptr destination for pure preflighting: empty dummy string
    670        // otherwise, alias the destination buffer
    671        res.setTo(result, 0, resultLength);
    672    }
    673 
    674    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    675    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    676    const RuleBasedNumberFormat* rbnf = nullptr;    // cast is below for performance
    677    if (df != nullptr) {
    678        switch(tag) {
    679        case UNUM_POSITIVE_PREFIX:
    680            df->getPositivePrefix(res);
    681            break;
    682 
    683        case UNUM_POSITIVE_SUFFIX:
    684            df->getPositiveSuffix(res);
    685            break;
    686 
    687        case UNUM_NEGATIVE_PREFIX:
    688            df->getNegativePrefix(res);
    689            break;
    690 
    691        case UNUM_NEGATIVE_SUFFIX:
    692            df->getNegativeSuffix(res);
    693            break;
    694 
    695        case UNUM_PADDING_CHARACTER:
    696            res = df->getPadCharacterString();
    697            break;
    698 
    699        case UNUM_CURRENCY_CODE:
    700            res = UnicodeString(df->getCurrency());
    701            break;
    702 
    703        default:
    704            *status = U_UNSUPPORTED_ERROR;
    705            return -1;
    706        }
    707    } else  if ((rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf)) != nullptr) {
    708        U_ASSERT(rbnf != nullptr);
    709        if (tag == UNUM_DEFAULT_RULESET) {
    710            res = rbnf->getDefaultRuleSetName();
    711        } else if (tag == UNUM_PUBLIC_RULESETS) {
    712            int32_t count = rbnf->getNumberOfRuleSetNames();
    713            for (int i = 0; i < count; ++i) {
    714                res += rbnf->getRuleSetName(i);
    715                res += (char16_t)0x003b; // semicolon
    716            }
    717        } else {
    718            *status = U_UNSUPPORTED_ERROR;
    719            return -1;
    720        }
    721    } else {
    722        *status = U_UNSUPPORTED_ERROR;
    723        return -1;
    724    }
    725 
    726    return res.extract(result, resultLength, *status);
    727 }
    728 
    729 U_CAPI void U_EXPORT2
    730 unum_setTextAttribute(    UNumberFormat*                    fmt,
    731            UNumberFormatTextAttribute      tag,
    732            const    char16_t*                            newValue,
    733            int32_t                            newValueLength,
    734            UErrorCode                        *status)
    735 {
    736    if(U_FAILURE(*status))
    737        return;
    738 
    739    UnicodeString val(newValue, newValueLength);
    740    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    741    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    742    if (df != nullptr) {
    743      switch(tag) {
    744      case UNUM_POSITIVE_PREFIX:
    745        df->setPositivePrefix(val);
    746        break;
    747        
    748      case UNUM_POSITIVE_SUFFIX:
    749        df->setPositiveSuffix(val);
    750        break;
    751        
    752      case UNUM_NEGATIVE_PREFIX:
    753        df->setNegativePrefix(val);
    754        break;
    755        
    756      case UNUM_NEGATIVE_SUFFIX:
    757        df->setNegativeSuffix(val);
    758        break;
    759        
    760      case UNUM_PADDING_CHARACTER:
    761        df->setPadCharacter(val);
    762        break;
    763        
    764      case UNUM_CURRENCY_CODE:
    765        df->setCurrency(val.getTerminatedBuffer(), *status);
    766        break;
    767        
    768      default:
    769        *status = U_UNSUPPORTED_ERROR;
    770        break;
    771      }
    772    } else {
    773      RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf);
    774      U_ASSERT(rbnf != nullptr);
    775      if (tag == UNUM_DEFAULT_RULESET) {
    776        rbnf->setDefaultRuleSet(val, *status);
    777      } else {
    778        *status = U_UNSUPPORTED_ERROR;
    779      }
    780    }
    781 }
    782 
    783 U_CAPI int32_t U_EXPORT2
    784 unum_toPattern(    const    UNumberFormat*          fmt,
    785        UBool                  isPatternLocalized,
    786        char16_t*                  result,
    787        int32_t                 resultLength,
    788        UErrorCode*             status)
    789 {
    790    if(U_FAILURE(*status))
    791        return -1;
    792    
    793    UnicodeString pat;
    794    if(!(result==nullptr && resultLength==0)) {
    795        // nullptr destination for pure preflighting: empty dummy string
    796        // otherwise, alias the destination buffer
    797        pat.setTo(result, 0, resultLength);
    798    }
    799 
    800    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
    801    const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
    802    const RuleBasedNumberFormat* rbnf = nullptr;    // cast is below for performance
    803    if (df != nullptr) {
    804      if(isPatternLocalized)
    805        df->toLocalizedPattern(pat);
    806      else
    807        df->toPattern(pat);
    808    } else if ((rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf)) != nullptr) {
    809        pat = rbnf->getRules();
    810    } else {
    811        // leave `pat` empty
    812    }
    813    return pat.extract(result, resultLength, *status);
    814 }
    815 
    816 U_CAPI int32_t U_EXPORT2
    817 unum_getSymbol(const UNumberFormat *fmt,
    818               UNumberFormatSymbol symbol,
    819               char16_t *buffer,
    820               int32_t size,
    821               UErrorCode *status) UPRV_NO_SANITIZE_UNDEFINED {
    822    if(status==nullptr || U_FAILURE(*status)) {
    823        return 0;
    824    }
    825    if(fmt==nullptr || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
    826        *status=U_ILLEGAL_ARGUMENT_ERROR;
    827        return 0;
    828    }
    829    const NumberFormat *nf = reinterpret_cast<const NumberFormat *>(fmt);
    830    const DecimalFormat *dcf = dynamic_cast<const DecimalFormat *>(nf);
    831    if (dcf == nullptr) {
    832      *status = U_UNSUPPORTED_ERROR;
    833      return 0;
    834    }
    835 
    836    return dcf->
    837      getDecimalFormatSymbols()->
    838        getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol).
    839          extract(buffer, size, *status);
    840 }
    841 
    842 U_CAPI void U_EXPORT2
    843 unum_setSymbol(UNumberFormat *fmt,
    844               UNumberFormatSymbol symbol,
    845               const char16_t *value,
    846               int32_t length,
    847               UErrorCode *status) UPRV_NO_SANITIZE_UNDEFINED {
    848    if(status==nullptr || U_FAILURE(*status)) {
    849        return;
    850    }
    851    if(fmt==nullptr || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==nullptr || length<-1) {
    852        *status=U_ILLEGAL_ARGUMENT_ERROR;
    853        return;
    854    }
    855    NumberFormat *nf = reinterpret_cast<NumberFormat *>(fmt);
    856    DecimalFormat *dcf = dynamic_cast<DecimalFormat *>(nf);
    857    if (dcf == nullptr) {
    858      *status = U_UNSUPPORTED_ERROR;
    859      return;
    860    }
    861 
    862    DecimalFormatSymbols symbols(*dcf->getDecimalFormatSymbols());
    863    symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol,
    864        UnicodeString(value, length));  /* UnicodeString can handle the case when length = -1. */
    865    dcf->setDecimalFormatSymbols(symbols);
    866 }
    867 
    868 U_CAPI void U_EXPORT2
    869 unum_applyPattern(  UNumberFormat  *fmt,
    870                    UBool          localized,
    871                    const char16_t *pattern,
    872                    int32_t        patternLength,
    873                    UParseError    *parseError,
    874                    UErrorCode*    status)
    875 {
    876    UErrorCode tStatus = U_ZERO_ERROR;
    877    UParseError tParseError;
    878    
    879    if(parseError == nullptr){
    880        parseError = &tParseError;
    881    }
    882    
    883    if(status==nullptr){
    884        status = &tStatus;
    885    }
    886    
    887    int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
    888    const UnicodeString pat((char16_t*)pattern, len, len);
    889 
    890    // Verify if the object passed is a DecimalFormat object
    891    NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
    892    DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
    893    if (df != nullptr) {
    894      if(localized) {
    895        df->applyLocalizedPattern(pat,*parseError, *status);
    896      } else {
    897        df->applyPattern(pat,*parseError, *status);
    898      }
    899    } else {
    900      *status = U_UNSUPPORTED_ERROR;
    901      return;
    902    }
    903 }
    904 
    905 U_CAPI const char* U_EXPORT2
    906 unum_getLocaleByType(const UNumberFormat *fmt,
    907                     ULocDataLocaleType type,
    908                     UErrorCode* status)
    909 {
    910    if (fmt == nullptr) {
    911        if (U_SUCCESS(*status)) {
    912            *status = U_ILLEGAL_ARGUMENT_ERROR;
    913        }
    914        return nullptr;
    915    }
    916    return ((const Format*)fmt)->getLocaleID(type, *status);
    917 }
    918 
    919 U_CAPI void U_EXPORT2
    920 unum_setContext(UNumberFormat* fmt, UDisplayContext value, UErrorCode* status)
    921 {
    922    if (U_FAILURE(*status)) {
    923        return;
    924    }
    925    ((NumberFormat*)fmt)->setContext(value, *status);
    926 }
    927 
    928 U_CAPI UDisplayContext U_EXPORT2
    929 unum_getContext(const UNumberFormat *fmt, UDisplayContextType type, UErrorCode* status)
    930 {
    931    if (U_FAILURE(*status)) {
    932        return (UDisplayContext)0;
    933    }
    934    return ((const NumberFormat*)fmt)->getContext(type, *status);
    935 }
    936 
    937 U_CAPI UFormattable * U_EXPORT2
    938 unum_parseToUFormattable(const UNumberFormat* fmt,
    939                         UFormattable *result,
    940                         const char16_t* text,
    941                         int32_t textLength,
    942                         int32_t* parsePos, /* 0 = start */
    943                         UErrorCode* status) {
    944  UFormattable *newFormattable = nullptr;
    945  if (U_FAILURE(*status)) return result;
    946  if (fmt == nullptr || (text==nullptr && textLength!=0)) {
    947    *status = U_ILLEGAL_ARGUMENT_ERROR;
    948    return result;
    949  }
    950  if (result == nullptr) { // allocate if not allocated.
    951    newFormattable = result = ufmt_open(status);
    952  }
    953  parseRes(*(Formattable::fromUFormattable(result)), fmt, text, textLength, parsePos, status);
    954  if (U_FAILURE(*status) && newFormattable != nullptr) {
    955    ufmt_close(newFormattable);
    956    result = nullptr; // deallocate if there was a parse error
    957  }
    958  return result;
    959 }
    960 
    961 U_CAPI int32_t U_EXPORT2
    962 unum_formatUFormattable(const UNumberFormat* fmt,
    963                        const UFormattable *number,
    964                        char16_t *result,
    965                        int32_t resultLength,
    966                        UFieldPosition *pos, /* ignored if 0 */
    967                        UErrorCode *status) {
    968    if (U_FAILURE(*status)) {
    969      return 0;
    970    }
    971    if (fmt == nullptr || number==nullptr ||
    972        (result==nullptr ? resultLength!=0 : resultLength<0)) {
    973      *status = U_ILLEGAL_ARGUMENT_ERROR;
    974      return 0;
    975    }
    976    UnicodeString res(result, 0, resultLength);
    977 
    978    FieldPosition fp;
    979 
    980    if (pos != nullptr)
    981        fp.setField(pos->field);
    982 
    983    ((const NumberFormat*)fmt)->format(*(Formattable::fromUFormattable(number)), res, fp, *status);
    984 
    985    if (pos != nullptr) {
    986        pos->beginIndex = fp.getBeginIndex();
    987        pos->endIndex = fp.getEndIndex();
    988    }
    989 
    990    return res.extract(result, resultLength, *status);
    991 }
    992 
    993 #endif /* #if !UCONFIG_NO_FORMATTING */