tor-browser

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

umsg.cpp (20323B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 *
      6 *   Copyright (C) 1999-2012, International Business Machines
      7 *   Corporation and others.  All Rights Reserved.
      8 *
      9 *******************************************************************************
     10 *   file name:  umsg.cpp
     11 *   encoding:   UTF-8
     12 *   tab size:   8 (not used)
     13 *   indentation:4
     14 *
     15 * This is a C wrapper to MessageFormat C++ API.
     16 *
     17 *   Change history:
     18 *
     19 *   08/5/2001  Ram         Added C wrappers for C++ API. Changed implementation of old API's
     20 *                          Removed pattern parser.
     21 * 
     22 */
     23 
     24 #include "unicode/utypes.h"
     25 
     26 #if !UCONFIG_NO_FORMATTING
     27 
     28 #include "unicode/umsg.h"
     29 #include "unicode/ustring.h"
     30 #include "unicode/fmtable.h"
     31 #include "unicode/msgfmt.h"
     32 #include "unicode/unistr.h"
     33 #include "cpputils.h"
     34 #include "uassert.h"
     35 #include "ustr_imp.h"
     36 
     37 U_NAMESPACE_BEGIN
     38 /**
     39 * This class isolates our access to private internal methods of
     40 * MessageFormat.  It is never instantiated; it exists only for C++
     41 * access management.
     42 */
     43 class MessageFormatAdapter {
     44 public:
     45    static const Formattable::Type* getArgTypeList(const MessageFormat& m,
     46                                                   int32_t& count);
     47    static UBool hasArgTypeConflicts(const MessageFormat& m) {
     48        return m.hasArgTypeConflicts;
     49    }
     50 };
     51 const Formattable::Type*
     52 MessageFormatAdapter::getArgTypeList(const MessageFormat& m,
     53                                     int32_t& count) {
     54    return m.getArgTypeList(count);
     55 }
     56 U_NAMESPACE_END
     57 
     58 U_NAMESPACE_USE
     59 
     60 U_CAPI int32_t
     61 u_formatMessage(const char  *locale,
     62                const char16_t *pattern,
     63                int32_t     patternLength,
     64                char16_t    *result,
     65                int32_t     resultLength,
     66                UErrorCode  *status,
     67                ...)
     68 {
     69    va_list    ap;
     70    int32_t actLen;        
     71    //argument checking deferred to subsequent method calls
     72    // start vararg processing
     73    va_start(ap, status);
     74 
     75    actLen = u_vformatMessage(locale,pattern,patternLength,result,resultLength,ap,status);
     76    // end vararg processing
     77    va_end(ap);
     78 
     79    return actLen;
     80 }
     81 
     82 U_CAPI int32_t U_EXPORT2
     83 u_vformatMessage(   const char  *locale,
     84                    const char16_t *pattern,
     85                    int32_t     patternLength,
     86                    char16_t    *result,
     87                    int32_t     resultLength,
     88                    va_list     ap,
     89                    UErrorCode  *status)
     90 
     91 {
     92    //argument checking deferred to subsequent method calls
     93    UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,nullptr,status);
     94    int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
     95    umsg_close(fmt);
     96    return retVal;
     97 }
     98 
     99 U_CAPI int32_t
    100 u_formatMessageWithError(const char *locale,
    101                        const char16_t *pattern,
    102                        int32_t     patternLength,
    103                        char16_t    *result,
    104                        int32_t     resultLength,
    105                        UParseError *parseError,
    106                        UErrorCode  *status,
    107                        ...)
    108 {
    109    va_list    ap;
    110    int32_t actLen;
    111    //argument checking deferred to subsequent method calls
    112    // start vararg processing
    113    va_start(ap, status);
    114 
    115    actLen = u_vformatMessageWithError(locale,pattern,patternLength,result,resultLength,parseError,ap,status);
    116 
    117    // end vararg processing
    118    va_end(ap);
    119    return actLen;
    120 }
    121 
    122 U_CAPI int32_t U_EXPORT2
    123 u_vformatMessageWithError(  const char  *locale,
    124                            const char16_t *pattern,
    125                            int32_t     patternLength,
    126                            char16_t    *result,
    127                            int32_t     resultLength,
    128                            UParseError *parseError,
    129                            va_list     ap,
    130                            UErrorCode  *status)
    131 
    132 {
    133    //argument checking deferred to subsequent method calls
    134    UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,parseError,status);
    135    int32_t retVal = umsg_vformat(fmt,result,resultLength,ap,status);
    136    umsg_close(fmt);
    137    return retVal;
    138 }
    139 
    140 
    141 // For parse, do the reverse of format:
    142 //  1. Call through to the C++ APIs
    143 //  2. Just assume the user passed in enough arguments.
    144 //  3. Iterate through each formattable returned, and assign to the arguments
    145 U_CAPI void
    146 u_parseMessage( const char   *locale,
    147                const char16_t  *pattern,
    148                int32_t      patternLength,
    149                const char16_t  *source,
    150                int32_t      sourceLength,
    151                UErrorCode   *status,
    152                ...)
    153 {
    154    va_list    ap;
    155    //argument checking deferred to subsequent method calls
    156 
    157    // start vararg processing
    158    va_start(ap, status);
    159 
    160    u_vparseMessage(locale,pattern,patternLength,source,sourceLength,ap,status);
    161    // end vararg processing
    162    va_end(ap);
    163 }
    164 
    165 U_CAPI void U_EXPORT2
    166 u_vparseMessage(const char  *locale,
    167                const char16_t *pattern,
    168                int32_t     patternLength,
    169                const char16_t *source,
    170                int32_t     sourceLength,
    171                va_list     ap,
    172                UErrorCode  *status)
    173 {
    174    //argument checking deferred to subsequent method calls
    175    UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,nullptr,status);
    176    int32_t count = 0;
    177    umsg_vparse(fmt,source,sourceLength,&count,ap,status);
    178    umsg_close(fmt);
    179 }
    180 
    181 U_CAPI void
    182 u_parseMessageWithError(const char  *locale,
    183                        const char16_t *pattern,
    184                        int32_t     patternLength,
    185                        const char16_t *source,
    186                        int32_t     sourceLength,
    187                        UParseError *error,
    188                        UErrorCode  *status,
    189                        ...)
    190 {
    191    va_list    ap;
    192 
    193    //argument checking deferred to subsequent method calls
    194 
    195    // start vararg processing
    196    va_start(ap, status);
    197 
    198    u_vparseMessageWithError(locale,pattern,patternLength,source,sourceLength,ap,error,status);
    199    // end vararg processing
    200    va_end(ap);
    201 }
    202 U_CAPI void U_EXPORT2
    203 u_vparseMessageWithError(const char  *locale,
    204                         const char16_t *pattern,
    205                         int32_t     patternLength,
    206                         const char16_t *source,
    207                         int32_t     sourceLength,
    208                         va_list     ap,
    209                         UParseError *error,
    210                         UErrorCode* status)
    211 {
    212    //argument checking deferred to subsequent method calls
    213    UMessageFormat *fmt = umsg_open(pattern,patternLength,locale,error,status);
    214    int32_t count = 0;
    215    umsg_vparse(fmt,source,sourceLength,&count,ap,status);
    216    umsg_close(fmt);
    217 }
    218 //////////////////////////////////////////////////////////////////////////////////
    219 //
    220 //  Message format C API
    221 //
    222 /////////////////////////////////////////////////////////////////////////////////
    223 
    224 
    225 U_CAPI UMessageFormat* U_EXPORT2
    226 umsg_open(  const char16_t  *pattern,
    227            int32_t         patternLength,
    228            const  char     *locale,
    229            UParseError     *parseError,
    230            UErrorCode      *status)
    231 {
    232    //check arguments
    233    if(status==nullptr || U_FAILURE(*status))
    234    {
    235      return nullptr;
    236    }
    237    if(pattern==nullptr||patternLength<-1){
    238        *status=U_ILLEGAL_ARGUMENT_ERROR;
    239        return nullptr;
    240    }
    241 
    242    UParseError tErr;
    243    if(parseError==nullptr)
    244    {
    245        parseError = &tErr;
    246    }
    247 
    248    int32_t len = (patternLength == -1 ? u_strlen(pattern) : patternLength);
    249    UnicodeString patString(patternLength == -1, pattern, len);
    250 
    251    MessageFormat* retVal = new MessageFormat(patString,Locale(locale),*parseError,*status);
    252    if(retVal == nullptr) {
    253        *status = U_MEMORY_ALLOCATION_ERROR;
    254        return nullptr;
    255    }
    256    if (U_SUCCESS(*status) && MessageFormatAdapter::hasArgTypeConflicts(*retVal)) {
    257        *status = U_ARGUMENT_TYPE_MISMATCH;
    258    }
    259    return (UMessageFormat*)retVal;
    260 }
    261 
    262 U_CAPI void U_EXPORT2
    263 umsg_close(UMessageFormat* format)
    264 {
    265    //check arguments
    266    if(format==nullptr){
    267        return;
    268    }
    269    delete (MessageFormat*) format;
    270 }
    271 
    272 U_CAPI UMessageFormat U_EXPORT2
    273 umsg_clone(const UMessageFormat *fmt,
    274           UErrorCode *status)
    275 {
    276    //check arguments
    277    if(status==nullptr || U_FAILURE(*status)){
    278        return nullptr;
    279    }
    280    if(fmt==nullptr){
    281        *status = U_ILLEGAL_ARGUMENT_ERROR;
    282        return nullptr;
    283    }
    284    UMessageFormat retVal = (UMessageFormat)((MessageFormat*)fmt)->clone();
    285    if (retVal == nullptr) {
    286        *status = U_MEMORY_ALLOCATION_ERROR;
    287        return nullptr;
    288    }
    289    return retVal;    
    290 }
    291 
    292 U_CAPI void  U_EXPORT2
    293 umsg_setLocale(UMessageFormat *fmt, const char* locale)
    294 {
    295    //check arguments
    296    if(fmt==nullptr){
    297        return;
    298    }
    299    ((MessageFormat*)fmt)->setLocale(Locale(locale));   
    300 }
    301 
    302 U_CAPI const char*  U_EXPORT2
    303 umsg_getLocale(const UMessageFormat *fmt)
    304 {
    305    //check arguments
    306    if(fmt==nullptr){
    307        return "";
    308    }
    309    return ((const MessageFormat*)fmt)->getLocale().getName();
    310 }
    311 
    312 U_CAPI void  U_EXPORT2
    313 umsg_applyPattern(UMessageFormat *fmt,
    314                           const char16_t* pattern,
    315                           int32_t patternLength,
    316                           UParseError* parseError,
    317                           UErrorCode* status)
    318 {
    319    //check arguments
    320    UParseError tErr;
    321    if(status ==nullptr||U_FAILURE(*status)){
    322        return ;
    323    }
    324    if(fmt==nullptr || (pattern==nullptr && patternLength!=0) || patternLength<-1) {
    325        *status=U_ILLEGAL_ARGUMENT_ERROR;
    326        return ;
    327    }
    328 
    329    if(parseError==nullptr){
    330      parseError = &tErr;
    331    }
    332 
    333    // UnicodeString(pattern, -1) calls u_strlen().
    334    ((MessageFormat*)fmt)->applyPattern(UnicodeString(pattern,patternLength),*parseError,*status);  
    335 }
    336 
    337 U_CAPI int32_t  U_EXPORT2
    338 umsg_toPattern(const UMessageFormat *fmt,
    339               char16_t* result,
    340               int32_t resultLength,
    341               UErrorCode* status)
    342 {
    343    //check arguments
    344    if(status ==nullptr||U_FAILURE(*status)){
    345        return -1;
    346    }
    347    if (fmt == nullptr || resultLength < 0 || (resultLength > 0 && result == nullptr)) {
    348        *status=U_ILLEGAL_ARGUMENT_ERROR;
    349        return -1;
    350    }
    351 
    352 
    353    UnicodeString res;
    354    if(!(result==nullptr && resultLength==0)) {
    355        // nullptr destination for pure preflighting: empty dummy string
    356        // otherwise, alias the destination buffer
    357        res.setTo(result, 0, resultLength);
    358    }
    359    ((const MessageFormat*)fmt)->toPattern(res);
    360    return res.extract(result, resultLength, *status);
    361 }
    362 
    363 U_CAPI int32_t
    364 umsg_format(    const UMessageFormat *fmt,
    365                char16_t       *result,
    366                int32_t        resultLength,
    367                UErrorCode     *status,
    368                ...)
    369 {
    370    va_list    ap;
    371    int32_t actLen;  
    372    //argument checking deferred to last method call umsg_vformat which
    373    //saves time when arguments are valid and we don't care when arguments are not
    374    //since we return an error anyway
    375 
    376    
    377    // start vararg processing
    378    va_start(ap, status);
    379 
    380    actLen = umsg_vformat(fmt,result,resultLength,ap,status);
    381 
    382    // end vararg processing
    383    va_end(ap);
    384 
    385    return actLen;
    386 }
    387 
    388 U_CAPI int32_t U_EXPORT2
    389 umsg_vformat(   const UMessageFormat *fmt,
    390                char16_t       *result,
    391                int32_t        resultLength,
    392                va_list        ap,
    393                UErrorCode     *status)
    394 {
    395    //check arguments
    396    if (status == nullptr || U_FAILURE(*status))
    397    {
    398        return -1;
    399    }
    400    if (fmt == nullptr || resultLength < 0 || (resultLength > 0 && result == nullptr)) {
    401        *status=U_ILLEGAL_ARGUMENT_ERROR;
    402        return -1;
    403    }
    404 
    405    int32_t count =0;
    406    const Formattable::Type* argTypes =
    407        MessageFormatAdapter::getArgTypeList(*(const MessageFormat*)fmt, count);
    408    // Allocate at least one element.  Allocating an array of length
    409    // zero causes problems on some platforms (e.g. Win32).
    410    Formattable* args = new Formattable[count ? count : 1];
    411 
    412    // iterate through the vararg list, and get the arguments out
    413    for(int32_t i = 0; i < count; ++i) {
    414        
    415        char16_t *stringVal;
    416        double tDouble=0;
    417        int32_t tInt =0;
    418        int64_t tInt64 = 0;
    419        UDate tempDate = 0;
    420        switch(argTypes[i]) {
    421        case Formattable::kDate:
    422            tempDate = va_arg(ap, UDate);
    423            args[i].setDate(tempDate);
    424            break;
    425            
    426        case Formattable::kDouble:
    427            tDouble =va_arg(ap, double);
    428            args[i].setDouble(tDouble);
    429            break;
    430            
    431        case Formattable::kLong:
    432            tInt = va_arg(ap, int32_t);
    433            args[i].setLong(tInt);
    434            break;
    435 
    436        case Formattable::kInt64:
    437            tInt64 = va_arg(ap, int64_t);
    438            args[i].setInt64(tInt64);
    439            break;
    440            
    441        case Formattable::kString:
    442            // For some reason, a temporary is needed
    443            stringVal = va_arg(ap, char16_t*);
    444            if(stringVal){
    445                args[i].setString(UnicodeString(stringVal));
    446            }else{
    447                *status=U_ILLEGAL_ARGUMENT_ERROR;
    448            }
    449            break;
    450            
    451        case Formattable::kArray:
    452            // throw away this argument
    453            // this is highly platform-dependent, and probably won't work
    454            // so, if you try to skip arguments in the list (and not use them)
    455            // you'll probably crash
    456            va_arg(ap, int);
    457            break;
    458 
    459        case Formattable::kObject:
    460            // Unused argument number. Read and ignore a pointer argument.
    461            va_arg(ap, void*);
    462            break;
    463 
    464        default:
    465            // Unknown/unsupported argument type.
    466            UPRV_UNREACHABLE_EXIT;
    467        }
    468    }
    469    UnicodeString resultStr;
    470    FieldPosition fieldPosition(FieldPosition::DONT_CARE);
    471    
    472    /* format the message */
    473    ((const MessageFormat*)fmt)->format(args,count,resultStr,fieldPosition,*status);
    474 
    475    delete[] args;
    476 
    477    if(U_FAILURE(*status)){
    478        return -1;
    479    }
    480 
    481    return resultStr.extract(result, resultLength, *status);
    482 }
    483 
    484 U_CAPI void
    485 umsg_parse( const UMessageFormat *fmt,
    486            const char16_t *source,
    487            int32_t        sourceLength,
    488            int32_t        *count,
    489            UErrorCode     *status,
    490            ...)
    491 {
    492    va_list    ap;
    493    //argument checking deferred to last method call umsg_vparse which
    494    //saves time when arguments are valid and we don't care when arguments are not
    495    //since we return an error anyway
    496 
    497    // start vararg processing
    498    va_start(ap, status);
    499 
    500    umsg_vparse(fmt,source,sourceLength,count,ap,status);
    501 
    502    // end vararg processing
    503    va_end(ap);
    504 }
    505 
    506 U_CAPI void U_EXPORT2
    507 umsg_vparse(const UMessageFormat *fmt,
    508            const char16_t *source,
    509            int32_t        sourceLength,
    510            int32_t        *count,
    511            va_list        ap,
    512            UErrorCode     *status)
    513 {
    514    //check arguments
    515    if(status==nullptr||U_FAILURE(*status))
    516    {
    517        return;
    518    }
    519    if(fmt==nullptr||source==nullptr || sourceLength<-1 || count==nullptr){
    520        *status=U_ILLEGAL_ARGUMENT_ERROR;
    521        return;
    522    }
    523    if(sourceLength==-1){
    524        sourceLength=u_strlen(source);
    525    }
    526 
    527    UnicodeString srcString(source,sourceLength);
    528    Formattable *args = ((const MessageFormat*)fmt)->parse(srcString,*count,*status);
    529    UDate *aDate;
    530    double *aDouble;
    531    char16_t *aString;
    532    int32_t* aInt;
    533    int64_t* aInt64;
    534    UnicodeString temp;
    535    int len =0;
    536    // assign formattables to varargs
    537    for(int32_t i = 0; i < *count; i++) {
    538        switch(args[i].getType()) {
    539 
    540        case Formattable::kDate:
    541            aDate = va_arg(ap, UDate*);
    542            if(aDate){
    543                *aDate = args[i].getDate();
    544            }else{
    545                *status=U_ILLEGAL_ARGUMENT_ERROR;
    546            }
    547            break;
    548 
    549        case Formattable::kDouble:
    550            aDouble = va_arg(ap, double*);
    551            if(aDouble){
    552                *aDouble = args[i].getDouble();
    553            }else{
    554                *status=U_ILLEGAL_ARGUMENT_ERROR;
    555            }
    556            break;
    557 
    558        case Formattable::kLong:
    559            aInt = va_arg(ap, int32_t*);
    560            if(aInt){
    561                *aInt = args[i].getLong();
    562            }else{
    563                *status=U_ILLEGAL_ARGUMENT_ERROR;
    564            }
    565            break;
    566 
    567        case Formattable::kInt64:
    568            aInt64 = va_arg(ap, int64_t*);
    569            if(aInt64){
    570                *aInt64 = args[i].getInt64();
    571            }else{
    572                *status=U_ILLEGAL_ARGUMENT_ERROR;
    573            }
    574            break;
    575 
    576        case Formattable::kString:
    577            aString = va_arg(ap, char16_t*);
    578            if(aString){
    579                args[i].getString(temp);
    580                len = temp.length();
    581                temp.extract(0,len,aString);
    582                aString[len]=0;
    583            }else{
    584                *status= U_ILLEGAL_ARGUMENT_ERROR;
    585            }
    586            break;
    587 
    588        case Formattable::kObject:
    589            // This will never happen because MessageFormat doesn't
    590            // support kObject.  When MessageFormat is changed to
    591            // understand MeasureFormats, modify this code to do the
    592            // right thing. [alan]
    593            UPRV_UNREACHABLE_EXIT;
    594 
    595        // better not happen!
    596        case Formattable::kArray:
    597            UPRV_UNREACHABLE_EXIT;
    598        }
    599    }
    600 
    601    // clean up
    602    delete [] args;
    603 }
    604 
    605 #define SINGLE_QUOTE      ((char16_t)0x0027)
    606 #define CURLY_BRACE_LEFT  ((char16_t)0x007B)
    607 #define CURLY_BRACE_RIGHT ((char16_t)0x007D)
    608 
    609 #define STATE_INITIAL 0
    610 #define STATE_SINGLE_QUOTE 1
    611 #define STATE_IN_QUOTE 2
    612 #define STATE_MSG_ELEMENT 3
    613 
    614 #define MAppend(c) if (len < destCapacity) dest[len++] = c; else len++
    615 
    616 int32_t umsg_autoQuoteApostrophe(const char16_t* pattern,
    617                 int32_t patternLength,
    618                 char16_t* dest,
    619                 int32_t destCapacity,
    620                 UErrorCode* ec)
    621 {
    622    int32_t state = STATE_INITIAL;
    623    int32_t braceCount = 0;
    624    int32_t len = 0;
    625 
    626    if (ec == nullptr || U_FAILURE(*ec)) {
    627        return -1;
    628    }
    629 
    630    if (pattern == nullptr || patternLength < -1 || (dest == nullptr && destCapacity > 0)) {
    631        *ec = U_ILLEGAL_ARGUMENT_ERROR;
    632        return -1;
    633    }
    634    U_ASSERT(destCapacity >= 0);
    635 
    636    if (patternLength == -1) {
    637        patternLength = u_strlen(pattern);
    638    }
    639 
    640    for (int i = 0; i < patternLength; ++i) {
    641        char16_t c = pattern[i];
    642        switch (state) {
    643        case STATE_INITIAL:
    644            switch (c) {
    645            case SINGLE_QUOTE:
    646                state = STATE_SINGLE_QUOTE;
    647                break;
    648            case CURLY_BRACE_LEFT:
    649                state = STATE_MSG_ELEMENT;
    650                ++braceCount;
    651                break;
    652            }
    653            break;
    654 
    655        case STATE_SINGLE_QUOTE:
    656            switch (c) {
    657            case SINGLE_QUOTE:
    658                state = STATE_INITIAL;
    659                break;
    660            case CURLY_BRACE_LEFT:
    661            case CURLY_BRACE_RIGHT:
    662                state = STATE_IN_QUOTE;
    663                break;
    664            default:
    665                MAppend(SINGLE_QUOTE);
    666                state = STATE_INITIAL;
    667                break;
    668            }
    669        break;
    670 
    671        case STATE_IN_QUOTE:
    672            switch (c) {
    673            case SINGLE_QUOTE:
    674                state = STATE_INITIAL;
    675                break;
    676            }
    677            break;
    678 
    679        case STATE_MSG_ELEMENT:
    680            switch (c) {
    681            case CURLY_BRACE_LEFT:
    682                ++braceCount;
    683                break;
    684            case CURLY_BRACE_RIGHT:
    685                if (--braceCount == 0) {
    686                    state = STATE_INITIAL;
    687                }
    688                break;
    689            }
    690            break;
    691 
    692        default: // Never happens.
    693            break;
    694        }
    695 
    696        U_ASSERT(len >= 0);
    697        MAppend(c);
    698    }
    699 
    700    // End of scan
    701    if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
    702        MAppend(SINGLE_QUOTE);
    703    }
    704 
    705    return u_terminateUChars(dest, destCapacity, len, ec);
    706 }
    707 
    708 #endif /* #if !UCONFIG_NO_FORMATTING */